-
Notifications
You must be signed in to change notification settings - Fork 17
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
crdutil: Add feature to also apply single files #58
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -26,6 +26,7 @@ import ( | |||||||||||||||
"path/filepath" | ||||||||||||||||
"strings" | ||||||||||||||||
|
||||||||||||||||
"github.com/spf13/pflag" | ||||||||||||||||
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" | ||||||||||||||||
"k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset" | ||||||||||||||||
v1 "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset/typed/apiextensions/v1" | ||||||||||||||||
|
@@ -37,38 +38,31 @@ import ( | |||||||||||||||
ctrl "sigs.k8s.io/controller-runtime" | ||||||||||||||||
) | ||||||||||||||||
|
||||||||||||||||
type StringList []string | ||||||||||||||||
|
||||||||||||||||
func (s *StringList) String() string { | ||||||||||||||||
return strings.Join(*s, ", ") | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
func (s *StringList) Set(value string) error { | ||||||||||||||||
*s = append(*s, value) | ||||||||||||||||
return nil | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
var ( | ||||||||||||||||
crdsDir StringList | ||||||||||||||||
filenames []string | ||||||||||||||||
recursive bool | ||||||||||||||||
) | ||||||||||||||||
|
||||||||||||||||
func initFlags() { | ||||||||||||||||
flag.Var(&crdsDir, "crds-dir", "Path to the directory containing the CRD manifests") | ||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are we concerned about this as a breaking change since the command line arguments are changed? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I was also thinking about this but this pkg is pretty new and we are only using it for the network-operator currently. Do you think we should deprecate it? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If the network-operator is not released with this change, better to just update as it will be first use of this package. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The network-operator 24.10.0 has been released 2 days ago with the change in it, see https://github.com/Mellanox/network-operator/blob/v24.10.0/deployment/network-operator/templates/upgrade-crd-hook.yaml#L84. But IMO it is totally fine to change it, because it is a Helm pre-install hook. If it fails, it fails the installation/upgrade and the user has to use the latest Helm chart. There is no dependency to the runtime which can cause the operator to fail. tl;dr: this PR changes the flag There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If there is a concern, we could support both -- marking There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We can also revert it to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @shivamerla WDYT? Should we remove the flag rename and recursive flag (see #58 (comment)) out of this PR and change it in a follow-up? I'd say this will reduce the size of this PR. |
||||||||||||||||
flag.Parse() | ||||||||||||||||
pflag.CommandLine.AddGoFlagSet(flag.CommandLine) | ||||||||||||||||
pflag.StringSliceVarP(&filenames, "filename", "f", filenames, "The files that contain the configurations to apply.") | ||||||||||||||||
pflag.BoolVarP(&recursive, "recursive", "R", false, "Process the directory used in -f, --filename recursively.") | ||||||||||||||||
pflag.Parse() | ||||||||||||||||
|
||||||||||||||||
if len(crdsDir) == 0 { | ||||||||||||||||
log.Fatalf("CRDs directory is required") | ||||||||||||||||
if len(filenames) == 0 { | ||||||||||||||||
log.Fatalf("CRDs directory or single CRDs are required") | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
for _, crdDir := range crdsDir { | ||||||||||||||||
for _, crdDir := range filenames { | ||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||
if _, err := os.Stat(crdDir); os.IsNotExist(err) { | ||||||||||||||||
log.Fatalf("CRDs directory %s does not exist", crdsDir) | ||||||||||||||||
log.Fatalf("CRDs directory %s does not exist", filenames) | ||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should this be:
Suggested change
|
||||||||||||||||
} | ||||||||||||||||
} | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
// EnsureCRDsCmd reads each YAML file in the directory, splits it into documents, and applies each CRD to the cluster. | ||||||||||||||||
// The parameter --crds-dir is required and should point to the directory containing the CRD manifests. | ||||||||||||||||
// TODO: add unit test for this command. | ||||||||||||||||
func EnsureCRDsCmd() { | ||||||||||||||||
ctx := context.Background() | ||||||||||||||||
|
||||||||||||||||
|
@@ -84,38 +78,59 @@ func EnsureCRDsCmd() { | |||||||||||||||
log.Fatalf("Failed to create API extensions client: %v", err) | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
if err := walkCrdsDir(ctx, client.ApiextensionsV1().CustomResourceDefinitions()); err != nil { | ||||||||||||||||
log.Fatalf("Failed to apply CRDs: %v", err) | ||||||||||||||||
dirsToApply, err := walkCRDs(recursive, filenames) | ||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||
if err != nil { | ||||||||||||||||
log.Fatalf("Failed to walk through CRDs: %v", err) | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
for _, dir := range dirsToApply { | ||||||||||||||||
log.Printf("Apply CRDs from file: %s", dir) | ||||||||||||||||
if err := applyCRDs(ctx, client.ApiextensionsV1().CustomResourceDefinitions(), dir); err != nil { | ||||||||||||||||
log.Fatalf("Failed to apply CRDs: %v", err) | ||||||||||||||||
} | ||||||||||||||||
} | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
// walkCrdsDir walks the CRDs directory and applies each YAML file. | ||||||||||||||||
func walkCrdsDir(ctx context.Context, crdClient v1.CustomResourceDefinitionInterface) error { | ||||||||||||||||
for _, crdDir := range crdsDir { | ||||||||||||||||
// walkCRDs walks the CRDs directory and applies each YAML file. | ||||||||||||||||
// TODO: add unit test for this function. | ||||||||||||||||
func walkCRDs(recursive bool, crdDirs []string) ([]string, error) { | ||||||||||||||||
Comment on lines
+94
to
+96
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Note that we also need to rename some local variables to better indicate what we are collecting. |
||||||||||||||||
var dirs []string | ||||||||||||||||
for _, crdDir := range crdDirs { | ||||||||||||||||
// We need the parent directory to check if we are in the top-level directory. | ||||||||||||||||
// This is necessary for the recursive logic. | ||||||||||||||||
// We can skip the errors as it has been checked in initFlags. | ||||||||||||||||
parentDir, _ := os.Stat(crdDir) | ||||||||||||||||
// Walk the directory recursively and apply each YAML file. | ||||||||||||||||
err := filepath.Walk(crdDir, func(path string, info os.FileInfo, err error) error { | ||||||||||||||||
if err != nil { | ||||||||||||||||
return err | ||||||||||||||||
} | ||||||||||||||||
if info.IsDir() || filepath.Ext(path) != ".yaml" { | ||||||||||||||||
// If this is a directory, skip it. | ||||||||||||||||
// filepath.Walk() is also called for directories, but we only want to apply CRDs from files. | ||||||||||||||||
if info.IsDir() { | ||||||||||||||||
tobiasgiese marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||
return nil | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
log.Printf("Apply CRDs from file: %s", path) | ||||||||||||||||
if err := applyCRDsFromFile(ctx, crdClient, path); err != nil { | ||||||||||||||||
return fmt.Errorf("apply CRD %s: %w", path, err) | ||||||||||||||||
if filepath.Ext(path) != ".yaml" && filepath.Ext(path) != ".yml" { | ||||||||||||||||
return nil | ||||||||||||||||
} | ||||||||||||||||
// If not recursive we want to only apply the CRDs in the top-level directory. | ||||||||||||||||
// filepath.Dir() does not add a trailing slash, thus we need to trim it in the crdDir. | ||||||||||||||||
if !recursive && parentDir.IsDir() && filepath.Dir(path) != strings.TrimRight(crdDir, "/") { | ||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should we add a test case for this new branch or should these all be included in the "TODO add unit tests" comment you have added? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let me take another look at the tests, I think I can easily test the |
||||||||||||||||
return nil | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
dirs = append(dirs, path) | ||||||||||||||||
return nil | ||||||||||||||||
}) | ||||||||||||||||
if err != nil { | ||||||||||||||||
return fmt.Errorf("walk the path %s: %w", crdsDir, err) | ||||||||||||||||
return []string{}, fmt.Errorf("walk the path %s: %w", crdDirs, err) | ||||||||||||||||
} | ||||||||||||||||
} | ||||||||||||||||
return nil | ||||||||||||||||
return dirs, nil | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
// applyCRDsFromFile reads a YAML file, splits it into documents, and applies each CRD to the cluster. | ||||||||||||||||
func applyCRDsFromFile(ctx context.Context, crdClient v1.CustomResourceDefinitionInterface, filePath string) error { | ||||||||||||||||
// applyCRDs reads a YAML file, splits it into documents, and applies each CRD to the cluster. | ||||||||||||||||
func applyCRDs(ctx context.Context, crdClient v1.CustomResourceDefinitionInterface, filePath string) error { | ||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This rename wasn't strictly required, correct? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No, it's not required. It was a review finding #58 (comment) |
||||||||||||||||
file, err := os.Open(filePath) | ||||||||||||||||
if err != nil { | ||||||||||||||||
return fmt.Errorf("open file %q: %w", filePath, err) | ||||||||||||||||
|
@@ -170,14 +185,19 @@ func applyCRD( | |||||||||||||||
if err != nil { | ||||||||||||||||
return fmt.Errorf("create CRD %s: %w", crd.Name, err) | ||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Note: we already add
Suggested change
(and similarly for |
||||||||||||||||
} | ||||||||||||||||
} else { | ||||||||||||||||
log.Printf("Update CRD %s", crd.Name) | ||||||||||||||||
// Set resource version to update an existing CRD. | ||||||||||||||||
crd.SetResourceVersion(curCRD.GetResourceVersion()) | ||||||||||||||||
_, err = crdClient.Update(ctx, crd, metav1.UpdateOptions{}) | ||||||||||||||||
if err != nil { | ||||||||||||||||
return fmt.Errorf("update CRD %s: %w", crd.Name, err) | ||||||||||||||||
} | ||||||||||||||||
return nil | ||||||||||||||||
} | ||||||||||||||||
if err != nil { | ||||||||||||||||
return fmt.Errorf("get CRD %s: %w", crd.Name, err) | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
log.Printf("Update CRD %s", crd.Name) | ||||||||||||||||
// Set resource version to update an existing CRD. | ||||||||||||||||
crd.SetResourceVersion(curCRD.GetResourceVersion()) | ||||||||||||||||
_, err = crdClient.Update(ctx, crd, metav1.UpdateOptions{}) | ||||||||||||||||
if err != nil { | ||||||||||||||||
return fmt.Errorf("update CRD %s: %w", crd.Name, err) | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
return nil | ||||||||||||||||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does it make sense to separate the handling of multiple non-recursive paths (including files) from the addition of recursive handling?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
AFAIK
kubectl
is also not separating it, so it is totally fine to keep it pretty open IMO. But also fine to me to split it somehow (you mean like: if multiple files are passed the recursive flag is not possible?)There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I actually just meant as separate PRs. From NVIDIA/gpu-operator#1137 it seems that we don't use recursive mode. Is it used in the network operator?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, it is not used by the network-operator. Maybe it makes sense to remove this new feature from the PR, you are right. The request adding it to this PR came through #58 (comment) (at least that's how I understood it)