Skip to content

Commit 52d849e

Browse files
committed
feat: split runtime resource getter from the apply action add general printer output
1 parent 0eb4ad4 commit 52d849e

File tree

5 files changed

+76
-58
lines changed

5 files changed

+76
-58
lines changed

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
0.2.1
1+
0.2.2

examples/kcl-apply.yaml

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,18 @@
1-
functionConfig:
2-
# kcl-fn-config.yaml
3-
apiVersion: krm.kcl.dev/v1alpha1
4-
kind: KCLRun
5-
metadata:
6-
# EDIT THE SOURCE!
7-
# This should be your KCL code which preloads the `ResourceList` to `option("resource_list")
8-
spec:
9-
source: |
10-
[resource | {if resource.kind == "Deployment": metadata.annotations: {"managed-by" = "krm-kcl"}} for resource in option("resource_list").items]
1+
apiVersion: krm.kcl.dev/v1alpha1
2+
kind: KCLRun
3+
metadata:
4+
name: web-service-abtraction
5+
spec:
6+
params:
7+
name: app
8+
containers:
9+
ngnix:
10+
image: ngnix
11+
ports:
12+
- containerPort: 80
13+
service:
14+
ports:
15+
- port: 80
16+
labels:
17+
name: app
18+
source: oci://docker.io/kcllang/web-service

pkg/client/client.go

Lines changed: 35 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,26 @@ package client
22

33
import (
44
"io"
5+
"os"
56

7+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
8+
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
69
"k8s.io/apimachinery/pkg/runtime"
10+
"k8s.io/apimachinery/pkg/types"
11+
utilerrors "k8s.io/apimachinery/pkg/util/errors"
712
"k8s.io/cli-runtime/pkg/genericclioptions"
813
"k8s.io/cli-runtime/pkg/printers"
914
"k8s.io/cli-runtime/pkg/resource"
1015
"k8s.io/kubectl/pkg/scheme"
1116
)
1217

1318
type KubeCliRuntime struct {
14-
Flags *genericclioptions.ConfigFlags
15-
AllNamespaces bool
16-
Namespace string
17-
Selector string
18-
FieldSelector string
19+
Flags *genericclioptions.ConfigFlags
20+
AllNamespaces bool
21+
Namespace string
22+
Selector string
23+
FieldSelector string
24+
ForceConflicts bool
1925
}
2026

2127
func NewKubeCliRuntime() *KubeCliRuntime {
@@ -65,6 +71,8 @@ func (k *KubeCliRuntime) GetObjects(flags resource.RESTClientGetter, r io.Reader
6571

6672
// Apply yaml file from io reader
6773
func (k *KubeCliRuntime) Apply(flags resource.RESTClientGetter, r io.Reader) error {
74+
// Generates the objects using the resource builder if they have not
75+
// already been stored by calling "SetObjects()" in the pre-processor.
6876
errs := []error{}
6977
infos, err := k.GetObjects(flags, r)
7078
if err != nil {
@@ -83,24 +91,41 @@ func (k *KubeCliRuntime) Apply(flags resource.RESTClientGetter, r io.Reader) err
8391
return errs[0]
8492
}
8593
if len(errs) > 1 {
86-
return errs[0]
94+
return utilerrors.NewAggregate(errs)
8795
}
8896
return nil
8997
}
9098

9199
func (k *KubeCliRuntime) applyOneObject(info *resource.Info) error {
92-
helper := resource.NewHelper(info.Client, info.Mapping).WithFieldManager("kubectl-client-side-apply")
93-
obj, err := helper.Replace(
100+
helper := resource.NewHelper(info.Client, info.Mapping).WithFieldManager("kubectl-kcl-client-side-apply")
101+
// Send the full object to be applied on the server side.
102+
data, err := runtime.Encode(unstructured.UnstructuredJSONScheme, info.Object)
103+
if err != nil {
104+
return err
105+
}
106+
obj, err := helper.Patch(
94107
info.Namespace,
95108
info.Name,
96-
true,
97-
info.Object,
109+
types.ApplyPatchType,
110+
data,
111+
&metav1.PatchOptions{
112+
Force: &k.ForceConflicts,
113+
},
98114
)
99115
if err != nil {
100116
return err
101117
}
102118
if err := info.Refresh(obj, true); err != nil {
103119
return err
104120
}
121+
// TODO: use kubectl ApplyOptions intead of genericclioptions.
122+
printer, err := genericclioptions.NewPrintFlags("configured").ToPrinter()
123+
if err != nil {
124+
return err
125+
}
126+
127+
if err = printer.PrintObj(info.Object, os.Stdout); err != nil {
128+
return err
129+
}
105130
return nil
106131
}

pkg/options/apply.go

Lines changed: 17 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package options
33
import (
44
"bufio"
55
"bytes"
6-
"errors"
76
"io"
87
"os"
98

@@ -14,10 +13,7 @@ import (
1413

1514
// ApplyOptions is the options for the apply sub command.
1615
type ApplyOptions struct {
17-
// InputPath is the -f flag
18-
InputPath string
19-
// OutputPath is the -o flag
20-
OutputPath string
16+
RunOptions
2117

2218
// Namespace is the -n flag --namespace. It will set kubernetes namespace scope
2319
Namespace string
@@ -37,20 +33,13 @@ func NewApplyOptions() *ApplyOptions {
3733

3834
// Run apply command option.
3935
func (o *ApplyOptions) Run() error {
40-
var buf bytes.Buffer
4136
cli := o.getCliRuntime()
42-
if err := cli.GetGeneralResources(&buf); err != nil {
43-
logger.GetLogger().Errorf("get general resource err: %s", err.Error())
44-
return err
45-
}
46-
_, bs, err := o.reader()
37+
38+
reader, err := o.reader()
4739
if err != nil {
48-
logger.GetLogger().Errorf("read kcl code err: %s", err.Error())
40+
logger.GetLogger().Errorf("read manifests err: %s", err.Error())
4941
return err
5042
}
51-
n := append(buf.Bytes(), bs...)
52-
reader := bytes.NewReader(n)
53-
5443
// use the io pipe feat to connect io writer to io reader
5544
pr, pw := io.Pipe()
5645
go func() {
@@ -67,7 +56,15 @@ func (o *ApplyOptions) Run() error {
6756
return err
6857
}
6958
if err := cli.Apply(cli.Flags, &input); err != nil {
70-
logger.GetLogger().Errorf("cli apply err: %s", err.Error())
59+
logger.GetLogger().Errorf("apply err: %s", err.Error())
60+
return err
61+
}
62+
return nil
63+
}
64+
65+
func (o *ApplyOptions) getGeneralResource(w io.Writer) error {
66+
cli := o.getCliRuntime()
67+
if err := cli.GetGeneralResources(w); err != nil {
7168
return err
7269
}
7370
return nil
@@ -86,29 +83,15 @@ func (o *ApplyOptions) Validate() error {
8683
return nil
8784
}
8885

89-
func (o *ApplyOptions) reader() (io.Reader, []byte, error) {
86+
func (o *ApplyOptions) reader() (io.Reader, error) {
9087
if o.InputPath == "-" {
91-
scanner := bufio.NewScanner(os.Stdin)
92-
if !scanner.Scan() {
93-
return nil, nil, errors.New("input scan err")
94-
}
95-
line := scanner.Bytes()
96-
return os.Stdin, line, nil
88+
return os.Stdin, nil
9789
} else {
9890
file, err := os.Open(o.InputPath)
9991
if err != nil {
100-
return nil, nil, err
101-
}
102-
stat, err := file.Stat()
103-
if err != nil {
104-
return nil, nil, err
105-
}
106-
bs := make([]byte, stat.Size())
107-
_, err = bufio.NewReader(file).Read(bs)
108-
if err != nil {
109-
return nil, nil, err
92+
return nil, err
11093
}
111-
return bufio.NewReader(file), bs, nil
94+
return bufio.NewReader(file), nil
11295
}
11396
}
11497

pkg/options/apply_test.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,11 @@ func TestApplyOptions_Run(t *testing.T) {
2828
for _, tt := range tests {
2929
t.Run(tt.name, func(t *testing.T) {
3030
o := &ApplyOptions{
31-
InputPath: tt.fields.InputPath,
32-
OutputPath: tt.fields.OutputPath,
33-
Namespace: tt.fields.Namespace,
31+
RunOptions: RunOptions{
32+
InputPath: tt.fields.InputPath,
33+
OutputPath: tt.fields.OutputPath,
34+
},
35+
Namespace: tt.fields.Namespace,
3436
}
3537
if err := o.Run(); (err != nil) != tt.wantErr {
3638
t.Errorf("ApplyOptions.Run() error = %v, wantErr %v", err, tt.wantErr)

0 commit comments

Comments
 (0)