sigs.k8s.io/kubebuilder/v3@v3.14.0/pkg/plugins/golang/v3/webhook.go (about)

     1  /*
     2  Copyright 2020 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  //go:deprecated This package has been deprecated in favor of v4
    18  package v3
    19  
    20  import (
    21  	"fmt"
    22  
    23  	"github.com/spf13/pflag"
    24  
    25  	"sigs.k8s.io/kubebuilder/v3/pkg/config"
    26  	"sigs.k8s.io/kubebuilder/v3/pkg/machinery"
    27  	"sigs.k8s.io/kubebuilder/v3/pkg/model/resource"
    28  	"sigs.k8s.io/kubebuilder/v3/pkg/plugin"
    29  	pluginutil "sigs.k8s.io/kubebuilder/v3/pkg/plugin/util"
    30  	goPlugin "sigs.k8s.io/kubebuilder/v3/pkg/plugins/golang"
    31  	"sigs.k8s.io/kubebuilder/v3/pkg/plugins/golang/v3/scaffolds"
    32  )
    33  
    34  // defaultWebhookVersion is the default mutating/validating webhook config API version to scaffold.
    35  const defaultWebhookVersion = "v1"
    36  
    37  var _ plugin.CreateWebhookSubcommand = &createWebhookSubcommand{}
    38  
    39  type createWebhookSubcommand struct {
    40  	config config.Config
    41  	// For help text.
    42  	commandName string
    43  
    44  	options *goPlugin.Options
    45  
    46  	resource *resource.Resource
    47  
    48  	// force indicates that the resource should be created even if it already exists
    49  	force bool
    50  }
    51  
    52  func (p *createWebhookSubcommand) UpdateMetadata(cliMeta plugin.CLIMetadata, subcmdMeta *plugin.SubcommandMetadata) {
    53  	p.commandName = cliMeta.CommandName
    54  
    55  	subcmdMeta.Description = `Scaffold a webhook for an API resource. You can choose to scaffold defaulting,
    56  validating and/or conversion webhooks.
    57  `
    58  	subcmdMeta.Examples = fmt.Sprintf(`  # Create defaulting and validating webhooks for Group: ship, Version: v1beta1
    59    # and Kind: Frigate
    60    %[1]s create webhook --group ship --version v1beta1 --kind Frigate --defaulting --programmatic-validation
    61  
    62    # Create conversion webhook for Group: ship, Version: v1beta1
    63    # and Kind: Frigate
    64    %[1]s create webhook --group ship --version v1beta1 --kind Frigate --conversion
    65  `, cliMeta.CommandName)
    66  }
    67  
    68  func (p *createWebhookSubcommand) BindFlags(fs *pflag.FlagSet) {
    69  	p.options = &goPlugin.Options{}
    70  
    71  	fs.StringVar(&p.options.Plural, "plural", "", "resource irregular plural form")
    72  
    73  	fs.StringVar(&p.options.WebhookVersion, "webhook-version", defaultWebhookVersion,
    74  		"version of {Mutating,Validating}WebhookConfigurations to scaffold. Options: [v1, v1beta1]")
    75  	fs.BoolVar(&p.options.DoDefaulting, "defaulting", false,
    76  		"if set, scaffold the defaulting webhook")
    77  	fs.BoolVar(&p.options.DoValidation, "programmatic-validation", false,
    78  		"if set, scaffold the validating webhook")
    79  	fs.BoolVar(&p.options.DoConversion, "conversion", false,
    80  		"if set, scaffold the conversion webhook")
    81  
    82  	fs.BoolVar(&p.force, "force", false,
    83  		"attempt to create resource even if it already exists")
    84  
    85  	// (not required raise an error in this case)
    86  	// nolint:errcheck,gosec
    87  	fs.MarkDeprecated("webhook-version", deprecateMsg)
    88  }
    89  
    90  func (p *createWebhookSubcommand) InjectConfig(c config.Config) error {
    91  	p.config = c
    92  
    93  	return nil
    94  }
    95  
    96  func (p *createWebhookSubcommand) InjectResource(res *resource.Resource) error {
    97  	p.resource = res
    98  
    99  	p.options.UpdateResource(p.resource, p.config)
   100  
   101  	if err := p.resource.Validate(); err != nil {
   102  		return err
   103  	}
   104  
   105  	if !p.resource.HasDefaultingWebhook() && !p.resource.HasValidationWebhook() && !p.resource.HasConversionWebhook() {
   106  		return fmt.Errorf("%s create webhook requires at least one of --defaulting,"+
   107  			" --programmatic-validation and --conversion to be true", p.commandName)
   108  	}
   109  
   110  	// check if resource exist to create webhook
   111  	if r, err := p.config.GetResource(p.resource.GVK); err != nil {
   112  		return fmt.Errorf("%s create webhook requires a previously created API ", p.commandName)
   113  	} else if r.Webhooks != nil && !r.Webhooks.IsEmpty() && !p.force {
   114  		return fmt.Errorf("webhook resource already exists")
   115  	}
   116  
   117  	// nolint:staticcheck
   118  	if pluginutil.HasDifferentWebhookVersion(p.config, p.resource.Webhooks.WebhookVersion) {
   119  		return fmt.Errorf("only one webhook version can be used for all resources, cannot add %q",
   120  			p.resource.Webhooks.WebhookVersion)
   121  	}
   122  
   123  	return nil
   124  }
   125  
   126  func (p *createWebhookSubcommand) Scaffold(fs machinery.Filesystem) error {
   127  	scaffolder := scaffolds.NewWebhookScaffolder(p.config, *p.resource, p.force)
   128  	scaffolder.InjectFS(fs)
   129  	return scaffolder.Scaffold()
   130  }
   131  
   132  func (p *createWebhookSubcommand) PostScaffold() error {
   133  	if p.resource.Webhooks.WebhookVersion == "v1beta1" {
   134  		if err := applyScaffoldCustomizationsForVbeta1(); err != nil {
   135  			return err
   136  		}
   137  	}
   138  
   139  	err := pluginutil.RunCmd("Update dependencies", "go", "mod", "tidy")
   140  	if err != nil {
   141  		return err
   142  	}
   143  
   144  	err = pluginutil.RunCmd("Running make", "make", "generate")
   145  	if err != nil {
   146  		return err
   147  	}
   148  	fmt.Print("Next: implement your new Webhook and generate the manifests with:\n$ make manifests\n")
   149  
   150  	return nil
   151  }