github.skymusic.top/operator-framework/operator-sdk@v0.8.2/cmd/operator-sdk/add/api.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 add
    16  
    17  import (
    18  	"fmt"
    19  
    20  	"github.com/operator-framework/operator-sdk/cmd/operator-sdk/internal/genutil"
    21  	"github.com/operator-framework/operator-sdk/internal/pkg/scaffold"
    22  	"github.com/operator-framework/operator-sdk/internal/pkg/scaffold/input"
    23  	"github.com/operator-framework/operator-sdk/internal/util/projutil"
    24  
    25  	log "github.com/sirupsen/logrus"
    26  	"github.com/spf13/cobra"
    27  )
    28  
    29  var (
    30  	apiVersion string
    31  	kind       string
    32  )
    33  
    34  func newAddApiCmd() *cobra.Command {
    35  	apiCmd := &cobra.Command{
    36  		Use:   "api",
    37  		Short: "Adds a new api definition under pkg/apis",
    38  		Long: `operator-sdk add api --kind=<kind> --api-version=<group/version> creates the
    39  api definition for a new custom resource under pkg/apis. This command must be
    40  run from the project root directory. If the api already exists at
    41  pkg/apis/<group>/<version> then the command will not overwrite and return an
    42  error.
    43  
    44  This command runs Kubernetes deepcopy and OpenAPI V3 generators on tagged
    45  types in all paths under pkg/apis. Go code is generated under
    46  pkg/apis/<group>/<version>/zz_generated.{deepcopy,openapi}.go. CRD's are
    47  generated, or updated if they exist for a particular group + version + kind,
    48  under deploy/crds/<group>_<version>_<kind>_crd.yaml; OpenAPI V3 validation YAML
    49  is generated as a 'validation' object.
    50  
    51  Example:
    52  	$ operator-sdk add api --api-version=app.example.com/v1alpha1 --kind=AppService
    53  	$ tree pkg/apis
    54  	pkg/apis/
    55  	├── addtoscheme_app_appservice.go
    56  	├── apis.go
    57  	└── app
    58  		└── v1alpha1
    59  			├── doc.go
    60  			├── register.go
    61  			├── appservice_types.go
    62  			├── zz_generated.deepcopy.go
    63  			├── zz_generated.openapi.go
    64  	$ tree deploy/crds
    65  	├── deploy/crds/app_v1alpha1_appservice_cr.yaml
    66  	├── deploy/crds/app_v1alpha1_appservice_crd.yaml
    67  `,
    68  		RunE: apiRun,
    69  	}
    70  
    71  	apiCmd.Flags().StringVar(&apiVersion, "api-version", "", "Kubernetes APIVersion that has a format of $GROUP_NAME/$VERSION (e.g app.example.com/v1alpha1)")
    72  	if err := apiCmd.MarkFlagRequired("api-version"); err != nil {
    73  		log.Fatalf("Failed to mark `api-version` flag for `add api` subcommand as required")
    74  	}
    75  	apiCmd.Flags().StringVar(&kind, "kind", "", "Kubernetes resource Kind name. (e.g AppService)")
    76  	if err := apiCmd.MarkFlagRequired("kind"); err != nil {
    77  		log.Fatalf("Failed to mark `kind` flag for `add api` subcommand as required")
    78  	}
    79  
    80  	return apiCmd
    81  }
    82  
    83  func apiRun(cmd *cobra.Command, args []string) error {
    84  	projutil.MustInProjectRoot()
    85  
    86  	// Only Go projects can add apis.
    87  	if err := projutil.CheckGoProjectCmd(cmd); err != nil {
    88  		return err
    89  	}
    90  
    91  	log.Infof("Generating api version %s for kind %s.", apiVersion, kind)
    92  
    93  	// Create and validate new resource.
    94  	r, err := scaffold.NewResource(apiVersion, kind)
    95  	if err != nil {
    96  		return err
    97  	}
    98  
    99  	absProjectPath := projutil.MustGetwd()
   100  
   101  	cfg := &input.Config{
   102  		Repo:           projutil.CheckAndGetProjectGoPkg(),
   103  		AbsProjectPath: absProjectPath,
   104  	}
   105  
   106  	s := &scaffold.Scaffold{}
   107  	err = s.Execute(cfg,
   108  		&scaffold.Types{Resource: r},
   109  		&scaffold.AddToScheme{Resource: r},
   110  		&scaffold.Register{Resource: r},
   111  		&scaffold.Doc{Resource: r},
   112  		&scaffold.CR{Resource: r},
   113  		&scaffold.CRD{Resource: r, IsOperatorGo: projutil.IsOperatorGo()},
   114  	)
   115  	if err != nil {
   116  		return fmt.Errorf("api scaffold failed: (%v)", err)
   117  	}
   118  
   119  	// update deploy/role.yaml for the given resource r.
   120  	if err := scaffold.UpdateRoleForResource(r, absProjectPath); err != nil {
   121  		return fmt.Errorf("failed to update the RBAC manifest for the resource (%v, %v): (%v)", r.APIVersion, r.Kind, err)
   122  	}
   123  
   124  	// Run k8s codegen for deepcopy
   125  	if err := genutil.K8sCodegen(); err != nil {
   126  		return err
   127  	}
   128  
   129  	// Generate a validation spec for the new CRD.
   130  	if err := genutil.OpenAPIGen(); err != nil {
   131  		return err
   132  	}
   133  
   134  	log.Info("API generation complete.")
   135  	return nil
   136  }