From 79d8ce30550fb052a5d9a5a85f28484f72c58d1f Mon Sep 17 00:00:00 2001 From: Yann Hamon Date: Sun, 31 May 2020 01:09:53 +0200 Subject: [PATCH] forgot to commit files --- pkg/registry/kubernetesjsonschema.go | 78 ++++++++++++++++++++++++++++ pkg/registry/local.go | 68 ++++++++++++++++++++++++ 2 files changed, 146 insertions(+) create mode 100644 pkg/registry/kubernetesjsonschema.go create mode 100644 pkg/registry/local.go diff --git a/pkg/registry/kubernetesjsonschema.go b/pkg/registry/kubernetesjsonschema.go new file mode 100644 index 0000000..608b68d --- /dev/null +++ b/pkg/registry/kubernetesjsonschema.go @@ -0,0 +1,78 @@ +package registry + +import ( + "fmt" + "github.com/xeipuuv/gojsonschema" + "io/ioutil" + "net/http" + "strings" +) + +type KubernetesRegistry struct { + baseURL string + strict bool +} + +type downloadError struct { + err error + isRetryable bool +} +func newDownloadError(err error, isRetryable bool) *downloadError{ + return &downloadError{err, isRetryable} +} +func (e *downloadError) IsRetryable() bool { return e.isRetryable } +func (e *downloadError) Error() string { return e.err.Error() } + +func NewKubernetesRegistry(strict bool) *KubernetesRegistry { + return &KubernetesRegistry{ + baseURL: "https://kubernetesjsonschema.dev", + strict: strict, + } +} + +func (r KubernetesRegistry) schemaURL(resourceKind, resourceAPIVersion, k8sVersion string) string { + normalisedVersion := k8sVersion + if normalisedVersion != "master" { + normalisedVersion = "v" + normalisedVersion + } + + strictSuffix := "" + if r.strict { + strictSuffix = "-strict" + } + + groupParts := strings.Split(resourceAPIVersion, "/") + versionParts := strings.Split(groupParts[0], ".") + + kindSuffix := "-" + strings.ToLower(versionParts[0]) + if len(groupParts) > 1 { + kindSuffix += "-" + strings.ToLower(groupParts[1]) + } + + return fmt.Sprintf("%s/%s-standalone%s/%s%s.json", r.baseURL, normalisedVersion, strictSuffix, strings.ToLower(resourceKind), kindSuffix) +} + +func (r KubernetesRegistry) DownloadSchema(resourceKind, resourceAPIVersion, k8sVersion string) (*gojsonschema.Schema, error) { + url := r.schemaURL(resourceKind, resourceAPIVersion, k8sVersion) + + resp, err := http.Get(url) + if err != nil { + return nil, fmt.Errorf("failed downloading schema at %s: %s", url, err) + } + defer resp.Body.Close() + + if resp.StatusCode == http.StatusNotFound{ + return nil, newDownloadError(fmt.Errorf("no schema found"), false) + } + + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("error while downloading schema - received HTTP status %s", resp.StatusCode) + } + + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, fmt.Errorf("failed downloading schema at %s: %s", url, err) + } + + return gojsonschema.NewSchema(gojsonschema.NewBytesLoader(body)) +} diff --git a/pkg/registry/local.go b/pkg/registry/local.go new file mode 100644 index 0000000..cbd52de --- /dev/null +++ b/pkg/registry/local.go @@ -0,0 +1,68 @@ +package registry + +import ( + "fmt" + "github.com/xeipuuv/gojsonschema" + "sigs.k8s.io/yaml" + "io/ioutil" + "os" + "strings" +) + +type LocalSchemas struct { + schemas map[string]*gojsonschema.Schema +} + + +func NewLocalSchemas(schemaFiles []string) (*LocalSchemas, error) { + schemas := &LocalSchemas{ + schemas: map[string]*gojsonschema.Schema{}, + } + + for _, schemaFile := range schemaFiles { + f, err := os.Open(schemaFile) + if err != nil { + return nil, fmt.Errorf("failed to open schema %s", schemaFile) + } + defer f.Close() + content, err := ioutil.ReadAll(f) + if err != nil { + return nil, fmt.Errorf("failed to read schema %s", schemaFile) + } + + var parsedSchema struct{ + Spec struct { + Names struct { + Kind string `json:"Kind"` + } `json:"Names"` + } `json:"Spec"` + } + err = yaml.Unmarshal(content, &parsedSchema) + if err != nil { + return nil, fmt.Errorf("failed parsing schema %s", schemaFile) + } + + if strings.HasSuffix(schemaFile, ".yml") || strings.HasSuffix(schemaFile, ".yaml") { + asJSON, err := yaml.YAMLToJSON(content) + if err != nil { + return nil, fmt.Errorf("error converting manifest %s to JSON: %s", schemaFile, err) + } + + schema, err := gojsonschema.NewSchema(gojsonschema.NewBytesLoader(asJSON)) + if err != nil { + return nil, err + } + schemas.schemas[parsedSchema.Spec.Names.Kind] = schema + } + } + + return schemas, nil +} + +func (r LocalSchemas) DownloadSchema(resourceKind, resourceAPIVersion, k8sVersion string) (*gojsonschema.Schema, error) { + schema, ok := r.schemas[resourceKind] + if !ok { + return nil, fmt.Errorf("no local schema for Kind %s", resourceKind) + } + return schema, nil +}