github.com/tilt-dev/tilt@v0.33.15-0.20240515162809-0a22ed45d8a0/internal/cli/openapi.go (about) 1 package cli 2 3 import ( 4 "context" 5 "encoding/json" 6 "net/http" 7 "time" 8 9 "github.com/spf13/cobra" 10 "k8s.io/cli-runtime/pkg/genericclioptions" 11 "k8s.io/client-go/rest" 12 "k8s.io/client-go/transport" 13 14 "github.com/tilt-dev/tilt-apiserver/pkg/server/apiserver" 15 "github.com/tilt-dev/tilt/internal/analytics" 16 engineanalytics "github.com/tilt-dev/tilt/internal/engine/analytics" 17 "github.com/tilt-dev/tilt/internal/hud/server" 18 "github.com/tilt-dev/tilt/internal/store" 19 "github.com/tilt-dev/tilt/internal/xdg" 20 "github.com/tilt-dev/tilt/pkg/assets" 21 "github.com/tilt-dev/tilt/pkg/model" 22 ) 23 24 type openapiCmd struct { 25 streams genericclioptions.IOStreams 26 } 27 28 var _ tiltCmd = &openapiCmd{} 29 30 func newOpenapiCmd(streams genericclioptions.IOStreams) *openapiCmd { 31 return &openapiCmd{streams: streams} 32 } 33 34 func (c *openapiCmd) name() model.TiltSubcommand { return "openapi" } 35 36 func (c *openapiCmd) register() *cobra.Command { 37 cmd := &cobra.Command{ 38 Use: "openapi", 39 Short: "Print the openapi spec of the current tilt binary", 40 Example: "tilt dump openapi > swagger.json", 41 } 42 43 return cmd 44 } 45 46 func (c *openapiCmd) run(ctx context.Context, args []string) error { 47 a := analytics.Get(ctx) 48 49 cmdTags := engineanalytics.CmdTags(map[string]string{}) 50 a.Incr("cmd.openapi", cmdTags.AsMap()) 51 defer a.Flush(time.Second) 52 53 hs, err := newHeadlessServer(ctx) 54 if err != nil { 55 return err 56 } 57 defer hs.tearDown(ctx) 58 59 restConfig := hs.loopbackClientConfig 60 trConfig, err := restConfig.TransportConfig() 61 if err != nil { 62 return err 63 } 64 65 tr, err := transport.New(trConfig) 66 if err != nil { 67 return err 68 } 69 70 httpClient := http.Client{Transport: tr} 71 resp, err := httpClient.Get(restConfig.Host + "/openapi/v2") 72 if err != nil { 73 return err 74 } 75 defer resp.Body.Close() 76 77 var msg json.RawMessage 78 err = json.NewDecoder(resp.Body).Decode(&msg) 79 if err != nil { 80 return err 81 } 82 83 encoder := json.NewEncoder(c.streams.Out) 84 encoder.SetIndent("", " ") 85 return encoder.Encode(msg) 86 } 87 88 type headlessServer struct { 89 memconn apiserver.ConnProvider 90 hudsc *server.HeadsUpServerController 91 loopbackClientConfig *rest.Config 92 } 93 94 func newHeadlessServer(ctx context.Context) (*headlessServer, error) { 95 memconn := server.ProvideMemConn() 96 genCert, err := server.ProvideKeyCert("headless", "localhost", 0, xdg.NewTiltDevBase()) 97 if err != nil { 98 return nil, err 99 } 100 serverOptions, err := server.ProvideTiltServerOptionsForHeadless(ctx, genCert, memconn, tiltInfo()) 101 if err != nil { 102 return nil, err 103 } 104 webListener, err := server.ProvideWebListener("localhost", 0) 105 if err != nil { 106 return nil, err 107 } 108 hudsc := server.ProvideHeadsUpServerController( 109 nil, "tilt-headless", webListener, serverOptions, 110 &server.HeadsUpServer{}, assets.NewFakeServer(), model.WebURL{}) 111 st := store.NewTestingStore() 112 err = hudsc.SetUp(ctx, st) 113 if err != nil { 114 return nil, err 115 } 116 return &headlessServer{ 117 memconn: memconn, 118 hudsc: hudsc, 119 loopbackClientConfig: serverOptions.GenericConfig.LoopbackClientConfig, 120 }, nil 121 } 122 123 func (hs *headlessServer) tearDown(ctx context.Context) { 124 hs.hudsc.TearDown(ctx) 125 }