Skip to content

restructure certwriter and certprovisioner packages #113

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged

Conversation

mengqiy
Copy link
Member

@mengqiy mengqiy commented Aug 20, 2018

This PR is ready for 1st round review.
Will add the tests very soon.

godoc:
http://35.232.176.188/pkg/sigs.k8s.io/controller-runtime/pkg/webhook/

@k8s-ci-robot k8s-ci-robot added size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. labels Aug 20, 2018
Copy link
Contributor

@droot droot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review is still in progress. Have only reviewed till cert/doc.go.

I was wondering if there is a way to split this review. Long reviews are really discouraging for the reviewers :)

s.CertDir = path.Join("k8s-webhook-server", "cert")
}
if s.KVMap == nil {
s.KVMap = map[string]interface{}{}
}
s.setBootstrappingDefault()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

almost missed this because simply assumed all stuff is being defaulted inline here (no func call).
May be from readability perspective, we can group the inline defaults above in separate method and invoke the method here ?

@@ -54,7 +56,10 @@ func (s *Server) setDefault() {
s.Port = 443
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do the defaults for s.Host and s.Service should be moved here from the setBootstrappingDefault method ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s.Host and s.Service is for bootstrapping the AdmissionWebhookConfiguration and Service.

s.CertGenerator = &generator.SelfSignedCertGenerator{}
}
if s.Writer == nil {
s.Writer = os.Stdout
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am a bit confused about what belongs to boostrapping and what belongs at the server level ? Looking at the attributes looks like all of them can be done inline in the setDefaults ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually they were in the same defaulting function and I didn't plan to distinguish them. But the linter keeps complaining about high cyclomatic complexity. Then I have to split this defauting function :/

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok.

// Provision the cert by creating new one or refreshing existing one.
s.certProvisioner.Provision(false)
// Inject the cert into MutatingWebhookConfiguration, ValidatingWebhookConfiguration and ConversionWebhook
s.certProvisioner.Inject(s.mutatingWebhookConfig, s.validatingWebhookConfig)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-reading the code, I have a few naming suggestion for Inject:
ApplyConfig ?
ConfigureWebhook ?
Configure ?

So it will read like:
Provision the certs and then the configure or apply the config for webhooks.

cc, err := s.clientConfig()

s.certProvisioner = &cert.Provisioner{
ClientConfig: cc,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wondering if this should be a parameter to the Inject method ?

Do we envision certProvisioner's Inject being called with different configs ? (by other programs)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we do that, then certProvisioner and certWrtier initialization can be moved to setDefault probably ? and bootstrap just becomes:

  • Generate the configuration
  • Apply the configuration

// TODO: use the helper in #98 when it merges.
func createOrReplace(c client.Client, obj runtime.Object, fn mutateFn) error {
func createOrReplaceHelper(c client.Client, obj runtime.Object, fn mutateFn) error {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm....looks like this could be useful in general. We might be able to move these under controller-runtime under some clientutil pkg.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This may be a temporary thing.
#98 will land sometime.

func (w *webhookClientConfig) withPath(path string) error {
if w.URL != nil {
u, err := url.Parse(*w.URL)
func (s *Server) clientConfigWithPath(path string) (*admissionregistration.WebhookClientConfig, error) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

comment explaining path will be helpful here.

}

if len(mutatingWebhooks) > 0 {
return &admissionregistration.MutatingWebhookConfiguration{
TypeMeta: metav1.TypeMeta{
APIVersion: "admissionregistration.k8s.io/v1beta1",
APIVersion: fmt.Sprintf("%s/%s", admissionregistration.GroupName, "v1beta1"),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think http pkg has some utility methods to manipulate the URL paths, would suggest using those.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm... Why handling apiVersion with URL manipulation util in http pkg?

if w.Service != nil {
w.Service.Path = &path
if cc.Service != nil {
cc.Service.Path = &path
}
return nil
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm..... may be we need ccWithPath type with methods it ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Made some changes here.

Build the Provisioner
provisioner := Provisioner{
CertWriter: admission.NewSecretCertWriter(admission.SecretCertWriterOptions{...}),
ClientConfig: cc,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I commented earlier if we can make it a parameter to the Inject method ?

Copy link
Contributor

@droot droot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Took another look, have some more comments.

return s.bootstrap(true)
}

// RefreshCert refreshes the certificate using Server's Provisioner if the certificate is expiring.
func (s *Server) RefreshCert() error {
func (s *Server) RefreshCert() (bool, error) {
objs := []runtime.Object{s.mutatingWebhookConfig, s.validatingWebhookConfig}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can have a method s.webhookConfigTarget() or s.webhookConfigObjects() (I am seeing this in multiple places) ?

err = s.RefreshCert()
if !changed {
continue
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should add a log statement indicating server is shutting down to refresh the certs.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@@ -189,21 +200,27 @@ func (s *Server) Start(stop <-chan struct{}) error {
errCh <- err
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wondering where writer is coming from ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

writer is package name here.

sMux: http.NewServeMux(),
registry: map[string]Webhook{},
ServerOptions: ops,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ops --> options

ops reads as operations :)

// Provision provisions certificates for for the WebhookClientConfig.
// It ensures the cert and CA are valid and not expiring.
// It updates the CABundle in the webhookClientConfig if necessary.
func (cp *Provisioner) Provision(dryrun bool) (bool, error) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am wondering if we should combine Provision and Inject methods into one by introducing parameters to Provision method because ideally, that should be one operation. provision and inject cc in the objects ?

}
}
return cp.CertWriter.Inject(objs...)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How do I ensure that caller have called Provision before Inject ? or is it okay ?

@@ -84,9 +89,15 @@ type BootstrapOptions struct {
// If neither Service nor Host is unspecified, Host will be defaulted to "localhost".
Host *string

// Provisioner provisions certificates for the admission webhook server.
// fid godoc Provisioner provisions certificates for the admission webhook server.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo: fid godoc

s.CertGenerator = &generator.SelfSignedCertGenerator{}
}
if s.Writer == nil {
s.Writer = os.Stdout
}
}

// bootstrap returns the configuration of admissionWebhookConfiguration in yaml format if dryrun is true.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment hasn't been updated.

if err != nil {
return nil, err

cc, err := s.clientConfig()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe you can have another function like getConfigs to get all the configs needed in bootstrap: mutatinWebhookConfig, validatingWHConfig and clientConfig

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clientConfig is not a runtime.Object. It's a field in both mutatinWebhookConfig and validatingWHConfig.

@@ -353,11 +381,11 @@ func (s *Server) admissionWebhook(path string, wh *admission.Webhook) (*admissio
if err != nil {
return nil, err
}
err = cc.withPath(path)
err = setPath(cc, path)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you using clientConfigWithPath instead of clientConfig and setPath?

// certGenerator generates the certificates.
certGenerator generator.CertGenerator
// path is the directory that the certificate and private key and CA certificate will be written.
path string
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you use FSCertWriterOptions instead of path and certGenerator? It has better readability

@mengqiy mengqiy force-pushed the prepare_for_conv_wh branch 2 times, most recently from 8395cd6 to 2b2a4ee Compare August 24, 2018 18:14
@mengqiy
Copy link
Member Author

mengqiy commented Aug 24, 2018

Addressed comments and rebased on #115. PTAL

@mengqiy
Copy link
Member Author

mengqiy commented Aug 24, 2018

Travis is failing due to an linter error.
It seems there is a bug with structcheck linter that it doesn't handle inlined fields correctly.

EDIT: stuctcheck linter doesn't support embeded fields, it is a known issue

@mengqiy mengqiy force-pushed the prepare_for_conv_wh branch from 2b2a4ee to e3ce169 Compare August 24, 2018 21:44
Copy link
Contributor

@droot droot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me.

s.CertGenerator = &generator.SelfSignedCertGenerator{}
}
if s.Writer == nil {
s.Writer = os.Stdout
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok.

// Otherwise, it creates the the admissionWebhookConfiguration objects and service if any.
// It also provisions the certificate for your admission server.
// It also provisions the certificate for the admission server.
func (s *Server) bootstrap(dryrun bool) error {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

May be we should rename this function to installWebhookConfig to make it more explicit. Also, can dryrun be a server option ?

once sync.Once
// Objects are the objects that will use the ClientConfig above.
Objects []runtime.Object
// Dryrun controls if the objects are sent to the API server or output in the io.Writer
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/output in/written to

@mengqiy mengqiy force-pushed the prepare_for_conv_wh branch from 0e45f79 to 2f1180d Compare August 29, 2018 23:16
@mengqiy
Copy link
Member Author

mengqiy commented Aug 29, 2018

Rebased on #123
And cleanup tests and some stale files.

@mengqiy mengqiy force-pushed the prepare_for_conv_wh branch from 2f1180d to 7fdb8b1 Compare August 29, 2018 23:55
@mengqiy
Copy link
Member Author

mengqiy commented Aug 29, 2018

Cherry-picked #126

@droot
Copy link
Contributor

droot commented Aug 30, 2018

Looks good to me. You can squash the commits, then we can merge it.

@mengqiy mengqiy force-pushed the prepare_for_conv_wh branch from 7fdb8b1 to 617592c Compare August 30, 2018 17:04
@mengqiy
Copy link
Member Author

mengqiy commented Aug 30, 2018

@droot Done

@mengqiy mengqiy force-pushed the prepare_for_conv_wh branch from 617592c to f297678 Compare August 30, 2018 18:00
@droot
Copy link
Contributor

droot commented Aug 30, 2018

/lgtm

@k8s-ci-robot k8s-ci-robot added the lgtm "Looks good to me", indicates that a PR is ready to be merged. label Aug 30, 2018
@mengqiy mengqiy added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Aug 30, 2018
@k8s-ci-robot
Copy link
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

Approval requirements bypassed by manually added approval.

This pull-request has been approved by: mengqiy

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@k8s-ci-robot k8s-ci-robot merged commit 069efa2 into kubernetes-sigs:admissionwebhook Aug 30, 2018
@mengqiy mengqiy deleted the prepare_for_conv_wh branch August 30, 2018 20:38
DirectXMan12 pushed a commit that referenced this pull request Jan 31, 2020
Add basic test for kubebuilder create config --crds
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
approved Indicates a PR has been approved by an approver from all required OWNERS files. cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. lgtm "Looks good to me", indicates that a PR is ready to be merged. size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants