Browse Source

Works, mostly.

Signed-off-by: Martyn Ranyard <m@rtyn.berlin>
main v0.0.1
Martyn 1 year ago
parent
commit
f143e55f86
12 changed files with 962 additions and 0 deletions
  1. +19
    -0
      Makefile
  2. +58
    -0
      build/ci/drone.yml
  3. +18
    -0
      build/package/Dockerfile
  4. +252
    -0
      cmd/main.go
  5. +13
    -0
      go.mod
  6. +200
    -0
      go.sum
  7. +74
    -0
      internal/exporters/configmap.go
  8. +79
    -0
      internal/exporters/deployment.go
  9. +72
    -0
      internal/exporters/ingress.go
  10. +74
    -0
      internal/exporters/secret.go
  11. +72
    -0
      internal/exporters/service.go
  12. +31
    -0
      internal/exporters/yamltools.go

+ 19
- 0
Makefile View File

@ -0,0 +1,19 @@
BUILD=`date +%FT%T%z`
LDFLAGS=-ldflags "-X main.buildDate=${BUILD}"
LDFLAGS_STATIC=-ldflags "-s -X main.buildDate=${BUILD}"
.PHONY: deps build dist
test:
go test git.martyn.berlin/martyn/helm-import/cmd
build:
go build cmd ${LDFLAGS}
deps:
GO111MODULE=on go mod download
dist:
mkdir -p bin || true
cd cmd && go build ${LDFLAGS_STATIC} -installsuffix cgo -o ../bin/helm-import .

+ 58
- 0
build/ci/drone.yml View File

@ -0,0 +1,58 @@
kind: pipeline
type: docker
name: linux-amd64-taggedver
platform:
arch: amd64
os: linux
steps:
- name: build
image: golang
commands:
- pwd
- mkdir -p /go/src/git.martyn.berlin/martyn
- ln -s /drone/src /go/src/git.martyn.berlin/martyn/helm-import
- cd /go/src/git.martyn.berlin/martyn/helm-import
- make deps
- make dist
- name: publish
image: plugins/docker:18
settings:
auto_tag: true
auto_tag_suffix: linux-amd64
dockerfile: build/package/Dockerfile
repo: imartyn/helm-import
username:
from_secret: docker_username
password:
from_secret: docker_password
when:
event:
- push
- tag
trigger:
ref:
- refs/tags/v*
---
kind: pipeline
type: docker
name: linux-amd64-devel-main
platform:
arch: amd64
os: linux
steps:
- name: build
image: golang
commands:
- pwd
- mkdir -p /go/src/git.martyn.berlin/martyn
- ln -s /drone/src /go/src/git.martyn.berlin/martyn/helm-import
- cd /go/src/git.martyn.berlin/martyn/helm-import
- make deps
- make dist

+ 18
- 0
build/package/Dockerfile View File

@ -0,0 +1,18 @@
FROM golang:1.14.12-alpine3.12 AS libjq
RUN apk --no-cache add curl ca-certificates alpine-sdk && \
cd /tmp ; curl -L -fsS https://github.com/stedolan/jq/releases/download/jq-1.5/jq-1.5.tar.gz | tar -xz && \
cd jq-1.5 && \
./configure --disable-maintainer-mode --prefix=/usr && \
make install-libLTLIBRARIES install-includeHEADERS
FROM libjq AS builder
RUN update-ca-certificates
COPY go.mod /go/src/git.martyn.berlin/martyn/helm-import/
COPY cmd/ /go/src/git.martyn.berlin/martyn/helm-import/cmd/
COPY internal/ /go/src/git.martyn.berlin/martyn/helm-import/internal/
COPY Makefile /go/src/git.martyn.berlin/martyn/helm-import/
RUN cd /go/src/git.martyn.berlin/martyn/helm-import/; make deps && make dist
FROM alpine:3.12
COPY --from=builder /go/src/git.martyn.berlin/martyn/helm-import/bin/helm-import /
COPY --from=builder /usr/lib/libjq.* /usr/lib/

+ 252
- 0
cmd/main.go View File

@ -0,0 +1,252 @@
package main
import (
"flag"
"fmt"
"io/ioutil"
"path/filepath"
"strings"
"gopkg.in/yaml.v2"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/client-go/util/homedir"
"git.martyn.berlin/martyn/helm-import/internal/exporters"
//
// Uncomment to load all auth plugins
// "k8s.io/client-go/plugin/pkg/client/auth"
//
// Or uncomment to load specific auth plugins
// _ "k8s.io/client-go/plugin/pkg/client/auth/azure"
// _ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
// _ "k8s.io/client-go/plugin/pkg/client/auth/oidc"
// _ "k8s.io/client-go/plugin/pkg/client/auth/openstack"
)
type objectFlags []string
func (i *objectFlags) String() string {
return strings.Join(*i, ", ")
}
func (i *objectFlags) Set(value string) error {
*i = append(*i, value)
return nil
}
type jqCommands []string
func (i *jqCommands) String() string {
return strings.Join(*i, ", ")
}
func (i *jqCommands) Set(value string) error {
*i = append(*i, value)
return nil
}
var deployments objectFlags
var services objectFlags
var configmaps objectFlags
var secrets objectFlags
var ingresses objectFlags
var namespace string
var noBuiltinMods bool
var lessOpinions bool
var deploymentJqCommands jqCommands
var serviceJqCommands jqCommands
var ingressJqCommands jqCommands
var globalJqCommands jqCommands
var configmapJqCommands jqCommands
var secretJqCommands jqCommands
type chartDef struct {
APIVersion string `json: "apiVersion"`
Name string `json: "name"`
Description string `json: "description"`
Type string `json: "type"`
Version string `json: "version"`
AppVersion string `json: "appVersion"`
}
var chart chartDef
func main() {
chartYamlFile, err := ioutil.ReadFile("Chart.yaml")
if err != nil {
panic("Run this from the chart folder, where Chart.yaml is. Error: " + err.Error())
}
err = yaml.Unmarshal(chartYamlFile, &chart)
if err != nil {
panic("Could not read the chart yaml as expected. Error: " + err.Error())
}
var kubeconfig *string
if home := homedir.HomeDir(); home != "" {
kubeconfig = flag.String("kubeconfig", filepath.Join(home, ".kube", "config"), "(optional) absolute path to the kubeconfig file")
} else {
kubeconfig = flag.String("kubeconfig", "", "absolute path to the kubeconfig file")
}
flag.StringVar(&namespace, "namespace", "default", "namespace to work in")
flag.Var(&deployments, "deployment", "deployment to import into the helm chart (can be specified multiple times)")
flag.Var(&services, "service", "service to import into the helm chart (can be specified multiple times)")
flag.Var(&configmaps, "configmap", "configmap to import into the helm chart (can be specified multiple times)")
flag.Var(&secrets, "secret", "secret to import into the helm chart (can be specified multiple times)")
flag.Var(&ingresses, "ingress", "ingress to import into the helm chart (can be specified multiple times)")
flag.BoolVar(&noBuiltinMods, "nobuiltinmods", false, "don't do the built-in modifications, only ones passed in by user")
flag.BoolVar(&lessOpinions, "lessopinions", false, "just import the objects into files, don't get opinionated")
flag.Var(&globalJqCommands, "globalJqCommands", "extra jq commands to apply to all k8s objects")
flag.Var(&deploymentJqCommands, "deploymentJqCommands", "extra jq commands to apply to deployments")
flag.Var(&serviceJqCommands, "serviceJqCommands", "extra jq commands to apply to services")
flag.Var(&configmapJqCommands, "configmapJqCommands", "extra jq commands to apply to configmaps")
flag.Var(&secretJqCommands, "secretJqCommands", "extra jq commands to apply to secrets")
flag.Var(&ingressJqCommands, "ingressJqCommands", "extra jq commands to apply to ingresses")
flag.Parse()
// use the current context in kubeconfig
config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig)
if err != nil {
panic(err.Error())
}
// create the clientset
clientset, err := kubernetes.NewForConfig(config)
if err != nil {
panic(err.Error())
}
var y = ""
fileString := ""
for _, deployment := range deployments {
deploymentObject, err := clientset.AppsV1().Deployments(namespace).Get(deployment, metav1.GetOptions{})
if errors.IsNotFound(err) {
fmt.Printf("Deployment %s in namespace %s not found\n", deployment, namespace)
} else if statusError, isStatus := err.(*errors.StatusError); isStatus {
fmt.Printf("Error getting deployment %s in namespace %s: %v\n",
deployment, namespace, statusError.ErrStatus.Message)
} else if err != nil {
panic(err.Error())
} else {
fmt.Printf("Found deployment %s in namespace %s\n", deployment, namespace)
y = exporters.Deployment(deploymentObject, append(deploymentJqCommands, globalJqCommands...), noBuiltinMods, chart.Name, lessOpinions)
if fileString != "" {
fileString += "---\n"
}
fileString += y
}
}
if y != "" {
err = ioutil.WriteFile("templates/imported-deployment.yaml", []byte(fileString), 0644)
if err != nil {
panic(err.Error())
}
}
for _, service := range services {
serviceObject, err := clientset.CoreV1().Services(namespace).Get(service, metav1.GetOptions{})
if errors.IsNotFound(err) {
fmt.Printf("service %s in namespace %s not found\n", service, namespace)
} else if statusError, isStatus := err.(*errors.StatusError); isStatus {
fmt.Printf("Error getting service %s in namespace %s: %v\n",
service, namespace, statusError.ErrStatus.Message)
} else if err != nil {
panic(err.Error())
} else {
fmt.Printf("Found service %s in namespace %s\n", service, namespace)
y = exporters.Service(serviceObject, append(serviceJqCommands, globalJqCommands...), noBuiltinMods, chart.Name, lessOpinions)
if fileString != "" {
fileString += "---\n"
}
fileString += y
}
}
if y != "" {
err = ioutil.WriteFile("templates/imported-service.yaml", []byte(fileString), 0644)
if err != nil {
panic(err.Error())
}
}
for _, configmap := range configmaps {
configmapObject, err := clientset.CoreV1().ConfigMaps(namespace).Get(configmap, metav1.GetOptions{})
if errors.IsNotFound(err) {
fmt.Printf("configmap %s in namespace %s not found\n", configmap, namespace)
} else if statusError, isStatus := err.(*errors.StatusError); isStatus {
fmt.Printf("Error getting configmap %s in namespace %s: %v\n",
configmap, namespace, statusError.ErrStatus.Message)
} else if err != nil {
panic(err.Error())
} else {
fmt.Printf("Found configmap %s in namespace %s\n", configmap, namespace)
y = exporters.Configmap(configmapObject, append(serviceJqCommands, globalJqCommands...), noBuiltinMods, chart.Name, lessOpinions)
}
if fileString != "" {
fileString += "---\n"
}
fileString += y
}
if y != "" {
err = ioutil.WriteFile("templates/imported-configmap.yaml", []byte(fileString), 0644)
if err != nil {
panic(err.Error())
}
}
for _, secret := range secrets {
secretObject, err := clientset.CoreV1().Secrets(namespace).Get(secret, metav1.GetOptions{})
if errors.IsNotFound(err) {
fmt.Printf("secret %s in namespace %s not found\n", secret, namespace)
} else if statusError, isStatus := err.(*errors.StatusError); isStatus {
fmt.Printf("Error getting secret %s in namespace %s: %v\n",
secret, namespace, statusError.ErrStatus.Message)
} else if err != nil {
panic(err.Error())
} else {
fmt.Printf("Found secret %s in namespace %s\n", secret, namespace)
y = exporters.Secret(secretObject, append(serviceJqCommands, globalJqCommands...), noBuiltinMods, chart.Name, lessOpinions)
}
if fileString != "" {
fileString += "---\n"
}
fileString += y
}
if y != "" {
err = ioutil.WriteFile("templates/imported-secret.yaml", []byte(fileString), 0644)
if err != nil {
panic(err.Error())
}
}
for _, ingress := range ingresses {
ingressObject, err := clientset.ExtensionsV1beta1().Ingresses(namespace).Get(ingress, metav1.GetOptions{})
if errors.IsNotFound(err) {
fmt.Printf("ingress %s in namespace %s not found\n", ingress, namespace)
} else if statusError, isStatus := err.(*errors.StatusError); isStatus {
fmt.Printf("Error getting ingress %s in namespace %s: %v\n",
ingress, namespace, statusError.ErrStatus.Message)
} else if err != nil {
panic(err.Error())
} else {
fmt.Printf("Found ingress %s in namespace %s\n", ingress, namespace)
y = exporters.Ingress(ingressObject, append(serviceJqCommands, globalJqCommands...), noBuiltinMods, chart.Name, lessOpinions)
}
if fileString != "" {
fileString += "---\n"
}
fileString += y
}
if y != "" {
err = ioutil.WriteFile("templates/imported-ingress.yaml", []byte(fileString), 0644)
if err != nil {
panic(err.Error())
}
}
}

+ 13
- 0
go.mod View File

@ -0,0 +1,13 @@
module git.martyn.berlin/martyn/helm-import
go 1.13
require (
github.com/ashb/jqrepl v0.1.0
github.com/cheekybits/is v0.0.0-20150225183255-68e9c0620927 // indirect
gopkg.in/yaml.v2 v2.2.8
k8s.io/api v0.16.15
k8s.io/apimachinery v0.16.15
k8s.io/client-go v0.16.15
sigs.k8s.io/yaml v1.1.0
)

+ 200
- 0
go.sum View File

@ -0,0 +1,200 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.38.0 h1:ROfEUZz+Gh5pa62DJWXSaonyu3StP6EA6lPEXPI6mCo=
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
github.com/Azure/go-autorest/autorest v0.9.0 h1:MRvx8gncNaXJqOoLmhNjUAKh33JJF8LyxPhomEtOsjs=
github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI=
github.com/Azure/go-autorest/autorest/adal v0.5.0 h1:q2gDruN08/guU9vAjuPWff0+QIrpH6ediguzdAzXAUU=
github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0=
github.com/Azure/go-autorest/autorest/date v0.1.0 h1:YGrhWfrgtFs84+h0o46rJrlmsZtyZRg470CqAXTZaGM=
github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA=
github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0=
github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0=
github.com/Azure/go-autorest/logger v0.1.0 h1:ruG4BSDXONFRrZZJ2GUXDiUyVpayPmb1GnWeHDdaNKY=
github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc=
github.com/Azure/go-autorest/tracing v0.5.0 h1:TRn4WjSnkcSy5AEG3pnbtFSwNtwzjr4VYyQflFE619k=
github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
github.com/ashb/jqrepl v0.1.0 h1:lugLTnp0F8mKE6pfhf5eExcjSTvUAuGXnB9pVixTfSY=
github.com/ashb/jqrepl v0.1.0/go.mod h1:dFTYRmXpWcRRjMqu2SMMxRoXONIdB/aN4/auvtre64I=
github.com/cheekybits/is v0.0.0-20150225183255-68e9c0620927 h1:SKI1/fuSdodxmNNyVBR8d7X/HuLnRpvvFO0AgyQk764=
github.com/cheekybits/is v0.0.0-20150225183255-68e9c0620927/go.mod h1:h/aW8ynjgkuj+NQRlZcDbAbM1ORAbXjXX77sX7T289U=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM=
github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0=
github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg=
github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc=
github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I=
github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d h1:3PaI8p3seN09VjbTYC/QWlUZdZ1qS1zGjy7LH2Wt07I=
github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d h1:7XGaL1e6bYS1yIonGp9761ExpPPV1ui0SAC59Yube9k=
github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
github.com/gophercloud/gophercloud v0.1.0 h1:P/nh25+rzXouhytV2pUHBb65fnds26Ghl8/391+sT5o=
github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8=
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/imdario/mergo v0.3.5 h1:JboBksRwiiAJWvIYJVo46AfV+IAIKZpfrSzVKj42R4Q=
github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.7 h1:KfgG9LzI+pYjr4xvmz/5H4FXjokeP+rlHLhv3iH62Fo=
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180320133207-05fbef0ca5da/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975 h1:/Tl7pH94bvbAAHBdZJT947M/+gp0+CqQXDtMRC0fseo=
golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20191004110552-13f9640d40b9 h1:rjwSpXsdiK0dV8/Naq3kAw9ymfAeJIyd0upUIElB+lI=
golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a h1:aYOabOQFp6Vj6W1F80affTUvO9UxmJRx8K0gsfABByQ=
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.5.0 h1:KxkO13IPW4Lslp2bz+KHP2E3gtFlrIGNThxkZQ3g+4c=
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
k8s.io/api v0.16.15 h1:6yvV9YNGwnebDAsA4Sfj+1b1S9j5OYfmckjTdc9b1bI=
k8s.io/api v0.16.15/go.mod h1:8z880CLtpCJqHWe9vmBkZMQeMKHNvdTQuqLW2QUefUA=
k8s.io/apimachinery v0.16.15 h1:4cmEfuRsKuV8pMpaQ6z0AKEUXZ3r+u/NKaz5dvIjySk=
k8s.io/apimachinery v0.16.15/go.mod h1:xAtIC8Gj83Pn2OCs2g57wZpZembRhJhiXIlQIqanwas=
k8s.io/client-go v0.16.15 h1:cuSmM5begnN77V0beNgmhQ9yob6TFUnN+YaqAfRBD40=
k8s.io/client-go v0.16.15/go.mod h1:onpbkg9XeonG579HOlK9RS56ixfOJdbBM5dKluyFM8c=
k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8=
k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I=
k8s.io/kube-openapi v0.0.0-20200410163147-594e756bea31/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E=
k8s.io/utils v0.0.0-20190801114015-581e00157fb1 h1:+ySTxfHnfzZb9ys375PXNlLhkJPLKgHajBU0N62BDvE=
k8s.io/utils v0.0.0-20190801114015-581e00157fb1/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI=
sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs=
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=

+ 74
- 0
internal/exporters/configmap.go View File

@ -0,0 +1,74 @@
package exporters
import (
"encoding/json"
"regexp"
v1 "k8s.io/api/core/v1"
"sigs.k8s.io/yaml"
)
// Configmap removes basic stuff like namespace, status, managedBy and lastAppliedConfiguration
func Configmap(cm *v1.ConfigMap, jqcommands []string, nobuiltinmods bool, chartname string, lessOpinions bool) string {
if !nobuiltinmods {
// All the below do not belong in a helm chart yaml
delete(cm.ObjectMeta.Annotations, "kubectl.kubernetes.io/last-applied-configuration")
delete(cm.ObjectMeta.Annotations, "deployment.kubernetes.io/revision")
cm.ObjectMeta.ManagedFields = nil
cm.ObjectMeta.Namespace = ""
cm.ObjectMeta.ResourceVersion = ""
cm.ObjectMeta.Generation = 0
cm.ObjectMeta.SelfLink = ""
cm.ObjectMeta.UID = ""
jqcommands = append(jqcommands, "del(.metadata.creationTimestamp)")
// Here's where we get more opinionated though
if !lessOpinions {
jqcommands = append(jqcommands, ".metadata.name = \"{{ $fullName }}\"")
jqcommands = append(jqcommands, ".metadata.labels += {HELMTEMPLATEDELETEKEY: \"{{- include \\\""+chartname+".labels\\\" . | nindent 4 }}\"}")
jqcommands = append(jqcommands, ".metadata.annotations += {HELMTEMPLATEDELETEKEY: \"{{- include \\\""+chartname+".annotations\\\" . | nindent 4 }}\"}")
jqcommands = append(jqcommands, ".data += { \"HELMTEMPLATEDELETEKEY0\": \"{{- range $key, $value := .Values."+chartname+".env }}\" }")
jqcommands = append(jqcommands, ".data += { \"HELMTEMPLATEDELETEKEY1\": \"{{ $key }}: {{ $value | quote }}\" }")
jqcommands = append(jqcommands, ".data += { \"HELMTEMPLATEDELETEKEY2\": \"{{- end }}\" }")
}
}
// Jump to json for jq ;-)
jsonForm, err := json.Marshal(cm)
if err != nil {
panic(err.Error())
}
var intermediateJSONForm []byte
var finalJSONForm []byte
if len(jqcommands) > 0 {
for _, command := range jqcommands {
intermediateJSONForm = jQOnJSONByteArray(command, jsonForm)
jsonForm = intermediateJSONForm
}
finalJSONForm = jsonForm
} else {
finalJSONForm = jsonForm
}
y, err := yaml.JSONToYAML(finalJSONForm)
if err != nil {
panic(err.Error())
}
ret := "{{- $fullName := include \"" + chartname + ".fullname\" . -}}\n"
ret += "kind: ConfigMap\n"
ret += "apiVersion: v1\n"
out := string(y)
var re = regexp.MustCompile(`HELMTEMPLATEDELETEKEY: '([^']*)'`)
out = re.ReplaceAllString(out, "$1")
re = regexp.MustCompile(`HELMTEMPLATEDELETEKEY0: '([^']*)'`)
out = re.ReplaceAllString(out, "$1")
re = regexp.MustCompile(`HELMTEMPLATEDELETEKEY1: '([^']*)'`)
out = re.ReplaceAllString(out, "$1")
re = regexp.MustCompile(`HELMTEMPLATEDELETEKEY2: '([^']*)'`)
out = re.ReplaceAllString(out, "$1")
re = regexp.MustCompile(`(?s)- HELMTEMPLATEDELETEKEYANDARRAYMARKER: '([^']*)'`)
out = re.ReplaceAllString(out, "$1")
ret += string(out)
return ret
}

+ 79
- 0
internal/exporters/deployment.go View File

@ -0,0 +1,79 @@
package exporters
import (
"encoding/json"
"regexp"
v1 "k8s.io/api/apps/v1"
"sigs.k8s.io/yaml"
)
// Deployment removes basic stuff like namespace, status, managedBy and lastAppliedConfiguration
func Deployment(deploy *v1.Deployment, jqcommands []string, nobuiltinmods bool, chartname string, lessOpinions bool) string {
if !nobuiltinmods {
// All the below do not belong in a helm chart yaml
delete(deploy.ObjectMeta.Annotations, "kubectl.kubernetes.io/last-applied-configuration")
delete(deploy.ObjectMeta.Annotations, "deployment.kubernetes.io/revision")
deploy.ObjectMeta.ManagedFields = nil
deploy.ObjectMeta.Namespace = ""
deploy.ObjectMeta.ResourceVersion = ""
deploy.ObjectMeta.Generation = 0
deploy.ObjectMeta.SelfLink = ""
deploy.ObjectMeta.UID = ""
jqcommands = append(jqcommands, "del(.metadata.creationTimestamp)")
jqcommands = append(jqcommands, "del(.status)")
if !lessOpinions {
jqcommands = append(jqcommands, ".metadata.name = \"{{ $fullName }}\"")
jqcommands = append(jqcommands, ".spec.replicas = \"{{ .values.replicaCount }}\"")
jqcommands = append(jqcommands, ".metadata.labels += {HELMTEMPLATEDELETEKEY: \"{{- include \\\""+chartname+".labels\\\" . | nindent 4 }}\"}")
jqcommands = append(jqcommands, ".metadata.annotations += {HELMTEMPLATEDELETEKEY: \"{{- include \\\""+chartname+".annotations\\\" . | nindent 4 }}\"}")
// damn, "checksum/config" works as a key in yaml, not in json!
jqcommands = append(jqcommands, ".metadata.annotations += {checksumConfig: \"{{- include (print $.Template.BasePath \\\"/configmap.yaml\\\") . | sha256sum }}\"}")
jqcommands = append(jqcommands, ".metadata.annotations += {checksumSecret: \"{{- include (print $.Template.BasePath \\\"/secret.yaml\\\") . | sha256sum }}\"}")
jqcommands = append(jqcommands, ".spec.selector.matchLabels += {HELMTEMPLATEDELETEKEY: \"{{- include \\\""+chartname+".selectorLabels\\\" . | nindent 6 }}\"}")
jqcommands = append(jqcommands, ".spec.template.metadata.labels += {HELMTEMPLATEDELETEKEY: \"{{- include \\\""+chartname+".labels\\\" . | nindent 8 }}\"}")
jqcommands = append(jqcommands, ".spec.template.metadata.annotations += {HELMTEMPLATEDELETEKEY: \"{{- include \\\""+chartname+".annotations\\\" . | nindent 8 }}\"}")
jqcommands = append(jqcommands, ".spec.template.spec.serviceAccountName = \"{{ include \\\""+chartname+".serviceAccountName\\\" . }}\"")
jqcommands = append(jqcommands, ".spec.template.spec.securityContext += {HELMTEMPLATEDELETEKEY: \"{{- toYaml .podSecurityContext | nindent 8 }}\"}")
jqcommands = append(jqcommands, ".spec.template.spec.containers[0].env += [{HELMTEMPLATEDELETEKEYANDARRAYMARKER: \"{{- range $key, $value := .Values."+chartname+".env }}\"}]")
jqcommands = append(jqcommands, ".spec.template.spec.containers[0].env += [{ name: \"{{ $key }}\", valueFrom: {configMapKeyRef: {name: \"{{ $fullName }}\", key: \"{{ $key | quote }}\" }} }]")
jqcommands = append(jqcommands, ".spec.template.spec.containers[0].env += [{HELMTEMPLATEDELETEKEYANDARRAYMARKER: \"{{- end }}\"}]")
jqcommands = append(jqcommands, ".spec.template.spec.containers[0].env += [{HELMTEMPLATEDELETEKEYANDARRAYMARKER: \"{{- range $key, $value := .Values."+chartname+".secretenv }}\"}]")
jqcommands = append(jqcommands, ".spec.template.spec.containers[0].env += [{ name: \"{{ $key }}\", valueFrom: {secretKeyRef: {name: \"{{ $fullName }}\", key: \"{{ $key | quote }}\" }} }]")
jqcommands = append(jqcommands, ".spec.template.spec.containers[0].env += [{HELMTEMPLATEDELETEKEYANDARRAYMARKER: \"{{- end }}\"}]")
}
}
// Jump to json for jq ;-)
jsonForm, err := json.Marshal(deploy)
if err != nil {
panic(err.Error())
}
var intermediateJSONForm []byte
var finalJSONForm []byte
if len(jqcommands) > 0 {
for _, command := range jqcommands {
intermediateJSONForm = jQOnJSONByteArray(command, jsonForm)
jsonForm = intermediateJSONForm
}
finalJSONForm = jsonForm
} else {
finalJSONForm = jsonForm
}
y, err := yaml.JSONToYAML(finalJSONForm)
if err != nil {
panic(err.Error())
}
ret := "{{- $fullName := include \"" + chartname + ".fullname\" . -}}\n"
ret += "kind: Deployment\n"
ret += "apiVersion: Apps/v1\n"
out := string(y)
var re = regexp.MustCompile(`HELMTEMPLATEDELETEKEY: '([^']*)'`)
out = re.ReplaceAllString(out, "$1")
re = regexp.MustCompile(`(?s)- HELMTEMPLATEDELETEKEYANDARRAYMARKER: '([^']*)'`)
out = re.ReplaceAllString(out, "$1")
ret += string(out)
return ret
}

+ 72
- 0
internal/exporters/ingress.go View File

@ -0,0 +1,72 @@
package exporters
import (
"encoding/json"
"regexp"
v1beta1 "k8s.io/api/extensions/v1beta1"
"sigs.k8s.io/yaml"
)
// Configmap removes basic stuff like namespace, status, managedBy and lastAppliedConfiguration
func Ingress(ing *v1beta1.Ingress, jqcommands []string, nobuiltinmods bool, chartname string, lessOpinions bool) string {
if !nobuiltinmods {
// All the below do not belong in a helm chart yaml
delete(ing.ObjectMeta.Annotations, "kubectl.kubernetes.io/last-applied-configuration")
delete(ing.ObjectMeta.Annotations, "deployment.kubernetes.io/revision")
ing.ObjectMeta.ManagedFields = nil
ing.ObjectMeta.Namespace = ""
ing.ObjectMeta.ResourceVersion = ""
ing.ObjectMeta.Generation = 0
ing.ObjectMeta.SelfLink = ""
ing.ObjectMeta.UID = ""
jqcommands = append(jqcommands, "del(.metadata.creationTimestamp)")
// Here's where we get more opinionated though
if !lessOpinions {
jqcommands = append(jqcommands, ".metadata.name = \"{{ $fullName }}\"")
jqcommands = append(jqcommands, ".metadata.labels += {HELMTEMPLATEDELETEKEY: \"{{- include \\\""+chartname+".labels\\\" . | nindent 4 }}\"}")
jqcommands = append(jqcommands, ".metadata.annotations += {HELMTEMPLATEDELETEKEY: \"{{- include \\\""+chartname+".annotations\\\" . | nindent 4 }}\"}")
}
}
// Jump to json for jq ;-)
jsonForm, err := json.Marshal(ing)
if err != nil {
panic(err.Error())
}
var intermediateJSONForm []byte
var finalJSONForm []byte
if len(jqcommands) > 0 {
for _, command := range jqcommands {
intermediateJSONForm = jQOnJSONByteArray(command, jsonForm)
jsonForm = intermediateJSONForm
}
finalJSONForm = jsonForm
} else {
finalJSONForm = jsonForm
}
y, err := yaml.JSONToYAML(finalJSONForm)
if err != nil {
panic(err.Error())
}
ret := "{{- if .Values.ingress.enabled -}}\n"
ret += "{{- $fullName := include \"" + chartname + ".fullname\" . -}}\n"
ret += "{{- $releaseName := .Release.Name}}\n"
ret += "{{- $svcPort := .Values.service.port -}}\n"
ret += "{{- if semverCompare \">=1.14-0\" .Capabilities.KubeVersion.GitVersion -}}\n"
ret += "apiVersion: networking.k8s.io/v1beta1\n"
ret += "{{- else -}}\n"
ret += "apiVersion: extensions/v1beta1\n"
ret += "{{- end }}\n"
ret += "kind: Ingress\n"
out := string(y)
var re = regexp.MustCompile(`HELMTEMPLATEDELETEKEY: '([^']*)'`)
out = re.ReplaceAllString(out, "$1")
re = regexp.MustCompile(`(?s)- HELMTEMPLATEDELETEKEYANDARRAYMARKER: '([^']*)'`)
out = re.ReplaceAllString(out, "$1")
ret += string(out)
return ret
}

+ 74
- 0
internal/exporters/secret.go View File

@ -0,0 +1,74 @@
package exporters
import (
"encoding/json"
"regexp"
v1 "k8s.io/api/core/v1"
"sigs.k8s.io/yaml"
)
// Secret removes basic stuff like namespace, status, managedBy and lastAppliedConfiguration
func Secret(secret *v1.Secret, jqcommands []string, nobuiltinmods bool, chartname string, lessOpinions bool) string {
if !nobuiltinmods {
// All the below do not belong in a helm chart yaml
delete(secret.ObjectMeta.Annotations, "kubectl.kubernetes.io/last-applied-configuration")
delete(secret.ObjectMeta.Annotations, "deployment.kubernetes.io/revision")
secret.ObjectMeta.ManagedFields = nil
secret.ObjectMeta.Namespace = ""
secret.ObjectMeta.ResourceVersion = ""
secret.ObjectMeta.Generation = 0
secret.ObjectMeta.SelfLink = ""
secret.ObjectMeta.UID = ""
jqcommands = append(jqcommands, "del(.metadata.creationTimestamp)")
// Here's where we get more opinionated though
if !lessOpinions {
jqcommands = append(jqcommands, ".metadata.name = \"{{ $fullName }}\"")
jqcommands = append(jqcommands, ".metadata.labels += {HELMTEMPLATEDELETEKEY: \"{{- include \\\""+chartname+".labels\\\" . | nindent 4 }}\"}")
jqcommands = append(jqcommands, ".metadata.annotations += {HELMTEMPLATEDELETEKEY: \"{{- include \\\""+chartname+".annotations\\\" . | nindent 4 }}\"}")
jqcommands = append(jqcommands, ".data += { \"HELMTEMPLATEDELETEKEY0\": \"{{- range $key, $value := .Values."+chartname+".secretenv }}\" }")
jqcommands = append(jqcommands, ".data += { \"HELMTEMPLATEDELETEKEY1\": \"{{ $key }}: {{ $value | quote }}\" }")
jqcommands = append(jqcommands, ".data += { \"HELMTEMPLATEDELETEKEY2\": \"{{- end }}\" }")
}
}
// Jump to json for jq ;-)
jsonForm, err := json.Marshal(secret)
if err != nil {
panic(err.Error())
}
var intermediateJSONForm []byte
var finalJSONForm []byte
if len(jqcommands) > 0 {
for _, command := range jqcommands {
intermediateJSONForm = jQOnJSONByteArray(command, jsonForm)
jsonForm = intermediateJSONForm
}
finalJSONForm = jsonForm
} else {
finalJSONForm = jsonForm
}
y, err := yaml.JSONToYAML(finalJSONForm)
if err != nil {
panic(err.Error())
}
ret := "{{- $fullName := include \"" + chartname + ".fullname\" . -}}\n"
ret += "kind: Secret\n"
ret += "apiVersion: v1\n"
out := string(y)
var re = regexp.MustCompile(`HELMTEMPLATEDELETEKEY: '([^']*)'`)
out = re.ReplaceAllString(out, "$1")
re = regexp.MustCompile(`HELMTEMPLATEDELETEKEY0: '([^']*)'`)
out = re.ReplaceAllString(out, "$1")
re = regexp.MustCompile(`HELMTEMPLATEDELETEKEY1: '([^']*)'`)
out = re.ReplaceAllString(out, "$1")
re = regexp.MustCompile(`HELMTEMPLATEDELETEKEY2: '([^']*)'`)
out = re.ReplaceAllString(out, "$1")
re = regexp.MustCompile(`(?s)- HELMTEMPLATEDELETEKEYANDARRAYMARKER: '([^']*)'`)
out = re.ReplaceAllString(out, "$1")
ret += string(out)
return ret
}

+ 72
- 0
internal/exporters/service.go View File

@ -0,0 +1,72 @@
package exporters
import (
"encoding/json"
"regexp"
v1 "k8s.io/api/core/v1"
"sigs.k8s.io/yaml"
)
// Service removes basic stuff like namespace, status, managedBy and lastAppliedConfiguration
func Service(svc *v1.Service, jqcommands []string, nobuiltinmods bool, chartname string, lessOpinions bool) string {
if !nobuiltinmods {
// All the below do not belong in a helm chart yaml
delete(svc.ObjectMeta.Annotations, "kubectl.kubernetes.io/last-applied-configuration")
delete(svc.ObjectMeta.Annotations, "deployment.kubernetes.io/revision")
svc.ObjectMeta.ManagedFields = nil
svc.ObjectMeta.Namespace = ""
svc.ObjectMeta.ResourceVersion = ""
svc.ObjectMeta.Generation = 0
svc.ObjectMeta.SelfLink = ""
svc.ObjectMeta.UID = ""
jqcommands = append(jqcommands, "del(.metadata.creationTimestamp)")
jqcommands = append(jqcommands, "del(.status)")
// Here's where we get more opinionated though
if !lessOpinions {
jqcommands = append(jqcommands, ".metadata.name = \"{{ $fullName }}\"")
jqcommands = append(jqcommands, ".metadata.labels += {HELMTEMPLATEDELETEKEY: \"{{- include \\\""+chartname+".labels\\\" . | nindent 4 }}\"}")
jqcommands = append(jqcommands, ".metadata.annotations += {HELMTEMPLATEDELETEKEY: \"{{- include \\\""+chartname+".annotations\\\" . | nindent 4 }}\"}")
jqcommands = append(jqcommands, "del(.spec.clusterIP)")
jqcommands = append(jqcommands, ".spec.externalTrafficPolicy = \"{{ .Values.service.externalTrafficPolicy }}\"")
jqcommands = append(jqcommands, ".spec.type = \"{{ .Values.service.type }}\"")
jqcommands = append(jqcommands, "del(.spec.ports[].nodePort)")
}
}
// Jump to json for jq ;-)
jsonForm, err := json.Marshal(svc)
if err != nil {
panic(err.Error())
}
var intermediateJSONForm []byte
var finalJSONForm []byte
if len(jqcommands) > 0 {
for _, command := range jqcommands {
intermediateJSONForm = jQOnJSONByteArray(command, jsonForm)
jsonForm = intermediateJSONForm
}
finalJSONForm = jsonForm
} else {
finalJSONForm = jsonForm
}
y, err := yaml.JSONToYAML(finalJSONForm)
if err != nil {
panic(err.Error())
}
ret := "{{- if .Values.service.enabled -}}\n"
ret += "{{- $fullName := include \"" + chartname + ".fullname\" . -}}\n"
ret += "kind: Service\n"
ret += "apiVersion: v1\n"
out := string(y)
var re = regexp.MustCompile(`HELMTEMPLATEDELETEKEY: '([^']*)'`)
out = re.ReplaceAllString(out, "$1")
re = regexp.MustCompile(`(?s)- HELMTEMPLATEDELETEKEYANDARRAYMARKER: '([^']*)'`)
out = re.ReplaceAllString(out, "$1")
ret += string(out)
ret += "{{- end -}}" // if .Values.service.enabled
return ret
}

+ 31
- 0
internal/exporters/yamltools.go View File

@ -0,0 +1,31 @@
package exporters
import (
"fmt"
"github.com/ashb/jqrepl/jq"
)
func jQOnJSONByteArray(command string, jsonByteArray []byte) []byte {
jqInForm, err := jq.JvFromJSONBytes(jsonByteArray)
if err != nil {
panic(err.Error())
}
jqObj, err := jq.New()
if err != nil {
panic(err.Error())
}
errs := jqObj.Compile(command, jq.JvArray())
if errs != nil {
for _, e := range errs {
fmt.Printf("E: %s\n", e.Error())
}
panic("Errors above!")
}
jQForm, err := jqObj.Execute(jqInForm)
if err != nil {
panic(err.Error())
}
finalJSONForm := []byte(jQForm[0].Dump(jq.JvPrintNone))
return finalJSONForm
}

Loading…
Cancel
Save