Skip to content

Commit 479ebf5

Browse files
authored
Merge pull request #76 from kcp-dev/toolkit
replace crd-puller with pubres-toolkit
2 parents 9a0e811 + abc4d88 commit 479ebf5

File tree

13 files changed

+421
-148
lines changed

13 files changed

+421
-148
lines changed

cmd/crd-puller/.gitignore

Lines changed: 0 additions & 2 deletions
This file was deleted.

cmd/crd-puller/README.md

Lines changed: 0 additions & 18 deletions
This file was deleted.

cmd/crd-puller/main.go

Lines changed: 0 additions & 78 deletions
This file was deleted.

cmd/pubres-toolkit/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
/pubres-toolkit
2+
*.yaml

cmd/pubres-toolkit/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# PublishedResource Toolkit
2+
3+
The `pubres-toolkit` can be used for testing and development in order to
4+
simulate how the agent would process a PublishedResource.

cmd/pubres-toolkit/cmd/crd/command.go

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
/*
2+
Copyright 2021 The KCP Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package crd
18+
19+
import (
20+
"context"
21+
"errors"
22+
"fmt"
23+
24+
"github.com/spf13/cobra"
25+
26+
"github.com/kcp-dev/api-syncagent/cmd/pubres-toolkit/util"
27+
"github.com/kcp-dev/api-syncagent/internal/discovery"
28+
"github.com/kcp-dev/api-syncagent/internal/kcp"
29+
"github.com/kcp-dev/api-syncagent/internal/projection"
30+
31+
"sigs.k8s.io/yaml"
32+
)
33+
34+
func NewCommand(ctx context.Context) *cobra.Command {
35+
opts := newDefaultOptions()
36+
37+
cmd := &cobra.Command{
38+
Use: "crd [--no-projection] [--ars] pubres.yaml",
39+
Short: "Outputs a CRD based on a PublishedResource",
40+
RunE: func(c *cobra.Command, args []string) error {
41+
if err := opts.Complete(); err != nil {
42+
return err
43+
}
44+
45+
if err := opts.Validate(); err != nil {
46+
return err
47+
}
48+
49+
if len(args) != 1 {
50+
return errors.New("expected exactly one argument")
51+
}
52+
53+
return run(ctx, opts, args[0])
54+
},
55+
}
56+
57+
opts.AddFlags(cmd.Flags())
58+
59+
return cmd
60+
}
61+
62+
func run(ctx context.Context, o *options, pubResFile string) error {
63+
// load the given PubRes
64+
pubResource, err := util.ReadPublishedResourceFile(pubResFile)
65+
if err != nil {
66+
return fmt.Errorf("failed to read %q: %w", pubResFile, err)
67+
}
68+
69+
// parse kubeconfig
70+
kubeconfig, err := util.ReadKubeconfig(o.KubeconfigFile, o.Context)
71+
if err != nil {
72+
return fmt.Errorf("invalid kubeconfig: %w", err)
73+
}
74+
75+
clientConfig, err := kubeconfig.ClientConfig()
76+
if err != nil {
77+
return err
78+
}
79+
80+
client, err := discovery.NewClient(clientConfig)
81+
if err != nil {
82+
return fmt.Errorf("failed to create discovery client: %w", err)
83+
}
84+
85+
// find the CRD that the PublishedResource is referring to
86+
localGK := projection.PublishedResourceSourceGK(pubResource)
87+
88+
// fetch the original, full CRD from the cluster
89+
crd, err := client.RetrieveCRD(ctx, localGK)
90+
if err != nil {
91+
return fmt.Errorf("failed to discover CRD defined in PublishedResource: %w", err)
92+
}
93+
94+
// project the CRD (i.e. strip unwanted versions, rename values etc.)
95+
if !o.NoProjection {
96+
crd, err = projection.ProjectCRD(crd, pubResource)
97+
if err != nil {
98+
return fmt.Errorf("failed to apply projection rules: %w", err)
99+
}
100+
}
101+
102+
// output the CRD right away if desired
103+
if !o.APIResourceSchema {
104+
enc, err := yaml.Marshal(crd)
105+
if err != nil {
106+
return fmt.Errorf("failed to encode CRD as YAML: %w", err)
107+
}
108+
109+
fmt.Println(string(enc))
110+
return nil
111+
}
112+
113+
// convert to APIResourceSchema otherwise
114+
arsName := kcp.GetAPIResourceSchemaName(crd)
115+
ars, err := kcp.CreateAPIResourceSchema(crd, arsName, "pubres-toolkit")
116+
if err != nil {
117+
return fmt.Errorf("failed to create APIResourceSchema: %w", err)
118+
}
119+
120+
enc, err := yaml.Marshal(ars)
121+
if err != nil {
122+
return fmt.Errorf("failed to encode APIResourceSchema as YAML: %w", err)
123+
}
124+
125+
fmt.Println(string(enc))
126+
127+
return nil
128+
}

cmd/pubres-toolkit/cmd/crd/options.go

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/*
2+
Copyright 2022 The KCP Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package crd
18+
19+
import (
20+
"fmt"
21+
"os"
22+
23+
"github.com/spf13/pflag"
24+
25+
utilerrors "k8s.io/apimachinery/pkg/util/errors"
26+
)
27+
28+
type options struct {
29+
KubeconfigFile string
30+
Context string
31+
32+
NoProjection bool
33+
APIResourceSchema bool
34+
}
35+
36+
func newDefaultOptions() *options {
37+
return &options{}
38+
}
39+
40+
func (o *options) AddFlags(flags *pflag.FlagSet) {
41+
flags.BoolVar(&o.NoProjection, "no-projection", o.NoProjection, "Disables projecting the GVK of the selected CRD")
42+
flags.BoolVar(&o.APIResourceSchema, "ars", o.APIResourceSchema, "Outputs an APIResourceSchema instead of a CustomResourceDefinition")
43+
44+
flags.StringVar(&o.Context, "context", o.Context, "Name of the context in the kubeconfig file to use")
45+
flags.StringVar(&o.KubeconfigFile, "kubeconfig", o.KubeconfigFile, "The kubeconfig file of the cluster to read CRDs from (defaults to $KUBECONFIG).")
46+
}
47+
48+
func (o *options) Complete() error {
49+
errs := []error{}
50+
51+
if len(o.KubeconfigFile) == 0 {
52+
o.KubeconfigFile = os.Getenv("KUBECONFIG")
53+
}
54+
55+
return utilerrors.NewAggregate(errs)
56+
}
57+
58+
func (o *options) Validate() error {
59+
errs := []error{}
60+
61+
if len(o.KubeconfigFile) == 0 {
62+
errs = append(errs, fmt.Errorf("--kubeconfig or $KUBECONFIG are required for this command"))
63+
}
64+
65+
return utilerrors.NewAggregate(errs)
66+
}

cmd/pubres-toolkit/main.go

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/*
2+
Copyright 2025 The KCP Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package main
18+
19+
import (
20+
"context"
21+
"os"
22+
23+
"github.com/spf13/cobra"
24+
25+
crdcommand "github.com/kcp-dev/api-syncagent/cmd/pubres-toolkit/cmd/crd"
26+
27+
"k8s.io/component-base/cli"
28+
"k8s.io/component-base/version"
29+
)
30+
31+
func main() {
32+
ctx := context.Background()
33+
cmd := &cobra.Command{
34+
Use: "pubres-toolkit",
35+
Short: "Toolkit for PublishedResources",
36+
SilenceUsage: true,
37+
SilenceErrors: true,
38+
}
39+
40+
cmd.AddCommand(crdcommand.NewCommand(ctx))
41+
42+
if v := version.Get().String(); len(v) == 0 {
43+
cmd.Version = "<unknown>"
44+
} else {
45+
cmd.Version = v
46+
}
47+
48+
os.Exit(cli.Run(cmd))
49+
}

cmd/pubres-toolkit/util/kubeconfig.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*
2+
Copyright 2025 The KCP Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package util
18+
19+
import "k8s.io/client-go/tools/clientcmd"
20+
21+
func ReadKubeconfig(filename, context string) (clientcmd.ClientConfig, error) {
22+
loadingRules := clientcmd.NewDefaultClientConfigLoadingRules()
23+
loadingRules.ExplicitPath = filename
24+
25+
startingConfig, err := loadingRules.GetStartingConfig()
26+
if err != nil {
27+
return nil, err
28+
}
29+
30+
overrides := &clientcmd.ConfigOverrides{
31+
CurrentContext: context,
32+
}
33+
34+
clientConfig := clientcmd.NewDefaultClientConfig(*startingConfig, overrides)
35+
return clientConfig, nil
36+
}

0 commit comments

Comments
 (0)