Skip to content

Modify apply logic in direct.go #128

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

Closed

Conversation

atoato88
Copy link
Contributor

This PR changes a logic to apply in direct.go, because current codes ignores some features which are validate and namespace defaulting, etc.

I would like to add tests for this topics later.

@k8s-ci-robot k8s-ci-robot added do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. labels Oct 28, 2020
@k8s-ci-robot k8s-ci-robot added the size/S Denotes a PR that changes 10-29 lines, ignoring generated files. label Oct 28, 2020
@atoato88 atoato88 changed the title [WIP] Modify apply login in direct.go [WIP] Modify apply logic in direct.go Nov 3, 2020
@atoato88
Copy link
Contributor Author

atoato88 commented Nov 5, 2020

I think current codes has two points to fix.

  1. namespace is ignored in apply process

namespace is set at here, but this field is ignored, because SetObject is used here.
In SetObject, o.objectsCached is set to true.
This objectsCached is used at GetObjects in ApplyOptions.

namespace is used at here in GetObjects, and validate also.
But this logic don't be processed if o.objectsCached is true.

For fixing this, we should not use SetObject. This is why this PR uses TempFile.

  1. Use validate option on args

We should use a validator in applyOpts settings.

@atoato88
Copy link
Contributor Author

atoato88 commented Nov 5, 2020

I try to add some unit tests, but some features which are related to validator and namespace needs real k8s cluster.
It's difficult to add unit test for this code...

@atoato88 atoato88 changed the title [WIP] Modify apply logic in direct.go Modify apply logic in direct.go Nov 5, 2020
@k8s-ci-robot k8s-ci-robot removed the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Nov 5, 2020
@atoato88
Copy link
Contributor Author

atoato88 commented Nov 5, 2020

Current PR set is just update function in direct.go, not includes tests related with this PR.
I would like to try to add test to this code, but I think it is better to review updated code first.
Could you review this?

@atoato88
Copy link
Contributor Author

/assign @justinsb
Could you review this?

@k8s-ci-robot
Copy link
Contributor

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: atoato88
To complete the pull request process, please assign justinsb after the PR has been reviewed.
You can assign the PR to them by writing /assign @justinsb in a comment when ready.

The full list of commands accepted by this bot can be found 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 added size/L Denotes a PR that changes 100-499 lines, ignoring generated files. and removed size/S Denotes a PR that changes 10-29 lines, ignoring generated files. labels Jan 13, 2021
@atoato88 atoato88 force-pushed the modify-direct-apply branch from 1b19c86 to 9f479ca Compare January 13, 2021 07:12
@k8s-ci-robot k8s-ci-robot added size/M Denotes a PR that changes 30-99 lines, ignoring generated files. and removed size/L Denotes a PR that changes 100-499 lines, ignoring generated files. labels Jan 13, 2021
@atoato88
Copy link
Contributor Author

I've update code set, and this PR fix errors in guestbook-operator.

Copy link
Contributor

@darkowlzz darkowlzz left a comment

Choose a reason for hiding this comment

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

Hi, Thanks for working on improving the applier. I've been using the applier package in some of my projects. Based on some experience using it and my use cases, I've left a few comments.
Hope they are helpful 🙂

@@ -27,24 +26,36 @@ func (d *DirectApplier) Apply(ctx context.Context,
validate bool,
extraArgs ...string,
) error {
tmpFile, err := ioutil.TempFile("", "tmp-manifest")
Copy link
Contributor

Choose a reason for hiding this comment

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

Do you think it'll be safer to have some randomness in the name?
I've a use case where two go routines use the applier on separate manifests at the same time.
With a constant name, there can be conflict.
A random name with a prefix and/or suffic may be safer?
I'm referring to the suffix example in https://golang.org/pkg/io/ioutil/#TempFile

}
tmpFile.Write([]byte(manifest))
tmpFile.Close()
tmpFile, err = os.Open(tmpFile.Name())
Copy link
Contributor

@darkowlzz darkowlzz Jan 14, 2021

Choose a reason for hiding this comment

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

We can have an error check for this.

BTW, does this not work if you assign tmpFile to os.Stdin directly, instead of closing and opening the same file? Both are *os.File for the same file.

@atoato88
Copy link
Contributor Author

@darkowlzz
Thank you to comment here. 😄
I'll check it and update code-set.

This commit changes a logic to apply in direct.go, because current codes
ignores some features which are validate, etc.
@atoato88 atoato88 force-pushed the modify-direct-apply branch from 9f479ca to a1fe1ee Compare January 21, 2021 01:21
@courageJ
Copy link

Hi, any updates for this?

We met similar issue because of the non-defaulting namespace. Taking the sample operator as an example (I manually added the namespace to all resources in manifest file so all resources should be deployed successfully), in the latest kubebuilder-declaritive-pattern, when the reconciled calls to update the Status of CR, it fails to find the CR while the CR is available when running kubectl -n <namespace> get guestbook guestbook-sample.

Error in controller:

2021-04-19T15:47:18.288-0400	INFO	updating status	{"name": "guestbook-sample", "status": {"healthy":true}}
2021-04-19T15:47:18.344-0400	ERROR	updating status	{"error": "guestbooks.addons.example.org \"guestbook-sample\" not found"}
github.com/go-logr/zapr.(*zapLogger).Error
	/usr/local/google/home/wujie/go/pkg/mod/github.com/go-logr/[email protected]/zapr.go:132
sigs.k8s.io/kubebuilder-declarative-pattern/pkg/patterns/addon/pkg/status.(*aggregator).Reconciled
	/usr/local/google/home/wujie/go/src/github.com/kubebuilder-declarative-pattern/pkg/patterns/addon/pkg/status/aggregate.go:100
sigs.k8s.io/kubebuilder-declarative-pattern/pkg/patterns/declarative.(*StatusBuilder).Reconciled
	/usr/local/google/home/wujie/go/src/github.com/kubebuilder-declarative-pattern/pkg/patterns/declarative/status.go:62
sigs.k8s.io/kubebuilder-declarative-pattern/pkg/patterns/declarative.(*Reconciler).reconcileExists.func1
	/usr/local/google/home/wujie/go/src/github.com/kubebuilder-declarative-pattern/pkg/patterns/declarative/reconciler.go:182
sigs.k8s.io/kubebuilder-declarative-pattern/pkg/patterns/declarative.(*Reconciler).reconcileExists
	/usr/local/google/home/wujie/go/src/github.com/kubebuilder-declarative-pattern/pkg/patterns/declarative/reconciler.go:270
sigs.k8s.io/kubebuilder-declarative-pattern/pkg/patterns/declarative.(*Reconciler).Reconcile
	/usr/local/google/home/wujie/go/src/github.com/kubebuilder-declarative-pattern/pkg/patterns/declarative/reconciler.go:144
sigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller).reconcileHandler
	/usr/local/google/home/wujie/go/pkg/mod/sigs.k8s.io/[email protected]/pkg/internal/controller/controller.go:293
sigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller).processNextWorkItem
	/usr/local/google/home/wujie/go/pkg/mod/sigs.k8s.io/[email protected]/pkg/internal/controller/controller.go:248
sigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller).Start.func1.1
	/usr/local/google/home/wujie/go/pkg/mod/sigs.k8s.io/[email protected]/pkg/internal/controller/controller.go:211
k8s.io/apimachinery/pkg/util/wait.JitterUntilWithContext.func1
	/usr/local/google/home/wujie/go/pkg/mod/k8s.io/[email protected]/pkg/util/wait/wait.go:185
k8s.io/apimachinery/pkg/util/wait.BackoffUntil.func1
	/usr/local/google/home/wujie/go/pkg/mod/k8s.io/[email protected]/pkg/util/wait/wait.go:155
k8s.io/apimachinery/pkg/util/wait.BackoffUntil
	/usr/local/google/home/wujie/go/pkg/mod/k8s.io/[email protected]/pkg/util/wait/wait.go:156
k8s.io/apimachinery/pkg/util/wait.JitterUntil
	/usr/local/google/home/wujie/go/pkg/mod/k8s.io/[email protected]/pkg/util/wait/wait.go:133
k8s.io/apimachinery/pkg/util/wait.JitterUntilWithContext
	/usr/local/google/home/wujie/go/pkg/mod/k8s.io/[email protected]/pkg/util/wait/wait.go:185
k8s.io/apimachinery/pkg/util/wait.UntilWithContext
	/usr/local/google/home/wujie/go/pkg/mod/k8s.io/[email protected]/pkg/util/wait/wait.go:99

Fetch CR in cluster

⇒  k get guestbook guestbook-sample -n <namespace>
NAME               AGE
guestbook-sample   2m34s

Thanks

@atoato88
Copy link
Contributor Author

@courageJ
Thank you to comment 🎉

(I manually added the namespace to all resources in manifest file so all resources should be deployed successfully),

As I said comment above, Current code of direct.go bypass the namespace defaulting, metadata.namespace field in all manifests is mandatory in current code, I think.
So current guestbook-operator will error because this operator use manifests which doesn't have metadata.namespace field.

This error doesn't occur when use exec.go not direct.go by changing here.

We needs to add metadata.namespace to manifests as a workaround.
Actually, other addon-operators (example: coredns-operator) use manifests which includes metadata.namespace. This is because cluster-addons usually run on kube-system namespace, I think.

Current code of this PR may fix this behavior, but we need a test code for this Apply function before this PR merge.
That's why I create a other PR which add tests for direct.go on yesterday.

@atoato88
Copy link
Contributor Author

@justinsb
What do you think about above?
It's appreciate if any comments.

@JeffLuoo
Copy link

JeffLuoo commented Jun 16, 2021

I tried to run the guestbook sample locally following the instruction here and ran into the following error:

        /usr/local/google/home/jeffluoo/dev/kubebuilder-declarative-pattern/examples/guestbook-operator/vendor/k8s.io/apimachinery/pkg/util/wait/wait.go:156
k8s.io/apimachinery/pkg/util/wait.JitterUntil
        /usr/local/google/home/jeffluoo/dev/kubebuilder-declarative-pattern/examples/guestbook-operator/vendor/k8s.io/apimachinery/pkg/util/wait/wait.go:133
k8s.io/apimachinery/pkg/util/wait.JitterUntilWithContext
        /usr/local/google/home/jeffluoo/dev/kubebuilder-declarative-pattern/examples/guestbook-operator/vendor/k8s.io/apimachinery/pkg/util/wait/wait.go:185
k8s.io/apimachinery/pkg/util/wait.UntilWithContext
        /usr/local/google/home/jeffluoo/dev/kubebuilder-declarative-pattern/examples/guestbook-operator/vendor/k8s.io/apimachinery/pkg/util/wait/wait.go:99
2021-06-16T14:33:26.548Z        ERROR   controller-runtime.manager.controller.guestbook-controller      Reconciler error        {"name": "guestbook-sample", "namespace": "kube-system", "error": "error applying manifest: [error when retrieving current configuration of:\nResource: \"apps/v1, Resource=deployments\", GroupVersionKind: \"apps/v1, Kind=Deployment\"\nName: \"frontend\", Namespace: \"\"\nfrom server for: \"manifestString\": an empty namespace may not be set when a resource name is provided, error when retrieving current configuration of:\nResource: \"apps/v1, Resource=deployments\", GroupVersionKind: \"apps/v1, Kind=Deployment\"\nName: \"redis-master\", Namespace: \"\"\nfrom server for: \"manifestString\": an empty namespace may not be set when a resource name is provided, error when retrieving current configuration of:\nResource: \"apps/v1, Resource=deployments\", GroupVersionKind: \"apps/v1, Kind=Deployment\"\nName: \"redis-slave\", Namespace: \"\"\nfrom server for: \"manifestString\": an empty namespace may not be set when a resource name is provided, error when retrieving current configuration of:\nResource: \"/v1, Resource=services\", GroupVersionKind: \"/v1, Kind=Service\"\nName: \"frontend\", Namespace: \"\"\nfrom server for: \"manifestString\": an empty namespace may not be set when a resource name is provided, error when retrieving current configuration of:\nResource: \"/v1, Resource=services\", GroupVersionKind: \"/v1, Kind=Service\"\nName: \"redis-master\", Namespace: \"\"\nfrom server for: \"manifestString\": an empty namespace may not be set when a resource name is provided, error when retrieving current configuration of:\nResource: \"/v1, Resource=services\", GroupVersionKind: \"/v1, Kind=Service\"\nName: \"redis-slave\", Namespace: \"\"\nfrom server for: \"manifestString\": an empty namespace may not be set when a resource name is provided]"}
github.com/go-logr/zapr.(*zapLogger).Error

From error message I observed that an empty namespace may not be set when a resource name is provided so I guessed for some reasons the namespace is ignored.

if err != nil {
return err
}
applyOpts.DeleteOptions = applyOpts.DeleteFlags.ToOptions(applyOpts.DynamicClient, applyOpts.IOStreams)
Copy link
Contributor

Choose a reason for hiding this comment

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

It looks like we overwrite DeleteOptions on line 69 below?

@@ -53,6 +69,7 @@ func (d *DirectApplier) Apply(ctx context.Context,
applyOpts.DeleteOptions = &cmdDelete.DeleteOptions{
IOStreams: ioStreams,
}
applyOpts.DeleteOptions.Filenames = []string{tmpFile.Name()}
Copy link
Contributor

Choose a reason for hiding this comment

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

Looking at the code, it seems that despite being in DeleteOptions.Filenames, this the filename of the objects we want to apply. Is that right? If that's right, do you mind adding a comment?

if err != nil {
return err
}
tmpFile.Write([]byte(manifest))
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: the error handling here is really tricky. I would split this into a function, like this:

func WriteTempFile(dir, pattern string, contents []byte) (string, error) {
  tmpFile, err := ioutil.TempFile(dir, pattern)
  if err != nil {
    return "", err
  }
  success := false
  defer func() {
    if !success {
      tmpFile.Close()
      os.Remove(tmpFile.Name())
    }
  }()
  if _, err :=  tmpFile.Write(contents); err != nil {
    return "", err
  }
  if err := tmpFile.Close(); err != nil {
    return "", err
  }
  success = true // don't remove the temp file
  return tmpFile.Name(), nil
}

I'm happy to send a follow-on PR to add this if that's easier!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thank you to comment 😄
Current codes are something rough idea, so any review comments are very appreciate.

@justinsb
Copy link
Contributor

Sorry for the (huge) delay here. I think I finally understood what was going on - I was very confused by DeleteOptions.Filenames. If I'm right as to what it is for, a comment there would be very helpful!

@atoato88
Copy link
Contributor Author

Thank you to comment.
I'll remind the content because of this PR is pretty old.. 😅

@justinsb
Copy link
Contributor

I was able to reproduce the namespace problem with the direct-applier and I uploaded a fix for that - #173. I'm guessing you achieve that by having the Apply logic parse the yaml, which includes the call to SetNamespace

@k8s-ci-robot
Copy link
Contributor

@atoato88: PR needs rebase.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository.

@k8s-ci-robot k8s-ci-robot added the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Sep 15, 2021
@atoato88
Copy link
Contributor Author

/close

As of now #173 is merged which updates the apply logic.
Is has the same purpose as this PR.
I can close this PR.

@k8s-ci-robot
Copy link
Contributor

@atoato88: Closed this PR.

In response to this:

/close

As of now #173 is merged which updates the apply logic.
Is has the same purpose as this PR.
I can close this PR.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. sig/api-machinery Categorizes an issue or PR as relevant to SIG API Machinery. size/M Denotes a PR that changes 30-99 lines, ignoring generated files.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants