Skip to content

Commit bcdf539

Browse files
author
Mengqi Yu
committed
make kubeval hermetic
1 parent 38546ac commit bcdf539

File tree

8 files changed

+96005
-25
lines changed

8 files changed

+96005
-25
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ node_modules
66
.DS_Store
77
.nyc_output
88
bin/
9+
__pycache__
910

1011
# We use sed -i.bak when doing in-line replace, because it works better cross-platform
1112
*.bak

examples/kubeval/simple/README.md

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,30 @@
1-
# Kubeval
1+
# kubeval: simple example
22

33
The `kubeval` KRM config function validates Kubernetes resources using kubeval.
44
Learn more on the [kubeval website].
55

6-
This example invokes the kubeval function against Kubernetes v1.18.0.
6+
This example invokes the kubeval function against the builtin Kubernetes
7+
v1.19.8 schema.
78

89
## Function invocation
910

1011
Get this example and try it out by running the following commands:
1112

12-
<!-- TODO: no --network. See: https://github.com/GoogleContainerTools/kpt/issues/1621 -->
13-
1413
```sh
1514
kpt pkg get https://github.com/GoogleContainerTools/kpt-functions-catalog.git/examples/kubeval .
16-
kpt fn run kubeval --network
15+
kpt fn run kubeval
1716
```
1817

1918
## Expected Results
2019

2120
This should give the following output:
2221

2322
```sh
24-
[ERROR] Invalid type. Expected: [integer,null], given: string in object 'v1/ReplicationController//bob' in file example-config.yaml in field spec.replicas
23+
[ERROR] Invalid type. Expected: [integer,null], given: string in object 'v1/ReplicationController//bob' in file resources.yaml in field spec.replicas
2524
error: exit status 1
2625
```
2726

28-
In the `example-config.yaml` file, replace the value of `spec.replicas`
27+
In the `resources.yaml` file, replace the value of `spec.replicas`
2928
with an integer to pass validation and rerun the command. This will return
3029
success (no output).
3130

examples/kubeval/simple/fn-config.yaml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,4 @@ metadata:
66
config.k8s.io/function: |
77
container:
88
image: gcr.io/kpt-fn/kubeval:unstable
9-
network: true
109
config.kubernetes.io/local-config: 'true'
11-
data:
12-
schema_location: https://kubernetesjsonschema.dev/

functions/ts/kubeval/build/kubeval.Dockerfile

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
FROM node:14.15-alpine3.12 as builder
22

3-
ARG KUBEVAL_VERSION="0.15.0"
3+
ARG KUBEVAL_VERSION="v0.16.1"
44
RUN apk add curl && \
55
curl -sSLf https://github.com/instrumenta/kubeval/releases/download/${KUBEVAL_VERSION}/kubeval-linux-amd64.tar.gz | \
66
tar xzf - -C /usr/local/bin
@@ -27,15 +27,20 @@ RUN npm run build && \
2727

2828
FROM node:14.15-alpine3.12
2929

30+
RUN apk add --update --no-cache python3 py3-pip && ln -sf python3 /usr/bin/python
31+
RUN pip install pyyaml jsonref click
32+
COPY forked/github.com/instrumenta/openapi2jsonschema/*.py /openapi2jsonschema/
33+
RUN chmod +x /openapi2jsonschema/command.py && ln -s /openapi2jsonschema/command.py /usr/bin/openapi2jsonschema
34+
3035
# Run as non-root user as a best-practices:
3136
# https://github.com/nodejs/docker-node/blob/master/docs/BestPractices.md
3237
USER node
3338

3439
WORKDIR /home/node/app
3540

3641
COPY --from=builder /home/node/app /home/node/app
37-
3842
COPY --from=builder /usr/local/bin /usr/local/bin
43+
COPY openapi.json /home/node/
3944

4045
ENV PATH /usr/local/bin:$PATH
4146

functions/ts/kubeval/forked/github.com/instrumenta/openapi2jsonschema/command.py

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,15 @@
99
from jsonref import JsonRef # type: ignore
1010
import click
1111

12-
from openapi2jsonschema.log import info, debug, error
13-
from openapi2jsonschema.util import (
12+
from log import info, debug, error
13+
from util import (
1414
additional_properties,
1515
replace_int_or_string,
1616
allow_null_optional_fields,
1717
change_dict_values,
1818
append_no_duplicates,
1919
)
20-
from openapi2jsonschema.errors import UnsupportedError
20+
from errors import UnsupportedError
2121

2222

2323
@click.command()
@@ -48,11 +48,22 @@
4848
is_flag=True,
4949
help="Prohibits properties not in the schema (additionalProperties: false)",
5050
)
51+
@click.option(
52+
"--apiversionkind",
53+
metavar="apiVersion1,kind1;apiVersion2,kind2",
54+
help="the target resources",
55+
)
5156
@click.argument("schema", metavar="SCHEMA_URL")
52-
def default(output, schema, prefix, stand_alone, expanded, kubernetes, strict):
57+
def default(output, schema, prefix, stand_alone, expanded, kubernetes, strict, apiversionkind):
5358
"""
5459
Converts a valid OpenAPI specification into a set of JSON Schema files
5560
"""
61+
apiVersionKindSet = set()
62+
avkList = apiversionkind.strip("'\"").split(";")
63+
for avk in avkList:
64+
elements = avk.split(",")
65+
apiVersionKindSet.add((elements[0], elements[1].lower()))
66+
5667
info("Downloading schema")
5768
if sys.version_info < (3, 0):
5869
response = urllib.urlopen(schema)
@@ -96,7 +107,7 @@ def default(output, schema, prefix, stand_alone, expanded, kubernetes, strict):
96107
type_def = definitions[type_name]
97108
if "x-kubernetes-group-version-kind" in type_def:
98109
for kube_ext in type_def["x-kubernetes-group-version-kind"]:
99-
if expanded and "apiVersion" in type_def["properties"]:
110+
if expanded and "properties" in type_def and "apiVersion" in type_def["properties"]:
100111
api_version = (
101112
kube_ext["group"] + "/" +
102113
kube_ext["version"]
@@ -108,7 +119,7 @@ def default(output, schema, prefix, stand_alone, expanded, kubernetes, strict):
108119
"enum",
109120
api_version,
110121
)
111-
if "kind" in type_def["properties"]:
122+
if "properties" in type_def and "kind" in type_def["properties"]:
112123
kind = kube_ext["kind"]
113124
append_no_duplicates(
114125
type_def["properties"]["kind"], "enum", kind
@@ -131,6 +142,9 @@ def default(output, schema, prefix, stand_alone, expanded, kubernetes, strict):
131142
if kubernetes:
132143
group = title.split(".")[-3].lower()
133144
api_version = title.split(".")[-2].lower()
145+
tup = (group + "/" + api_version if group and group != "core" else api_version, kind)
146+
if tup not in apiVersionKindSet:
147+
continue
134148
specification = components[title]
135149
specification["$schema"] = "http://json-schema.org/schema#"
136150
specification.setdefault("type", "object")
@@ -183,7 +197,7 @@ def default(output, schema, prefix, stand_alone, expanded, kubernetes, strict):
183197
specification = updated
184198

185199
if stand_alone:
186-
base = "file://%s/%s/" % (os.getcwd(), output)
200+
base = "file://%s/" % (os.path.realpath(output))
187201
specification = JsonRef.replace_refs(
188202
specification, base_uri=base)
189203

functions/ts/kubeval/forked/github.com/instrumenta/openapi2jsonschema/test_command.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import pytest # type: ignore
33
from click.testing import CliRunner
44

5-
from openapi2jsonschema.command import default
5+
from command import default
66

77
FIXTURE_DIR = os.path.join(os.path.dirname(os.path.realpath(__file__)), "../fixtures")
88

0 commit comments

Comments
 (0)