github.com/mkimuram/operator-sdk@v0.7.1-0.20190410172100-52ad33a4bda0/cmd/operator-sdk/internal/genutil/openapi.go (about) 1 // Copyright 2018 The Operator-SDK Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package genutil 16 17 import ( 18 "fmt" 19 "os/exec" 20 "path/filepath" 21 "strings" 22 23 "github.com/operator-framework/operator-sdk/internal/pkg/scaffold" 24 "github.com/operator-framework/operator-sdk/internal/pkg/scaffold/input" 25 "github.com/operator-framework/operator-sdk/internal/util/k8sutil" 26 "github.com/operator-framework/operator-sdk/internal/util/projutil" 27 28 log "github.com/sirupsen/logrus" 29 ) 30 31 // OpenAPIGen generates OpenAPI validation specs for all CRD's in dirs. hf is 32 // a path to a header file containing text to add to generated files. 33 func OpenAPIGen(hf string) error { 34 projutil.MustInProjectRoot() 35 36 absProjectPath := projutil.MustGetwd() 37 repoPkg := projutil.CheckAndGetProjectGoPkg() 38 srcDir := filepath.Join(absProjectPath, "vendor", "k8s.io", "kube-openapi") 39 binDir := filepath.Join(absProjectPath, scaffold.BuildBinDir) 40 41 if err := buildOpenAPIGenBinary(binDir, srcDir); err != nil { 42 return err 43 } 44 45 gvMap, err := parseGroupVersions() 46 if err != nil { 47 return fmt.Errorf("failed to parse group versions: (%v)", err) 48 } 49 gvb := &strings.Builder{} 50 for g, vs := range gvMap { 51 gvb.WriteString(fmt.Sprintf("%s:%v, ", g, vs)) 52 } 53 54 log.Infof("Running OpenAPI code-generation for Custom Resource group versions: [%v]\n", gvb.String()) 55 56 apisPkg := filepath.Join(repoPkg, scaffold.ApisDir) 57 fqApiStr := createFQApis(apisPkg, gvMap) 58 fqApis := strings.Split(fqApiStr, ",") 59 f := func(a string) error { return openAPIGen(binDir, a, fqApis) } 60 if err = withHeaderFile(hf, f); err != nil { 61 return err 62 } 63 64 s := &scaffold.Scaffold{} 65 cfg := &input.Config{ 66 Repo: repoPkg, 67 AbsProjectPath: absProjectPath, 68 ProjectName: filepath.Base(absProjectPath), 69 } 70 crds, err := k8sutil.GetCRDs(scaffold.CRDsDir) 71 if err != nil { 72 return err 73 } 74 for _, crd := range crds { 75 g, v, k := crd.Spec.Group, crd.Spec.Version, crd.Spec.Names.Kind 76 if v == "" { 77 if len(crd.Spec.Versions) != 0 { 78 v = crd.Spec.Versions[0].Name 79 } else { 80 return fmt.Errorf("crd of group %s kind %s has no version", g, k) 81 } 82 } 83 r, err := scaffold.NewResource(g+"/"+v, k) 84 if err != nil { 85 return err 86 } 87 err = s.Execute(cfg, 88 &scaffold.CRD{Resource: r, IsOperatorGo: projutil.IsOperatorGo()}, 89 ) 90 if err != nil { 91 return err 92 } 93 } 94 95 log.Info("Code-generation complete.") 96 return nil 97 } 98 99 func buildOpenAPIGenBinary(binDir, codegenSrcDir string) error { 100 genDirs := []string{"./cmd/openapi-gen"} 101 return buildCodegenBinaries(genDirs, binDir, codegenSrcDir) 102 } 103 104 func openAPIGen(binDir, hf string, fqApis []string) (err error) { 105 cgPath := filepath.Join(binDir, "openapi-gen") 106 for _, fqApi := range fqApis { 107 args := []string{ 108 "--input-dirs", fqApi, 109 "--output-package", fqApi, 110 "--output-file-base", "zz_generated.openapi", 111 // openapi-gen requires a boilerplate file. Either use header or an 112 // empty file if header is empty. 113 "--go-header-file", hf, 114 } 115 cmd := exec.Command(cgPath, args...) 116 if err = projutil.ExecCmd(cmd); err != nil { 117 return fmt.Errorf("failed to perform openapi code-generation: %v", err) 118 } 119 } 120 return nil 121 }