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

Open
wants to merge 8 commits into
base: master
Choose a base branch
from

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
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

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 👀

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>
@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 are missing coverage. Please review.

Project coverage is 29.31%. Comparing base (6a3a5d0) to head (8adaa0b).
Report is 3 commits behind head on master.

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.33%   29.31%   -0.03%     
==========================================
  Files         322      323       +1     
  Lines       40868    40984     +116     
==========================================
+ Hits        11989    12014      +25     
- Misses      27919    28008      +89     
- 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

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 requested a review from khanhtc1202 May 31, 2024 06:20
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

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.

None yet

3 participants