Skip to content
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

Change resource key logic for k8s #4916

Merged
merged 9 commits into from
Jun 11, 2024
Merged

Conversation

ffjlabo
Copy link
Member

@ffjlabo ffjlabo commented May 15, 2024

What this PR does / why we need it:

This fix will solve the problem that the cluster-scoped resource can't be deleted when we set the namespace in app.pipecd.yaml.
context: #4269 (comment)

expected behavior

  • We can delete the cluster-scoped resource.

livestate side

  • use "" for the cluster-scoped resource
  • use the namespace for the namespace scoped resource

When reading the manifests from git

  • use "" for the cluster-scoped resource
  • for the namespace scoped resource,
    • use spec.input.namespace in app.pipecd.yaml if it is set.
    • use the namespace on the manifest from git if it is set.
    • use default if both of spec.input.namespace and the namespace are not set

Currently, we use the resource key to identify each k8s resource.
It is created by MakeResourceKey, and the rule is below.

livestate side

  • use default when the resource obj doesn't have the namespace.
  • use the namespace when the resource obj has the namespace.

When reading the manifests from git

  • use spec.input.namespace in app.pipecd.yaml if it is set.
  • use the namespace on the manifest from git if it is set.
  • use default when the namespace on the manifest is "".

This rule doesn't consider the cluster-scoped resource.
So for example, cluster-scoped resource don't have any namespace, but if we set the spec.input.namespace in the app.pipecd.yaml, it sets the value as the namespace to the resource key.

This causes the problem that can't prune the resource because the resource key can't identify the resource correctly.
So I fixed the the logic like below.

livestate side

  • use "" for the cluster-scoped resource
  • use the namespace for the namespace scoped resource

When reading the manifests from git

  • use "" for the cluster-scoped resource
  • for the namespace scoped resource,
    • use spec.input.namespace in app.pipecd.yaml if it is set.
    • use the namespace on the manifest from git if it is set.
    • use default if both of spec.input.namespace and the namespace are not set

Which issue(s) this PR fixes:

Part of #4269

  • Does this PR introduce a user-facing change?:

  • How are users affected by this change:

  • Is this breaking change:

  • How to migrate (if breaking change):

@ffjlabo ffjlabo force-pushed the change-resource-key-logic-for-k8s branch from 1b0b3f7 to d617a06 Compare May 16, 2024 08:34
@ffjlabo
Copy link
Member Author

ffjlabo commented May 16, 2024

The Overview of the fix

refine the namespace by loader.refineNamespace when reading the manifests from git repo

  • fixed to obtain information to determine whether each k8s resource is cluster scoped when executor, planner, plan preview, and detector start. (provider.GetIsNamespacedResources)

remove the logic to determine the namespace from MakeResourceKey

  • I think MakeResourceKey shouldn't determine the namespace. This is only loader's responsibility.

@ffjlabo ffjlabo marked this pull request as ready for review May 16, 2024 10:01
@ffjlabo
Copy link
Member Author

ffjlabo commented May 16, 2024

@khanhtc1202 @t-kikuc
This issue is complex and my explanation may be insufficient. If you have any questions, please feel free to ask. :) 🙏

@khanhtc1202
Copy link
Member

@ffjlabo some testcases are failed 👀

@ffjlabo
Copy link
Member Author

ffjlabo commented May 17, 2024

@khanhtc1202 Sorry, I fixed some of them. 🙏
There are some failings, but these are under the /pipecdv1. I want to fix it after the current implementation looks good.

@t-kikuc
Copy link
Member

t-kikuc commented May 27, 2024

/review

Copy link
Contributor

PR Analysis

Main theme

Enhancement and Refactoring

PR summary

This PR introduces enhancements and refactoring to various components that interact with Kubernetes resources, such as planners, appliers, and detection mechanisms. It involves propagating the knowledge of namespaced versus non-namespaced resources through the system.

Type of PR

Enhancement, Refactoring

PR Feedback:

General suggestions

This PR contains quite a large set of changes across multiple components, focusing on ensuring that the system properly respects namespaced and cluster-wide resources in Kubernetes. While the PR introduces a central mechanism to define whether a GroupVersionKind is namespaced, it's vital to ensure that this information remains consistent and the system's behavior follows the cluster's actual state. Testing these changes in a staging environment before release would be highly recommended to catch any edge cases or regressions.

Code feedback

  • relevant file: pkg/app/piped/platformprovider/kubernetes/loader.go
    suggestion: |-
    It is essential to guarantee that the information regarding namespaced resources is always fresh and accurate. As this is probably cached information and the cluster's state may change (e.g., CRDs being added/removed), consider adding a refresh mechanism to update the isNamespacedResources map periodically or when a certain type of error suggests it might be out of date. (important)
    relevant line: + isNamespacedResources: make(map[schema.GroupVersionKind]bool),

  • relevant file: pkg/app/piped/platformprovider/kubernetes/loader.go
    suggestion: |-
    There appears to be some unused or deleted code in the LoadManifests method, specifically regarding the initiation of Nashorn VM that was previously removed. Ensure that any references or initialization logic related to removed components are cleaned up to avoid confusion. (medium)
    relevant line: l.initOnce.Do(func() {

  • relevant key: pkg/app/piped/platformprovider/kubernetes/loader.go
    suggestion: |-
    Ensure that error messages are informative and actionable. For example, when handling an 'unknown resource kind', the error message should suggest what actions a developer might take or indicate if this is an expected case during normal operations or an exceptional scenario. (medium)
    relevant line: + return fmt.Errorf("unknown resource 登录 [PII] %s", m.u.GroupVersionKind().String())

Security concerns:

no

The code changes introduced in this PR do not seem to introduce any obvious security concerns such as SQL injection, XSS, or CSRF vulnerabilities. The updates mostly deal with internal configuration and state management concerning Kubernetes resources. However, the security of the mechanism used to determine the namespaced status of Kubernetes resources should be considered to ensure that it cannot be misused or lead to incorrect assumptions about resource accessibility and isolation.

@khanhtc1202
Copy link
Member

@ffjlabo Please rebase this PR due to pipedv1 package change 👀

@ffjlabo ffjlabo force-pushed the change-resource-key-logic-for-k8s branch from f07abcb to 9ac0a78 Compare May 29, 2024 04:52
Copy link

codecov bot commented May 29, 2024

Codecov Report

Attention: Patch coverage is 10.05291% with 170 lines in your changes missing coverage. Please review.

Project coverage is 29.31%. Comparing base (b2dca47) to head (5a83716).

Files Patch % Lines
pkg/app/piped/planpreview/kubernetesdiff.go 0.00% 33 Missing ⚠️
pkg/app/piped/executor/kubernetes/rollback.go 0.00% 32 Missing ⚠️
...pp/piped/platformprovider/kubernetes/kubernetes.go 0.00% 20 Missing ⚠️
pkg/app/piped/executor/kubernetes/primary.go 0.00% 19 Missing ⚠️
pkg/app/piped/executor/kubernetes/baseline.go 0.00% 17 Missing ⚠️
pkg/app/piped/planner/kubernetes/kubernetes.go 0.00% 17 Missing ⚠️
...kg/app/piped/platformprovider/kubernetes/loader.go 57.57% 14 Missing ⚠️
pkg/app/piped/executor/kubernetes/kubernetes.go 0.00% 13 Missing ⚠️
pkg/app/piped/planpreview/builder.go 0.00% 4 Missing ⚠️
...g/app/piped/platformprovider/kubernetes/applier.go 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #4916      +/-   ##
==========================================
- Coverage   29.39%   29.31%   -0.09%     
==========================================
  Files         322      323       +1     
  Lines       40852    40984     +132     
==========================================
+ Hits        12010    12014       +4     
- Misses      27882    28008     +126     
- Partials      960      962       +2     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@ffjlabo
Copy link
Member Author

ffjlabo commented May 29, 2024

The failing test is solved by this PR 🙏 #4926

e.LogPersister.Errorf("failed to fetch preferred resources: %v", zap.Error(err))
return model.StageStatus_STAGE_FAILURE
}
e.LogPersister.Info(fmt.Sprintf("successfully preferred resources that contains for %d groups", len(groupResources)))
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
e.LogPersister.Info(fmt.Sprintf("successfully preferred resources that contains for %d groups", len(groupResources)))
e.LogPersister.Infof("successfully preferred resources that contains for %d groups", len(groupResources))

And remove "fmt" package

Copy link
Member Author

Choose a reason for hiding this comment

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

Thanks! fixed ff15986

// 1. The namespace set in the application configuration.
// 2. The namespace set in the manifest.
// 3. The default namespace.
func (l *loader) refineNamespace(m *Manifest) error {
Copy link
Member

Choose a reason for hiding this comment

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

Should it be named determineResourceNamespace or determineNamespace? 🤔

Copy link
Member Author

@ffjlabo ffjlabo May 30, 2024

Choose a reason for hiding this comment

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

Thanks! fixed as determineNamespace 5d22c75

Comment on lines +183 to 214
// determineNamespace fix the namespace of the given manifest.
// The priority is as follows:
// If the resource is cluster-scoped, it returns an empty string.
// Otherwise, it is the namespace-scoped resource and the namespace is determined by the following order:
// 1. The namespace set in the application configuration.
// 2. The namespace set in the manifest.
// 3. The default namespace.
func (l *loader) determineNamespace(m *Manifest) error {
namespaced, ok := l.isNamespacedResources[m.u.GroupVersionKind()]
if !ok {
return fmt.Errorf("unknown resource kind %s", m.u.GroupVersionKind().String())
}
for i := range manifests {
manifests[i].Key.Namespace = namespace

namespace := "" // empty if cluster-scoped resource

if namespaced {
namespace = "default"

if ns := m.u.GetNamespace(); ns != "" {
namespace = ns
}

if l.input.Namespace != "" {
namespace = l.input.Namespace
}
}

m.Key.Namespace = namespace
m.u.SetNamespace(namespace)

return nil
}
Copy link
Member Author

Choose a reason for hiding this comment

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

📝 Check the current logic

@ffjlabo
Copy link
Member Author

ffjlabo commented Jun 10, 2024

I tested it using QuickSync with the scenario below, and it works well.

scenario:
tried the following operations with and without setting spec.input.namespace in app.pipecd.yaml for cluster scoped resource and namespaced resource.

  • create a k8s app
  • update manifests
  • fix the actual resource with kubectl edit
  • delete manifests

I chose and tried them with ClusterRole (cluster scoped) and Deployment (namespaced) resources.

checkpoint:

  • create, update, and delete the resources successfully
  • reflect the operations result on the application livestate (check on the Web UI)
  • detect OutOfSync after kubectl edit

Warashi
Warashi previously approved these changes Jun 10, 2024
Copy link
Contributor

@Warashi Warashi left a comment

Choose a reason for hiding this comment

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

Seems good to me.
I commented on one nitpick for your information.

secretDecrypter: sd,
gitRepos: make(map[string]git.Repo),
syncStates: make(map[string]model.ApplicationSyncState),
isNamespacedResources: make(map[schema.GroupVersionKind]bool),
Copy link
Contributor

Choose a reason for hiding this comment

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

nits

isNamespacedResources seems to be an immutable map. After construction, there is no operation to add an element to this map.
In this case, a nil map is enough to express an empty map.

example code
https://go.dev/play/p/A8qeO9dCyuw

Copy link
Member Author

Choose a reason for hiding this comment

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

After that, I removed isNamespacedResources from the struct detector because it currently gets it every time it executes the detector's check logic. 🙏
a885bab

Copy link
Contributor

@Warashi Warashi left a comment

Choose a reason for hiding this comment

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

LGTM

Copy link
Member

@khanhtc1202 khanhtc1202 left a comment

Choose a reason for hiding this comment

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

Great work, thank you 🪨

Copy link
Member

@t-kikuc t-kikuc left a comment

Choose a reason for hiding this comment

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

greatest work

@ffjlabo ffjlabo force-pushed the change-resource-key-logic-for-k8s branch from a885bab to 3c1a493 Compare June 10, 2024 09:58
ffjlabo added 9 commits June 11, 2024 13:33
Signed-off-by: Yoshiki Fujikane <ffjlabo@gmail.com>
Details:
- [feat] get the resource info from the actual cluster in the deployExecutor.Execute
- [faet] implement the loader.refineNamespace to infer the namespace from the manifests and app.pipecd.yaml stored in the git repo
- [refactor] fix loader.NewLoader to pass isNamespacedResource
  - deployExecutor
  - rollbackExecutor
- [refactor] fix to pass isNamespacedResource on detector
  - [memo] detector checks the diff by 1 minute. It might think about the amount of the traffic to the k8s cluster.
- [refactor] fix to pass isNamespacedResource on planner
- [refactor] fix to pass isNamespacedResource on planpreview
- [refactor] remove the logic to fix the namespace when craeting the resource key on MakeResourceKey
  - maybe this is the refactoring for livestatestore
- [refactor] use the actual resource key, not the annotation's one.

Signed-off-by: Yoshiki Fujikane <ffjlabo@gmail.com>
Signed-off-by: Yoshiki Fujikane <ffjlabo@gmail.com>
Signed-off-by: Yoshiki Fujikane <ffjlabo@gmail.com>
Signed-off-by: Yoshiki Fujikane <ffjlabo@gmail.com>
Signed-off-by: Yoshiki Fujikane <ffjlabo@gmail.com>
Signed-off-by: Yoshiki Fujikane <ffjlabo@gmail.com>
Signed-off-by: Yoshiki Fujikane <ffjlabo@gmail.com>
Signed-off-by: Yoshiki Fujikane <ffjlabo@gmail.com>
@ffjlabo ffjlabo force-pushed the change-resource-key-logic-for-k8s branch from 3c1a493 to 5a83716 Compare June 11, 2024 04:33
@ffjlabo
Copy link
Member Author

ffjlabo commented Jun 11, 2024

Thank you for reviewing 🙏

@ffjlabo ffjlabo merged commit 8129078 into master Jun 11, 2024
15 of 18 checks passed
@ffjlabo ffjlabo deleted the change-resource-key-logic-for-k8s branch June 11, 2024 06:40
@github-actions github-actions bot mentioned this pull request Jun 12, 2024
ffjlabo added a commit that referenced this pull request Jun 25, 2024
ffjlabo added a commit that referenced this pull request Jun 25, 2024
This reverts commit 8129078.

Signed-off-by: Yoshiki Fujikane <40124947+ffjlabo@users.noreply.github.com>
@github-actions github-actions bot mentioned this pull request Jul 4, 2024
hungran pushed a commit to hungran/pipecd that referenced this pull request Jul 6, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants