github.com/jmrodri/operator-sdk@v0.5.0/commands/operator-sdk/cmd/generate/k8s.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 generate
    16  
    17  import (
    18  	"fmt"
    19  	"io/ioutil"
    20  	"os/exec"
    21  	"path/filepath"
    22  	"strings"
    23  
    24  	genutil "github.com/operator-framework/operator-sdk/commands/operator-sdk/cmd/generate/internal"
    25  	"github.com/operator-framework/operator-sdk/internal/util/projutil"
    26  	"github.com/operator-framework/operator-sdk/pkg/scaffold"
    27  
    28  	log "github.com/sirupsen/logrus"
    29  	"github.com/spf13/cobra"
    30  )
    31  
    32  func NewGenerateK8SCmd() *cobra.Command {
    33  	return &cobra.Command{
    34  		Use:   "k8s",
    35  		Short: "Generates Kubernetes code for custom resource",
    36  		Long: `k8s generator generates code for custom resources given the API
    37  specs in pkg/apis/<group>/<version> directories to comply with kube-API
    38  requirements. Go code is generated under
    39  pkg/apis/<group>/<version>/zz_generated.deepcopy.go.
    40  
    41  Example:
    42  	$ operator-sdk generate k8s
    43  	$ tree pkg/apis
    44  	pkg/apis/
    45  	└── app
    46  		└── v1alpha1
    47  			├── zz_generated.deepcopy.go
    48  `,
    49  		RunE: k8sFunc,
    50  	}
    51  }
    52  
    53  func k8sFunc(cmd *cobra.Command, args []string) error {
    54  	if len(args) != 0 {
    55  		return fmt.Errorf("command %s doesn't accept any arguments", cmd.CommandPath())
    56  	}
    57  
    58  	// Only Go projects can generate k8s deepcopy code.
    59  	if err := projutil.CheckGoProjectCmd(cmd); err != nil {
    60  		return err
    61  	}
    62  
    63  	return K8sCodegen()
    64  }
    65  
    66  // K8sCodegen performs deepcopy code-generation for all custom resources under pkg/apis
    67  func K8sCodegen() error {
    68  	projutil.MustInProjectRoot()
    69  
    70  	wd := projutil.MustGetwd()
    71  	repoPkg := projutil.CheckAndGetProjectGoPkg()
    72  	srcDir := filepath.Join(wd, "vendor", "k8s.io", "code-generator")
    73  	binDir := filepath.Join(wd, scaffold.BuildBinDir)
    74  
    75  	if err := buildCodegenBinaries(binDir, srcDir); err != nil {
    76  		return err
    77  	}
    78  
    79  	gvMap, err := genutil.ParseGroupVersions()
    80  	if err != nil {
    81  		return fmt.Errorf("failed to parse group versions: (%v)", err)
    82  	}
    83  	gvb := &strings.Builder{}
    84  	for g, vs := range gvMap {
    85  		gvb.WriteString(fmt.Sprintf("%s:%v, ", g, vs))
    86  	}
    87  
    88  	log.Infof("Running deepcopy code-generation for Custom Resource group versions: [%v]\n", gvb.String())
    89  
    90  	if err := deepcopyGen(binDir, repoPkg, gvMap); err != nil {
    91  		return err
    92  	}
    93  
    94  	if err = defaulterGen(binDir, repoPkg, gvMap); err != nil {
    95  		return err
    96  	}
    97  
    98  	log.Info("Code-generation complete.")
    99  	return nil
   100  }
   101  
   102  func buildCodegenBinaries(binDir, codegenSrcDir string) error {
   103  	genDirs := []string{
   104  		"./cmd/defaulter-gen",
   105  		"./cmd/client-gen",
   106  		"./cmd/lister-gen",
   107  		"./cmd/informer-gen",
   108  		"./cmd/deepcopy-gen",
   109  	}
   110  	return genutil.BuildCodegenBinaries(genDirs, binDir, codegenSrcDir)
   111  }
   112  
   113  func deepcopyGen(binDir, repoPkg string, gvMap map[string][]string) (err error) {
   114  	apisPkg := filepath.Join(repoPkg, scaffold.ApisDir)
   115  	args := []string{
   116  		"--input-dirs", genutil.CreateFQApis(apisPkg, gvMap),
   117  		"--output-file-base", "zz_generated.deepcopy",
   118  		"--bounding-dirs", apisPkg,
   119  	}
   120  	cmd := exec.Command(filepath.Join(binDir, "deepcopy-gen"), args...)
   121  	if projutil.IsGoVerbose() {
   122  		err = projutil.ExecCmd(cmd)
   123  	} else {
   124  		cmd.Stdout = ioutil.Discard
   125  		cmd.Stderr = ioutil.Discard
   126  		err = cmd.Run()
   127  	}
   128  	if err != nil {
   129  		return fmt.Errorf("failed to perform deepcopy code-generation: %v", err)
   130  	}
   131  	return nil
   132  }
   133  
   134  func defaulterGen(binDir, repoPkg string, gvMap map[string][]string) (err error) {
   135  	apisPkg := filepath.Join(repoPkg, scaffold.ApisDir)
   136  	args := []string{
   137  		"--input-dirs", genutil.CreateFQApis(apisPkg, gvMap),
   138  		"--output-file-base", "zz_generated.defaults",
   139  	}
   140  	cmd := exec.Command(filepath.Join(binDir, "defaulter-gen"), args...)
   141  	if projutil.IsGoVerbose() {
   142  		err = projutil.ExecCmd(cmd)
   143  	} else {
   144  		cmd.Stdout = ioutil.Discard
   145  		cmd.Stderr = ioutil.Discard
   146  		err = cmd.Run()
   147  	}
   148  	if err != nil {
   149  		return fmt.Errorf("failed to perform defaulter code-generation: %v", err)
   150  	}
   151  	return nil
   152  }