Skip to content

Commit

Permalink
crdutil: Add feature to also apply also single files
Browse files Browse the repository at this point in the history
Signed-off-by: Tobias Giese <[email protected]>
  • Loading branch information
tobiasgiese committed Nov 27, 2024
1 parent 1ad8938 commit 4cd95ea
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 23 deletions.
48 changes: 32 additions & 16 deletions pkg/crdutil/crdutil.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
"path/filepath"
"strings"

"github.com/spf13/pflag"

Check failure on line 29 in pkg/crdutil/crdutil.go

View workflow job for this annotation

GitHub Actions / lint

import 'github.com/spf13/pflag' is not allowed from list 'main' (depguard)
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"
Expand All @@ -49,20 +50,23 @@ func (s *StringList) Set(value string) error {
}

var (
crdsDir StringList
files []string
recursive bool
)

func initFlags() {
flag.Var(&crdsDir, "crds-dir", "Path to the directory containing the CRD manifests")
flag.Parse()
pflag.CommandLine.AddGoFlagSet(flag.CommandLine)
pflag.StringSliceVarP(&files, "filename", "f", files, "The files that contain the configurations to apply.")
pflag.BoolVarP(&recursive, "recursive", "R", false, "Process the directory used in -f, --filename recursively. Useful when you want to manage related manifests organized within the same directory.")
pflag.Parse()

if len(crdsDir) == 0 {
log.Fatalf("CRDs directory is required")
if len(files) == 0 {
log.Fatalf("CRDs directory or single CRDs are required")
}

for _, crdDir := range crdsDir {
for _, crdDir := range files {
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", files)
}
}
}
Expand All @@ -84,38 +88,47 @@ func EnsureCRDsCmd() {
log.Fatalf("Failed to create API extensions client: %v", err)
}

if err := walkCrdsDir(ctx, client.ApiextensionsV1().CustomResourceDefinitions()); err != nil {
if err := walkCRDs(ctx, client.ApiextensionsV1().CustomResourceDefinitions()); 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.
func walkCRDs(ctx context.Context, crdClient v1.CustomResourceDefinitionInterface) error {
for _, crdDir := range files {
// 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 info.IsDir() {
return nil
}
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.
if !recursive && parentDir.IsDir() && filepath.Dir(path) != strings.TrimRight(crdDir, "/") {
return nil
}

log.Printf("Apply CRDs from file: %s", path)
if err := applyCRDsFromFile(ctx, crdClient, path); err != nil {
if err := applyCRDs(ctx, crdClient, path); err != nil {
return fmt.Errorf("apply CRD %s: %w", path, err)
}
return nil
})
if err != nil {
return fmt.Errorf("walk the path %s: %w", crdsDir, err)
return fmt.Errorf("walk the path %s: %w", files, err)
}
}
return 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 {
file, err := os.Open(filePath)
if err != nil {
return fmt.Errorf("open file %q: %w", filePath, err)
Expand Down Expand Up @@ -171,6 +184,9 @@ func applyCRD(
return fmt.Errorf("create CRD %s: %w", crd.Name, err)
}
} else {
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())
Expand Down
14 changes: 7 additions & 7 deletions pkg/crdutil/crdutil_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,13 @@ var _ = Describe("CRD Application", func() {
Expect(testCRDClient.DeleteCollection(ctx, metav1.DeleteOptions{}, metav1.ListOptions{})).NotTo(HaveOccurred())
})

Describe("applyCRDsFromFile", func() {
Describe("applyCRDs", func() {
It("should apply CRDs multiple times from a valid YAML file", func() {
By("applying CRDs")
Expect(applyCRDsFromFile(ctx, testCRDClient, "test-files/test-crds.yaml")).To(Succeed())
Expect(applyCRDsFromFile(ctx, testCRDClient, "test-files/test-crds.yaml")).To(Succeed())
Expect(applyCRDsFromFile(ctx, testCRDClient, "test-files/test-crds.yaml")).To(Succeed())
Expect(applyCRDsFromFile(ctx, testCRDClient, "test-files/test-crds.yaml")).To(Succeed())
Expect(applyCRDs(ctx, testCRDClient, "test-files/test-crds.yaml")).To(Succeed())
Expect(applyCRDs(ctx, testCRDClient, "test-files/test-crds.yaml")).To(Succeed())
Expect(applyCRDs(ctx, testCRDClient, "test-files/test-crds.yaml")).To(Succeed())
Expect(applyCRDs(ctx, testCRDClient, "test-files/test-crds.yaml")).To(Succeed())

By("verifying CRDs are applied")
crds, err := testCRDClient.List(ctx, metav1.ListOptions{})
Expand All @@ -54,7 +54,7 @@ var _ = Describe("CRD Application", func() {

It("should update CRDs", func() {
By("applying CRDs")
Expect(applyCRDsFromFile(ctx, testCRDClient, "test-files/test-crds.yaml")).To(Succeed())
Expect(applyCRDs(ctx, testCRDClient, "test-files/test-crds.yaml")).To(Succeed())

By("verifying CRDs do not have spec.foobar")
for _, crdName := range []string{"bars.example.com", "foos.example.com"} {
Expand All @@ -66,7 +66,7 @@ var _ = Describe("CRD Application", func() {
}

By("updating CRDs")
Expect(applyCRDsFromFile(ctx, testCRDClient, "test-files/updated-test-crds.yaml")).To(Succeed())
Expect(applyCRDs(ctx, testCRDClient, "test-files/updated-test-crds.yaml")).To(Succeed())

By("verifying CRDs are updated")
for _, crdName := range []string{"bars.example.com", "foos.example.com"} {
Expand Down

0 comments on commit 4cd95ea

Please sign in to comment.