@@ -6,6 +6,8 @@ package main
66
77import (
88 "fmt"
9+ "io"
10+ "net/http"
911 "net/url"
1012 "os"
1113 "path/filepath"
@@ -87,7 +89,7 @@ func loadSDKVersionFromFile(file string) (string, error) {
8789
8890 sdkVersion := strings .TrimSpace (string (version ))
8991 if sdkVersion == "" {
90- return "" , fmt .Errorf ("sdk version cannot be empty: %s" , file )
92+ return "" , fmt .Errorf ("sdk version cannot be empty: %s" , f )
9193 }
9294
9395 return sdkVersion , nil
@@ -96,29 +98,70 @@ func loadSDKVersionFromFile(file string) (string, error) {
9698func loadAPIFromFile (file string ) (* openapi3.T , error ) {
9799 wd , err := os .Getwd ()
98100 if err != nil {
99- return nil , fmt .Errorf ("error getting current working directory: %v" , err )
100-
101+ return nil , fmt .Errorf ("error getting current working directory: %w" , err )
101102 }
103+
102104 p := filepath .Join (filepath .Dir (wd ), file )
103105 omicronVersion , err := os .ReadFile (p )
104106 if err != nil {
105- return nil , fmt .Errorf ("error retrieving Omicron version: %v" , err )
107+ return nil , fmt .Errorf ("error retrieving omicron version from %s : %w" , p , err )
106108 }
109+
107110 ov := strings .TrimSpace (string (omicronVersion ))
111+ if ov == "" {
112+ return nil , fmt .Errorf ("omicron version cannot be empty: %s" , p )
113+ }
108114
109- // TODO: actually host the spec here.
110- // uri := "https://api.oxide.computer"
111- uri := fmt .Sprintf ("https://raw.githubusercontent.com/oxidecomputer/omicron/%s/openapi/nexus.json" , ov )
112- u , err := url .Parse (uri )
115+ specURL , err := getOpenAPISpecURL (ov )
113116 if err != nil {
114- return nil , fmt .Errorf ("error parsing url %q : %v" , uri , err )
117+ return nil , fmt .Errorf ("error getting openapi specification url : %w" , err )
115118 }
116119
117- // Load the open API spec from the URI.
118- doc , err := openapi3 .NewLoader ().LoadFromURI (u )
120+ doc , err := openapi3 .NewLoader ().LoadFromURI (specURL )
119121 if err != nil {
120- return nil , fmt .Errorf ("error loading openAPI spec from %q: %v " , uri , err )
122+ return nil , fmt .Errorf ("error loading openapi specification from %q: %w " , specURL , err )
121123 }
122124
123125 return doc , nil
124126}
127+
128+ // getOpenAPISpecURL returns the URL of the versioned OpenAPI specification for
129+ // the given Omicron version.
130+ //
131+ // The upstream Omicron repository contains versioned OpenAPI specifications
132+ // (e.g., nexus-2025120300.0.0-dfe193.json). The nexus-latest.json file is a
133+ // symbolic link to the current versioned specification file. Since
134+ // raw.githubusercontent.com doesn't follow symbolic links, we first fetch the
135+ // symbolic link target to get the versioned filename, then construct the URL
136+ // to the actual versioned specification.
137+ func getOpenAPISpecURL (omicronVersion string ) (* url.URL , error ) {
138+ rawURL := fmt .Sprintf ("https://raw.githubusercontent.com/oxidecomputer/omicron/%s" , omicronVersion )
139+ baseURL , err := url .Parse (rawURL )
140+ if err != nil {
141+ return nil , fmt .Errorf ("error parsing base url %q: %w" , rawURL , err )
142+ }
143+
144+ latestURL := baseURL .JoinPath ("openapi" , "nexus" , "nexus-latest.json" )
145+ resp , err := http .DefaultClient .Get (latestURL .String ())
146+ if err != nil {
147+ return nil , fmt .Errorf ("error fetching latest openapi file from %q: %w" , latestURL , err )
148+ }
149+ defer resp .Body .Close ()
150+
151+ body , err := io .ReadAll (resp .Body )
152+ if err != nil {
153+ return nil , fmt .Errorf ("error reading response body from %q: %w" , latestURL , err )
154+ }
155+
156+ if resp .StatusCode != http .StatusOK {
157+ return nil , fmt .Errorf ("unexpected status code %d fetching %q: %s" ,
158+ resp .StatusCode , latestURL , strings .TrimSpace (string (body )))
159+ }
160+
161+ versioned := strings .TrimSpace (string (body ))
162+ if versioned == "" {
163+ return nil , fmt .Errorf ("versioned filename is empty in %q" , latestURL )
164+ }
165+
166+ return baseURL .JoinPath ("openapi" , "nexus" , versioned ), nil
167+ }
0 commit comments