From 6b90cbd5453c8eddf894823a62ef8373c043c8c7 Mon Sep 17 00:00:00 2001 From: Ashok Pon Kumar Date: Fri, 18 Sep 2020 22:03:15 +0530 Subject: [PATCH] initial working version of move2kube Signed-off-by: Ashok Pon Kumar --- Dockerfile | 36 + LICENSE | 5 +- Makefile | 154 ++ README.md | 52 +- USAGE.md | 21 + cmd/move2kube/collect.go | 72 + cmd/move2kube/move2kube.go | 76 + cmd/move2kube/plan.go | 81 + cmd/move2kube/translate.go | 161 ++ cmd/move2kube/version.go | 44 + code-of-conduct.md | 129 + contributing.md | 22 + go.mod | 48 + go.sum | 2461 +++++++++++++++++ imgs/arch.png | Bin 0 -> 567493 bytes imgs/usage.png | Bin 0 -> 418890 bytes internal/apiresource/apiresource.go | 184 ++ internal/apiresource/deployment.go | 449 +++ internal/apiresource/imagestream.go | 114 + internal/apiresource/knativeservice.go | 83 + internal/apiresource/networkpolicy.go | 113 + internal/apiresource/service.go | 460 +++ internal/apiresource/storage.go | 292 ++ internal/apiresourceset/apiresourceset.go | 38 + internal/apiresourceset/k8sapiresourceset.go | 143 + .../apiresourceset/knativeapiresourceset.go | 137 + internal/assets/assets.go | 19 + internal/assets/constants.go | 23 + internal/assets/dockerfiles/django/Dockerfile | 21 + .../assets/dockerfiles/django/m2kdfdetect.sh | 22 + internal/assets/dockerfiles/golang/Dockerfile | 36 + .../assets/dockerfiles/golang/m2kdfdetect.sh | 22 + .../assets/dockerfiles/javaant/Dockerfile | 28 + .../assets/dockerfiles/javaant/m2kdfdetect.sh | 20 + .../assets/dockerfiles/javagradle/Dockerfile | 30 + .../dockerfiles/javagradle/m2kdfdetect.sh | 20 + .../assets/dockerfiles/javamaven/Dockerfile | 26 + .../dockerfiles/javamaven/m2kdfdetect.sh | 20 + internal/assets/dockerfiles/nodejs/Dockerfile | 20 + .../assets/dockerfiles/nodejs/m2kdfdetect.sh | 20 + internal/assets/dockerfiles/php/Dockerfile | 25 + .../assets/dockerfiles/php/m2kdfdetect.sh | 24 + internal/assets/dockerfiles/python/Dockerfile | 22 + .../assets/dockerfiles/python/m2kdfdetect.sh | 28 + internal/assets/s2i/golang/.s2i/environment | 5 + internal/assets/s2i/golang/m2ks2idetect.sh | 29 + internal/assets/s2i/java/.s2i/environment | 5 + internal/assets/s2i/java/m2ks2idetect.sh | 41 + internal/assets/s2i/nodejs/.s2i/environment | 5 + internal/assets/s2i/nodejs/m2ks2idetect.sh | 21 + internal/assets/s2i/php/.s2i/environment | 5 + internal/assets/s2i/php/m2ks2idetect.sh | 25 + internal/assets/s2i/python/.s2i/environment | 5 + internal/assets/s2i/python/m2ks2idetect.sh | 29 + internal/assets/s2i/ruby/.s2i/environment | 5 + internal/assets/s2i/ruby/m2ks2idetect.sh | 23 + internal/collector/cfappscollector.go | 102 + .../collector/cfcontainertypescollector.go | 211 ++ internal/collector/clustercollector.go | 648 +++++ internal/collector/collector.go | 29 + internal/collector/imagescollector.go | 171 ++ .../collector/sourcetypes/cfinstanceapps.go | 39 + .../collector/sourcetypes/dockercompose.go | 28 + .../collector/sourcetypes/dockerinspect.go | 31 + internal/common/constants.go | 67 + internal/common/generator/generator.go | 211 ++ internal/common/generator/generator_test.go | 274 ++ .../testdata/conststempemptyskiptimestamp.txt | 24 + .../conststempfilledskiptimestamp.txt | 38 + .../testdata/datafortempfilled/test1.json | 5 + .../testdata/datafortempfilled/test2.yml | 7 + .../datafortempfilled/testconfigs/test3.yml | 7 + .../testdata/maptempemptyskiptimestamp.txt | 24 + .../testdata/maptempfilledskiptimestamp.txt | 38 + .../tartempfilledskiptimestampandtar.txt | 20 + internal/common/tar.go | 116 + internal/common/tar_test.go | 277 ++ .../datafortestingtar/tobetarred/test1.json | 5 + .../datafortestingtar/tobetarred/test1.yaml | 17 + .../datafortestingtar/tobetarred/test2.yml | 17 + .../datafortestingtar/untarstring.json | 7 + .../common/testdata/invalidfiles/test1.json | 5 + .../common/testdata/invalidfiles/test1.yaml | 2 + .../common/testdata/validfiles/test1.json | 5 + .../common/testdata/validfiles/test1.yaml | 16 + internal/common/testdata/validfiles/test2.yml | 16 + .../testdata/validfiles/versioninfo.json | 6 + .../testdata/validfiles/versioninfo.yaml | 6 + internal/common/utils.go | 436 +++ internal/common/utils_test.go | 827 ++++++ .../cnb/containerruntimeprovider.go | 133 + .../cnb/containerruntimeprovider_test.go | 63 + internal/containerizer/cnb/packprovider.go | 145 + internal/containerizer/cnb/provider.go | 109 + internal/containerizer/cnb/runcprovider.go | 208 ++ internal/containerizer/cnbcontainerizer.go | 97 + internal/containerizer/containerizer.go | 86 + .../containerizer/dockerfilecontainerizer.go | 179 ++ .../dockerfilecontainerizer_test.go | 100 + internal/containerizer/manualcontainerizer.go | 52 + .../containerizer/manualcontainerizer_test.go | 73 + internal/containerizer/reusecontainerizer.go | 52 + .../containerizer/reusecontainerizer_test.go | 72 + .../reusedockerfilecontainerizer.go | 70 + internal/containerizer/s2icontainerizer.go | 176 ++ .../containerizer/s2icontainerizer_test.go | 120 + internal/containerizer/scripts/CNBBuilder.sh | 15 + internal/containerizer/scripts/Dockerbuild.sh | 15 + internal/containerizer/scripts/S2IBuilder.sh | 15 + internal/containerizer/scripts/constants.go | 73 + .../getcontainer/incorrectbuilder/plan.yaml | 29 + .../incorrectbuilder/service.yaml | 16 + .../getcontainer/incorrectservice/plan.yaml | 29 + .../incorrectservice/service.yaml | 16 + .../getcontainer/normal/container.yaml | 45 + .../getcontainer/normal/plan.yaml | 29 + .../getcontainer/normal/service.yaml | 16 + .../getcontainer/incorrectservice/plan.yaml | 29 + .../incorrectservice/service.yaml | 16 + .../getcontainer/normal/plan.yaml | 29 + .../getcontainer/normal/service.yaml | 16 + .../getcontainer/incorrectservice/plan.yaml | 29 + .../incorrectservice/service.yaml | 16 + .../getcontainer/normal/plan.yaml | 29 + .../getcontainer/normal/service.yaml | 16 + .../getcontainer/incorrectbuilder/plan.yaml | 29 + .../incorrectbuilder/service.yaml | 16 + .../getcontainer/incorrectservice/plan.yaml | 29 + .../incorrectservice/service.yaml | 16 + .../getcontainer/normal/container.yaml | 25 + .../getcontainer/normal/plan.yaml | 29 + .../getcontainer/normal/service.yaml | 16 + internal/customizer/customizer.go | 49 + internal/customizer/registrycustomizer.go | 289 ++ internal/customizer/storagecustomizer.go | 213 ++ internal/metadata/clustermdloader.go | 93 + internal/metadata/clustermdloader_test.go | 182 ++ internal/metadata/clusters/constants.go | 482 ++++ internal/metadata/clusters/kubernetes.yaml | 162 ++ internal/metadata/clusters/openshift.yaml | 291 ++ internal/metadata/k8sfiles.go | 80 + internal/metadata/metadata.go | 34 + internal/metadata/qacaches.go | 57 + .../metadata/testdata/emptyfiles/test1.yaml | 0 .../metadata/testdata/emptyfiles/test2.yml | 0 .../metadata/testdata/invalidfiles/test1.yaml | 10 + .../metadata/testdata/invalidfiles/test2.yml | 10 + .../metadata/testdata/validfiles/test1.yaml | 19 + .../metadata/testdata/validfiles/test2.yml | 19 + .../validfilesnostorageclasses/test1.yaml | 16 + .../validfilesnostorageclasses/test2.yml | 16 + internal/move2kube/collector.go | 68 + internal/move2kube/planner.go | 224 ++ internal/move2kube/planner_test.go | 106 + .../testdata/expectedplanfornodejsapp.yaml | 29 + internal/move2kube/translator.go | 85 + internal/move2kube/version.go | 33 + .../optimizer/imagepullpolicyoptimizer.go | 38 + internal/optimizer/ingressoptimizer.go | 72 + .../optimizer/normalizecharactersoptimizer.go | 64 + internal/optimizer/optimizer.go | 52 + internal/optimizer/portmergeoptimizer.go | 44 + internal/optimizer/replicaoptimizer.go | 40 + .../parameterizer/imagenameparameterizer.go | 69 + internal/parameterizer/parameterizer.go | 51 + .../storageclassparameterizer.go | 59 + internal/qaengine/cacheengine.go | 43 + internal/qaengine/cliengine.go | 177 ++ internal/qaengine/defaultengine.go | 40 + internal/qaengine/engine.go | 123 + internal/qaengine/httprestengine.go | 143 + internal/source/any2kube.go | 177 ++ internal/source/any2kube_test.go | 401 +++ internal/source/cfmanifest2kube.go | 473 ++++ internal/source/compose/utils.go | 58 + internal/source/compose/v1v2.go | 389 +++ internal/source/compose/v3.go | 607 ++++ internal/source/compose2kube.go | 148 + internal/source/data/Cfbuildpacks.yaml | 18 + internal/source/data/constants.go | 45 + internal/source/dockerfile2kube.go | 324 +++ internal/source/knative2kube.go | 48 + internal/source/kube2kube.go | 48 + .../expectedirfornodejsapp.yaml | 106 + .../servicesfromnodejsapp.yaml | 34 + ...icesforjavamavenappwithm2kignorecase2.yaml | 18 + .../expectedservicesfornodejsapp.yaml | 18 + ...ervicesfornodejsappwithm2kignorecase1.yaml | 18 + .../javamavenappwithm2kignorecase2/.m2kignore | 6 + .../includeme/excludeme1/src/simplewebapp.php | 20 + .../includeme/excludeme2/main.js | 23 + .../includeme/excludeme2/package.json | 9 + .../includeme/includeme/java-maven/pom.xml | 29 + .../src/main/webapp/WEB-INF/web.xml | 24 + .../java-maven/src/main/webapp/index.jsp | 22 + .../package.json | 1 + .../testdata/m2kignoreforignorecontents | 2 + .../nodejsappwithm2kignorecase1/.m2kignore | 1 + .../excludeme/includeme/main.js | 23 + .../excludeme/includeme/package.json | 9 + .../excludeme/main.js | 23 + .../excludeme/package.json | 9 + .../testdata/testmultiplem2kignores.tar | Bin 0 -> 12800 bytes internal/source/translator.go | 72 + internal/transformer/composetransformer.go | 101 + internal/transformer/k8stransformer.go | 228 ++ internal/transformer/knativetransformer.go | 99 + internal/transformer/templates/Buildimages.sh | 18 + internal/transformer/templates/Chart.tpl | 8 + internal/transformer/templates/CopySources.sh | 14 + internal/transformer/templates/Deploy.sh | 15 + internal/transformer/templates/Helminstall.sh | 15 + internal/transformer/templates/K8sReadme.md | 21 + .../transformer/templates/KnativeReadme.md | 17 + .../transformer/templates/Manualimages.md | 6 + internal/transformer/templates/Pushimages.sh | 30 + internal/transformer/templates/constants.go | 181 ++ internal/transformer/transformer.go | 203 ++ internal/types/ir.go | 298 ++ internal/types/ir_test.go | 777 ++++++ misc/centos.repo | 13 + samples/.m2kignore | 1 + samples/docker-compose/api/Dockerfile | 6 + samples/docker-compose/api/index.js | 51 + samples/docker-compose/api/package-lock.json | 42 + samples/docker-compose/api/package.json | 13 + samples/docker-compose/docker-compose.yaml | 19 + samples/docker-compose/web/Dockerfile | 2 + samples/docker-compose/web/fib.php | 31 + samples/docker-compose/web/index.php | 15 + samples/dockerfile/Dockerfile | 6 + samples/dockerfile/index.js | 7 + samples/dockerfile/package-lock.json | 374 +++ samples/dockerfile/package.json | 13 + samples/dockerfile/public/about.html | 23 + samples/dockerfile/public/index.html | 23 + samples/golang/main.go | 33 + samples/java-gradle/build.gradle | 29 + .../main/java/simplewebapp/MainServlet.java | 28 + .../src/main/webapp/WEB-INF/web.xml | 34 + samples/java-maven/pom.xml | 29 + .../src/main/webapp/WEB-INF/web.xml | 24 + samples/java-maven/src/main/webapp/index.jsp | 22 + samples/nodejs/main.js | 23 + samples/nodejs/package.json | 9 + samples/php/src/simplewebapp.php | 20 + samples/python/main.py | 25 + samples/python/requirements.txt | 15 + samples/ruby/Gemfile | 18 + samples/ruby/app.rb | 22 + samples/ruby/config.ru | 16 + samples/ruby/views/main.erb | 24 + scripts/installdeps.sh | 41 + scripts/licensecheck.sh | 39 + types/collection/cfcontainerizers.go | 55 + types/collection/cfcontainerizers_test.go | 31 + types/collection/cfinstanceapps.go | 59 + types/collection/cfinstanceapps_test.go | 31 + types/collection/cluster.go | 129 + types/collection/cluster_test.go | 138 + types/collection/image.go | 50 + types/collection/image_test.go | 31 + types/info/versioninfo.go | 100 + types/info/versioninfo_test.go | 63 + types/output/helmvaluesoutput.go | 77 + types/output/helmvaluesoutput_test.go | 105 + types/plan/plan.go | 393 +++ types/plan/plan_test.go | 444 +++ types/qaengine/cache.go | 130 + types/qaengine/cache_test.go | 31 + types/qaengine/doc.go | 20 + types/qaengine/problem.go | 288 ++ types/types.go | 52 + 273 files changed, 24233 insertions(+), 4 deletions(-) create mode 100644 Dockerfile create mode 100644 Makefile create mode 100644 USAGE.md create mode 100644 cmd/move2kube/collect.go create mode 100644 cmd/move2kube/move2kube.go create mode 100644 cmd/move2kube/plan.go create mode 100644 cmd/move2kube/translate.go create mode 100644 cmd/move2kube/version.go create mode 100644 code-of-conduct.md create mode 100644 contributing.md create mode 100644 go.mod create mode 100644 go.sum create mode 100644 imgs/arch.png create mode 100644 imgs/usage.png create mode 100644 internal/apiresource/apiresource.go create mode 100644 internal/apiresource/deployment.go create mode 100644 internal/apiresource/imagestream.go create mode 100644 internal/apiresource/knativeservice.go create mode 100644 internal/apiresource/networkpolicy.go create mode 100644 internal/apiresource/service.go create mode 100644 internal/apiresource/storage.go create mode 100644 internal/apiresourceset/apiresourceset.go create mode 100644 internal/apiresourceset/k8sapiresourceset.go create mode 100644 internal/apiresourceset/knativeapiresourceset.go create mode 100644 internal/assets/assets.go create mode 100644 internal/assets/constants.go create mode 100644 internal/assets/dockerfiles/django/Dockerfile create mode 100755 internal/assets/dockerfiles/django/m2kdfdetect.sh create mode 100644 internal/assets/dockerfiles/golang/Dockerfile create mode 100755 internal/assets/dockerfiles/golang/m2kdfdetect.sh create mode 100644 internal/assets/dockerfiles/javaant/Dockerfile create mode 100755 internal/assets/dockerfiles/javaant/m2kdfdetect.sh create mode 100644 internal/assets/dockerfiles/javagradle/Dockerfile create mode 100755 internal/assets/dockerfiles/javagradle/m2kdfdetect.sh create mode 100644 internal/assets/dockerfiles/javamaven/Dockerfile create mode 100755 internal/assets/dockerfiles/javamaven/m2kdfdetect.sh create mode 100644 internal/assets/dockerfiles/nodejs/Dockerfile create mode 100755 internal/assets/dockerfiles/nodejs/m2kdfdetect.sh create mode 100644 internal/assets/dockerfiles/php/Dockerfile create mode 100755 internal/assets/dockerfiles/php/m2kdfdetect.sh create mode 100644 internal/assets/dockerfiles/python/Dockerfile create mode 100755 internal/assets/dockerfiles/python/m2kdfdetect.sh create mode 100644 internal/assets/s2i/golang/.s2i/environment create mode 100644 internal/assets/s2i/golang/m2ks2idetect.sh create mode 100644 internal/assets/s2i/java/.s2i/environment create mode 100644 internal/assets/s2i/java/m2ks2idetect.sh create mode 100644 internal/assets/s2i/nodejs/.s2i/environment create mode 100755 internal/assets/s2i/nodejs/m2ks2idetect.sh create mode 100644 internal/assets/s2i/php/.s2i/environment create mode 100644 internal/assets/s2i/php/m2ks2idetect.sh create mode 100644 internal/assets/s2i/python/.s2i/environment create mode 100755 internal/assets/s2i/python/m2ks2idetect.sh create mode 100644 internal/assets/s2i/ruby/.s2i/environment create mode 100644 internal/assets/s2i/ruby/m2ks2idetect.sh create mode 100644 internal/collector/cfappscollector.go create mode 100644 internal/collector/cfcontainertypescollector.go create mode 100644 internal/collector/clustercollector.go create mode 100644 internal/collector/collector.go create mode 100644 internal/collector/imagescollector.go create mode 100644 internal/collector/sourcetypes/cfinstanceapps.go create mode 100644 internal/collector/sourcetypes/dockercompose.go create mode 100644 internal/collector/sourcetypes/dockerinspect.go create mode 100644 internal/common/constants.go create mode 100644 internal/common/generator/generator.go create mode 100644 internal/common/generator/generator_test.go create mode 100644 internal/common/generator/testdata/conststempemptyskiptimestamp.txt create mode 100644 internal/common/generator/testdata/conststempfilledskiptimestamp.txt create mode 100644 internal/common/generator/testdata/datafortempfilled/test1.json create mode 100644 internal/common/generator/testdata/datafortempfilled/test2.yml create mode 100644 internal/common/generator/testdata/datafortempfilled/testconfigs/test3.yml create mode 100644 internal/common/generator/testdata/maptempemptyskiptimestamp.txt create mode 100644 internal/common/generator/testdata/maptempfilledskiptimestamp.txt create mode 100644 internal/common/generator/testdata/tartempfilledskiptimestampandtar.txt create mode 100644 internal/common/tar.go create mode 100644 internal/common/tar_test.go create mode 100644 internal/common/testdata/datafortestingtar/tobetarred/test1.json create mode 100644 internal/common/testdata/datafortestingtar/tobetarred/test1.yaml create mode 100644 internal/common/testdata/datafortestingtar/tobetarred/test2.yml create mode 100644 internal/common/testdata/datafortestingtar/untarstring.json create mode 100644 internal/common/testdata/invalidfiles/test1.json create mode 100644 internal/common/testdata/invalidfiles/test1.yaml create mode 100644 internal/common/testdata/validfiles/test1.json create mode 100644 internal/common/testdata/validfiles/test1.yaml create mode 100644 internal/common/testdata/validfiles/test2.yml create mode 100644 internal/common/testdata/validfiles/versioninfo.json create mode 100644 internal/common/testdata/validfiles/versioninfo.yaml create mode 100644 internal/common/utils.go create mode 100644 internal/common/utils_test.go create mode 100644 internal/containerizer/cnb/containerruntimeprovider.go create mode 100644 internal/containerizer/cnb/containerruntimeprovider_test.go create mode 100644 internal/containerizer/cnb/packprovider.go create mode 100644 internal/containerizer/cnb/provider.go create mode 100644 internal/containerizer/cnb/runcprovider.go create mode 100644 internal/containerizer/cnbcontainerizer.go create mode 100644 internal/containerizer/containerizer.go create mode 100644 internal/containerizer/dockerfilecontainerizer.go create mode 100644 internal/containerizer/dockerfilecontainerizer_test.go create mode 100644 internal/containerizer/manualcontainerizer.go create mode 100644 internal/containerizer/manualcontainerizer_test.go create mode 100644 internal/containerizer/reusecontainerizer.go create mode 100644 internal/containerizer/reusecontainerizer_test.go create mode 100644 internal/containerizer/reusedockerfilecontainerizer.go create mode 100644 internal/containerizer/s2icontainerizer.go create mode 100644 internal/containerizer/s2icontainerizer_test.go create mode 100644 internal/containerizer/scripts/CNBBuilder.sh create mode 100644 internal/containerizer/scripts/Dockerbuild.sh create mode 100644 internal/containerizer/scripts/S2IBuilder.sh create mode 100644 internal/containerizer/scripts/constants.go create mode 100644 internal/containerizer/testdata/dockerfilecontainerizer/getcontainer/incorrectbuilder/plan.yaml create mode 100644 internal/containerizer/testdata/dockerfilecontainerizer/getcontainer/incorrectbuilder/service.yaml create mode 100644 internal/containerizer/testdata/dockerfilecontainerizer/getcontainer/incorrectservice/plan.yaml create mode 100644 internal/containerizer/testdata/dockerfilecontainerizer/getcontainer/incorrectservice/service.yaml create mode 100644 internal/containerizer/testdata/dockerfilecontainerizer/getcontainer/normal/container.yaml create mode 100644 internal/containerizer/testdata/dockerfilecontainerizer/getcontainer/normal/plan.yaml create mode 100644 internal/containerizer/testdata/dockerfilecontainerizer/getcontainer/normal/service.yaml create mode 100644 internal/containerizer/testdata/manualcontainerizer/getcontainer/incorrectservice/plan.yaml create mode 100644 internal/containerizer/testdata/manualcontainerizer/getcontainer/incorrectservice/service.yaml create mode 100644 internal/containerizer/testdata/manualcontainerizer/getcontainer/normal/plan.yaml create mode 100644 internal/containerizer/testdata/manualcontainerizer/getcontainer/normal/service.yaml create mode 100644 internal/containerizer/testdata/reusecontainerizer/getcontainer/incorrectservice/plan.yaml create mode 100644 internal/containerizer/testdata/reusecontainerizer/getcontainer/incorrectservice/service.yaml create mode 100644 internal/containerizer/testdata/reusecontainerizer/getcontainer/normal/plan.yaml create mode 100644 internal/containerizer/testdata/reusecontainerizer/getcontainer/normal/service.yaml create mode 100644 internal/containerizer/testdata/s2icontainerizer/getcontainer/incorrectbuilder/plan.yaml create mode 100644 internal/containerizer/testdata/s2icontainerizer/getcontainer/incorrectbuilder/service.yaml create mode 100644 internal/containerizer/testdata/s2icontainerizer/getcontainer/incorrectservice/plan.yaml create mode 100644 internal/containerizer/testdata/s2icontainerizer/getcontainer/incorrectservice/service.yaml create mode 100644 internal/containerizer/testdata/s2icontainerizer/getcontainer/normal/container.yaml create mode 100644 internal/containerizer/testdata/s2icontainerizer/getcontainer/normal/plan.yaml create mode 100644 internal/containerizer/testdata/s2icontainerizer/getcontainer/normal/service.yaml create mode 100644 internal/customizer/customizer.go create mode 100644 internal/customizer/registrycustomizer.go create mode 100644 internal/customizer/storagecustomizer.go create mode 100644 internal/metadata/clustermdloader.go create mode 100644 internal/metadata/clustermdloader_test.go create mode 100644 internal/metadata/clusters/constants.go create mode 100644 internal/metadata/clusters/kubernetes.yaml create mode 100644 internal/metadata/clusters/openshift.yaml create mode 100644 internal/metadata/k8sfiles.go create mode 100644 internal/metadata/metadata.go create mode 100644 internal/metadata/qacaches.go create mode 100644 internal/metadata/testdata/emptyfiles/test1.yaml create mode 100644 internal/metadata/testdata/emptyfiles/test2.yml create mode 100644 internal/metadata/testdata/invalidfiles/test1.yaml create mode 100644 internal/metadata/testdata/invalidfiles/test2.yml create mode 100644 internal/metadata/testdata/validfiles/test1.yaml create mode 100644 internal/metadata/testdata/validfiles/test2.yml create mode 100644 internal/metadata/testdata/validfilesnostorageclasses/test1.yaml create mode 100644 internal/metadata/testdata/validfilesnostorageclasses/test2.yml create mode 100644 internal/move2kube/collector.go create mode 100644 internal/move2kube/planner.go create mode 100644 internal/move2kube/planner_test.go create mode 100644 internal/move2kube/testdata/expectedplanfornodejsapp.yaml create mode 100644 internal/move2kube/translator.go create mode 100644 internal/move2kube/version.go create mode 100644 internal/optimizer/imagepullpolicyoptimizer.go create mode 100644 internal/optimizer/ingressoptimizer.go create mode 100644 internal/optimizer/normalizecharactersoptimizer.go create mode 100644 internal/optimizer/optimizer.go create mode 100644 internal/optimizer/portmergeoptimizer.go create mode 100644 internal/optimizer/replicaoptimizer.go create mode 100644 internal/parameterizer/imagenameparameterizer.go create mode 100644 internal/parameterizer/parameterizer.go create mode 100644 internal/parameterizer/storageclassparameterizer.go create mode 100644 internal/qaengine/cacheengine.go create mode 100644 internal/qaengine/cliengine.go create mode 100644 internal/qaengine/defaultengine.go create mode 100644 internal/qaengine/engine.go create mode 100644 internal/qaengine/httprestengine.go create mode 100644 internal/source/any2kube.go create mode 100644 internal/source/any2kube_test.go create mode 100644 internal/source/cfmanifest2kube.go create mode 100644 internal/source/compose/utils.go create mode 100755 internal/source/compose/v1v2.go create mode 100755 internal/source/compose/v3.go create mode 100644 internal/source/compose2kube.go create mode 100644 internal/source/data/Cfbuildpacks.yaml create mode 100644 internal/source/data/constants.go create mode 100644 internal/source/dockerfile2kube.go create mode 100644 internal/source/knative2kube.go create mode 100644 internal/source/kube2kube.go create mode 100644 internal/source/testdata/datafortestingtranslate/expectedirfornodejsapp.yaml create mode 100644 internal/source/testdata/datafortestingtranslate/servicesfromnodejsapp.yaml create mode 100644 internal/source/testdata/expectedservicesforjavamavenappwithm2kignorecase2.yaml create mode 100644 internal/source/testdata/expectedservicesfornodejsapp.yaml create mode 100644 internal/source/testdata/expectedservicesfornodejsappwithm2kignorecase1.yaml create mode 100644 internal/source/testdata/javamavenappwithm2kignorecase2/.m2kignore create mode 100644 internal/source/testdata/javamavenappwithm2kignorecase2/includeme/excludeme1/src/simplewebapp.php create mode 100644 internal/source/testdata/javamavenappwithm2kignorecase2/includeme/excludeme2/main.js create mode 100644 internal/source/testdata/javamavenappwithm2kignorecase2/includeme/excludeme2/package.json create mode 100644 internal/source/testdata/javamavenappwithm2kignorecase2/includeme/includeme/java-maven/pom.xml create mode 100644 internal/source/testdata/javamavenappwithm2kignorecase2/includeme/includeme/java-maven/src/main/webapp/WEB-INF/web.xml create mode 100644 internal/source/testdata/javamavenappwithm2kignorecase2/includeme/includeme/java-maven/src/main/webapp/index.jsp create mode 100644 internal/source/testdata/javamavenappwithm2kignorecase2/package.json create mode 100644 internal/source/testdata/m2kignoreforignorecontents create mode 100644 internal/source/testdata/nodejsappwithm2kignorecase1/.m2kignore create mode 100644 internal/source/testdata/nodejsappwithm2kignorecase1/excludeme/includeme/main.js create mode 100644 internal/source/testdata/nodejsappwithm2kignorecase1/excludeme/includeme/package.json create mode 100644 internal/source/testdata/nodejsappwithm2kignorecase1/excludeme/main.js create mode 100644 internal/source/testdata/nodejsappwithm2kignorecase1/excludeme/package.json create mode 100644 internal/source/testdata/testmultiplem2kignores.tar create mode 100644 internal/source/translator.go create mode 100644 internal/transformer/composetransformer.go create mode 100644 internal/transformer/k8stransformer.go create mode 100644 internal/transformer/knativetransformer.go create mode 100644 internal/transformer/templates/Buildimages.sh create mode 100644 internal/transformer/templates/Chart.tpl create mode 100644 internal/transformer/templates/CopySources.sh create mode 100644 internal/transformer/templates/Deploy.sh create mode 100644 internal/transformer/templates/Helminstall.sh create mode 100644 internal/transformer/templates/K8sReadme.md create mode 100644 internal/transformer/templates/KnativeReadme.md create mode 100644 internal/transformer/templates/Manualimages.md create mode 100644 internal/transformer/templates/Pushimages.sh create mode 100644 internal/transformer/templates/constants.go create mode 100644 internal/transformer/transformer.go create mode 100644 internal/types/ir.go create mode 100644 internal/types/ir_test.go create mode 100644 misc/centos.repo create mode 100644 samples/.m2kignore create mode 100644 samples/docker-compose/api/Dockerfile create mode 100644 samples/docker-compose/api/index.js create mode 100644 samples/docker-compose/api/package-lock.json create mode 100644 samples/docker-compose/api/package.json create mode 100644 samples/docker-compose/docker-compose.yaml create mode 100644 samples/docker-compose/web/Dockerfile create mode 100644 samples/docker-compose/web/fib.php create mode 100644 samples/docker-compose/web/index.php create mode 100644 samples/dockerfile/Dockerfile create mode 100644 samples/dockerfile/index.js create mode 100644 samples/dockerfile/package-lock.json create mode 100644 samples/dockerfile/package.json create mode 100644 samples/dockerfile/public/about.html create mode 100644 samples/dockerfile/public/index.html create mode 100644 samples/golang/main.go create mode 100644 samples/java-gradle/build.gradle create mode 100644 samples/java-gradle/src/main/java/simplewebapp/MainServlet.java create mode 100644 samples/java-gradle/src/main/webapp/WEB-INF/web.xml create mode 100644 samples/java-maven/pom.xml create mode 100644 samples/java-maven/src/main/webapp/WEB-INF/web.xml create mode 100644 samples/java-maven/src/main/webapp/index.jsp create mode 100644 samples/nodejs/main.js create mode 100644 samples/nodejs/package.json create mode 100644 samples/php/src/simplewebapp.php create mode 100644 samples/python/main.py create mode 100644 samples/python/requirements.txt create mode 100644 samples/ruby/Gemfile create mode 100644 samples/ruby/app.rb create mode 100644 samples/ruby/config.ru create mode 100644 samples/ruby/views/main.erb create mode 100644 scripts/installdeps.sh create mode 100755 scripts/licensecheck.sh create mode 100644 types/collection/cfcontainerizers.go create mode 100644 types/collection/cfcontainerizers_test.go create mode 100644 types/collection/cfinstanceapps.go create mode 100644 types/collection/cfinstanceapps_test.go create mode 100644 types/collection/cluster.go create mode 100644 types/collection/cluster_test.go create mode 100644 types/collection/image.go create mode 100644 types/collection/image_test.go create mode 100644 types/info/versioninfo.go create mode 100644 types/info/versioninfo_test.go create mode 100644 types/output/helmvaluesoutput.go create mode 100644 types/output/helmvaluesoutput_test.go create mode 100644 types/plan/plan.go create mode 100644 types/plan/plan_test.go create mode 100644 types/qaengine/cache.go create mode 100644 types/qaengine/cache_test.go create mode 100644 types/qaengine/doc.go create mode 100644 types/qaengine/problem.go create mode 100644 types/types.go diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 000000000..d781d986f --- /dev/null +++ b/Dockerfile @@ -0,0 +1,36 @@ +# Build image +FROM registry.access.redhat.com/ubi8/ubi:latest AS build_base +ARG APPNAME=move2kube +# Get Dependencies +WORKDIR /temp +ENV GOPATH=/go +ENV PATH=$GOPATH/bin:/usr/local/go/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin +RUN curl -o go.tar.gz https://dl.google.com/go/go1.15.linux-amd64.tar.gz +RUN tar -xzf go.tar.gz && mv go /usr/local/ +RUN yum install git make -y +RUN mkdir -p $GOPATH/src $GOPATH/bin && chmod -R 777 $GOPATH +ENV WORKDIR=${GOPATH}/src/${APPNAME} +WORKDIR ${WORKDIR} +COPY go.mod . +COPY go.sum . +RUN go mod download +COPY scripts/installdeps.sh scripts/installdeps.sh +RUN cd / && source ${WORKDIR}/scripts/installdeps.sh && cd - +COPY . . +# Build +RUN make build +RUN cp bin/${APPNAME} /bin/${APPNAME} + +# Run image +FROM registry.access.redhat.com/ubi8/ubi:latest +COPY misc/centos.repo /etc/yum.repos.d/centos.repo +RUN yum update -y && yum install -y podman && yum clean all +COPY --from=build_base /bin/${APPNAME} /bin/${APPNAME} +COPY --from=build_base /bin/pack /bin/pack +COPY --from=build_base /bin/kubectl /bin/kubectl +COPY --from=build_base /bin/operator-sdk /bin/operator-sdk +VOLUME ["/wksps"] +#"/var/run/docker.sock" needs to be mounted for CNB containerization to be used. +# Start app +WORKDIR /wksps +CMD [${APPNAME}] \ No newline at end of file diff --git a/LICENSE b/LICENSE index 261eeb9e9..0dae2b3f0 100644 --- a/LICENSE +++ b/LICENSE @@ -1,3 +1,4 @@ + Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ @@ -186,7 +187,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright [yyyy] [name of copyright owner] + Copyright IBM Corporation [yyyy] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -198,4 +199,4 @@ distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and - limitations under the License. + limitations under the License. \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 000000000..bdaa439c6 --- /dev/null +++ b/Makefile @@ -0,0 +1,154 @@ +# Copyright IBM Corporation 2020 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +BINNAME ?= move2kube +BINDIR := $(CURDIR)/bin +DISTDIR := $(CURDIR)/_dist +TARGETS := darwin/amd64 linux/amd64 + +GOPATH = $(shell go env GOPATH) +GOX = $(GOPATH)/bin/gox +GOLINT = $(GOPATH)/bin/golint +GOTEST = ${GOPATH}/bin/gotest +GOLANGCILINT = $(GOPATH)/bin/golangci-lint +GOLANGCOVER = $(GOPATH)/bin/goveralls + +PKG := ./... +LDFLAGS := -w -s + +SRC = $(shell find . -type f -name '*.go' -print) +ARCH = $(shell uname -p) +GIT_COMMIT = $(shell git rev-parse HEAD) +GIT_SHA = $(shell git rev-parse --short HEAD) +GIT_TAG = $(shell git describe --tags --abbrev=0 --exact-match 2>/dev/null) +GIT_DIRTY = $(shell test -n "`git status --porcelain`" && echo "dirty" || echo "clean") + +GOGET := cd / && GO111MODULE=on go get -u + +ifdef VERSION + BINARY_VERSION = $(VERSION) +endif +BINARY_VERSION ?= ${GIT_TAG} +ifneq ($(BINARY_VERSION),) + LDFLAGS += -X github.com/konveyor/${BINNAME}/types/info.version=${BINARY_VERSION} + VERSION = $(BINARY_VERSION) +endif + +VERSION_METADATA = unreleased +ifneq ($(GIT_TAG),) + VERSION_METADATA = +endif +LDFLAGS += -X github.com/konveyor/${BINNAME}/types/info.metadata=${VERSION_METADATA} + +LDFLAGS += -X github.com/konveyor/${BINNAME}/types/info.gitCommit=${GIT_COMMIT} +LDFLAGS += -X github.com/konveyor/${BINNAME}/types/info.gitTreeState=${GIT_DIRTY} +LDFLAGS += -extldflags "-static" + +# HELP +# This will output the help for each task +.PHONY: help +help: ## This help. + @awk 'BEGIN {FS = ":.*?## "} /^[0-9a-zA-Z_-]+:.*?## / {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST) + +# -- Build -- + +.PHONY: build +build: get $(BINDIR)/$(BINNAME) ## Build go code + +$(BINDIR)/$(BINNAME): $(SRC) + @go build -tags excludecodegen -ldflags '$(LDFLAGS)' -o $(BINDIR)/$(BINNAME) ./cmd/${BINNAME} + @cp $(BINDIR)/$(BINNAME) $(GOPATH)/bin/ + +.PHONY: get +get: go.mod + @go mod download + +.PHONY: generate +generate: + @go generate ${PKG} + +.PHONY: deps +deps: + @source scripts/installdeps.sh + +# -- Test -- + +.PHONY: test +test: ## Run tests + @go test -run . $(PKG) -race + +${GOTEST}: + ${GOGET} github.com/rakyll/gotest + +.PHONY: test-verbose +test-verbose: ${GOTEST} + @gotest -run . $(PKG) -race -v + +${GOLANGCOVER}: + ${GOGET} github.com/mattn/goveralls@v0.0.6 + +.PHONY: test-coverage +test-coverage: ${GOLANGCOVER} ## Run tests with coverage + @go test -run . $(PKG) -covermode=atomic + +${GOLANGCILINT}: + @curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(GOPATH)/bin v1.30.0 + +${GOLINT}: + ${GOGET} golang.org/x/lint/golint + +.PHONY: test-style +test-style: ${GOLANGCILINT} ${GOLINT} + ${GOLANGCILINT} run + ${GOLINT} ${PKG} + scripts/licensecheck.sh + +# -- Release -- + +$(GOX): + ${GOGET} github.com/mitchellh/gox@v1.0.1 + +.PHONY: build-cross +build-cross: $(GOX) clean + CGO_ENABLED=0 $(GOX) -parallel=3 -output="$(DISTDIR)/{{.OS}}-{{.Arch}}/$(BINNAME)" -osarch='$(TARGETS)' -ldflags '$(LDFLAGS)' ./cmd/${BINNAME} + +.PHONY: dist +dist: clean build-cross ## Build Distribution + @mkdir -p $(DISTDIR)/files + @cp -r ./{LICENSE,scripts/installdeps.sh,USAGE.md,samples} $(DISTDIR)/files/ + @cd $(DISTDIR) && \ + find * -maxdepth 1 -name "*-*" -type d \ + -exec cp -r $(DISTDIR)/files/* {} \; \ + -exec tar -zcf ${BINNAME}-${VERSION}-{}.tar.gz {} \; \ + -exec sh -c 'shasum -a 256 ${BINNAME}-${VERSION}-{}.tar.gz > ${BINNAME}-${VERSION}-{}.tar.gz.sha256sum' \; \ + -exec zip -r ${BINNAME}-${VERSION}-{}.zip {} \; \ + -exec sh -c 'shasum -a 256 ${BINNAME}-${VERSION}-{}.zip > ${BINNAME}-${VERSION}-{}.zip.sha256sum' \; + +.PHONY: clean +clean: + @rm -rf $(BINDIR) $(DISTDIR) + @go clean -cache + +.PHONY: info +info: ## Get version info + @echo "Version: ${VERSION}" + @echo "Git Tag: ${GIT_TAG}" + @echo "Git Commit: ${GIT_COMMIT}" + @echo "Git Tree State: ${GIT_DIRTY}" + +# -- Docker -- + +.PHONY: cbuild +cbuild: ## Build docker image + @docker build -t ${BINNAME}:latest . diff --git a/README.md b/README.md index 3bd1873eb..96436052f 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,50 @@ -# move2kube -Move2Kube is a command-line tool that accelerates the process of re-platforming to Kubernetes/Openshift. + +# Move2Kube + +Move2Kube is a command-line tool that accelerates the process of re-platforming to Kubernetes/Openshift. It does so by analysing the environment and source artifacts, and asking guidance from the user when required. + +![Pipeline](imgs/arch.png?raw=true "Pipeline") + +## Usage + +![Usage](./imgs/usage.png) + +Instructions can be found [here](./USAGE.md) + +## Setup + +1. Obtain a recent version of `golang`. Known to work with `1.15`. +1. Ensure `$GOPATH` is set. If it's not set: + 1. `mkdir ~/go` + 1. `export GOPATH=~/go` +1. Obtain this repo: + 1. `mkdir -p $GOPATH/src/` + 1. Clone this repo into the above directory. + 1. `cd $GOPATH/src/move2kube` +1. Build: `make build` +1. Run unit tests: `make test` + +## Artifacts Required + +| Source | Artifact available | Features supported | +|:-------|:-------------------|:-------------------| +| Cloud Foundry | Manifest files | Containerization options from buildpacks, Deployment artifacts | +| Cloud Foundry | Manifest files, Source code | Containerization options based on buildpack/source code, Deployment artifacts | +| Cloud Foundry | Manifest files, Source code, Access to running instance | Containerization options based on buildpack/source code, Deployment artifacts, Metadata from runtime | +| Cloud Foundry | Access to running instance | Metadata from runtime, Containerization options based on buildpack, Deployment artifacts | +| Docker Compose/Swarm | Docker compose files | Deployment artifacts | +| Docker Compose/Swarm | Docker compose files, Docker images | Deployment artifacts, Ability to enhance images to run in secure environments like Openshift. | +| Source Directories | Source code with no source metadata | Containerization options based on source code, Deployment artifacts | +| Any source | Access to target cluster | Ability to create artifacts customized for that particular cluster with the most preferred GroupVersion for the kind. | + +## Output + +* Containerization scripts + * Dockerfile + * Source 2 Image (S2I) + * Cloud Native Buildpack +* Deployment artifacts + * Kubernetes/Openshift Yamls + * Helm charts + * Operator + * Docker compose diff --git a/USAGE.md b/USAGE.md new file mode 100644 index 000000000..a03bae6ca --- /dev/null +++ b/USAGE.md @@ -0,0 +1,21 @@ +# Move2Kube + +Move2Kube is a command-line tool that accelerates the process of re-platforming to Kubernetes/Openshift. It does so by analysing the environment and source artifacts, and asking guidance from the user when required. + +## Setup + +1. Ensure that the move2kube executable is in path. `export PATH=$PATH:$PWD` +1. To install dependencies such as `pack`, `kubectl` and `operator-sdk`, invoke `source installdeps.sh`. + +## Usage + +1. _Plan_ : Place source code in a directory say `src` and generate a plan. For example, you can use the `samples` directory. + `move2kube plan -s src` +1. _Translate_ : In the same directory, invoke the below command. + `move2kube translate` + +Note: If information about any runtime instance say cloud foundry or kubernetes cluster needs to be collected use `move2kube collect`. You can place the collected data in the `src` directory used in the plan. + +## Contact + +For more information, please contact Amith Singhee ([asinghee@in.ibm.com](mailto:asinghee@in.ibm.com)) or Ashok Pon Kumar ([ashokponkumar@in.ibm.com](mailto:ashokponkumar@in.ibm.com)) diff --git a/cmd/move2kube/collect.go b/cmd/move2kube/collect.go new file mode 100644 index 000000000..6101e6621 --- /dev/null +++ b/cmd/move2kube/collect.go @@ -0,0 +1,72 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +import ( + "os" + "path/filepath" + "strings" + + log "github.com/sirupsen/logrus" + "github.com/spf13/cobra" + "github.com/spf13/viper" + + "github.com/konveyor/move2kube/internal/move2kube" + "github.com/konveyor/move2kube/types" +) + +var ( + annotations string +) + +const ( + annotationsFlag = "annotations" +) + +var collectCmd = &cobra.Command{ + Use: "collect", + Short: "Collect and process metadata from multiple sources.", + Long: "Collect metadata from multiple sources (cluster, image repo etc.), filter and summarize it into a yaml.", + Run: func(cmd *cobra.Command, args []string) { + if srcpath != "" { + fi, err := os.Stat(srcpath) + if os.IsNotExist(err) { + log.Fatalf("Source directory does not exist: %s.", err) + } else if err != nil { + log.Fatalf("Error while accessing directory: %s. ", srcpath) + } else if !fi.IsDir() { + log.Fatalf("Source path is a file, expected directory: %s.", srcpath) + } + } + outpath = filepath.Join(filepath.Clean(outpath), types.AppNameShort+"_collect") + if annotations == "" { + move2kube.Collect(srcpath, outpath, []string{}) + } else { + move2kube.Collect(srcpath, outpath, strings.Split(annotations, ",")) + } + log.Infof("Collect Output in [%s]. Copy this directory into the source directory to be used for planning.", outpath) + }, +} + +func init() { + viper.AutomaticEnv() + + collectCmd.Flags().StringVarP(&annotations, annotationsFlag, "a", "", "Specify annotations to select collector subset.") + collectCmd.Flags().StringVarP(&outpath, outpathFlag, "o", ".", "Specify output directory for collect.") + collectCmd.Flags().StringVarP(&srcpath, sourceFlag, "s", "", "Specify source directory for the artifacts to be considered while collecting.") + rootCmd.AddCommand(collectCmd) +} diff --git a/cmd/move2kube/move2kube.go b/cmd/move2kube/move2kube.go new file mode 100644 index 000000000..4a6dc0881 --- /dev/null +++ b/cmd/move2kube/move2kube.go @@ -0,0 +1,76 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +import ( + "os" + + "github.com/konveyor/move2kube/internal/common" + log "github.com/sirupsen/logrus" + "github.com/spf13/cobra" +) + +var ( + verbose bool + + planfile string + outpath string + srcpath string + name string + ignoreEnv bool +) + +const ( + nameFlag = "name" + planFlag = "plan" + sourceFlag = "source" + ignoreEnvFlag = "ignoreenv" +) + +// RootCmd root level flags and commands +var rootCmd = &cobra.Command{ + Use: "move2kube", + Short: "A tool to modernize to kubernetes/openshift", + Long: `move2kube is a tool to help optimally translate from platforms such as docker-swarm, CF to Kubernetes.`, +} + +func getRootCmd() *cobra.Command { + rootCmd.PersistentPreRunE = func(cmd *cobra.Command, args []string) error { + if verbose { + log.SetLevel(log.DebugLevel) + } + return nil + } + return rootCmd +} + +func init() { + rootCmd.PersistentFlags().BoolVarP(&verbose, "verbose", "v", false, "Enable verbose output") +} + +func main() { + assetsPath, tempPath, err := common.CreateAssetsData() + if err != nil { + log.Fatalf("Unable to create the assets directory. Error: %q", err) + } + common.TempPath = tempPath + common.AssetsPath = assetsPath + defer os.RemoveAll(tempPath) + if err := getRootCmd().Execute(); err != nil { + log.Fatalf("Error: %q", err) + } +} diff --git a/cmd/move2kube/plan.go b/cmd/move2kube/plan.go new file mode 100644 index 000000000..8495b126a --- /dev/null +++ b/cmd/move2kube/plan.go @@ -0,0 +1,81 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +import ( + "os" + "path/filepath" + "strings" + + log "github.com/sirupsen/logrus" + "github.com/spf13/cobra" + "github.com/spf13/viper" + + "github.com/konveyor/move2kube/internal/common" + "github.com/konveyor/move2kube/internal/move2kube" +) + +var planCmd = &cobra.Command{ + Use: "plan", + Short: "Plan out a move", + Long: "Discover and create a plan file based on an input directory", + Run: func(cmd *cobra.Command, args []string) { + // Check if this is even a directory + fi, err := os.Stat(srcpath) + if err != nil { + log.Fatalf("Unable to access source directory : %s", err) + } + if !fi.IsDir() { + log.Fatalf("Input is a file, expected directory: %s", srcpath) + } + + fi, err = os.Stat(planfile) + if os.IsNotExist(err) { + if strings.HasSuffix(planfile, string(os.PathSeparator)) { + planfile = filepath.Join(planfile, common.DefaultPlanFile) + } else if !strings.Contains(filepath.Base(planfile), ".") { + planfile = filepath.Join(planfile, common.DefaultPlanFile) + } + } else if err != nil { + log.Fatalf("Error while accessing plan file path %s : %s ", planfile, err) + } else if fi.IsDir() { + planfile = filepath.Join(planfile, common.DefaultPlanFile) + } + + p := move2kube.CreatePlan(srcpath, name) + err = move2kube.WritePlan(p, planfile) + if err != nil { + log.Errorf("Unable to write plan file (%s) : %s", planfile, err) + } else { + log.Infof("Plan can be found at [%s].", planfile) + } + }, +} + +func init() { + viper.AutomaticEnv() + + planCmd.Flags().StringVarP(&srcpath, sourceFlag, "s", ".", "Specify source directory.") + planCmd.Flags().StringVarP(&planfile, planFlag, "p", common.DefaultPlanFile, "Specify a file path to save plan to.") + planCmd.Flags().StringVarP(&name, nameFlag, "n", common.DefaultProjectName, "Specify the project name.") + + if err := planCmd.MarkFlagRequired(sourceFlag); err != nil { + log.Fatalf("Failed to mark flag source as required.") + } + + rootCmd.AddCommand(planCmd) +} diff --git a/cmd/move2kube/translate.go b/cmd/move2kube/translate.go new file mode 100644 index 000000000..811fc544d --- /dev/null +++ b/cmd/move2kube/translate.go @@ -0,0 +1,161 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +import ( + "os" + "path/filepath" + + log "github.com/sirupsen/logrus" + "github.com/spf13/cobra" + "github.com/spf13/viper" + + "github.com/konveyor/move2kube/internal/common" + "github.com/konveyor/move2kube/internal/move2kube" + "github.com/konveyor/move2kube/internal/qaengine" + "github.com/konveyor/move2kube/types/plan" +) + +const ( + outpathFlag = "outpath" + curateFlag = "curate" + qadisablecliFlag = "qadisablecli" + qaskipFlag = "qaskip" + qaportFlag = "qaport" + qacacheFlag = "qacache" +) + +var ( + curate bool + qadisablecli bool + qaskip bool + qaport int + qacaches []string +) + +var translateCmd = &cobra.Command{ + Use: "translate", + Short: "Translate using move2kube plan", + Long: "Translate artifacts using move2kube plan", + Run: func(cmd *cobra.Command, args []string) { + // Global settings + if !ignoreEnv { + common.IgnoreEnvironment = true + } + qaengine.StartEngine(qaskip, qaport, qadisablecli) + cachepaths := []string{} + for i := len(qacaches) - 1; i >= 0; i-- { + cachepaths = append(cachepaths, qacaches[i]) + } + qaengine.AddCaches(cachepaths) + + // Parameter cleaning and curate plan + var p plan.Plan + fi, err := os.Stat(planfile) + if err == nil && fi.IsDir() { + planfile = filepath.Join(planfile, common.DefaultPlanFile) + _, err = os.Stat(planfile) + } + if err != nil { + if !cmd.Flags().Changed(planFlag) && cmd.Flags().Changed(sourceFlag) { + p = move2kube.CreatePlan(srcpath, name) + err := qaengine.SetWriteCache(filepath.Join(outpath, p.Name, common.QACacheFile)) + if err != nil { + log.Warnf("Unable to write cache : %s", err) + } + p = move2kube.CuratePlan(p) + } else { + log.Fatalf("Error while accessing plan file path %s : %s ", planfile, err) + } + } else { + p, err = move2kube.ReadPlan(planfile) + if err != nil { + log.Fatalf("Unable to read plan : %s", err) + } + if cmd.Flags().Changed(nameFlag) { + p.Name = name + } + if curate { + err = qaengine.SetWriteCache(filepath.Join(outpath, p.Name, common.QACacheFile)) + if err != nil { + log.Warnf("Unable to write cache : %s", err) + } + p = move2kube.CuratePlan(p) + } + } + if srcpath != "" { + p.Spec.Inputs.RootDir = srcpath + } + fi, err = os.Stat(p.Spec.Inputs.RootDir) + if os.IsNotExist(err) { + log.Fatalf("Source directory does not exist: %s.", err) + } else if err != nil { + log.Fatalf("Error while accessing source directory: %s. ", p.Spec.Inputs.RootDir) + } else if !fi.IsDir() { + log.Fatalf("Source path is a file, expected directory: %s.", p.Spec.Inputs.RootDir) + } + outpath = filepath.Clean(outpath) + if outpath == "." { + outpath = "" + } + outpath = filepath.Join(outpath, p.Name) + fi, err = os.Stat(outpath) + if os.IsNotExist(err) { + log.Debugf("Translated artifacts will be written to %s.", outpath) + } else if err != nil { + log.Fatalf("Error while accessing output directory: %s (%s). Exiting", outpath, err) + } else if !fi.IsDir() { + log.Fatalf("Output path is a file, expected directory: %s. Exiting", outpath) + } else { + log.Infof("Output directory exists: %s. The contents might get overwritten.", outpath) + } + err = qaengine.SetWriteCache(filepath.Join(outpath, common.QACacheFile)) + if err != nil { + log.Warnf("Unable to write cache : %s", err) + } + + // Translate + move2kube.Translate(p, outpath) + log.Infof("Translated target artifacts can be found at [%s].", outpath) + }, +} + +func init() { + viper.AutomaticEnv() + + // Basic options + translateCmd.Flags().StringVarP(&planfile, planFlag, "p", common.DefaultPlanFile, "Specify a plan file to execute.") + translateCmd.Flags().BoolVarP(&curate, curateFlag, "c", false, "Specify whether to curate the plan with a q/a.") + translateCmd.Flags().StringVarP(&srcpath, sourceFlag, "s", "", "Specify source directory to translate. If you already have a m2k.plan then this will override the rootdir value specified in that plan.") + translateCmd.Flags().StringVarP(&outpath, outpathFlag, "o", "", "Path for output. Default will be directory with the project name.") + translateCmd.Flags().StringVarP(&name, nameFlag, "n", common.DefaultProjectName, "Specify the project name.") + translateCmd.Flags().StringSliceVarP(&qacaches, qacacheFlag, "q", []string{}, "Specify qa cache file locations") + + // Advanced options + translateCmd.Flags().BoolVar(&ignoreEnv, ignoreEnvFlag, false, "Ignore data from local machine.") + + // Hidden options + translateCmd.Flags().BoolVar(&qadisablecli, qadisablecliFlag, false, "Enable/disable the QA Cli sub-system. Without this system, you will have to use the REST API to interact.") + translateCmd.Flags().BoolVar(&qaskip, qaskipFlag, false, "Enable/disable the default answers to questions posed in QA Cli sub-system. If disabled, you will have to answer the questions posed by QA during interaction.") + translateCmd.Flags().IntVar(&qaport, qaportFlag, 0, "Port for the QA service. By default it chooses a random free port.") + + _ = translateCmd.Flags().MarkHidden(qadisablecliFlag) + _ = translateCmd.Flags().MarkHidden(qaskipFlag) + _ = translateCmd.Flags().MarkHidden(qaportFlag) + + rootCmd.AddCommand(translateCmd) +} diff --git a/cmd/move2kube/version.go b/cmd/move2kube/version.go new file mode 100644 index 000000000..9ea450b1f --- /dev/null +++ b/cmd/move2kube/version.go @@ -0,0 +1,44 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +import ( + "fmt" + + "github.com/konveyor/move2kube/internal/move2kube" + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +var long bool + +var versionCmd = &cobra.Command{ + Use: "version", + Short: "Print the client version information", + Long: "Print the client version information", + Run: func(cmd *cobra.Command, args []string) { + fmt.Println(move2kube.GetVersion(long)) + }, +} + +func init() { + viper.AutomaticEnv() + + versionCmd.Flags().BoolVarP(&long, "long", "l", false, "print the version details") + + rootCmd.AddCommand(versionCmd) +} diff --git a/code-of-conduct.md b/code-of-conduct.md new file mode 100644 index 000000000..fbb92f4dd --- /dev/null +++ b/code-of-conduct.md @@ -0,0 +1,129 @@ + +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, religion, or sexual identity +and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our +community include: + +* Demonstrating empathy and kindness toward other people +* Being respectful of differing opinions, viewpoints, and experiences +* Giving and gracefully accepting constructive feedback +* Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +* Focusing on what is best not just for us as individuals, but for the + overall community + +Examples of unacceptable behavior include: + +* The use of sexualized language or imagery, and sexual attention or + advances of any kind +* Trolling, insulting or derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or email + address, without their explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, and will communicate reasons for moderation +decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official e-mail address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported to the community leaders responsible for enforcement at +ashokponkumar@in.ibm.com. +All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining +the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing +clarity around the nature of the violation and an explanation of why the +behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series +of actions. + +**Consequence**: A warning with consequences for continued behavior. No +interaction with the people involved, including unsolicited interaction with +those enforcing the Code of Conduct, for a specified period of time. This +includes avoiding interactions in community spaces as well as external channels +like social media. Violating these terms may lead to a temporary or +permanent ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including +sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public +communication with the community for a specified period of time. No public or +private interaction with the people involved, including unsolicited interaction +with those enforcing the Code of Conduct, is allowed during this period. +Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community +standards, including sustained inappropriate behavior, harassment of an +individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within +the community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 2.0, available at +https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. + +Community Impact Guidelines were inspired by [Mozilla's code of conduct +enforcement ladder](https://github.com/mozilla/diversity). + +[homepage]: https://www.contributor-covenant.org + +For answers to common questions about this code of conduct, see the FAQ at +https://www.contributor-covenant.org/faq. Translations are available at +https://www.contributor-covenant.org/translations. diff --git a/contributing.md b/contributing.md new file mode 100644 index 000000000..5065a4960 --- /dev/null +++ b/contributing.md @@ -0,0 +1,22 @@ +# Contributing +Please read our code of conduct before contributing and make sure to follow it in all interactions with the project. + +If your proposed feature requires extensive changes/additions please contact us or raise a Github issue first. + +In order to contribute please follow this process: + +1. Fork the repo on github and clone your fork. +2. Make a new branch for your feature/bug fix. Example: `git checkout -b myfeature` +3. Make your changes and commit. + - Note: Please run `make test-style` and `make test` before making any commits to run the linters and ensure they pass build and test. This requirement allows the use of `git bisect` to find the exact commit that introduced a specific bug. +4. Make sure to format your code properly (`go fmt`) and update any relevant documentation, README.md, etc. about the changes you made. + - Note: If it is a new feature please add unit tests for the same. If it is a bug fix please add tests/test cases to catch regressions in the future. + +## Pull Request Process +Once you are ready to have your work merged into the main repo follow these steps: + +1. Fetch the latest commits from upstream. `git fetch upstream` +2. Rebase the commits from your branch onto the master branch. `git rebase upstream/master` + - Note: You will need to fix any merge conflicts that occur. +3. Once all conflicts have been resolved, push the commits to your fork (`git push`) and submit a pull request on Github. +4. The pull request may be merged after CI checks have passed and at least one maintainer has signed off on it. diff --git a/go.mod b/go.mod new file mode 100644 index 000000000..656dd7377 --- /dev/null +++ b/go.mod @@ -0,0 +1,48 @@ +module github.com/konveyor/move2kube + +go 1.15 + +require ( + code.cloudfoundry.org/bytefmt v0.0.0-20200131002437-cf55d5288a48 // indirect + code.cloudfoundry.org/cli v7.1.0+incompatible + github.com/AlecAivazis/survey/v2 v2.1.1 + github.com/Masterminds/semver/v3 v3.1.0 + github.com/bmatcuk/doublestar v1.3.2 // indirect + github.com/charlievieth/fs v0.0.0-20170613215519-7dc373669fa1 // indirect + github.com/cloudfoundry/bosh-cli v6.4.0+incompatible + github.com/cloudfoundry/bosh-utils v0.0.0-20200909190919-f6fb70428c10 // indirect + github.com/containers/skopeo v1.1.1-0.20200811214205-ea10e61f7d60 + github.com/cppforlife/go-patch v0.2.0 // indirect + github.com/docker/cli v0.0.0-20200227165822-2298e6a3fe24 + github.com/docker/docker v17.12.0-ce-rc1.0.20200618181300-9dc6525e6118+incompatible // indirect + github.com/docker/libcompose v0.4.1-0.20171025083809-57bd716502dc + github.com/go-git/go-git/v5 v5.1.0 + github.com/gorilla/mux v1.8.0 + github.com/moby/buildkit v0.7.2 + github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d // indirect + github.com/opencontainers/runtime-spec v1.0.3-0.20200728170252-4d89ac9fbff6 + github.com/openshift/api v0.0.0-20200326160804-ecb9283fe820 // 4.1 + github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2 + github.com/pkg/errors v0.9.1 + github.com/sirupsen/logrus v1.6.0 + github.com/spf13/cast v1.3.1 + github.com/spf13/cobra v1.0.0 + github.com/spf13/viper v1.7.1 + github.com/tektoncd/pipeline v0.16.3 + github.com/xrash/smetrics v0.0.0-20200730060457-89a2a8a1fb0b + gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 + k8s.io/api v0.18.8 + k8s.io/apimachinery v0.19.0 + k8s.io/client-go v11.0.1-0.20190805182717-6502b5e7b1b5+incompatible + knative.dev/serving v0.17.2 +) + +replace ( + github.com/containerd/containerd v1.4.0-0 => github.com/containerd/containerd v1.4.0 + github.com/docker/cli => github.com/docker/cli v0.0.0-20200210162036-a4bedce16568 + github.com/docker/docker v0.0.0 => github.com/docker/docker v17.12.0-ce-rc1.0.20200618181300-9dc6525e6118+incompatible + github.com/xeipuuv/gojsonschema => github.com/xeipuuv/gojsonschema v0.0.0-20161030231247-84d19640f6a7 // indirect + k8s.io/api => k8s.io/api v0.17.6 + k8s.io/apimachinery => k8s.io/apimachinery v0.17.6 + k8s.io/client-go => k8s.io/client-go v0.17.6 +) diff --git a/go.sum b/go.sum new file mode 100644 index 000000000..2adff2998 --- /dev/null +++ b/go.sum @@ -0,0 +1,2461 @@ +bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8= +bazil.org/fuse v0.0.0-20180421153158-65cc252bf669/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8= +cloud.google.com/go v0.25.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.30.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/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.39.0/go.mod h1:rVLT6fkc8chs9sfPtFc1SBH6em7n+ZoXaG+87tDISts= +cloud.google.com/go v0.40.0/go.mod h1:Tk58MuI9rbLMKlAjeO/bDnteAx7tX2gJIXw4T5Jwlro= +cloud.google.com/go v0.43.0/go.mod h1:BOSR3VbTLkk6FDC/TcffxP4NF/FFBGA5ku+jvKOP7pg= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.47.0/go.mod h1:5p3Ky/7f3N10VBkhuR5LFtddroTiMyjZV/Kj5qOQFxU= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.51.0/go.mod h1:hWtGJ6gnXH+KgDv+V0zFGDvpi07n3z8ZNj3T1RW0Gcw= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go v0.55.0 h1:eoz/lYxKSL4CNAiaUJ0ZfD1J3bfMYbU5B3rwM1C1EIU= +cloud.google.com/go v0.55.0/go.mod h1:ZHmoY+/lIMNkN2+fBmuTiqZ4inFhvQad8ft7MT8IV5Y= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0 h1:EpMNVUorLiZIELdMZbCYX/ByTFCdoYopYAGxaGVz9ms= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.60.0/go.mod h1:yw2G51M9IfRboUH61Us8GqCeF1PzPblB823Mn2q2eAU= +cloud.google.com/go v0.61.0/go.mod h1:XukKJg4Y7QsUu0Hxg3qQKUWR4VuWivmyMK2+rUyxAqw= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.64.0/go.mod h1:xfORb36jGvE+6EexW71nMEtL025s3x6xvuYUKM4JLv4= +cloud.google.com/go v0.65.0 h1:Dg9iHVQfrhq82rUNu9ZxUDrJLaxFUe/HlCVaLyRruq8= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= +cloud.google.com/go/logging v1.0.0/go.mod h1:V1cc3ogwobYzQq5f2R7DS/GvRIrI4FKj01Gs5glwAls= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/pubsub v1.4.0/go.mod h1:LFrqilwgdw4X2cJS9ALgzYmMu+ULyrUN6IHV3CPK4TM= +cloud.google.com/go/pubsub v1.6.1/go.mod h1:kvW9rcn9OLEx6eTIzMBbWbpB8YsK3vu9jxgPolVz+p4= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= +cloud.google.com/go/storage v1.9.0/go.mod h1:m+/etGaqZbylxaNT876QGXqEHp4PR2Rq5GMqICWb9bU= +cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +cloud.google.com/go/storage v1.11.0 h1:bSLyzhbGjLMYxCratCDRSSH7+xRGpNApTBmowDUFGLk= +cloud.google.com/go/storage v1.11.0/go.mod h1:/PAbprKS+5msVYogBmczjWalDXnQ9mr64yEq9YnyPeo= +code.cloudfoundry.org/bytefmt v0.0.0-20200131002437-cf55d5288a48 h1:/EMHruHCFXR9xClkGV/t0rmHrdhX4+trQUcBqjwc9xE= +code.cloudfoundry.org/bytefmt v0.0.0-20200131002437-cf55d5288a48/go.mod h1:wN/zk7mhREp/oviagqUXY3EwuHhWyOvAdsn5Y4CzOrc= +code.cloudfoundry.org/cfnetworking-cli-api v0.0.0-20190103195135-4b04f26287a6 h1:Yc9r1p21kEpni9WlG4mwOZw87TB2QlyS9sAEebZ3+ak= +code.cloudfoundry.org/cfnetworking-cli-api v0.0.0-20190103195135-4b04f26287a6/go.mod h1:u5FovqC5GGAEbFPz+IdjycDA+gIjhUwqxnu0vbHwVeM= +code.cloudfoundry.org/cli v7.0.2+incompatible h1:/Ly0TD9X8QAz4l2KenlhfCNtL/RO0BPQF2+2NEcWaIY= +code.cloudfoundry.org/cli v7.0.2+incompatible/go.mod h1:e4d+EpbwevNhyTZKybrLlyTvpH+W22vMsmdmcTxs/Fo= +code.cloudfoundry.org/cli v7.1.0+incompatible h1:1Zn3I+epQBaBvnZAaTudCQQ0WdqcWtjtjEV9MBZP08Y= +code.cloudfoundry.org/cli v7.1.0+incompatible/go.mod h1:e4d+EpbwevNhyTZKybrLlyTvpH+W22vMsmdmcTxs/Fo= +code.cloudfoundry.org/cli-plugin-repo v0.0.0-20200914153654-c3a45f208585 h1:ErlA+NeoR9wkvWMapyrXI013vvc6zxy04pfoVCCzexE= +code.cloudfoundry.org/cli-plugin-repo v0.0.0-20200914153654-c3a45f208585/go.mod h1:R1EiyOAr7lW0l/YkZNqItUNZ01Q/dYUfbTn4X4Z+82M= +code.cloudfoundry.org/clock v1.0.0 h1:kFXWQM4bxYvdBw2X8BbBeXwQNgfoWv1vqAk2ZZyBN2o= +code.cloudfoundry.org/clock v1.0.0/go.mod h1:QD9Lzhd/ux6eNQVUDVRJX/RKTigpewimNYBi7ivZKY8= +code.cloudfoundry.org/go-log-cache v1.0.0 h1:e4FUVpwCDMBCFx0mSB+lGjYlVtSHT1JlK6/mxvUvTrU= +code.cloudfoundry.org/go-log-cache v1.0.0/go.mod h1:YtelJ6iHvZGxPWCIUdO98UlczOawv5jD79hxO8Ln8Pg= +code.cloudfoundry.org/go-loggregator v1.0.0 h1:z9oqyKwM5by2Q0Mvh1sP73Z/WuCqmDvrtEQDYSf2o/k= +code.cloudfoundry.org/go-loggregator v7.4.0+incompatible h1:KqZYloMQWM5Zg/BQKunOIA4OODh7djZbk48qqbowNFI= +code.cloudfoundry.org/go-loggregator v7.4.0+incompatible/go.mod h1:KPBTRqj+y738Nhf1+g4JHFaBU8j7dedirR5ETNHvMXU= +code.cloudfoundry.org/gofileutils v0.0.0-20170111115228-4d0c80011a0f h1:UrKzEwTgeiff9vxdrfdqxibzpWjxLnuXDI5m6z3GJAk= +code.cloudfoundry.org/gofileutils v0.0.0-20170111115228-4d0c80011a0f/go.mod h1:sk5LnIjB/nIEU7yP5sDQExVm62wu0pBh3yrElngUisI= +code.cloudfoundry.org/jsonry v1.1.0 h1:mbm3hZKTFgQ0mN/vmGmM8lmhMVXIG77rhYEtRrpFRd8= +code.cloudfoundry.org/jsonry v1.1.0/go.mod h1:iKx5oLd4DgbgnHF/vFuaAf9hR2ZJ9XlURHIU+yDKplk= +code.cloudfoundry.org/rfc5424 v0.0.0-20180905210152-236a6d29298a h1:8rqv2w8xEceNwckcF5ONeRt0qBHlh5bnNfFnYTrZbxs= +code.cloudfoundry.org/rfc5424 v0.0.0-20180905210152-236a6d29298a/go.mod h1:tkZo8GtzBjySJ7USvxm4E36lNQw1D3xM6oKHGqdaAJ4= +code.cloudfoundry.org/tlsconfig v0.0.0-20200131000646-bbe0f8da39b3 h1:2Qal+q+tw/DmDOoJBWwDCPE3lIJNj/1o7oMkkb2c5SI= +code.cloudfoundry.org/tlsconfig v0.0.0-20200131000646-bbe0f8da39b3/go.mod h1:eTbFJpyXRGuFVyg5+oaj9B2eIbIc+0/kZjH8ftbtdew= +code.cloudfoundry.org/workpool v0.0.0-20200131000409-2ac56b354115 h1:xm2g6uJ31UkWwrkuww9JYi13bueNh+l086tJA8Q/GM0= +code.cloudfoundry.org/workpool v0.0.0-20200131000409-2ac56b354115/go.mod h1:O9HdfntfyDvYRH9nh03XdpnGMbjyZVi8nb2Kh+6hDho= +code.cloudfoundry.org/ykk v0.0.0-20170424192843-e4df4ce2fd4d h1:M+zXqtXJqcsmpL76aU0tdl1ho23eYa4axYoM4gD62UA= +code.cloudfoundry.org/ykk v0.0.0-20170424192843-e4df4ce2fd4d/go.mod h1:YUJiVOr5xl0N/RjMxM1tHmgSpBbi5UM+KoVR5AoejO0= +code.gitea.io/sdk/gitea v0.12.0/go.mod h1:z3uwDV/b9Ls47NGukYM9XhnHtqPh/J+t40lsUrR6JDY= +contrib.go.opencensus.io/exporter/aws v0.0.0-20181029163544-2befc13012d0/go.mod h1:uu1P0UCM/6RbsMrgPa98ll8ZcHM858i/AD06a9aLRCA= +contrib.go.opencensus.io/exporter/ocagent v0.4.12/go.mod h1:450APlNTSR6FrvC3CTRqYosuDstRB9un7SOx2k/9ckA= +contrib.go.opencensus.io/exporter/ocagent v0.5.0/go.mod h1:ImxhfLRpxoYiSq891pBrLVhN+qmP8BTVvdH2YLs7Gl0= +contrib.go.opencensus.io/exporter/ocagent v0.6.0 h1:Z1n6UAyr0QwM284yUuh5Zd8JlvxUGAhFZcgMJkMPrGM= +contrib.go.opencensus.io/exporter/ocagent v0.6.0/go.mod h1:zmKjrJcdo0aYcVS7bmEeSEBLPA9YJp5bjrofdU3pIXs= +contrib.go.opencensus.io/exporter/ocagent v0.7.1-0.20200615190824-f8c219d2d895/go.mod h1:IshRmMJBhDfFj5Y67nVhMYTTIze91RUeT73ipWKs/GY= +contrib.go.opencensus.io/exporter/prometheus v0.1.0 h1:SByaIoWwNgMdPSgl5sMqM2KDE5H/ukPWBRo314xiDvg= +contrib.go.opencensus.io/exporter/prometheus v0.1.0/go.mod h1:cGFniUXGZlKRjzOyuZJ6mgB+PgBcCIa79kEKR8YCW+A= +contrib.go.opencensus.io/exporter/prometheus v0.2.1-0.20200609204449-6bcf6f8577f0/go.mod h1:MjHoxkI7Ny27toPeFkRbXbzVjzIGkwOAptrAy8Mxtm8= +contrib.go.opencensus.io/exporter/stackdriver v0.12.1/go.mod h1:iwB6wGarfphGGe/e5CWqyUk/cLzKnWsOKPVW3no6OTw= +contrib.go.opencensus.io/exporter/stackdriver v0.12.8/go.mod h1:XyyafDnFOsqoxHJgTFycKZMrRUrPThLh2iYTJF6uoO0= +contrib.go.opencensus.io/exporter/stackdriver v0.12.9-0.20191108183826-59d068f8d8ff/go.mod h1:XyyafDnFOsqoxHJgTFycKZMrRUrPThLh2iYTJF6uoO0= +contrib.go.opencensus.io/exporter/stackdriver v0.13.1 h1:RX9W6FelAqTVnBi/bRXJLXr9n18v4QkQwZYIdnNS51I= +contrib.go.opencensus.io/exporter/stackdriver v0.13.1/go.mod h1:z2tyTZtPmQ2HvWH4cOmVDgtY+1lomfKdbLnkJvZdc8c= +contrib.go.opencensus.io/exporter/stackdriver v0.13.2/go.mod h1:aXENhDJ1Y4lIg4EUaVTwzvYETVNZk10Pu26tevFKLUc= +contrib.go.opencensus.io/exporter/zipkin v0.1.1/go.mod h1:GMvdSl3eJ2gapOaLKzTKE3qDgUkJ86k9k3yY2eqwkzc= +contrib.go.opencensus.io/integrations/ocsql v0.1.4/go.mod h1:8DsSdjz3F+APR+0z0WkU1aRorQCFfRxvqjUUPMbF3fE= +contrib.go.opencensus.io/resource v0.1.1/go.mod h1:F361eGI91LCmW1I/Saf+rX0+OFcigGlFvXwEGEnkRLA= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= +git.apache.org/thrift.git v0.12.0/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= +github.com/14rcole/gopopulate v0.0.0-20180821133914-b175b219e774 h1:SCbEWT58NSt7d2mcFdvxC9uyrdcTfvBbPLThhkDmXzg= +github.com/14rcole/gopopulate v0.0.0-20180821133914-b175b219e774/go.mod h1:6/0dYRLLXyJjbkIPeeGyoJ/eKOSI0eU6eTlCBYibgd0= +github.com/AkihiroSuda/containerd-fuse-overlayfs v0.0.0-20200220082720-bb896865146c/go.mod h1:K4kx7xAA5JimeQCnN+dbeLlfaBxzZLaLiDD8lusFI8w= +github.com/AlecAivazis/survey/v2 v2.1.1 h1:LEMbHE0pLj75faaVEKClEX1TM4AJmmnOh9eimREzLWI= +github.com/AlecAivazis/survey/v2 v2.1.1/go.mod h1:9FJRdMdDm8rnT+zHVbvQT2RTSTLq0Ttd6q3Vl2fahjk= +github.com/Azure/azure-amqp-common-go/v2 v2.1.0/go.mod h1:R8rea+gJRuJR6QxTir/XuEd+YuKoUiazDC/N96FiDEU= +github.com/Azure/azure-pipeline-go v0.1.8/go.mod h1:XA1kFWRVhSK+KNFiOhfv83Fv8L9achrP7OxIzeTn1Yg= +github.com/Azure/azure-pipeline-go v0.1.9/go.mod h1:XA1kFWRVhSK+KNFiOhfv83Fv8L9achrP7OxIzeTn1Yg= +github.com/Azure/azure-pipeline-go v0.2.1/go.mod h1:UGSo8XybXnIGZ3epmeBw7Jdz+HiUVpqIlpz/HKHylF4= +github.com/Azure/azure-pipeline-go v0.2.2/go.mod h1:4rQ/NZncSvGqNkkOsNpOU1tgoNuIlp9AfUH5G1tvCHc= +github.com/Azure/azure-sdk-for-go v16.2.1+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/azure-sdk-for-go v19.1.1+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/azure-sdk-for-go v21.1.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/azure-sdk-for-go v28.1.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/azure-sdk-for-go v29.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/azure-sdk-for-go v30.1.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/azure-sdk-for-go v35.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/azure-sdk-for-go v38.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/azure-sdk-for-go v42.3.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/azure-service-bus-go v0.9.1/go.mod h1:yzBx6/BUGfjfeqbRZny9AQIbIe3AcV9WZbAdpkoXOa0= +github.com/Azure/azure-storage-blob-go v0.0.0-20190123011202-457680cc0804/go.mod h1:oGfmITT1V6x//CswqY2gtAHND+xIP64/qL7a5QJix0Y= +github.com/Azure/azure-storage-blob-go v0.8.0/go.mod h1:lPI3aLPpuLTeUwh1sViKXFxwl2B6teiRqI0deQUvsw0= +github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8= +github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/Azure/go-autorest v10.8.1+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest v10.15.5+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest v11.1.2+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest v12.0.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest v14.1.1+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest/autorest v0.1.0/go.mod h1:AKyIcETwSUFxIcs/Wnq/C+kwCtlEYGUVd7FPNb2slmg= +github.com/Azure/go-autorest/autorest v0.2.0/go.mod h1:AKyIcETwSUFxIcs/Wnq/C+kwCtlEYGUVd7FPNb2slmg= +github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= +github.com/Azure/go-autorest/autorest v0.9.3/go.mod h1:GsRuLYvwzLjjjRoWEIyMUaYq8GNUx2nRB378IPt/1p0= +github.com/Azure/go-autorest/autorest v0.9.6/go.mod h1:/FALq9T/kS7b5J5qsQ+RSTUdAmGFqi0vUdVNNx8q630= +github.com/Azure/go-autorest/autorest v0.10.2/go.mod h1:/FALq9T/kS7b5J5qsQ+RSTUdAmGFqi0vUdVNNx8q630= +github.com/Azure/go-autorest/autorest/adal v0.1.0/go.mod h1:MeS4XhScH55IST095THyTxElntu7WqB7pNbZo8Q5G3E= +github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= +github.com/Azure/go-autorest/autorest/adal v0.8.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc= +github.com/Azure/go-autorest/autorest/adal v0.8.1/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q= +github.com/Azure/go-autorest/autorest/adal v0.8.2/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q= +github.com/Azure/go-autorest/autorest/adal v0.8.3/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q= +github.com/Azure/go-autorest/autorest/azure/auth v0.4.2/go.mod h1:90gmfKdlmKgfjUpnCEpOJzsUEjrWDSLwHIG73tSXddM= +github.com/Azure/go-autorest/autorest/azure/cli v0.3.1/go.mod h1:ZG5p860J94/0kI9mNJVoIoLgXcirM2gF5i2kWloofxw= +github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= +github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g= +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/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM= +github.com/Azure/go-autorest/autorest/to v0.1.0/go.mod h1:GunWKJp1AEqgMaGLV+iocmRAJWqST1wQYhyyjXJ3SJc= +github.com/Azure/go-autorest/autorest/to v0.2.0/go.mod h1:GunWKJp1AEqgMaGLV+iocmRAJWqST1wQYhyyjXJ3SJc= +github.com/Azure/go-autorest/autorest/to v0.3.0/go.mod h1:MgwOyqaIuKdG4TL/2ywSsIWKAfJfgHDo8ObuUk3t5sA= +github.com/Azure/go-autorest/autorest/validation v0.1.0/go.mod h1:Ha3z/SqBeaalWQvokg3NZAlQTalVMtOIAs1aGK7G6u8= +github.com/Azure/go-autorest/autorest/validation v0.2.0/go.mod h1:3EEqHnBxQGHXRYq3HT1WyXAvT7LLY3tl70hw6tQIbjI= +github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= +github.com/Azure/go-autorest/tracing v0.1.0/go.mod h1:ROEEAFwXycQw7Sn3DXNtEedEvdeRAgDr0izn4z5Ij88= +github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= +github.com/BurntSushi/toml v0.3.0/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/DataDog/zstd v1.3.6-0.20190409195224-796139022798/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= +github.com/DataDog/zstd v1.4.1/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= +github.com/Djarvur/go-err113 v0.0.0-20200410182137-af658d038157/go.mod h1:4UJr5HIiMZrwgkSPdsjy2uOQExX/WEILpIrO9UPGuXs= +github.com/Djarvur/go-err113 v0.1.0/go.mod h1:4UJr5HIiMZrwgkSPdsjy2uOQExX/WEILpIrO9UPGuXs= +github.com/GoogleCloudPlatform/cloud-builders/gcs-fetcher v0.0.0-20191203181535-308b93ad1f39/go.mod h1:yfGmCjKuUzk9WzubMlW2zwjhCraIc/J+M40cufdemRM= +github.com/GoogleCloudPlatform/cloudsql-proxy v0.0.0-20191009163259-e802c2cb94ae/go.mod h1:mjwGPas4yKduTyubHvD1Atl9r1rUq8DfVy+gkVvZ+oo= +github.com/GoogleCloudPlatform/k8s-cloud-provider v0.0.0-20190822182118-27a4ced34534/go.mod h1:iroGtC8B3tQiqtds1l+mgk/BBOrxbqjH+eUfFQYRc14= +github.com/GoogleCloudPlatform/testgrid v0.0.1-alpha.3/go.mod h1:f96W2HYy3tiBNV5zbbRc+NczwYHgG1PHXMQfoEWv680= +github.com/GoogleCloudPlatform/testgrid v0.0.7/go.mod h1:lmtHGBL0M/MLbu1tR9BWV7FGZ1FEFIdPqmJiHNCL7y8= +github.com/GoogleCloudPlatform/testgrid v0.0.13/go.mod h1:UlC/MvnkKjiVGijIKOHxnVyhDiTDCydw9H1XzmclQGU= +github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd/go.mod h1:64YHyfSL2R96J44Nlwm39UHepQbyR5q10x7iYa1ks2E= +github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= +github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww= +github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= +github.com/Masterminds/semver/v3 v3.0.3/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= +github.com/Masterminds/semver/v3 v3.1.0 h1:Y2lUDsFKVRSYGojLJ1yLxSXdMmMYTYls0rCvoqmMUQk= +github.com/Masterminds/semver/v3 v3.1.0/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= +github.com/Masterminds/sprig/v3 v3.0.2/go.mod h1:oesJ8kPONMONaZgtiHNzUShJbksypC5kWczhZAf6+aU= +github.com/Masterminds/vcs v1.13.1/go.mod h1:N09YCmOQr6RLxC6UNHzuVwAdodYbbnycGHSmwVJjcKA= +github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA= +github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= +github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw= +github.com/Microsoft/hcsshim v0.8.6/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg= +github.com/Microsoft/hcsshim v0.8.7/go.mod h1:OHd7sQqRFrYd3RmSgbgji+ctCwkbq2wbEYNSzOYtcBQ= +github.com/Microsoft/hcsshim v0.8.9 h1:VrfodqvztU8YSOvygU+DN1BGaSGxmrNfqOv5oOuX2Bk= +github.com/Microsoft/hcsshim v0.8.9/go.mod h1:5692vkUqntj1idxauYlpoINNKeqCiG6Sg38RRsjT5y8= +github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= +github.com/Netflix/go-expect v0.0.0-20180615182759-c93bf25de8e8 h1:xzYJEypr/85nBpB11F9br+3HUrpgb+fcm5iADzXXYEw= +github.com/Netflix/go-expect v0.0.0-20180615182759-c93bf25de8e8/go.mod h1:oX5x61PbNXchhh0oikYAH+4Pcfw5LKv21+Jnpr6r6Pc= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/OpenPeeDeeP/depguard v1.0.1/go.mod h1:xsIw86fROiiwelg+jB2uM9PiKihMMmUx/1V+TNhjQvM= +github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/SermoDigital/jose v0.9.1 h1:atYaHPD3lPICcbK1owly3aPm0iaJGSGPi0WD4vLznv8= +github.com/SermoDigital/jose v0.9.1/go.mod h1:ARgCUhI1MHQH+ONky/PAtmVHQrP5JlGY0F3poXOp/fA= +github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ= +github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= +github.com/Shopify/sarama v1.23.1/go.mod h1:XLH1GYJnLVE0XCr6KdJGVJRTwY30moWNJ4sERjXX6fs= +github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= +github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= +github.com/VividCortex/ewma v1.1.1 h1:MnEK4VOv6n0RSY4vtRe3h11qjxL3+t0B8yOL8iMXdcM= +github.com/VividCortex/ewma v1.1.1/go.mod h1:2Tkkvm3sRDVXaiyucHiACn4cqf7DpdyLvmxzcbUokwA= +github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d h1:licZJFw2RwpHMqeKTCYkitsPqHNxTmd4SNR5r94FGM8= +github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d/go.mod h1:asat636LX7Bqt5lYEZ27JNDcqxfjdBQuJ/MM4CN/Lzo= +github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM= +github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= +github.com/alecthomas/kingpin v2.2.6+incompatible/go.mod h1:59OFYbFVLKQKq+mqrL6Rw5bR0c3ACQaawgXx0QYndlE= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= +github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= +github.com/andybalholm/brotli v0.0.0-20190621154722-5f990b63d2d6/go.mod h1:+lx6/Aqd1kLJ1GQfkvOnaZ1WGmLpMpbprPuIOOZX30U= +github.com/andygrunwald/go-gerrit v0.0.0-20190120104749-174420ebee6c/go.mod h1:0iuRQp6WJ44ts+iihy5E/WlPqfg5RNeQxOmzRkxCdtk= +github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= +github.com/antihax/optional v0.0.0-20180407024304-ca021399b1a6/go.mod h1:V8iCPQYkqmusNa815XgQio277wI47sdRh1dUOLdyC6Q= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/apache/thrift v0.0.0-20161221203622-b2a4d4ae21c7/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= +github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= +github.com/apex/log v1.1.4/go.mod h1:AlpoD9aScyQfJDVHmLMEcx4oU6LqzkWp4Mg9GdAcEvQ= +github.com/apex/log v1.3.0 h1:1fyfbPvUwD10nMoh3hY6MXzvZShJQn9/ck7ATgAt5pA= +github.com/apex/log v1.3.0/go.mod h1:jd8Vpsr46WAe3EZSQ/IUMs2qQD/GOycT5rPWCO1yGcs= +github.com/apex/logs v0.0.4/go.mod h1:XzxuLZ5myVHDy9SAmYpamKKRNApGj54PfYLcFrXqDwo= +github.com/aphistic/golf v0.0.0-20180712155816-02c07f170c5a/go.mod h1:3NqKYiepwy8kCu4PNA+aP7WUV72eXWJeP9/r3/K9aLE= +github.com/aphistic/sweet v0.2.0/go.mod h1:fWDlIh/isSE9n6EPsRmC0det+whmX6dJid3stzu0Xys= +github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= +github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= +github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= +github.com/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg= +github.com/aws/aws-k8s-tester v0.0.0-20190114231546-b411acf57dfe/go.mod h1:1ADF5tAtU1/mVtfMcHAYSm2fPw71DA7fFk0yed64/0I= +github.com/aws/aws-k8s-tester v0.9.3/go.mod h1:nsh1f7joi8ZI1lvR+Ron6kJM2QdCYPU/vFePghSSuTc= +github.com/aws/aws-k8s-tester v1.0.0/go.mod h1:NUNd9k43+h9O5tvwL+4N1Ctb//SapmeeFX1G0/2/0Qc= +github.com/aws/aws-sdk-go v1.15.11/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0= +github.com/aws/aws-sdk-go v1.15.27/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0= +github.com/aws/aws-sdk-go v1.15.90/go.mod h1:es1KtYUFs7le0xQ3rOihkuoVD90z7D0fR2Qm4S00/gU= +github.com/aws/aws-sdk-go v1.16.18/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go v1.16.26/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go v1.19.18/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go v1.19.45/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go v1.20.6/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go v1.23.20/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go v1.23.22/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go v1.25.11/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go v1.27.1/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go v1.29.32/go.mod h1:1KvfttTE3SPKMpo8g2c6jL3ZKfXtFvKscTgahTma5Xg= +github.com/aws/aws-sdk-go v1.29.34/go.mod h1:1KvfttTE3SPKMpo8g2c6jL3ZKfXtFvKscTgahTma5Xg= +github.com/aws/aws-sdk-go v1.30.4/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= +github.com/aws/aws-sdk-go v1.30.5 h1:i+sSesaMrSxiUt3NJddOApe2mXK+VNBgfcmRTvNFrXM= +github.com/aws/aws-sdk-go v1.30.5/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= +github.com/aws/aws-sdk-go v1.30.16/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= +github.com/aws/aws-sdk-go v1.31.6 h1:nKjQbpXhdImctBh1e0iLg9iQW/X297LPPuY/9f92R2k= +github.com/aws/aws-sdk-go v1.31.6/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= +github.com/aws/aws-sdk-go v1.31.12 h1:SxRRGyhlCagI0DYkhOg+FgdXGXzRTE3vEX/gsgFaiKQ= +github.com/aws/aws-sdk-go v1.31.12/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= +github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I= +github.com/bazelbuild/buildtools v0.0.0-20190917191645-69366ca98f89/go.mod h1:5JP0TXzWDHXv8qvxRC4InIazwdyDseBDbzESUMKk1yU= +github.com/beorn7/perks v0.0.0-20160804104726-4c0e84591b9a/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA= +github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= +github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb/go.mod h1:PkYb9DJNAwrSvRx5DYA+gUcOIgTGVMNkfSCbZM8cWpI= +github.com/blang/semver v3.1.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ= +github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/bmatcuk/doublestar v1.3.2 h1:mzUncgFmpzNUhIITFqGdZ8nUU0O7JTJzRO8VdkeLCSo= +github.com/bmatcuk/doublestar v1.3.2/go.mod h1:wiQtGV+rzVYxB7WIlirSN++5HPtPlXEo9MEoZQC/PmE= +github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= +github.com/bmizerany/pat v0.0.0-20170815010413-6226ea591a40 h1:y4B3+GPxKlrigF1ha5FFErxK+sr6sWxQovRMzwMhejo= +github.com/bmizerany/pat v0.0.0-20170815010413-6226ea591a40/go.mod h1:8rLXio+WjiTceGBHIoTvn60HIbs7Hm7bcHjyrSqYB9c= +github.com/bmizerany/perks v0.0.0-20141205001514-d9a9656a3a4b/go.mod h1:ac9efd0D1fsDb3EJvhqgXRbFx7bs2wqZ10HQPeU8U/Q= +github.com/bombsimon/wsl/v2 v2.0.0/go.mod h1:mf25kr/SqFEPhhcxW1+7pxzGlW+hIl/hYTKY95VwV8U= +github.com/bombsimon/wsl/v2 v2.2.0/go.mod h1:Azh8c3XGEJl9LyX0/sFC+CKMc7Ssgua0g+6abzXN4Pg= +github.com/bombsimon/wsl/v3 v3.0.0/go.mod h1:st10JtZYLE4D5sC7b8xV4zTKZwAQjCH/Hy2Pm1FNZIc= +github.com/bombsimon/wsl/v3 v3.1.0/go.mod h1:st10JtZYLE4D5sC7b8xV4zTKZwAQjCH/Hy2Pm1FNZIc= +github.com/bshuster-repo/logrus-logstash-hook v0.4.1/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk= +github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8= +github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50= +github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE= +github.com/bwmarrin/snowflake v0.0.0/go.mod h1:NdZxfVWX+oR6y2K0o6qAYv6gIOP9rjG0/E9WsDpxqwE= +github.com/c2h5oh/datasize v0.0.0-20200112174442-28bbd4740fee/go.mod h1:S/7n9copUssQ56c7aAgHqftWO4LTf4xY6CGWt8Bc+3M= +github.com/caarlos0/ctrlc v1.0.0/go.mod h1:CdXpj4rmq0q/1Eb44M9zi2nKB0QraNKuRGYGrrHhcQw= +github.com/campoy/unique v0.0.0-20180121183637-88950e537e7e/go.mod h1:9IOqJGCPMSc6E5ydlp5NIonxObaeu/Iub/X03EKPVYo= +github.com/cavaliercoder/go-cpio v0.0.0-20180626203310-925f9528c45e/go.mod h1:oDpT4efm8tSYHXV5tHSdRvBet/b/QzxZ+XyyPehvm3A= +github.com/census-instrumentation/opencensus-proto v0.2.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/census-instrumentation/opencensus-proto v0.2.1 h1:glEXhBS5PSLLv4IXzLA5yPRVX4bilULVyxxbrfOtDAk= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/cespare/xxhash/v2 v2.1.0/go.mod h1:dgIUBU3pDso/gPgZ1osOZ0iQf77oPR28Tjxl5dIMyVM= +github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5/go.mod h1:/iP1qXHoty45bqomnu2LM+VVyAEdWN+vtSHGlQgyxbw= +github.com/charlievieth/fs v0.0.0-20170613215519-7dc373669fa1 h1:vTlpHKxJqykyKdW9bkrDJNWeKNuSIAJ0TP/K4lRsz/Q= +github.com/charlievieth/fs v0.0.0-20170613215519-7dc373669fa1/go.mod h1:sAoA1zHCH4FJPE2gne5iBiiVG66U7Nyp6JqlOo+FEyg= +github.com/checkpoint-restore/go-criu/v4 v4.0.2/go.mod h1:xUQBLp4RLc5zJtWY++yjOoMoB5lihDt7fai+75m+rGw= +github.com/checkpoint-restore/go-criu/v4 v4.1.0/go.mod h1:xUQBLp4RLc5zJtWY++yjOoMoB5lihDt7fai+75m+rGw= +github.com/cheggaaa/pb v1.0.29 h1:FckUN5ngEk2LpvuG0fw1GEFx6LtyY2pWI/Z2QgCnEYo= +github.com/cheggaaa/pb v1.0.29/go.mod h1:W40334L7FMC5JKWldsTWbdGjLo0RxUKK73K+TuPxX30= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/cihub/seelog v0.0.0-20170130134532-f561c5e57575/go.mod h1:9d6lWj8KzO/fd/NrVaLscBKmPigpZpn5YawRPw+e3Yo= +github.com/cilium/ebpf v0.0.0-20200110133405-4032b1d8aae3/go.mod h1:MA5e5Lr8slmEg9bt0VpxxWqJlO4iwu3FBdHUzV7wQVg= +github.com/cilium/ebpf v0.0.0-20200507155900-a9f01edf17e3/go.mod h1:XT+cAw5wfvsodedcijoh1l9cf7v1x9FlFB/3VmF/O8s= +github.com/cilium/ebpf v0.0.0-20200702112145-1c8d4c9ef775/go.mod h1:7cR51M8ViRLIdUjrmSXlK9pkrsDlLHbO8jiB8X8JnOc= +github.com/clarketm/json v1.13.4/go.mod h1:ynr2LRfb0fQU34l07csRNBTcivjySLLiY1YzQqKVfdo= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cloudevents/sdk-go v0.0.0-20190509003705-56931988abe3/go.mod h1:j1nZWMLGg3om8SswStBoY6/SHvcLM19MuZqwDtMtmzs= +github.com/cloudevents/sdk-go v1.0.0 h1:gS5I0s2qPmdc4GBPlUmzZU7RH30BaiOdcRJ1RkXnPrc= +github.com/cloudevents/sdk-go v1.0.0/go.mod h1:3TkmM0cFqkhCHOq5JzzRU/RxRkwzoS8TZ+G448qVTog= +github.com/cloudevents/sdk-go/v2 v2.0.0/go.mod h1:3CTrpB4+u7Iaj6fd7E2Xvm5IxMdRoaAhqaRVnOr2rCU= +github.com/cloudevents/sdk-go/v2 v2.1.0 h1:bmgrU8k+K2ppZ+G/q5xEQx/Xk9HRtJmkrEO3qtDO2k0= +github.com/cloudevents/sdk-go/v2 v2.1.0/go.mod h1:3CTrpB4+u7Iaj6fd7E2Xvm5IxMdRoaAhqaRVnOr2rCU= +github.com/cloudfoundry/bosh-agent v0.0.60 h1:i3gitL0i8niy6QeNy4X+2vckaqKh6H7cOQF9y4ce9W0= +github.com/cloudfoundry/bosh-agent v2.333.0+incompatible h1:yyNqmvOe3mZbpnjuA1b1DHA4nSURfAGdGkpgEC/rf7c= +github.com/cloudfoundry/bosh-agent v2.333.0+incompatible/go.mod h1:7UvVn5vc/d6icLrBx6GhBlpSMwe2+x1C2A7x4TbPhiU= +github.com/cloudfoundry/bosh-cli v6.3.1+incompatible h1:t56xCMktKPfp3/HyQ1jbnLJlHwFGDo5p5WnqDXyKcx0= +github.com/cloudfoundry/bosh-cli v6.3.1+incompatible/go.mod h1:rzIB+e1sn7wQL/TJ54bl/FemPKRhXby5BIMS3tLuWFM= +github.com/cloudfoundry/bosh-cli v6.4.0+incompatible h1:1x6jneOWujeiwKoY+nSSYaZdPtyfJOBLRt36SZCudKM= +github.com/cloudfoundry/bosh-cli v6.4.0+incompatible/go.mod h1:rzIB+e1sn7wQL/TJ54bl/FemPKRhXby5BIMS3tLuWFM= +github.com/cloudfoundry/bosh-davcli v0.0.44 h1:y1G3B1+6aQ+xJ2/Bx6M8TF5wkwg9So1u5zn0IR2R4P8= +github.com/cloudfoundry/bosh-davcli v0.0.44/go.mod h1:WERSlcwbbm6fF7GJfz421BeAduzbD6JlDF7NCpYTXUE= +github.com/cloudfoundry/bosh-gcscli v0.0.18 h1:2ouLAiIcdF1pWSR+igurUPQu6fwedaXyKnpTD0RyVL8= +github.com/cloudfoundry/bosh-gcscli v0.0.18/go.mod h1:YqM92JrLuB9X8sb0aJtY2zvTgpL2wwX7n/bXGOzUGic= +github.com/cloudfoundry/bosh-s3cli v0.0.95 h1:GULEH4Kf+7YJsugACzv4tiseCKoZrQeY65u/pqOhdjM= +github.com/cloudfoundry/bosh-s3cli v0.0.95/go.mod h1:9qqPbgWJ4aXpo5It8RGpafc7S3/v+T//HLRjynVD4/8= +github.com/cloudfoundry/bosh-utils v0.0.0-20200815100254-677a8ebab4c4 h1:VU3IQZPO5GPdW2vAX3uO04aWFaSW6/lte3zjMu7E8VI= +github.com/cloudfoundry/bosh-utils v0.0.0-20200815100254-677a8ebab4c4/go.mod h1:JCrKwetZGjxbfq1U139TZuXDBfdGLtjOEAfxMWKV/QM= +github.com/cloudfoundry/bosh-utils v0.0.0-20200909190919-f6fb70428c10 h1:PjMfISPzkazTJjLN84n5wC9/TZsai5ZYll+76vKQJBk= +github.com/cloudfoundry/bosh-utils v0.0.0-20200909190919-f6fb70428c10/go.mod h1:JCrKwetZGjxbfq1U139TZuXDBfdGLtjOEAfxMWKV/QM= +github.com/cloudfoundry/config-server v0.1.21 h1:PvRL3KasbDEweX36pucSRY8h8tsgw6zG/EjOJXrrVlA= +github.com/cloudfoundry/config-server v0.1.21/go.mod h1:Y3b/MHqyp22CcG0X1qvEHG8lujoebxjD9IAslyS/Yk0= +github.com/cloudfoundry/go-socks5 v0.0.0-20180221174514-54f73bdb8a8e h1:FQdRViaoDphGRfgrotl2QGsX1gbloe57dbGBS5CG6KY= +github.com/cloudfoundry/go-socks5 v0.0.0-20180221174514-54f73bdb8a8e/go.mod h1:PXmcacyJB/pJjSxEl15IU6rEIKXrhZQRzsr0UTkgNNs= +github.com/cloudfoundry/noaa v2.1.0+incompatible h1:hr6VnM5VlYRN3YD+NmAedQLW8686sUMknOSe0mFS2vo= +github.com/cloudfoundry/noaa v2.1.0+incompatible/go.mod h1:5LmacnptvxzrTvMfL9+EJhgkUfIgcwI61BVSTh47ECo= +github.com/cloudfoundry/socks5-proxy v0.2.0 h1:ZRXcJxUqOyKmah+ytXh52K7m7S7SyuBacDUnd2g0ihU= +github.com/cloudfoundry/socks5-proxy v0.2.0/go.mod h1:0a+Ghg38uB86Dx+de84dFSkILTnBHzCpFMRnjHgSzi4= +github.com/cloudfoundry/sonde-go v0.0.0-20200416163440-a42463ba266b h1:cb7pGf4j2ZzRfnQMqVeTtMLv0l2Y81V5biZGF7zVokg= +github.com/cloudfoundry/sonde-go v0.0.0-20200416163440-a42463ba266b/go.mod h1:GS0pCHd7onIsewbw8Ue9qa9pZPv2V88cUZDttK6KzgI= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= +github.com/codahale/hdrhistogram v0.0.0-20160425231609-f8ad88b59a58/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= +github.com/codegangsta/negroni v1.0.0/go.mod h1:v0y3T5G7Y1UlFfyxFn/QLRU4a2EuNau2iZY63YTKWo0= +github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f h1:tSNMc+rJDfmYntojat8lljbt1mgKNpTxUZJsSzJ9Y1s= +github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f/go.mod h1:OApqhQ4XNSNC13gXIwDjhOQxjWa/NxkwZXJ1EvqT0ko= +github.com/containerd/cgroups v0.0.0-20200217135630-d732e370d46d/go.mod h1:CStdkl05lBnJej94BPFoJ7vB8cELKXwViS+dgfW0/M8= +github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw= +github.com/containerd/console v0.0.0-20191206165004-02ecf6a7291e/go.mod h1:8Pf4gM6VEbTNRIT26AyyU7hxdQU3MvAvxVI0sc00XBE= +github.com/containerd/console v0.0.0-20191219165238-8375c3424e4d/go.mod h1:8Pf4gM6VEbTNRIT26AyyU7hxdQU3MvAvxVI0sc00XBE= +github.com/containerd/console v1.0.0/go.mod h1:8Pf4gM6VEbTNRIT26AyyU7hxdQU3MvAvxVI0sc00XBE= +github.com/containerd/containerd v1.2.10/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.3.0-beta.2.0.20190828155532-0293cbd26c69/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.3.0/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.3.1-0.20200219222124-986d06785c4a/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.3.2/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.3.3 h1:LoIzb5y9x5l8VKAlyrbusNPXqBY0+kviRloxFUMFwKc= +github.com/containerd/containerd v1.3.3/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.4.0 h1:aWJB3lbDEaOxg1mkTBAINY2a+NsoKbAeRYefJPPRY+o= +github.com/containerd/containerd v1.4.0/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/continuity v0.0.0-20181001140422-bd77b46c8352/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= +github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= +github.com/containerd/continuity v0.0.0-20200107194136-26c1120b8d41 h1:kIFnQBO7rQ0XkMe6xEwbybYHBEaWmh/f++laI6Emt7M= +github.com/containerd/continuity v0.0.0-20200107194136-26c1120b8d41/go.mod h1:Dq467ZllaHgAtVp4p1xUQWBrFXR9s/wyoTpG8zOJGkY= +github.com/containerd/fifo v0.0.0-20190226154929-a9fb20d87448/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI= +github.com/containerd/fifo v0.0.0-20191213151349-ff969a566b00/go.mod h1:jPQ2IAeZRCYxpS/Cm1495vGFww6ecHmMk1YJH2Q5ln0= +github.com/containerd/go-cni v0.0.0-20200107172653-c154a49e2c75/go.mod h1:0mg8r6FCdbxvLDqCXwAx2rO+KA37QICjKL8+wHOG5OE= +github.com/containerd/go-runc v0.0.0-20180907222934-5a6d9f37cfa3/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0= +github.com/containerd/go-runc v0.0.0-20200220073739-7016d3ce2328/go.mod h1:PpyHrqVs8FTi9vpyHwPwiNEGaACDxT/N/pLcvMSRA9g= +github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o= +github.com/containerd/ttrpc v0.0.0-20191028202541-4f1b8fe65a5c/go.mod h1:LPm1u0xBw8r8NOKoOdNMeVHSawSsltak+Ihv+etqsE8= +github.com/containerd/ttrpc v0.0.0-20200121165050-0be804eadb15/go.mod h1:UAxOpgT9ziI0gJrmKvgcZivgxOp8iFPSk8httJEt98Y= +github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc= +github.com/containerd/typeurl v0.0.0-20190911142611-5eb25027c9fd/go.mod h1:GeKYzf2pQcqv7tJ0AoCuuhtnqhva5LNU3U+OyKxxJpk= +github.com/containerd/typeurl v0.0.0-20200205145503-b45ef1f1f737/go.mod h1:TB1hUtrpaiO88KEK56ijojHS1+NeF0izUACaJW2mdXg= +github.com/containernetworking/cni v0.7.1/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY= +github.com/containers/common v0.18.0 h1:pZB6f17N5QV43TcT06gtx1lb0rxd/4StFdVhP9CtgQg= +github.com/containers/common v0.18.0/go.mod h1:H2Wqvx6wkqdzT4RcTCqIG4W0HSOZwUbbNiUTX1+VohU= +github.com/containers/image/v5 v5.5.1 h1:h1FCOXH6Ux9/p/E4rndsQOC4yAdRU0msRTfLVeQ7FDQ= +github.com/containers/image/v5 v5.5.1/go.mod h1:4PyNYR0nwlGq/ybVJD9hWlhmIsNra4Q8uOQX2s6E2uM= +github.com/containers/libtrust v0.0.0-20190913040956-14b96171aa3b h1:Q8ePgVfHDplZ7U33NwHZkrVELsZP5fYj9pM5WBZB2GE= +github.com/containers/libtrust v0.0.0-20190913040956-14b96171aa3b/go.mod h1:9rfv8iPl1ZP7aqh9YA68wnZv2NUDbXdcdPHVz0pFbPY= +github.com/containers/ocicrypt v1.0.2/go.mod h1:nsOhbP19flrX6rE7ieGFvBlr7modwmNjsqWarIUce4M= +github.com/containers/ocicrypt v1.0.3 h1:vYgl+RZ9Q3DPMuTfxmN+qp0X2Bj52uuY2vnt6GzVe1c= +github.com/containers/ocicrypt v1.0.3/go.mod h1:CUBa+8MRNL/VkpxYIpaMtgn1WgXGyvPQj8jcy0EVG6g= +github.com/containers/skopeo v1.1.1-0.20200811214205-ea10e61f7d60 h1:7LKD4qhP/EetNpBd3Btz9pV3vpo39cyak5ODGEmxvzg= +github.com/containers/skopeo v1.1.1-0.20200811214205-ea10e61f7d60/go.mod h1:JXOB7/HVOSVu5ydwFdfKYVxXgxh0kyTMIcw44WAv4tk= +github.com/containers/storage v1.20.2/go.mod h1:oOB9Ie8OVPojvoaKWEGSEtHbXUAs+tSyr7RO7ZGteMc= +github.com/containers/storage v1.21.2/go.mod h1:I1EIAA7B4OwWRSA0b4yq2AW1wjvvfcY0zLWQuwTa4zw= +github.com/containers/storage v1.22.0/go.mod h1:CsuZHF4VyzHP6CZJsn0r0sZP3pc81Me4vUQmlGvMqfU= +github.com/coreos/bbolt v1.3.1-coreos.6/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= +github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= +github.com/coreos/bbolt v1.3.3/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/etcd v3.3.17+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= +github.com/coreos/go-oidc v0.0.0-20180117170138-065b426bd416/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= +github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= +github.com/coreos/go-semver v0.0.0-20180108230905-e214231b295a/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e h1:Wf6HqHfScWJN9/ZjdUKyjop4mf3Qdd+1TvvltAvM3m8= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= +github.com/coreos/go-systemd/v22 v22.1.0 h1:kq/SbG2BCKLkDKkjQf5OWwKWUKj1lgs3lFI4PxnR5lg= +github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= +github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cppforlife/go-patch v0.2.0 h1:Y14MnCQjDlbw7WXT4k+u6DPAA9XnygN4BfrSpI/19RU= +github.com/cppforlife/go-patch v0.2.0/go.mod h1:67a7aIi94FHDZdoeGSJRRFDp66l9MhaAG1yGxpUoFD8= +github.com/cppforlife/go-semi-semantic v0.0.0-20160921010311-576b6af77ae4 h1:J+ghqo7ZubTzelkjo9hntpTtP/9lUCWH9icEmAW+B+Q= +github.com/cppforlife/go-semi-semantic v0.0.0-20160921010311-576b6af77ae4/go.mod h1:socxpf5+mELPbosI149vWpNlHK6mbfWFxSWOoSndXR8= +github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/creack/pty v1.1.7 h1:6pwm8kMQKCmgUg0ZHTm5+/YvRK0s3THD/28+T6/kk4A= +github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +github.com/creack/pty v1.1.9 h1:uDmaGzcdjhF4i/plgjmEsriH11Y0o7RKapEf/LDaM3w= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/cyphar/filepath-securejoin v0.2.2 h1:jCwT2GTP+PY5nBz3c/YL5PAIbusElVrPujOBSCj8xRg= +github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4= +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/daviddengcn/go-colortext v0.0.0-20160507010035-511bcaf42ccd/go.mod h1:dv4zxwHi5C/8AeI+4gX4dCWOIvNi7I6JCSX0HvlKPgE= +github.com/deislabs/oras v0.8.1/go.mod h1:Mx0rMSbBNaNfY9hjpccEnxkOqJL6KGjtxNHPLC4G4As= +github.com/denisenkom/go-mssqldb v0.0.0-20190111225525-2fea367d496d/go.mod h1:xN/JuLBIz4bjkxNmByTiV1IbhfnYb6oo99phBn4Eqhc= +github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= +github.com/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba/go.mod h1:dV8lFg6daOBZbT6/BDGIz6Y3WFGn8juu6G+CQ6LHtl0= +github.com/devigned/tab v0.1.1/go.mod h1:XG9mPq0dFghrYvoBF3xdRrJzSTX1b7IQrvaL9mzjeJY= +github.com/dgrijalva/jwt-go v0.0.0-20160705203006-01aeca54ebda/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgrijalva/jwt-go v0.0.0-20170104182250-a601269ab70c/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgryski/go-gk v0.0.0-20200319235926-a69029f61654/go.mod h1:qm+vckxRlDt0aOla0RYJJVeqHZlWfOm2UIxHaqPB46E= +github.com/dgryski/go-lttb v0.0.0-20180810165845-318fcdf10a77/go.mod h1:Va5MyIzkU0rAM92tn3hb3Anb7oz7KcnixF49+2wOMe4= +github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8= +github.com/djherbis/atime v1.0.0/go.mod h1:5W+KBIuTwVGcqjIfaTwt+KSYX1o6uep8dtevevQP/f8= +github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= +github.com/docker/cli v0.0.0-20191017083524-a8ff7f821017/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/cli v0.0.0-20200130152716-5d0cf8839492/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/cli v0.0.0-20200210162036-a4bedce16568 h1:AbI1uj9w4yt6TvfKHfRu7G55KuQe7NCvWPQRKDoXggE= +github.com/docker/cli v0.0.0-20200210162036-a4bedce16568/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/cli v0.0.0-20200227165822-2298e6a3fe24 h1:bjsfAvm8BVtvQFxV7TYznmKa35J8+fmgrRJWvcS3yJo= +github.com/docker/cli v0.0.0-20200227165822-2298e6a3fe24/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/distribution v0.0.0-20191216044856-a8371794149d/go.mod h1:0+TTO4EOBfRPhZXAeF1Vu+W3hHZ8eLp8PgKVZlcvtFY= +github.com/docker/distribution v0.0.0-20200223014041-6b972e50feee/go.mod h1:xgJxuOjyp98AvnpRTR1+lGOqQ493ylRnRPmewD5GWtc= +github.com/docker/distribution v2.6.0-rc.1.0.20180327202408-83389a148052+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug= +github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v0.0.0-20180531152204-71cd53e4a197/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v1.4.2-0.20180531152204-71cd53e4a197/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v1.4.2-0.20190924003213-a8608b5b67c7/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v1.4.2-0.20191219165747-a9416c67da9f/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v1.4.2-0.20200203170920-46ec8731fbce/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v1.13.1/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v17.12.0-ce-rc1.0.20200618181300-9dc6525e6118+incompatible h1:iWPIG7pWIsCwT6ZtHnTUpoVMnete7O/pzd9HFE3+tn8= +github.com/docker/docker v17.12.0-ce-rc1.0.20200618181300-9dc6525e6118+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker-credential-helpers v0.6.0/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y= +github.com/docker/docker-credential-helpers v0.6.3 h1:zI2p9+1NQYdnG6sMU26EX4aVGlqbInSQxQXLvzJ4RPQ= +github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y= +github.com/docker/go-connections v0.3.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA= +github.com/docker/go-metrics v0.0.0-20180209012529-399ea8c73916/go.mod h1:/u0gXw0Gay3ceNrsHubL3BtdOL2fHf93USgMTe0W5dI= +github.com/docker/go-metrics v0.0.1 h1:AgB/0SvBxihN0X8OR4SjsblXkbMvalQ8cjmtKQ2rQV8= +github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw= +github.com/docker/go-units v0.3.1/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= +github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docker/libcompose v0.4.1-0.20171025083809-57bd716502dc h1:N92ATQRpctiOJCFodOWiyo8fbU/3xghg/FbGjSkoATw= +github.com/docker/libcompose v0.4.1-0.20171025083809-57bd716502dc/go.mod h1:EyqDS+Iyca0hS44T7qIMTeO1EOYWWWNOGpufHu9R8cs= +github.com/docker/libnetwork v0.8.0-dev.2.0.20200226230617-d8334ccdb9be/go.mod h1:93m0aTqz6z+g32wla4l4WxTrdtvBRmVzYRkYvasA5Z8= +github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE= +github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 h1:UhxFibDNY/bfvqU5CAUmr9zpesgbU6SWc8/B4mflAE4= +github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE= +github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96 h1:cenwrSVm+Z7QLSV/BsnenAOcDXdX4cMv4wP0B/5QbPg= +github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= +github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= +github.com/dsnet/compress v0.0.1/go.mod h1:Aw8dCMJ7RioblQeTqt88akK31OvO8Dhf5JflhBbQEHo= +github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY= +github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= +github.com/eapache/go-resiliency v1.2.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= +github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= +github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= +github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e h1:p1yVGRW3nmb85p1Sh1ZJSDm4A4iKLS5QNbvUHMgGu/M= +github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= +github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= +github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg= +github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= +github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0= +github.com/evanphx/json-patch v0.0.0-20190203023257-5858425f7550/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch v0.0.0-20200808040245-162e5629780b/go.mod h1:NAJj0yf/KaRKURN6nyi7A9IZydMivZEm9oQLWNjfKDc= +github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch v4.5.0+incompatible h1:ouOWdg56aJriqS0huScTkVXPC5IcNrDCXZ6OoTAWu7M= +github.com/evanphx/json-patch v4.5.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch v4.9.0+incompatible h1:kLcOMZeuLAJvL2BPWLMIj5oaZQobrkAqrL+WFZwQses= +github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZMPRZwes7CROmyNKgQzC3XPs6L/G2EJLHddWejkmf4= +github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s= +github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= +github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ= +github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= +github.com/fortytw2/leaktest v1.2.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= +github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= +github.com/frankban/quicktest v1.8.1/go.mod h1:ui7WezCLWMWxVWr1GETZY3smRy0G4KWq9vcPtJmFl7Y= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/fsouza/fake-gcs-server v0.0.0-20180612165233-e85be23bdaa8/go.mod h1:1/HufuJ+eaDf4KTnYdS6HJMGvMRU8d4cYTuu/1QaBbI= +github.com/fsouza/fake-gcs-server v1.19.4/go.mod h1:I0/88nHCASqJJ5M7zVF0zKODkYTcuXFW5J5yajsNJnE= +github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa/go.mod h1:KnogPXtdwXqoenmZCw6S+25EAm2MkxbG0deNDu4cbSA= +github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= +github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/ghodss/yaml v0.0.0-20180820084758-c7ce16629ff4/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= +github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= +github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= +github.com/go-bindata/go-bindata/v3 v3.1.3/go.mod h1:1/zrpXsLD8YDIbhZRqXzm1Ghc7NhEvIN9+Z6R5/xH4I= +github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98= +github.com/go-critic/go-critic v0.4.1/go.mod h1:7/14rZGnZbY6E38VEGk2kVhoq6itzc1E68facVDK23g= +github.com/go-critic/go-critic v0.4.3/go.mod h1:j4O3D4RoIwRqlZw5jJpx0BNfXWWbpcJoKu5cYSe4YmQ= +github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4= +github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E= +github.com/go-git/go-billy/v5 v5.0.0 h1:7NQHvd9FVid8VL4qVUMm8XifBK+2xCoZ2lSk0agRrHM= +github.com/go-git/go-billy/v5 v5.0.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= +github.com/go-git/go-git v1.0.0 h1:YcN9iDGDoXuIw0vHls6rINwV416HYa0EB2X+RBsyYp4= +github.com/go-git/go-git v4.7.0+incompatible h1:+W9rgGY4DOKKdX2x6HxSR7HNeTxqiKrOvKnuittYVdA= +github.com/go-git/go-git v4.7.0+incompatible/go.mod h1:6+421e08gnZWn30y26Vchf7efgYLe4dl5OQbBSUXShE= +github.com/go-git/go-git-fixtures/v4 v4.0.1/go.mod h1:m+ICp2rF3jDhFgEZ/8yziagdT1C+ZpZcrJjappBCDSw= +github.com/go-git/go-git/v5 v5.1.0 h1:HxJn9g/E7eYvKW3Fm7Jt4ee8LXfPOm/H1cdDu8vEssk= +github.com/go-git/go-git/v5 v5.1.0/go.mod h1:ZKfuPUoY1ZqIG4QG9BDBh3G4gLM5zvPuSJAozQrZuyM= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= +github.com/go-ini/ini v1.46.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= +github.com/go-ini/ini v1.55.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-lintpack/lintpack v0.5.2/go.mod h1:NwZuYi2nUHho8XEIZ6SIxihrnPoqBTDqfpXvXAN0sXM= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logr/logr v0.1.0 h1:M1Tv3VzNlEHg6uyACnRdtrploV2P7wZqH8BoQMtz0cg= +github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= +github.com/go-logr/logr v0.2.0 h1:QvGt2nLcHH0WK9orKa+ppBPAxREcH364nPUedEpK0TY= +github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= +github.com/go-logr/zapr v0.1.0/go.mod h1:tabnROwaDl0UNxkVeFRbY8bwB37GwRv0P8lg6aAiEnk= +github.com/go-logr/zapr v0.1.1/go.mod h1:tabnROwaDl0UNxkVeFRbY8bwB37GwRv0P8lg6aAiEnk= +github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8= +github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI= +github.com/go-openapi/analysis v0.17.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= +github.com/go-openapi/analysis v0.17.2/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= +github.com/go-openapi/analysis v0.18.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= +github.com/go-openapi/analysis v0.19.2/go.mod h1:3P1osvZa9jKjb8ed2TPng3f0i/UY9snX6gxi44djMjk= +github.com/go-openapi/analysis v0.19.5/go.mod h1:hkEAkxagaIvIP7VTn8ygJNkd4kAYON2rCu0v0ObL0AU= +github.com/go-openapi/errors v0.17.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= +github.com/go-openapi/errors v0.17.2/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= +github.com/go-openapi/errors v0.18.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= +github.com/go-openapi/errors v0.19.2/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94= +github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= +github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= +github.com/go-openapi/jsonpointer v0.18.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= +github.com/go-openapi/jsonpointer v0.19.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= +github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= +github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= +github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= +github.com/go-openapi/jsonreference v0.18.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= +github.com/go-openapi/jsonreference v0.19.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= +github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= +github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= +github.com/go-openapi/loads v0.17.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= +github.com/go-openapi/loads v0.17.2/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= +github.com/go-openapi/loads v0.18.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= +github.com/go-openapi/loads v0.19.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= +github.com/go-openapi/loads v0.19.2/go.mod h1:QAskZPMX5V0C2gvfkGZzJlINuP7Hx/4+ix5jWFxsNPs= +github.com/go-openapi/loads v0.19.4/go.mod h1:zZVHonKd8DXyxyw4yfnVjPzBjIQcLt0CCsn0N0ZrQsk= +github.com/go-openapi/runtime v0.0.0-20180920151709-4f900dc2ade9/go.mod h1:6v9a6LTXWQCdL8k1AO3cvqx5OtZY/Y9wKTgaoP6YRfA= +github.com/go-openapi/runtime v0.17.2/go.mod h1:QO936ZXeisByFmZEO1IS1Dqhtf4QV1sYYFtIq6Ld86Q= +github.com/go-openapi/runtime v0.19.0/go.mod h1:OwNfisksmmaZse4+gpV3Ne9AyMOlP1lt4sK4FXt0O64= +github.com/go-openapi/runtime v0.19.4/go.mod h1:X277bwSUBxVlCYR3r7xgZZGKVvBd/29gLDlFGtJ8NL4= +github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= +github.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= +github.com/go-openapi/spec v0.17.2/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= +github.com/go-openapi/spec v0.18.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= +github.com/go-openapi/spec v0.19.2/go.mod h1:sCxk3jxKgioEJikev4fgkNmwS+3kuYdJtcsZsD5zxMY= +github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= +github.com/go-openapi/spec v0.19.4/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= +github.com/go-openapi/spec v0.19.6/go.mod h1:Hm2Jr4jv8G1ciIAo+frC/Ft+rR2kQDh8JHKHb3gWUSk= +github.com/go-openapi/strfmt v0.17.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= +github.com/go-openapi/strfmt v0.18.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= +github.com/go-openapi/strfmt v0.19.0/go.mod h1:+uW+93UVvGGq2qGaZxdDeJqSAqBqBdl+ZPMF/cC8nDY= +github.com/go-openapi/strfmt v0.19.3/go.mod h1:0yX7dbo8mKIvc3XSKp7MNfxw4JytCfCD6+bY1AVL9LU= +github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= +github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= +github.com/go-openapi/swag v0.17.2/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= +github.com/go-openapi/swag v0.18.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= +github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.7/go.mod h1:ao+8BpOPyKdpQz3AOJfbeEVpLmWAvlT1IfTe5McPyhY= +github.com/go-openapi/validate v0.17.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4= +github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4= +github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2KDnRCRMUi7GTA= +github.com/go-openapi/validate v0.19.5/go.mod h1:8DJv2CVJQ6kGNpFW6eV9N3JviE1C85nY1c2z52x1Gk4= +github.com/go-sql-driver/mysql v0.0.0-20160411075031-7ebe0a500653/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.0.4/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= +github.com/go-toolsmith/astcast v1.0.0/go.mod h1:mt2OdQTeAQcY4DQgPSArJjHCcOwlX+Wl/kwN+LbLGQ4= +github.com/go-toolsmith/astcopy v1.0.0/go.mod h1:vrgyG+5Bxrnz4MZWPF+pI4R8h3qKRjjyvV/DSez4WVQ= +github.com/go-toolsmith/astequal v0.0.0-20180903214952-dcb477bfacd6/go.mod h1:H+xSiq0+LtiDC11+h1G32h7Of5O3CYFJ99GVbS5lDKY= +github.com/go-toolsmith/astequal v1.0.0/go.mod h1:H+xSiq0+LtiDC11+h1G32h7Of5O3CYFJ99GVbS5lDKY= +github.com/go-toolsmith/astfmt v0.0.0-20180903215011-8f8ee99c3086/go.mod h1:mP93XdblcopXwlyN4X4uodxXQhldPGZbcEJIimQHrkg= +github.com/go-toolsmith/astfmt v1.0.0/go.mod h1:cnWmsOAuq4jJY6Ct5YWlVLmcmLMn1JUPuQIHCY7CJDw= +github.com/go-toolsmith/astinfo v0.0.0-20180906194353-9809ff7efb21/go.mod h1:dDStQCHtmZpYOmjRP/8gHHnCCch3Zz3oEgCdZVdtweU= +github.com/go-toolsmith/astp v0.0.0-20180903215135-0af7e3c24f30/go.mod h1:SV2ur98SGypH1UjcPpCatrV5hPazG6+IfNHbkDXBRrk= +github.com/go-toolsmith/astp v1.0.0/go.mod h1:RSyrtpVlfTFGDYRbrjyWP1pYu//tSFcvdYrA8meBmLI= +github.com/go-toolsmith/pkgload v0.0.0-20181119091011-e9e65178eee8/go.mod h1:WoMrjiy4zvdS+Bg6z9jZH82QXwkcgCBX6nOfnmdaHks= +github.com/go-toolsmith/pkgload v1.0.0/go.mod h1:5eFArkbO80v7Z0kdngIxsRXRMTaX4Ilcwuh3clNrQJc= +github.com/go-toolsmith/strparse v1.0.0/go.mod h1:YI2nUKP9YGZnL/L1/DLFBfixrcjslWct4wyljWhSRy8= +github.com/go-toolsmith/typep v1.0.0/go.mod h1:JSQCQMUPdRlMZFswiq3TGpNp1GMktqkR2Ns5AIQkATU= +github.com/go-toolsmith/typep v1.0.2/go.mod h1:JSQCQMUPdRlMZFswiq3TGpNp1GMktqkR2Ns5AIQkATU= +github.com/go-xmlfmt/xmlfmt v0.0.0-20191208150333-d5b6f63a941b/go.mod h1:aUCEOzzezBEjDBbFBoSiya/gduyIiWYRP6CnSFIV8AM= +github.com/go-yaml/yaml v2.1.0+incompatible/go.mod h1:w2MrLa16VYP0jy6N7M5kHaCkaLENm+P+Tv+MfurjSw0= +github.com/gobuffalo/envy v1.6.5/go.mod h1:N+GkhhZ/93bGZc6ZKhJLP6+m+tCNPKwgSpH9kaifseQ= +github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= +github.com/gobuffalo/envy v1.7.1/go.mod h1:FurDp9+EDPE4aIUS3ZLyD+7/9fpx7YRt/ukY6jIHf0w= +github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= +github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e h1:BWhy2j3IXJhjCbC68FptL43tDKIq8FladmaTs3Xs7Z8= +github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= +github.com/godbus/dbus/v5 v5.0.3 h1:ZqHaoEF7TBzh4jzPmqVhE/5A1z9of6orkAe5uHoAeME= +github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gofrs/flock v0.0.0-20190320160742-5135e617513b/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= +github.com/gofrs/flock v0.7.0/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= +github.com/gofrs/flock v0.7.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= +github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= +github.com/gogo/googleapis v1.3.2/go.mod h1:5YRNX2z1oM5gXdAkurHa942MDgEJyk02w4OecKY87+c= +github.com/gogo/protobuf v0.0.0-20171007142547-342cbe0a0415/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.0.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.2.2-0.20190730201129-28a6bbf47e48/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls= +github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= +github.com/golang/gddo v0.0.0-20190419222130-af0f2af80721/go.mod h1:xEhNfoBDX1hzLm2Nf80qUvZ2sVwoMZ8d6IE2SrsQfh4= +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/groupcache v0.0.0-20180513044358-24b0969c4cb7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191027212112-611e8accdfc9/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= +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/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +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/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golangci/check v0.0.0-20180506172741-cfe4005ccda2/go.mod h1:k9Qvh+8juN+UKMCS/3jFtGICgW8O96FVaZsaxdzDkR4= +github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a/go.mod h1:ryS0uhF+x9jgbj/N71xsEqODy9BN81/GonCZiOzirOk= +github.com/golangci/errcheck v0.0.0-20181223084120-ef45e06d44b6/go.mod h1:DbHgvLiFKX1Sh2T1w8Q/h4NAI8MHIpzCdnBUDTXU3I0= +github.com/golangci/go-misc v0.0.0-20180628070357-927a3d87b613/go.mod h1:SyvUF2NxV+sN8upjjeVYr5W7tyxaT1JVtvhKhOn2ii8= +github.com/golangci/goconst v0.0.0-20180610141641-041c5f2b40f3/go.mod h1:JXrF4TWy4tXYn62/9x8Wm/K/dm06p8tCKwFRDPZG/1o= +github.com/golangci/gocyclo v0.0.0-20180528134321-2becd97e67ee/go.mod h1:ozx7R9SIwqmqf5pRP90DhR2Oay2UIjGuKheCBCNwAYU= +github.com/golangci/gocyclo v0.0.0-20180528144436-0a533e8fa43d/go.mod h1:ozx7R9SIwqmqf5pRP90DhR2Oay2UIjGuKheCBCNwAYU= +github.com/golangci/gofmt v0.0.0-20190930125516-244bba706f1a/go.mod h1:9qCChq59u/eW8im404Q2WWTrnBUQKjpNYKMbU4M7EFU= +github.com/golangci/golangci-lint v1.23.7/go.mod h1:g/38bxfhp4rI7zeWSxcdIeHTQGS58TCak8FYcyCmavQ= +github.com/golangci/golangci-lint v1.27.0/go.mod h1:+eZALfxIuthdrHPtfM7w/R3POJLjHDfJJw8XZl9xOng= +github.com/golangci/ineffassign v0.0.0-20190609212857-42439a7714cc/go.mod h1:e5tpTHCfVze+7EpLEozzMB3eafxo2KT5veNg1k6byQU= +github.com/golangci/lint-1 v0.0.0-20191013205115-297bf364a8e0/go.mod h1:66R6K6P6VWk9I95jvqGxkqJxVWGFy9XlDwLwVz1RCFg= +github.com/golangci/maligned v0.0.0-20180506175553-b1d89398deca/go.mod h1:tvlJhZqDe4LMs4ZHD0oMUlt9G2LWuDGoisJTBzLMV9o= +github.com/golangci/misspell v0.0.0-20180809174111-950f5d19e770/go.mod h1:dEbvlSfYbMQDtrpRMQU675gSDLDNa8sCPPChZ7PhiVA= +github.com/golangci/misspell v0.3.5/go.mod h1:dEbvlSfYbMQDtrpRMQU675gSDLDNa8sCPPChZ7PhiVA= +github.com/golangci/prealloc v0.0.0-20180630174525-215b22d4de21/go.mod h1:tf5+bzsHdTM0bsB7+8mt0GUMvjCgwLpTapNZHU8AajI= +github.com/golangci/revgrep v0.0.0-20180526074752-d9c87f5ffaf0/go.mod h1:qOQCunEYvmd/TLamH+7LlVccLvUH5kZNhbCgTHoBbp4= +github.com/golangci/revgrep v0.0.0-20180812185044-276a5c0a1039/go.mod h1:qOQCunEYvmd/TLamH+7LlVccLvUH5kZNhbCgTHoBbp4= +github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4/go.mod h1:Izgrg8RkN3rCIMLGE9CyYmU9pY2Jer6DgANEnZ/L/cQ= +github.com/golangplus/bytes v0.0.0-20160111154220-45c989fe5450/go.mod h1:Bk6SMAONeMXrxql8uvOKuAZSu8aM5RUGv+1C6IJaEho= +github.com/golangplus/fmt v0.0.0-20150411045040-2a5d6d7d2995/go.mod h1:lJgMEyOkYFkPcDKwRXegd+iM6E7matEszMG5HhwytU8= +github.com/golangplus/testing v0.0.0-20180327235837-af21d9c3145e/go.mod h1:0AA//k/eakGydO4jKRoRL2j92ZKSzTgj9tclaCrvXHk= +github.com/gomodule/redigo v1.7.0/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= +github.com/google/btree v0.0.0-20160524151835-7d79101e329e/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v0.0.0-20180124185431-e89373fe6b4a/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/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/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.4.1 h1:/exdXoGamhu5ONeUJH0deniYLWYvQwW66yvlfiiKTu0= +github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-containerregistry v0.0.0-20191010200024-a3d713f9b7f8/go.mod h1:KyKXa9ciM8+lgMXwOVsXi7UxGrsf9mM61Mzs+xKUrKE= +github.com/google/go-containerregistry v0.0.0-20200115214256-379933c9c22b/go.mod h1:Wtl/v6YdQxv397EREtzwgd9+Ud7Q5D8XMbi3Zazgkrs= +github.com/google/go-containerregistry v0.0.0-20200123184029-53ce695e4179/go.mod h1:Wtl/v6YdQxv397EREtzwgd9+Ud7Q5D8XMbi3Zazgkrs= +github.com/google/go-containerregistry v0.0.0-20200331213917-3d03ed9b1ca2 h1:k2YJ1fw6LwICNNUQHZNp9vTtHMuVqHJtMjZOc5SDIJo= +github.com/google/go-containerregistry v0.0.0-20200331213917-3d03ed9b1ca2/go.mod h1:pD1UFYs7MCAx+ZLShBdttcaOSbyc8F9Na/9IZLNwJeA= +github.com/google/go-containerregistry v0.1.1 h1:AG8FSAfXglim2l5qSrqp5VK2Xl03PiBf25NiTGGamws= +github.com/google/go-containerregistry v0.1.1/go.mod h1:npTSyywOeILcgWqd+rvtzGWflIPPcBQhYoOONaY4ltM= +github.com/google/go-containerregistry v0.1.2 h1:YjFNKqxzWUVZND8d4ItF9wuYlE75WQfECE7yKX/Nu3o= +github.com/google/go-containerregistry v0.1.2/go.mod h1:GPivBPgdAyd2SU+vf6EpsgOtWDuPqjW0hJZt4rNdTZ4= +github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= +github.com/google/go-github/v27 v27.0.6/go.mod h1:/0Gr8pJ55COkmv+S/yPKCczSkUPIM/LnFyubufRNIS0= +github.com/google/go-github/v28 v28.1.1/go.mod h1:bsqJWQX05omyWVmc00nEUql9mhQyv38lDZ8kPZcQVoM= +github.com/google/go-github/v29 v29.0.3/go.mod h1:CHKiKKPHJ0REzfwc14QMklvtHwCveD0PxlMjLlzAM5E= +github.com/google/go-licenses v0.0.0-20191112164736-212ea350c932/go.mod h1:16wa6pRqNDUIhOtwF0GcROVqMeXHZJ7H6eGDFUh5Pfk= +github.com/google/go-licenses v0.0.0-20200227160636-0fa8c766a591/go.mod h1:JWeTIGPLQ9gF618ZOdlUitd1gRR/l99WOkHOlmR/UVA= +github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk= +github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= +github.com/google/go-replayers/grpcreplay v0.1.0/go.mod h1:8Ig2Idjpr6gifRd6pNVggX6TC1Zw6Jx74AKp7QNH2QE= +github.com/google/go-replayers/httpreplay v0.1.0/go.mod h1:YKZViNhiGgqdBlUbI2MwGpq4pXxNmhJLPHQ7cv2b5no= +github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= +github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= +github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/licenseclassifier v0.0.0-20190926221455-842c0d70d702/go.mod h1:qsqn2hxC+vURpyBRygGUuinTO42MFRLcsmQ/P8v94+M= +github.com/google/licenseclassifier v0.0.0-20200402202327-879cb1424de0/go.mod h1:qsqn2hxC+vURpyBRygGUuinTO42MFRLcsmQ/P8v94+M= +github.com/google/licenseclassifier v0.0.0-20200708223521-3d09a0ea2f39/go.mod h1:qsqn2hxC+vURpyBRygGUuinTO42MFRLcsmQ/P8v94+M= +github.com/google/mako v0.0.0-20190821191249-122f8dcef9e3/go.mod h1:YzLcVlL+NqWnmUEPuhS1LxDDwGO9WNbVlEXaF4IH35g= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian v2.1.1-0.20190517191504-25dcb96d9e51+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190723021845-34ac40c74b70/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200507031123-427632fa3b1c/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/rpmpack v0.0.0-20191226140753-aa36bfddb3a0/go.mod h1:RaTPr0KUf2K7fnZYLNDrr8rxAamWs3iNywJLtQ2AzBg= +github.com/google/shlex v0.0.0-20150127133951-6f45313302b9/go.mod h1:RpwtwJQFrIEPstU94h88MWPXP2ektJZ8cZ0YntAmXiE= +github.com/google/subcommands v1.0.1/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= +github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/wire v0.3.0/go.mod h1:i1DMg/Lu8Sz5yYl25iOdmc5CT5qusaa+zmRWs16741s= +github.com/google/wire v0.4.0/go.mod h1:ngWDr9Qvq3yZA10YrxfyGELY/AFWGVpy9c1LTRi1EoU= +github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= +github.com/googleapis/gax-go v2.0.2+incompatible h1:silFMLAnr330+NRuag/VjIGF7TLp/LBrV2CJKFLWEww= +github.com/googleapis/gax-go v2.0.2+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+Tv3SM= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= +github.com/googleapis/gnostic v0.1.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= +github.com/googleapis/gnostic v0.2.2/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= +github.com/googleapis/gnostic v0.3.1/go.mod h1:on+2t9HRStVgn95RSsFWFz+6Q0Snyqv1awfrALZdbtU= +github.com/googleapis/gnostic v0.4.0 h1:BXDUo8p/DaxC+4FJY/SSx3gvnx9C1VdHNgaUkiEL5mk= +github.com/googleapis/gnostic v0.4.0/go.mod h1:on+2t9HRStVgn95RSsFWFz+6Q0Snyqv1awfrALZdbtU= +github.com/googleapis/gnostic v0.4.1 h1:DLJCy1n/vrD4HPjOvYcT8aYQXpPIzoRZONaYwyycI+I= +github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= +github.com/gookit/color v1.2.4/go.mod h1:AhIE+pS6D4Ql0SQWbBeXPHw7gY0/sjHoA4s/n1KB7xg= +github.com/gophercloud/gophercloud v0.0.0-20190126172459-c818fa66e4c8/go.mod h1:3WdhXV3rUYy9p6AUW8d94kr+HS62Y4VL9mBnFxsD8q4= +github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/goreleaser/goreleaser v0.136.0/go.mod h1:wiKrPUeSNh6Wu8nUHxZydSOVQ/OZvOaO7DTtFqie904= +github.com/goreleaser/nfpm v1.2.1/go.mod h1:TtWrABZozuLOttX2uDlYyECfQX7x5XYkVxhjYcR6G9w= +github.com/goreleaser/nfpm v1.3.0/go.mod h1:w0p7Kc9TAUgWMyrub63ex3M2Mgw88M4GZXoTq5UCb40= +github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= +github.com/gorilla/csrf v1.6.2/go.mod h1:7tSf8kmjNYr7IWDCYhd3U8Ck34iQ/Yw5CJu7bAkHEGI= +github.com/gorilla/handlers v0.0.0-20150720190736-60c7bfde3e33/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= +github.com/gorilla/handlers v1.4.2/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= +github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.7.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.7.4 h1:VuZ8uybHlWmqV03+zRzdwKL4tUnIp1MAQtp1mIFE1bc= +github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= +github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= +github.com/gorilla/sessions v1.1.3/go.mod h1:8KCfur6+4Mqcc6S0FEfKuN15Vl5MgXW92AE8ovaJD0w= +github.com/gorilla/sessions v1.2.0/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= +github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gostaticanalysis/analysisutil v0.0.0-20190318220348-4088753ea4d3/go.mod h1:eEOZF4jCKGi+aprrirO9e7WKB3beBRtWgqGunKl6pKE= +github.com/gostaticanalysis/analysisutil v0.0.3/go.mod h1:eEOZF4jCKGi+aprrirO9e7WKB3beBRtWgqGunKl6pKE= +github.com/gosuri/uitable v0.0.4/go.mod h1:tKR86bXuXPZazfOTG1FIzvjIdXzd0mo4Vtn16vt0PJo= +github.com/gotestyourself/gotestyourself v2.2.0+incompatible/go.mod h1:zZKM6oeNM8k+FRljX1mnzVYeS8wiGgQyvST1/GafPbY= +github.com/gregjones/httpcache v0.0.0-20170728041850-787624de3eb7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/gregjones/httpcache v0.0.0-20190212212710-3befbb6ad0cc/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/grpc-ecosystem/go-grpc-middleware v0.0.0-20190222133341-cfaf5686ec79/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-prometheus v0.0.0-20170330212424-2500245aa611/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.3.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= +github.com/grpc-ecosystem/grpc-gateway v1.4.1/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= +github.com/grpc-ecosystem/grpc-gateway v1.8.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.9.2/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.9.4/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.12.1/go.mod h1:8XEsbTttt/W+VvjtQhLACqCisSPWTxCZ7sBRjU6iH9c= +github.com/grpc-ecosystem/grpc-gateway v1.12.2 h1:D0EVSTwQoQOyfY35QNSuPJA4jpZRtkoGYWQMB7XNg5o= +github.com/grpc-ecosystem/grpc-gateway v1.12.2/go.mod h1:8XEsbTttt/W+VvjtQhLACqCisSPWTxCZ7sBRjU6iH9c= +github.com/grpc-ecosystem/grpc-gateway v1.14.6 h1:8ERzHx8aj1Sc47mu9n/AksaKCSWrMchFtkdrS4BIj5o= +github.com/grpc-ecosystem/grpc-gateway v1.14.6/go.mod h1:zdiPV4Yse/1gnckTHtghG4GkDEdKCRJduHpTxT3/jcw= +github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645/go.mod h1:6iZfnjpejD4L/4DwD7NryNaJyCQdzwWwH2MWhCA90Kw= +github.com/h2non/gock v1.0.9/go.mod h1:CZMcB0Lg5IWnr9bF79pPMg9WeV6WumxQiUJ1UvdO1iE= +github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= +github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-multierror v0.0.0-20161216184304-ed905158d874/go.mod h1:JMRHfdO9jKNzS/+BTlxCjKNQHg/jZAft8U7LloJvN7I= +github.com/hashicorp/go-multierror v0.0.0-20171204182908-b7773ae21874/go.mod h1:JMRHfdO9jKNzS/+BTlxCjKNQHg/jZAft8U7LloJvN7I= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.0 h1:B9UzwGQJehnUY1yNrnwREHc3fGbC2xefo8g4TbElacI= +github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= +github.com/hashicorp/go-retryablehttp v0.6.4/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= +github.com/hashicorp/go-retryablehttp v0.6.6/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= +github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= +github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= +github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= +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/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= +github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= +github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= +github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= +github.com/hashicorp/uuid v0.0.0-20160311170451-ebb0a03e909c/go.mod h1:fHzc09UnyJyqyW+bFuq864eh+wC7dj65aXmXLRe5to0= +github.com/hinshun/vt10x v0.0.0-20180616224451-1954e6464174 h1:WlZsjVhE8Af9IcZDGgJGQpNflI3+MJSBhsgT5PCtzBQ= +github.com/hinshun/vt10x v0.0.0-20180616224451-1954e6464174/go.mod h1:DqJ97dSdRW1W22yXSB90986pcOyQ7r45iio1KN2ez1A= +github.com/howeyc/gopass v0.0.0-20170109162249-bf9dde6d0d2c/go.mod h1:lADxMC39cJJqL93Duh1xhAs4I2Zs8mKS89XWXFGp9cs= +github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/huandu/xstrings v1.2.0/go.mod h1:DvyZB1rfVYsBIigL8HwpZgxHwXozlTgGqn63UyNX5k4= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.7/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.9 h1:UauaLniWCFHWd+Jp9oCEkTBj8VO/9DKg3PV3VCNMDIg= +github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/influxdata/influxdb v0.0.0-20161215172503-049f9b42e9a5/go.mod h1:qZna6X/4elxqT3yI9iZYdZrWWdeFOOprn86kgg4+IzY= +github.com/influxdata/tdigest v0.0.0-20181121200506-bf2b5ad3c0a9/go.mod h1:Js0mqiSBE6Ffsg94weZZ2c+v/ciT8QRHFOap7EKDrR0= +github.com/influxdata/tdigest v0.0.1/go.mod h1:Z0kXnxzbTC2qrx4NaIzYkE1k66+6oEDQTvL95hQFh5Y= +github.com/ishidawataru/sctp v0.0.0-20191218070446-00ab2ac2db07/go.mod h1:co9pwDoBCm1kGxawmb4sPq0cSIOOWNPT4KnHotMP1Zg= +github.com/jaguilar/vt100 v0.0.0-20150826170717-2703a27b14ea/go.mod h1:QMdK4dGB3YhEW2BmA1wgGpPYI3HZy/5gD705PXKUVSg= +github.com/jarcoal/httpmock v1.0.5/go.mod h1:ATjnClrvW/3tijVmpL/va5Z3aAyGvqU3gCT8nX0Txik= +github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= +github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= +github.com/jcmturner/gofork v0.0.0-20190328161633-dc7c13fece03/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o= +github.com/jcmturner/gofork v1.0.0/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o= +github.com/jenkins-x/go-scm v1.5.65/go.mod h1:MgGRkJScE/rJ30J/bXYqduN5sDPZqZFITJopsnZmTOw= +github.com/jenkins-x/go-scm v1.5.79/go.mod h1:PCT338UhP/pQ0IeEeMEf/hoLTYKcH7qjGEKd7jPkeYg= +github.com/jenkins-x/go-scm v1.5.117/go.mod h1:PCT338UhP/pQ0IeEeMEf/hoLTYKcH7qjGEKd7jPkeYg= +github.com/jessevdk/go-flags v0.0.0-20170926144705-f88afde2fa19/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jessevdk/go-flags v1.4.0 h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGARJA= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jingyugao/rowserrcheck v0.0.0-20191204022205-72ab7603b68a/go.mod h1:xRskid8CManxVta/ALEhJha/pweKBaVG6fWgc0yH25s= +github.com/jinzhu/gorm v0.0.0-20170316141641-572d0a0ab1eb/go.mod h1:Vla75njaFJ8clLU1W44h34PjIkijhjHIYnZxMqCdxqo= +github.com/jinzhu/gorm v1.9.12/go.mod h1:vhTjlKSJUTWNtcbQtrMBFCxy7eXTzeCAzfL5fBZT/Qs= +github.com/jinzhu/inflection v0.0.0-20190603042836-f5c5f50e6090/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= +github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= +github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/jinzhu/now v1.1.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/jirfag/go-printf-func-name v0.0.0-20191110105641-45db9963cdd3/go.mod h1:HEWGJkRDzjJY2sqdDwxccsGicWEf9BQOZsq2tV+xzM0= +github.com/jirfag/go-printf-func-name v0.0.0-20200119135958-7558a9eaa5af/go.mod h1:HEWGJkRDzjJY2sqdDwxccsGicWEf9BQOZsq2tV+xzM0= +github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jmespath/go-jmespath v0.0.0-20160803190731-bd40a432e4c7/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jmespath/go-jmespath v0.3.0 h1:OS12ieG61fsCg5+qLJ+SsW9NicxNkg3b25OyT2yCeUc= +github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik= +github.com/jmoiron/sqlx v1.2.1-0.20190826204134-d7d95172beb5/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks= +github.com/joefitzgerald/rainbow-reporter v0.1.0/go.mod h1:481CNgqmVHQZzdIbN52CupLJyoVwB10FQ/IQlF1pdL8= +github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= +github.com/jonboulle/clockwork v0.0.0-20141017032234-72f9bd7c4e0c/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/jpillora/backoff v0.0.0-20180909062703-3050d21c67d7 h1:K//n/AqR5HjG3qxbrBCL4vJPW0MVFSs9CPK1OOJdRME= +github.com/jpillora/backoff v0.0.0-20180909062703-3050d21c67d7/go.mod h1:2iMrUgbbvHEiQClaW2NsSzMyGHqN+rDFqY705q49KG0= +github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v0.0.0-20180701071628-ab8a2e0c74be/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1 h1:6QPYqodiu3GuPL+7mfx+NwDdp2eTkp9IfEUpgAwUN0o= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= +github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= +github.com/kelseyhightower/envconfig v1.3.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg= +github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8= +github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg= +github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd h1:Coekwdh0v2wtGp9Gmz1Ze3eVRAWJMLokvN3QjdzCHLY= +github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +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/klauspost/compress v1.4.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/klauspost/compress v1.9.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/klauspost/compress v1.10.2/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= +github.com/klauspost/compress v1.10.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= +github.com/klauspost/compress v1.10.8/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= +github.com/klauspost/compress v1.10.10 h1:a/y8CglcM7gLGYmlbP/stPE5sR3hbhFRUjCBfd/0B3I= +github.com/klauspost/compress v1.10.10/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= +github.com/klauspost/cpuid v0.0.0-20180405133222-e7e905edc00e/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= +github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= +github.com/klauspost/cpuid v1.2.2/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= +github.com/klauspost/pgzip v1.2.1/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= +github.com/klauspost/pgzip v1.2.4 h1:TQ7CNpYKovDOmqzRHKxJh0BeaBI7UdQZYc6p7pMQh1A= +github.com/klauspost/pgzip v1.2.4/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= +github.com/knative/build v0.1.2/go.mod h1:/sU74ZQkwlYA5FwYDJhYTy61i/Kn+5eWfln2jDbw3Qo= +github.com/konsorten/go-windows-terminal-sequences v0.0.0-20180402223658-b729f2633dfe/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJKvHsGVBgn1xWYf1NbHQhywc8= +github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pty v1.0.0/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.4/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= +github.com/kr/pty v1.1.8 h1:AkaSdXYQOWeaO3neb8EM634ahkXXe3jYbVh/F9lq+GI= +github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= +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/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE= +github.com/lightstep/tracecontext.go v0.0.0-20181129014701-1757c391b1ac h1:+2b6iGRJe3hvV/yVXrd41yVEjxuFHxasJqDhkIjS4gk= +github.com/lightstep/tracecontext.go v0.0.0-20181129014701-1757c391b1ac/go.mod h1:Frd2bnT3w5FB5q49ENTfVlztJES+1k/7lyWX2+9gq/M= +github.com/lithammer/dedent v1.1.0/go.mod h1:jrXYCQtgg0nJiN+StA2KgR7w6CiQNv9Fd/Z9BP0jIOc= +github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= +github.com/lunixbochs/vtclean v1.0.0 h1:xu2sLAri4lGiovBDQKxl5mrXyESr3gUr5m5SM5+LVb8= +github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= +github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= +github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= +github.com/mailru/easyjson v0.7.1-0.20191009090205-6c0755d89d1e h1:jcoUdG1TzY/M/eM5BLFLP8DJeMximx5NQYSlLL9YeWc= +github.com/mailru/easyjson v0.7.1-0.20191009090205-6c0755d89d1e/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= +github.com/maratori/testpackage v1.0.1/go.mod h1:ddKdw+XG0Phzhx8BFDTKgpWP4i7MpApTE5fXSKAqwDU= +github.com/markbates/inflect v1.0.4/go.mod h1:1fR9+pO2KHEO9ZRtto13gDwwZaAKstQzferVeWqbgNs= +github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho= +github.com/matoous/godox v0.0.0-20190911065817-5d6d842e92eb/go.mod h1:1BELzlh859Sh1c6+90blK8lbYy0kwQf1bYlBhBysy1s= +github.com/mattbaird/jsonpatch v0.0.0-20171005235357-81af80346b1a/go.mod h1:M1qoD/MqPgTZIk0EWKB38wE28ACRfVcn+cU08jyArI0= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= +github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA= +github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-colorable v0.1.6 h1:6Su7aK7lXmJ/U79bYtBjLNaha4Fs1Rg9plHpcH+vvnE= +github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-ieproxy v0.0.0-20190610004146-91bb50d98149/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc= +github.com/mattn/go-ieproxy v0.0.0-20190702010315-6dee0af9227d/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc= +github.com/mattn/go-ieproxy v0.0.1/go.mod h1:pYabZ6IHcRpFh7vIaLfK7rdcWgFEb3SFJ6/gNWuh88E= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= +github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-runewidth v0.0.8/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= +github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= +github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= +github.com/mattn/go-shellwords v1.0.9/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y= +github.com/mattn/go-shellwords v1.0.10 h1:Y7Xqm8piKOO3v10Thp7Z36h4FYFjt5xB//6XvOrs2Gw= +github.com/mattn/go-shellwords v1.0.10/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y= +github.com/mattn/go-sqlite3 v0.0.0-20160514122348-38ee283dabf1/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= +github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= +github.com/mattn/go-sqlite3 v2.0.1+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= +github.com/mattn/go-zglob v0.0.1/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo= +github.com/mattn/go-zglob v0.0.2/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo= +github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw= +github.com/matttproud/golang_protobuf_extensions v1.0.0/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY= +github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4= +github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= +github.com/mholt/archiver/v3 v3.3.0/go.mod h1:YnQtqsp+94Rwd0D/rk5cnLrxusUBUXg+08Ebtr1Mqao= +github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/miekg/dns v1.1.29/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= +github.com/mistifyio/go-zfs v2.1.1+incompatible h1:gAMO1HM9xBRONLHHYnu5iFsOJUiJdNZo6oqSENd4eW8= +github.com/mistifyio/go-zfs v2.1.1+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= +github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-ps v0.0.0-20190716172923-621e5597135b/go.mod h1:r1VsdOzOPt1ZSrGZWFoNhsAedKnEd6r9Np1+5blZCWk= +github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= +github.com/mitchellh/hashstructure v0.0.0-20170609045927-2bca23e0e452/go.mod h1:QjSHrPWS+BGUVBYkbTZWEnOh3G1DutKwClXU/ABz6AQ= +github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= +github.com/mitchellh/ioprogress v0.0.0-20180201004757-6a23b12fa88e/go.mod h1:waEya8ee1Ro/lgxpVhkJI4BVASzkm3UZqkx/cFJiYHM= +github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.3.1 h1:cCBH2gTD2K0OtLlv/Y5H01VQCqmlDxz30kS5Y5bqfLA= +github.com/mitchellh/mapstructure v1.3.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f/go.mod h1:OkQIRizQZAeMln+1tSwduZz7+Af5oFlKirV/MSYes2A= +github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/moby/buildkit v0.7.2 h1:wp4R0QMXSqwjTJKhhWlJNOCSQ/OVPnsCf3N8rs09+vQ= +github.com/moby/buildkit v0.7.2/go.mod h1:D3DN/Nl4DyMH1LkwpRUJuoghqdigdXd1A6HXt5aZS40= +github.com/moby/moby v1.13.1 h1:mC5WwQwCXt/dYxZ1cIrRsnJAWw7VdtcTZUIGr4tXzOM= +github.com/moby/moby v1.13.1/go.mod h1:fDXVQ6+S340veQPv35CzDahGBmHsiclFwfEygB/TWMc= +github.com/moby/sys/mountinfo v0.1.3/go.mod h1:w2t2Avltqx8vE7gX5l+QiBKxODu2TX0+Syr3h52Tw4o= +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/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= +github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/mozilla/tls-observatory v0.0.0-20190404164649-a3c1b6cfecfd/go.mod h1:SrKMQvPiws7F7iqYp8/TX+IhxCYhzr6N/1yb8cwHsGk= +github.com/mozilla/tls-observatory v0.0.0-20200317151703-4fa42e1c2dee/go.mod h1:SrKMQvPiws7F7iqYp8/TX+IhxCYhzr6N/1yb8cwHsGk= +github.com/mrunalp/fileutils v0.0.0-20171103030105-7d4729fb3618/go.mod h1:x8F1gnqOkIEiO4rqoeEEEqQbo7HjGMTvyoq3gej4iT0= +github.com/mrunalp/fileutils v0.0.0-20200520151820-abd8a0e76976/go.mod h1:x8F1gnqOkIEiO4rqoeEEEqQbo7HjGMTvyoq3gej4iT0= +github.com/mtrmac/gpgme v0.1.2 h1:dNOmvYmsrakgW7LcgiprD0yfRuQQe8/C8F6Z+zogO3s= +github.com/mtrmac/gpgme v0.1.2/go.mod h1:GYYHnGSuS7HK3zVS2n3y73y0okK/BeKzwnn5jgiVFNI= +github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= +github.com/nakabonne/nestif v0.3.0/go.mod h1:dI314BppzXjJ4HsCnbo7XzrJHPszZsjnk5wEBSYHI2c= +github.com/natefinch/lumberjack v2.0.0+incompatible/go.mod h1:Wi9p2TTF5DG5oU+6YfsmYQpsTIOm0B1VNzQg9Mw6nPk= +github.com/nats-io/gnatsd v1.4.1/go.mod h1:nqco77VO78hLCJpIcVfygDP2rPGfsEHkGTUk94uh5DQ= +github.com/nats-io/go-nats v1.7.0/go.mod h1:+t7RHT5ApZebkrQdnn6AhQJmhJJiKAvJUio1PiiCtj0= +github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= +github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU= +github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k= +github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w= +github.com/nats-io/nkeys v0.0.2/go.mod h1:dab7URMsZm6Z/jp9Z5UGa87Uutgc2mVpXLC4B7TDb/4= +github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= +github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= +github.com/nats-io/nuid v1.0.0/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= +github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= +github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms= +github.com/nbutton23/zxcvbn-go v0.0.0-20180912185939-ae427f1e4c1d/go.mod h1:o96djdrsSGy3AWPyBgZMAGfxZNfgntdJG+11KU4QvbU= +github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d h1:VhgPp6v9qf9Agr/56bj7Y/xa04UccTW04VP0Qed4vnQ= +github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d/go.mod h1:YUTz3bUH2ZwIWBy3CJBeOBEugqcmXREj14T+iG/4k4U= +github.com/nwaples/rardecode v1.0.0/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0= +github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/octago/sflags v0.2.0/go.mod h1:G0bjdxh4qPRycF74a2B8pU36iTp9QHGx0w0dFZXPt80= +github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v0.0.0-20171031171758-652e15c9a27e/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.2/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.13.0/go.mod h1:+REjRxOmWfHCjfv9TTWB1jD1Frx4XydAD3zm1lskyM0= +github.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA= +github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= +github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v0.0.0-20171105031654-1eecca0ba8e6/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v0.0.0-20190113212917-5533ce8a0da3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.4.2/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.8.1/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= +github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= +github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= +github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.0.0/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opencontainers/image-spec v1.0.2-0.20190823105129-775207bd45b6 h1:yN8BPXVwMBAm3Cuvh1L5XE8XpvYRMdsVLd82ILprhUU= +github.com/opencontainers/image-spec v1.0.2-0.20190823105129-775207bd45b6/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opencontainers/image-tools v0.0.0-20170926011501-6d941547fa1d/go.mod h1:A9btVpZLzttF4iFaKNychhPyrhfOjJ1OF5KrA8GcLj4= +github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opencontainers/runc v1.0.0-rc6/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opencontainers/runc v1.0.0-rc9.0.20200102164712-2b52db75279c/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opencontainers/runc v1.0.0-rc9.0.20200221051241-688cf6d43cc4/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opencontainers/runc v1.0.0-rc90/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opencontainers/runc v1.0.0-rc91/go.mod h1:3Sm6Dt7OT8z88EbdQqqcRN2oCT54jbi72tT/HqgflT8= +github.com/opencontainers/runc v1.0.0-rc92 h1:+IczUKCRzDzFDnw99O/PAqrcBBCoRp9xN3cB1SYSNS4= +github.com/opencontainers/runc v1.0.0-rc92/go.mod h1:X1zlU4p7wOlX4+WRCz+hvlRv8phdL7UqbYD+vQwNMmE= +github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.0.1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.0.3-0.20200520003142-237cc4f519e2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.0.3-0.20200728170252-4d89ac9fbff6 h1:NhsM2gc769rVWDqJvapK37r+7+CBXI8xHhnfnt8uQsg= +github.com/opencontainers/runtime-spec v1.0.3-0.20200728170252-4d89ac9fbff6/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-tools v0.0.0-20181011054405-1d69bd0f9c39/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs= +github.com/opencontainers/selinux v1.3.2/go.mod h1:yTcKuYAh6R95iDpefGLQaPaRwJFwyzAJufJyiTt7s0g= +github.com/opencontainers/selinux v1.5.1/go.mod h1:yTcKuYAh6R95iDpefGLQaPaRwJFwyzAJufJyiTt7s0g= +github.com/opencontainers/selinux v1.5.2/go.mod h1:yTcKuYAh6R95iDpefGLQaPaRwJFwyzAJufJyiTt7s0g= +github.com/opencontainers/selinux v1.6.0 h1:+bIAS/Za3q5FTwWym4fTB0vObnfCf3G/NC7K6Jx62mY= +github.com/opencontainers/selinux v1.6.0/go.mod h1:VVGKuOLlE7v4PJyT6h7mNWvq1rzqiriPsEqVhc+svHE= +github.com/openshift/api v0.0.0-20200326160804-ecb9283fe820 h1:pEmlKM0gcAPwPEOUt0JOMBd+3bDEOaSZLdvPTm2eU6E= +github.com/openshift/api v0.0.0-20200326160804-ecb9283fe820/go.mod h1:RKMJ5CBnljLfnej+BJ/xnOWc3kZDvJUaIAEq2oKSPtE= +github.com/openshift/build-machinery-go v0.0.0-20200211121458-5e3d6e570160/go.mod h1:1CkcsT3aVebzRBzVTSbiKSkJMsC/CASqxesfqEMfJEc= +github.com/opentracing-contrib/go-stdlib v0.0.0-20171029140428-b1a47cfbdd75/go.mod h1:PLldrQSroqzH70Xl+1DQcGnefIbqsKR7UDaiux3zV+w= +github.com/opentracing/opentracing-go v0.0.0-20171003133519-1361b9cd60be/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= +github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= +github.com/openzipkin/zipkin-go v0.2.0/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= +github.com/openzipkin/zipkin-go v0.2.2 h1:nY8Hti+WKaP0cRsSeQ026wU03QsM762XBeCXBb9NAWI= +github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= +github.com/ostreedev/ostree-go v0.0.0-20190702140239-759a8c1ac913 h1:TnbXhKzrTOyuvWrjI8W6pcoI9XPbLHFXCdN2dtUw7Rw= +github.com/ostreedev/ostree-go v0.0.0-20190702140239-759a8c1ac913/go.mod h1:J6OG6YJVEWopen4avK3VNQSnALmmjvniMmni/YFYAwc= +github.com/otiai10/copy v1.0.2/go.mod h1:c7RpqBkwMom4bYTSkLSym4VSJz/XtncWRAj/J4PEIMY= +github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE= +github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo= +github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= +github.com/pelletier/go-buffruneio v0.2.0/go.mod h1:JkE26KsDizTr40EUHkXVtNPvgGtbSNq5BcowyYOWdKo= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pelletier/go-toml v1.3.0/go.mod h1:PN7xzY2wHTK0K9p34ErDQMlFxa51Fk0OUruD3k1mMwo= +github.com/pelletier/go-toml v1.6.0 h1:aetoXYr0Tv7xRU/V4B4IZJ2QcbtMUFoNb3ORp7TzIK4= +github.com/pelletier/go-toml v1.6.0/go.mod h1:5N711Q9dKgbdkxHL+MEfF31hpT7l0S0s/t2kKREewys= +github.com/pelletier/go-toml v1.8.0 h1:Keo9qb7iRJs2voHvunFtuuYFsbWeOBh8/P9v/kVMFtw= +github.com/pelletier/go-toml v1.8.0/go.mod h1:D6yutnOGMveHEPV7VQOuvI/gXY61bv+9bAOTRnLElKs= +github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= +github.com/phayes/checkstyle v0.0.0-20170904204023-bfd46e6a821d/go.mod h1:3OzsM7FXDQlpCiw2j81fOmAwQLnZnLGXVKUzeKQXIAw= +github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2 h1:JhzVVoYvbOACxoUmOs6V/G4D5nPVUW73rKvXxP4XUJc= +github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= +github.com/pierrec/lz4 v0.0.0-20190327172049-315a67e90e41/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= +github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= +github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pierrec/lz4 v2.2.6+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pivotal-cf/paraphernalia v0.0.0-20180203224945-a64ae2051c20 h1:DR5eMfe2+6GzLkVyWytdtgUxgbPiOfvKDuqityTV3y8= +github.com/pivotal-cf/paraphernalia v0.0.0-20180203224945-a64ae2051c20/go.mod h1:Y3IqE20LKprEpLkXb7gXinJf4vvDdQe/BS8E4kL/dgE= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= +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/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= +github.com/pquerna/ffjson v0.0.0-20181028064349-e517b90714f7/go.mod h1:YARuvh7BUWHNhzDq2OM5tzR2RiCcN2D7sapiKyCel/M= +github.com/pquerna/ffjson v0.0.0-20190813045741-dac163c6c0a9 h1:kyf9snWXHvQc+yxE9imhdI8YAm4oKeZISlaAR+x73zs= +github.com/pquerna/ffjson v0.0.0-20190813045741-dac163c6c0a9/go.mod h1:YARuvh7BUWHNhzDq2OM5tzR2RiCcN2D7sapiKyCel/M= +github.com/prometheus/client_golang v0.0.0-20180209125602-c332b6f63c06/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM= +github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= +github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= +github.com/prometheus/client_golang v1.2.1/go.mod h1:XMU6Z2MjaRKVu/dC1qupJI9SiNkDYzz3xecMgSW/F+U= +github.com/prometheus/client_golang v1.5.0 h1:Ctq0iGpCmr3jeP77kbF2UxgvRwzWWz+4Bh9/vJTyg1A= +github.com/prometheus/client_golang v1.5.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_golang v1.6.0/go.mod h1:ZLOG9ck3JLRdB5MgO8f+lLTe83AXG6ro35rLTxvnIl4= +github.com/prometheus/client_model v0.0.0-20170216185247-6f3806018612/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.0.0-20180110214958-89604d197083/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.0.0-20180518154759-7600349dcfe1/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.0.0-20181020173914-7e9e6cabbd39/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= +github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= +github.com/prometheus/common v0.9.1 h1:KOMtN28tlbam3/7ZKEYKHhKoJZYYj3gMH4uc62x7X7U= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20180612222113-7d6f385de8be/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.0-20190522114515-bc1a522cf7b1/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= +github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= +github.com/prometheus/procfs v0.0.6/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/prometheus/procfs v0.0.10/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/prometheus/procfs v0.0.11 h1:DhHlBtkHWPYi8O2y31JkK0TF+DGM+51OopZjH/Ia5qI= +github.com/prometheus/procfs v0.0.11/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/statsd_exporter v0.15.0/go.mod h1:Dv8HnkoLQkeEjkIE4/2ndAA7WL1zHKK7WMqFQqu72rw= +github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/quasilyte/go-consistent v0.0.0-20190521200055-c6f3937de18c/go.mod h1:5STLWrekHfjyYwxBRVRXNOSewLJ3PWfDJd1VyTS21fI= +github.com/quasilyte/go-ruleguard v0.1.2-0.20200318202121-b00d7a75d3d8/go.mod h1:CGFX09Ci3pq9QZdj86B+VGIdNj4VyCo2iPOGS9esB/k= +github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/rcrowley/go-metrics v0.0.0-20190706150252-9beb055b7962/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/fastuuid v1.1.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.3.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.5.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rubiojr/go-vhd v0.0.0-20160810183302-0bfd3b39853c/go.mod h1:DM5xW0nvfNNm2uytzsvhI3OnX8uzaRAg8UX/CnDqbto= +github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/russross/blackfriday v2.0.0+incompatible/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/ryancurrah/gomodguard v1.0.4/go.mod h1:9T/Cfuxs5StfsocWr4WzDL36HqnX0fVb9d5fSEaLhoE= +github.com/ryancurrah/gomodguard v1.1.0/go.mod h1:4O8tr7hBODaGE6VIhfJDHcwzh5GUccKSJBU0UMXJFVM= +github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/sabhiram/go-gitignore v0.0.0-20180611051255-d3107576ba94 h1:G04eS0JkAIVZfaJLjla9dNxkJCPiKIGZlw9AfOhzOD0= +github.com/sabhiram/go-gitignore v0.0.0-20180611051255-d3107576ba94/go.mod h1:b18R55ulyQ/h3RaWyloPyER7fWQVZvimKKhnI5OfrJQ= +github.com/sajari/fuzzy v1.0.0 h1:+FmwVvJErsd0d0hAPlj4CxqxUtQY/fOoY0DwX4ykpRY= +github.com/sajari/fuzzy v1.0.0/go.mod h1:OjYR6KxoWOe9+dOlXeiCJd4dIbED4Oo8wpS89o0pwOo= +github.com/sassoftware/go-rpmutils v0.0.0-20190420191620-a8f1baeba37b/go.mod h1:am+Fp8Bt506lA3Rk3QCmSqmYmLMnPDhdDUcosQCAx+I= +github.com/satori/go.uuid v0.0.0-20160713180306-0aa62d5ddceb/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= +github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= +github.com/sclevine/agouti v3.0.0+incompatible/go.mod h1:b4WX9W9L1sfQKXeJf1mUTLZKJ48R1S7H23Ji7oFO5Bw= +github.com/sclevine/spec v1.2.0/go.mod h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24q7p+U= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/seccomp/libseccomp-golang v0.9.1 h1:NJjM5DNFOs0s3kYE1WUOr6G8V97sdt46rlXTMfXGWBo= +github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo= +github.com/securego/gosec v0.0.0-20200103095621-79fbf3af8d83/go.mod h1:vvbZ2Ae7AzSq3/kywjUDxSNq2SJ27RxCz2un0H3ePqE= +github.com/securego/gosec v0.0.0-20200401082031-e946c8c39989/go.mod h1:i9l/TNj+yDFh9SZXUTvspXTjbFXgZGP/UvhU1S65A4A= +github.com/securego/gosec/v2 v2.3.0/go.mod h1:UzeVyUXbxukhLeHKV3VVqo7HdoQR9MrRfFmZYotn8ME= +github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= +github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= +github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/serialx/hashring v0.0.0-20190422032157-8b2912629002/go.mod h1:/yeG0My1xr/u+HZrFQ1tOQQQQrOawfyMUH13ai5brBc= +github.com/shirou/gopsutil v0.0.0-20190901111213-e4ec7b275ada/go.mod h1:WWnYX4lzhCH5h/3YBfyVA3VbLYjlMZZAQcW9ojMexNc= +github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4/go.mod h1:qsXQc7+bwAM3Q1u/4XEfrquwF8Lw7D7y5cD8CuHnfIc= +github.com/shurcooL/githubv4 v0.0.0-20180925043049-51d7b505e2e9/go.mod h1:hAF0iLZy4td2EX+/8Tw+4nodhlMrwN3HupfaXj3zkGo= +github.com/shurcooL/githubv4 v0.0.0-20190718010115-4ba037080260/go.mod h1:hAF0iLZy4td2EX+/8Tw+4nodhlMrwN3HupfaXj3zkGo= +github.com/shurcooL/githubv4 v0.0.0-20191102174205-af46314aec7b/go.mod h1:hAF0iLZy4td2EX+/8Tw+4nodhlMrwN3HupfaXj3zkGo= +github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= +github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ= +github.com/shurcooL/graphql v0.0.0-20180924043259-e4a3a37e6d42/go.mod h1:AuYgA5Kyo4c7HfUmvRGs/6rGlMMV/6B1bVnB9JxJEEg= +github.com/shurcooL/graphql v0.0.0-20181231061246-d48a9a75455f/go.mod h1:AuYgA5Kyo4c7HfUmvRGs/6rGlMMV/6B1bVnB9JxJEEg= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.0.3/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= +github.com/sirupsen/logrus v1.0.4-0.20170822132746-89742aefa4b2/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= +github.com/sirupsen/logrus v1.0.5/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= +github.com/sirupsen/logrus v1.1.1/go.mod h1:zrgwTnHtNr00buQ1vSptGe8m1f/BbgsPukg8qsT7A+A= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I= +github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/assertions v1.0.0 h1:UVQPSSmc3qtTi+zPPkCXvZX9VvW/xT/NsRvKfwY81a8= +github.com/smartystreets/assertions v1.0.0/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM= +github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9/go.mod h1:SnhjPscd9TpLiy1LpzGSKh3bXCfxxXuqd9xmQJy3slM= +github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/smartystreets/gunit v1.0.0/go.mod h1:qwPWnhz6pn0NnRBP++URONOVyNkPyr4SauJk4cUOwJs= +github.com/soheilhy/cmux v0.1.3/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/sourcegraph/go-diff v0.5.1/go.mod h1:j2dHj3m8aZgQO8lMTcTnBcXkRRRqi34cd2MNlA9u1mE= +github.com/sourcegraph/go-diff v0.5.3/go.mod h1:v9JDtjCE4HHHCZGId75rg8gkKKa98RVjBcBGsVmMmak= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc= +github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng= +github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.0-20180319062004-c439c4fa0937/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= +github.com/spf13/cobra v0.0.6/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= +github.com/spf13/cobra v1.0.0 h1:6m/oheQuQ13N9ks4hubMG6BnvwOeaJrqSPLahSnczz8= +github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= +github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= +github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.1-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.2/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.3/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/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= +github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= +github.com/spf13/viper v1.6.1/go.mod h1:t3iDnF5Jlj76alVNuyFBk5oUMCvsrkbvZK0WQdfDi5k= +github.com/spf13/viper v1.6.2/go.mod h1:t3iDnF5Jlj76alVNuyFBk5oUMCvsrkbvZK0WQdfDi5k= +github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= +github.com/spf13/viper v1.7.1 h1:pM5oEahlgWv/WnHXpgbKz7iLIxRf65tye2Ci+XFK5sk= +github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= +github.com/square/certstrap v1.2.0/go.mod h1:CUHqV+fxJW0Y5UQFnnbYwQ7bpKXO1AKbic9g73799yw= +github.com/src-d/gcfg v1.4.0 h1:xXbNR5AlLSA315x2UO+fTSSAXCDf+Ar38/6oyGbDKQ4= +github.com/src-d/gcfg v1.4.0/go.mod h1:p/UMsR43ujA89BJY9duynAwIpvqEujIH/jFlfL7jWoI= +github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= +github.com/streadway/quantile v0.0.0-20150917103942-b0c588724d25/go.mod h1:lbP8tGiBjZ5YWIc2fzuRpTaz0b/53vT6PEs3QuAWzuU= +github.com/stretchr/objx v0.0.0-20180129172003-8a3f7159479f/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v0.0.0-20180303142811-b89eecf5ca5d/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= +github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= +github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2 h1:b6uOv7YOFK0TYG7HtkIgExQo+2RdLuwRft63jn2HWj8= +github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= +github.com/tchap/go-patricia v2.3.0+incompatible h1:GkY4dP3cEfEASBPPkWd+AmjYxhmDkqO9/zg7R0lSQRs= +github.com/tchap/go-patricia v2.3.0+incompatible/go.mod h1:bmLyhP68RS6kStMGxByiQ23RP/odRBOTVjwp2cDyi6I= +github.com/tdakkota/asciicheck v0.0.0-20200416190851-d7f85be797a2/go.mod h1:yHp0ai0Z9gUljN3o0xMhYJnH/IcvkdTBOX2fmJ93JEM= +github.com/tdakkota/asciicheck v0.0.0-20200416200610-e657995f937b/go.mod h1:yHp0ai0Z9gUljN3o0xMhYJnH/IcvkdTBOX2fmJ93JEM= +github.com/tedsuo/rata v1.0.0 h1:Sf9aZrYy6ElSTncjnGkyC2yuVvz5YJetBIUKJ4CmeKE= +github.com/tedsuo/rata v1.0.0/go.mod h1:X47ELzhOoLbfFIY0Cql9P6yo3Cdwf2CMX3FVZxRzJPc= +github.com/tektoncd/pipeline v0.8.0/go.mod h1:IZzJdiX9EqEMuUcgdnElozdYYRh0/ZRC+NKMLj1K3Yw= +github.com/tektoncd/pipeline v0.10.1/go.mod h1:D2X0exT46zYx95BU7ByM8+erpjoN7thmUBvlKThOszU= +github.com/tektoncd/pipeline v0.11.0 h1:kGeWm53R5ggajD/L2KU8kcsZ2lVd4ruN3kdqK1A/NwQ= +github.com/tektoncd/pipeline v0.11.0/go.mod h1:hlkH32S92+/UODROH0dmxzyuMxfRFp/Nc3e29MewLn8= +github.com/tektoncd/pipeline v0.13.1-0.20200625065359-44f22a067b75/go.mod h1:R5AlT46x/F8n/pFJFjZ1U1q71GWtVXgG7RZkkoRL554= +github.com/tektoncd/pipeline v0.15.2 h1:+dZyH87KKoAUIs6HAsGVT+AP4M/eV8PX2uCj9wOhGZg= +github.com/tektoncd/pipeline v0.15.2/go.mod h1:SaAxUpYbcFik2hKGOTX7NnvOa1VXTzXRGNZsY2TSwTs= +github.com/tektoncd/pipeline v0.16.3 h1:h5bJGOxbzYpa+5OwWGdlWphCEh9nmxnfVH+nhwaOFCQ= +github.com/tektoncd/pipeline v0.16.3/go.mod h1:5vn2IJH46ntWTKLkwNbtZNd38FYkNP0cBtu5sgqm5xA= +github.com/tektoncd/plumbing v0.0.0-20191216083742-847dcf196de9/go.mod h1:QZHgU07PRBTRF6N57w4+ApRu8OgfYLFNqCDlfEZaD9Y= +github.com/tektoncd/plumbing v0.0.0-20200217163359-cd0db6e567d2/go.mod h1:QZHgU07PRBTRF6N57w4+ApRu8OgfYLFNqCDlfEZaD9Y= +github.com/tektoncd/plumbing v0.0.0-20200430135134-e53521e1d887/go.mod h1:cZPJIeTIoP7UPTxQyTQLs7VE1TiXJSNj0te+If4Q+jI= +github.com/tektoncd/plumbing/pipelinerun-logs v0.0.0-20191206114338-712d544c2c21/go.mod h1:S62EUWtqmejjJgUMOGB1CCCHRp6C706laH06BoALkzU= +github.com/tetafro/godot v0.3.7/go.mod h1:/7NLHhv08H1+8DNj0MElpAACw1ajsCuf3TKNQxA5S+0= +github.com/tetafro/godot v0.4.2/go.mod h1:/7NLHhv08H1+8DNj0MElpAACw1ajsCuf3TKNQxA5S+0= +github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/timakin/bodyclose v0.0.0-20190930140734-f7f2e9bca95e/go.mod h1:Qimiffbc6q9tBWlVV6x0P9sat/ao1xEkREYPPj9hphk= +github.com/timakin/bodyclose v0.0.0-20200424151742-cb6215831a94/go.mod h1:Qimiffbc6q9tBWlVV6x0P9sat/ao1xEkREYPPj9hphk= +github.com/tj/assert v0.0.0-20171129193455-018094318fb0/go.mod h1:mZ9/Rh9oLWpLLDRpvE+3b7gP/C2YyLFYxNmcLnPTMe0= +github.com/tj/go-elastic v0.0.0-20171221160941-36157cbbebc2/go.mod h1:WjeM0Oo1eNAjXGDx2yma7uG2XoyRZTq1uv3M/o7imD0= +github.com/tj/go-kinesis v0.0.0-20171128231115-08b17f58cb1b/go.mod h1:/yhzCV0xPfx6jb1bBgRFjl5lytqVqZXEaeqWP8lTEao= +github.com/tj/go-spin v1.1.0/go.mod h1:Mg1mzmePZm4dva8Qz60H2lHwmJ2loum4VIrLgVnKwh4= +github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/tommy-muehle/go-mnd v1.1.1/go.mod h1:dSUh0FtTP8VhvkL1S+gUR1OKd9ZnSaozuI6r3m6wOig= +github.com/tommy-muehle/go-mnd v1.3.1-0.20200224220436-e6f9a994e8fa/go.mod h1:dSUh0FtTP8VhvkL1S+gUR1OKd9ZnSaozuI6r3m6wOig= +github.com/tonistiigi/fsutil v0.0.0-20200326231323-c2c7d7b0e144/go.mod h1:0G1sLZ/0ttFf09xvh7GR4AEECnjifHRNJN/sYbLianU= +github.com/tonistiigi/units v0.0.0-20180711220420-6950e57a87ea/go.mod h1:WPnis/6cRcDZSUvVmezrxJPkiO87ThFYsoUiMwWNDJk= +github.com/tsenart/go-tsz v0.0.0-20180814235614-0bd30b3df1c3/go.mod h1:SWZznP1z5Ki7hDT2ioqiFKEse8K9tU2OUvaRI0NeGQo= +github.com/tsenart/vegeta v12.7.1-0.20190725001342-b5f4fca92137+incompatible/go.mod h1:Smz/ZWfhKRcyDDChZkG3CyTHdj87lHzio/HOCkbndXM= +github.com/uber/jaeger-client-go v0.0.0-20180103221425-e02c85f9069e/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= +github.com/uber/jaeger-lib v1.2.1/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U= +github.com/ugorji/go v1.1.1/go.mod h1:hnLbHMwcvSihnDhEfx2/BzKp2xb0Y+ErdfYcrs9tkJQ= +github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= +github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/ulikunitz/xz v0.5.6/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8= +github.com/ulikunitz/xz v0.5.7 h1:YvTNdFzX6+W5m9msiYg/zpkSURPPtOlzbqYjrFn7Yt4= +github.com/ulikunitz/xz v0.5.7/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= +github.com/ultraware/funlen v0.0.2/go.mod h1:Dp4UiAus7Wdb9KUZsYWZEWiRzGuM2kXM1lPbfaF6xhA= +github.com/ultraware/whitespace v0.0.4/go.mod h1:aVMh/gQve5Maj9hQ/hg+F75lr/X5A89uZnzAmWSineA= +github.com/unrolled/secure v0.0.0-20180416205222-a1cf62cc2159/go.mod h1:mnPT77IAdsi/kV7+Es7y+pXALeV3h7G6dQF6mNYjcLA= +github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli v1.18.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli v1.21.0/go.mod h1:lxDj6qX9Q6lWQxIrbrT0nwecwUtRnhVZAJjJZrVUZZQ= +github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/uudashr/gocognit v1.0.1/go.mod h1:j44Ayx2KW4+oB6SWMv8KsmHzZrOInQav7D3cQMJ5JUM= +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasthttp v1.2.0/go.mod h1:4vX61m6KN+xDduDNwXrhIAVZaZaZiQ1luJk8LWSxF3s= +github.com/valyala/quicktemplate v1.2.0/go.mod h1:EH+4AkTd43SvgIbQHYu59/cJyxDoOVRUAfrukLPuGJ4= +github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= +github.com/vbatts/tar-split v0.11.1 h1:0Odu65rhcZ3JZaPHxl7tCI3V/C/Q9Zf82UFravl02dE= +github.com/vbatts/tar-split v0.11.1/go.mod h1:LEuURwDEiWjRjwu46yU3KVGuUdVv/dcnpcEPSzR8z6g= +github.com/vbauerster/mpb/v5 v5.2.2 h1:zIICVOm+XD+uV6crpSORaL6I0Q1WqOdvxZTp+r3L9cw= +github.com/vbauerster/mpb/v5 v5.2.2/go.mod h1:W5Fvgw4dm3/0NhqzV8j6EacfuTe5SvnzBRwiXxDR9ww= +github.com/vdemeester/k8s-pkg-credentialprovider v0.0.0-20200107171650-7c61ffa44238/go.mod h1:JwQJCMWpUDqjZrB5jpw0f5VbN7U95zxFy1ZDpoEarGo= +github.com/vdemeester/k8s-pkg-credentialprovider v1.13.12-1/go.mod h1:Fko0rTxEtDW2kju5Ky7yFJNS3IcNvW8IPsp4/e9oev0= +github.com/vdemeester/k8s-pkg-credentialprovider v1.17.4/go.mod h1:inCTmtUdr5KJbreVojo06krnTgaeAz/Z7lynpPk/Q2c= +github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw= +github.com/vishvananda/netlink v1.0.0/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk= +github.com/vishvananda/netlink v1.1.0 h1:1iyaYNBLmP6L0220aDnYQpo1QEV4t4hJ+xEEhhJH8j0= +github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= +github.com/vishvananda/netns v0.0.0-20180720170159-13995c7128cc/go.mod h1:ZjcWmFBXmLKZu9Nxj3WKYEafiSqer2rnvPr0en9UNpI= +github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df h1:OviZH7qLw/7ZovXvuNyL3XQl8UFofeikI1NW1Gypu7k= +github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= +github.com/vito/go-interact v1.0.0 h1:niLW3NjGoMWOayoR6iQ8AxWVM1Q4rR8VGZ1mt6uK3BM= +github.com/vito/go-interact v1.0.0/go.mod h1:W1mz+UVUZScRM3eUjQhEQiLDnQ+yLnXkB2rjBfGPrXg= +github.com/vmware/govmomi v0.20.3/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU= +github.com/willf/bitset v1.1.11-0.20200630133818-d5bec3311243 h1:R43TdZy32XXSXjJn7M/HhALJ9imq6ztLnChfYJpVDnM= +github.com/willf/bitset v1.1.11-0.20200630133818-d5bec3311243/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= +github.com/xanzy/go-gitlab v0.31.0/go.mod h1:sPLojNBn68fMUWSxIJtdVVIP8uSBYqesTfDUseX11Ug= +github.com/xanzy/go-gitlab v0.32.0/go.mod h1:sPLojNBn68fMUWSxIJtdVVIP8uSBYqesTfDUseX11Ug= +github.com/xanzy/ssh-agent v0.2.1 h1:TCbipTQL2JiiCprBWx9frJ2eJlCYT00NmctrHxVAr70= +github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4= +github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= +github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonpointer v0.0.0-20190809123943-df4f5c81cb3b h1:6cLsL+2FW6dRAdl5iMtHgRogVCff0QpRi9653YmdcJA= +github.com/xeipuuv/gojsonpointer v0.0.0-20190809123943-df4f5c81cb3b/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= +github.com/xeipuuv/gojsonschema v0.0.0-20161030231247-84d19640f6a7 h1:lrPFiLn7iuI5BPhrGUtOINABGYcgSNM2nSB4QteC3kI= +github.com/xeipuuv/gojsonschema v0.0.0-20161030231247-84d19640f6a7/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs= +github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos= +github.com/xiang90/probing v0.0.0-20160813154853-07dd2e8dfe18/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xlab/handysort v0.0.0-20150421192137-fb3537ed64a1/go.mod h1:QcJo0QPSfTONNIgpN5RA8prR7fF8nkF6cTWTcNerRO8= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +github.com/xrash/smetrics v0.0.0-20200730060457-89a2a8a1fb0b h1:tnWgqoOBmInkt5pbLjagwNVjjT4RdJhFHzL1ebCSRh8= +github.com/xrash/smetrics v0.0.0-20200730060457-89a2a8a1fb0b/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs= +github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA= +github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg= +go.etcd.io/bbolt v1.3.1-etcd.7/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/bbolt v1.3.4/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= +go.etcd.io/etcd v0.0.0-20181031231232-83304cfc808c/go.mod h1:weASp41xM3dk0YHg1s/W8ecdGP5G4teSTMBPpYAaUgA= +go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= +go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= +go.mongodb.org/mongo-driver v1.1.1/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= +go.mongodb.org/mongo-driver v1.1.2/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= +go.mozilla.org/pkcs7 v0.0.0-20200128120323-432b2356ecb1 h1:A/5uWzF44DlIgdm/PQFwfMkW0JX+cIcQi/SwLAmZP5M= +go.mozilla.org/pkcs7 v0.0.0-20200128120323-432b2356ecb1/go.mod h1:SNgMg+EgDFwmvSmLRTNKC5fegJjB7v23qTQ0XLGUNHk= +go.opencensus.io v0.15.0/go.mod h1:UffZAU+4sDEINUGP/B7UfBBkq4fqLu9zXAX7ke6CHW0= +go.opencensus.io v0.17.0/go.mod h1:mp1VrMQxhlqqDpKvH4UcQUa4YwlzNmymAjPrDdfxNpI= +go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= +go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.1/go.mod h1:Ap50jQcDJrx6rB6VgeeFPtuPIf3wMRvRfrfYDO6+BmA= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4-0.20200608061201-1901b56b9515/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4 h1:LYy1Hy3MJdrCdMwwzxA/dRok4ejH+RwNGbuoD9fCjto= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.uber.org/atomic v0.0.0-20181018215023-8dc6146f7569/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/atomic v1.5.1/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk= +go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/automaxprocs v1.3.0/go.mod h1:9CWT6lKIep8U41DDaPiH6eFscnTyjfTANNQNx6LrIcA= +go.uber.org/multierr v0.0.0-20180122172545-ddea229ff1df/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= +go.uber.org/multierr v1.4.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= +go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A= +go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= +go.uber.org/zap v0.0.0-20180814183419-67bc79d13d15/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.9.2-0.20180814183419-67bc79d13d15/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= +go.uber.org/zap v1.14.1 h1:nYDKopTbvAPq/NrUVZwT15y2lpROBiLLyoRTbXOYWOo= +go.uber.org/zap v1.14.1/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= +go.uber.org/zap v1.15.0 h1:ZZCA22JRF2gQE5FoNmhmrf7jeJJ2uhqDUNRYKm8dvmM= +go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= +go4.org v0.0.0-20190218023631-ce4c26f7be8e/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= +gocloud.dev v0.19.0/go.mod h1:SmKwiR8YwIMMJvQBKLsC3fHNyMwXLw3PMDO+VVteJMI= +golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20180608092829-8ac0e0d97ce4/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181015023909-0c41d7ab0a0e/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181025213731-e84da0312774/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181127143415-eb0de9b17e85/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/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-20190320223903-b7391e95e576/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190404164418-38d8ce5564a5/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= +golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190617133340-57b3e21c3d56/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191002192127-34f69633bfdc/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191117063200-497ca9f6d64f/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200423211502-4bdfaf469ed5 h1:Q7tZBpemrlsc2I7IyODzhtallWRSm4Q0d09pL6XbQtU= +golang.org/x/crypto v0.0.0-20200423211502-4bdfaf469ed5/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37 h1:cg5LA/zNPRzIXIWSCxQW10Rvpy94aQh3LT/ShoCpkHw= +golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a h1:vclmkQCjlDX5OydZ9wv8rBCcS0QyQY66Mpf/7BZbInM= +golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190312203227-4b39c73a6495/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191002040644-a1355ae1e2c3/go.mod h1:NOZ3BPKG0ec/BKJQgnvsSFpcKLM5xXVWnvZS97DWHgE= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +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/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mobile v0.0.0-20190806162312-597adff16ade/go.mod h1:AlhUtkH4DA4asiFC5RgK7ZKmauvtkAVcy9L0epCzlWo= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180418062111-d41e8174641f/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-20180911220305-26e67e76b6c3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181108082009-03003ca0c849/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/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-20190125091013-d26f9f9a57f3/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-20190320064053-1272bf9dcd53/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190619014844-b5b0513f8c1b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190812203447-cdfb69ac37fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190912160710-24e19bdeb0f2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191002035440-2ec189313ef0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191112182307-2180aed22343/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191119073136-fc4aabc6c914/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7 h1:AeiKBIuRw3UomYXSbLy0Mc2dDLfdtbT/IVn4keq83P0= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2 h1:eDrdRpKgkcCqKZQwyZRyeFZgfqt37SL7Kv3tok06cKE= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344 h1:vGXIOMxbNfDTk/aXCmfdLgkrSV+Z2tcbze+pEc3v5W4= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202 h1:VvcQYSHwXgi7W+TpUR6A9g6Up98WAHf3f/ulnJ62IyA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/oauth2 v0.0.0-20180724155351-3d292e4d0cdc/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/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-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d h1:TzXSXBo42m9gQenoE3b9BGiEpg5IG2JkU5FkPIawgtw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/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/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a h1:WXEvlFVvvGxCJLG6REjsT03iWnKLEWinaScsxF2Vm2o= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208 h1:qwRHBd0NqMbJxfbotnDhm2ByMI1Shq4Y6oRJo21SGJA= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/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-20180419222023-a2a45943ae67/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/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-20180905080454-ebe1bf3edb33/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-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181128092732-4ed8d59d0b35/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/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-20190219203350-90b0e4468f99/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190321052220-f7bb7a8bee54/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190514135907-3a4b5fb9f71f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190522044717-8097e1b27ff5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190530182044-ad28b68e88f1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190602015325-4c4f7f33c9ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190620070143-6f217b454f45/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190912141932-bc967efca4b8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191112214154-59a1497f0cea/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191113165036-4c7a9d0fe056/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191119060738-e882bf8e40c2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191210023423-ac6580df4449/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200120151820-655fe14d7479/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200317113312-5766fd39f98d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200327173247-9dae0f8f5775/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200610111108-226ff32320da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1 h1:sIky/MyNRSHTrdxfsiUSS4WIAMvInbeXljJz+jDjeYE= +golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200802091954-4b90ce9b60b3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200828081204-131dc92a58d5 h1:7bMlihXlwJGQO5wkUzKoDE1wEy13q+lWFO6dMYQx92o= +golang.org/x/sys v0.0.0-20200828081204-131dc92a58d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/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.1-0.20181227161524-e6919f6577db/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/time v0.0.0-20161028155119-f51c12702a4d/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1 h1:NusfzzA6yGQ+ua51ck7E3omNUX/JuqbFSaRGqU8CcLI= +golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e h1:EHBhcS0mlXEAVwNyO2dLfjToGsyY4j24pTs2ScHnX7s= +golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +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-20181117154741-2ddaf7f79a09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190110163146-51295c7ec13a/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-20190125232054-d66bd3c5d5a6/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190221204921-83362c3779f5/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190311215038-5c2858a9cfe5/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190322203728-c1a832b0ad89/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190422233926-fe54fb35175b/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190521203540-521d6ed310dd/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190617190820-da514acc4774/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190706070813-72ffa07ba3db/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= +golang.org/x/tools v0.0.0-20190719005602-e377ae9d6386/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= +golang.org/x/tools v0.0.0-20190729092621-ff9f1409240a/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= +golang.org/x/tools v0.0.0-20190807223507-b346f7fd45de/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190910044552-dd2b5c81c578/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190927191325-030b2cf1153e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191010075000-0337d82405ff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191010171213-8abd42400456/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191112005509-a3f652f18032/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113232020-e2727e816f5a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191118222007-07fc4c7f2b98/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200102140908-9497f49d5709/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200115044656-831fdb1e1868/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200115165105-de0b1760071a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204192400-7124308813f3/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200210192313-1ace956b0e17/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200214144324-88be01311a71/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200303214625-2b0b585e22fe/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200317043434-63da46f3035e/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200324003944-a576cf524670/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200329025819-fd4102a86c65 h1:1KSbntBked74wYsKq0jzXYy7ZwcjAUtrl7EmPE97Iiw= +golang.org/x/tools v0.0.0-20200329025819-fd4102a86c65/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200331202046-9d5940d49312/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200414032229-332987a829c3/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200422022333-3d57cf2e726e/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200426102838-f3a5411a4c3b/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200502202811-ed308ab3e770/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200527183253-8e7acdbce89d h1:SR+e35rACZFBohNb4Om1ibX6N3iO0FtdbwqGSuD9dBU= +golang.org/x/tools v0.0.0-20200527183253-8e7acdbce89d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200601175630-2caf76543d99/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200626171337-aa94e735be7f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200701000337-a32c0cb1d5b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200709181711-e327e1019dfe/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200713011307-fd294ab11aed/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200725200936-102e7d357031/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200731060945-b5fad4ed8dd6/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200817023811-d00afeaade8f/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200823205832-c024452afbcd h1:KNSumuk5eGuQV7zbOrDDZ3MIkwsQr0n5oKiH4oE0/hU= +golang.org/x/tools v0.0.0-20200823205832-c024452afbcd/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200827163409-021d7c6f1ec3/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200828013309-97019fc2e64b h1:TlHrnfzYWpw9fgHafO5AaiaqK81ZaJzPi+srvBuZUIQ= +golang.org/x/tools v0.0.0-20200828013309-97019fc2e64b/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gomodules.xyz/jsonpatch/v2 v2.0.1/go.mod h1:IhYNNY4jnS53ZnfE4PAmpKtDpTCj1JFXc+3mwe7XcUU= +gomodules.xyz/jsonpatch/v2 v2.1.0 h1:Phva6wqu+xR//Njw6iorylFFgn/z547tw5Ne3HZPQ+k= +gomodules.xyz/jsonpatch/v2 v2.1.0/go.mod h1:IhYNNY4jnS53ZnfE4PAmpKtDpTCj1JFXc+3mwe7XcUU= +gonum.org/v1/gonum v0.0.0-20181121035319-3f7ecaa7e8ca/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= +gonum.org/v1/gonum v0.0.0-20190331200053-3d26580ed485/go.mod h1:2ltnJ7xHfj0zHS40VVPYEAAMTa3ZGguvHGBSJeRWqE0= +gonum.org/v1/netlib v0.0.0-20181029234149-ec6d1f5cefe6/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= +gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= +gonum.org/v1/netlib v0.0.0-20190331212654-76723241ea4e/go.mod h1:kS+toOQn6AQKjmKJ7gzohV1XkqsFehRA2FbsbkopSuQ= +google.golang.org/api v0.0.0-20160322025152-9bf6e6e569ff/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= +google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= +google.golang.org/api v0.0.0-20181021000519-a2651947f503/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= +google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.5.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.6.0/go.mod h1:btoxGiFvQNVUZQ8W08zLtrVS08CNpINPEfxXxgJL1Q4= +google.golang.org/api v0.6.1-0.20190607001116-5213b8090861/go.mod h1:btoxGiFvQNVUZQ8W08zLtrVS08CNpINPEfxXxgJL1Q4= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.10.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0 h1:jz2KixHX7EcCPiQrySzPdnYT7DbINAypCqKZ1Z7GM40= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.25.0 h1:LodzhlzZEUfhXzNUMIfVlf9Gr6Ua5MMtoFWh7+f47qA= +google.golang.org/api v0.25.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.26.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0 h1:yfrXXP61wVuLb0vBcG6qaOoIoqYEzOQS8jum51jkv2w= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.2/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5 h1:tycE03LOZYQNhDpS27tcQdAzLCVMaj7QT2SXxebnpCM= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.6 h1:lMO5rYAqUxkmaj76jAkRUvt5JZgFymx/+Q5Mzfivuhc= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/cloud v0.0.0-20151119220103-975617b05ea8/go.mod h1:0H1ncTHf11KCFhTc/+EFRbzSCOZx+VUbRMk55Yv5MYk= +google.golang.org/genproto v0.0.0-20170731182057-09f6ed296fc6/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20180608181217-32ee49c4dd80/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20181016170114-94acd270e44e/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/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190508193815-b515fa19cec8/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190522204451-c2c4e71fbf69/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= +google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= +google.golang.org/genproto v0.0.0-20190620144150-6af8c5fc6601/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= +google.golang.org/genproto v0.0.0-20190708153700-3bdd9d9f5532/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= +google.golang.org/genproto v0.0.0-20190716160619-c506a9f90610/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20190927181202-20e1ac93f88c/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191009194640-548a555dbc03/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200117163144-32f20d992d24/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200227132054-3f1135a288c9/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200317114155-1f3552e48f24/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200326112834-f447254575fd h1:DVCc2PgW9UrvHGZGEv4Mt3uSeQtUrrs7r8pUw+bVwWI= +google.golang.org/genproto v0.0.0-20200326112834-f447254575fd/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200527145253-8367513e4ece h1:1YM0uhfumvoDu9sx8+RyWwTI63zoCQvI23IYFRlvte0= +google.golang.org/genproto v0.0.0-20200527145253-8367513e4ece/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200528110217-3d3490e7e671/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200603110839-e855014d5736/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200626011028-ee7919e894b5/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200701001935-0939c5918c31/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200709005830-7a2ca40e9dc3/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200711021454-869866162049/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200726014623-da3ae01ef02d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200731012542-8145dea6a485/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200815001618-f69a88009b70/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200827165113-ac2560b5e952/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200828030656-73b5761be4c5 h1:SXvXDcZm33V0P03upM01EgN1an0ggw+yntYrnvdWbCU= +google.golang.org/genproto v0.0.0-20200828030656-73b5761be4c5/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= +google.golang.org/grpc v1.13.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= +google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= +google.golang.org/grpc v1.15.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= +google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.19.1/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.22.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.28.1 h1:C1QC6KzgSiLyBabDi87BbjaGreoRgGUF5nOyvfrAZ1k= +google.golang.org/grpc v1.28.1/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1 h1:EC2SB8S04d2r73uptxphDSUG+kTKVgjRPF+N3xpxRB4= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.1 h1:SfXqXS5hkufcdZ/mHtYCh53P2b+92WQq/DZcKLgsFRs= +google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0 h1:UhZDfRO8JRQru4/+LlLE0BRKGF8L+PICnvYZmx/fEGA= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20141024133853-64131543e789/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/cheggaaa/pb.v1 v1.0.25 h1:Ev7yu1/f6+d+b3pi5vPdRPc6nNtP1umSfcWiEfRqv6I= +gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/gcfg.v1 v1.2.0/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= +gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= +gopkg.in/inf.v0 v0.9.0/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/ini.v1 v1.46.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.52.0 h1:j+Lt/M1oPPejkniCg1TkWE2J3Eh1oZTsHSXzMTzUXn4= +gopkg.in/ini.v1 v1.52.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.56.0 h1:DPMeDvGTM54DXbPkVIZsp19fp/I2K7zwA/itHYHKo8Y= +gopkg.in/ini.v1 v1.56.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/jcmturner/aescts.v1 v1.0.1/go.mod h1:nsR8qBOg+OucoIW+WMhB3GspUQXq9XorLnQb9XtvcOo= +gopkg.in/jcmturner/dnsutils.v1 v1.0.1/go.mod h1:m3v+5svpVOhtFAP/wSz+yzh4Mc0Fg7eRhxkJMWSIz9Q= +gopkg.in/jcmturner/gokrb5.v7 v7.2.3/go.mod h1:l8VISx+WGYp+Fp7KRbsiUuXTTOnxIc3Tuvyavf11/WM= +gopkg.in/jcmturner/gokrb5.v7 v7.3.0/go.mod h1:l8VISx+WGYp+Fp7KRbsiUuXTTOnxIc3Tuvyavf11/WM= +gopkg.in/jcmturner/rpc.v1 v1.1.0/go.mod h1:YIdkC4XfD6GXbzje11McwsDuOlZQSb9W4vfLvuNnlv8= +gopkg.in/natefinch/lumberjack.v2 v2.0.0-20150622162204-20b71e5b60d7/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= +gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/robfig/cron.v2 v2.0.0-20150107220207-be2e0b0deed5/go.mod h1:hiOFpYm0ZJbusNj2ywpbrXowU3G8U6GIQzqn2mw1UIE= +gopkg.in/square/go-jose.v2 v2.0.0-20180411045311-89060dee6a84/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/square/go-jose.v2 v2.3.1 h1:SK5KegNXmKmqE342YYN2qPHEnUYeoMiXXl1poUlI+o4= +gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/src-d/go-billy.v4 v4.3.2 h1:0SQA1pRztfTFx2miS8sA97XvooFeNOmvUenF4o0EcVg= +gopkg.in/src-d/go-billy.v4 v4.3.2/go.mod h1:nDjArDMp+XMs1aFAESLRjfGSgfvoYN0hDfzEk0GjC98= +gopkg.in/src-d/go-git-fixtures.v3 v3.5.0/go.mod h1:dLBcvytrw/TYZsNTWCnkNF2DSIlzWYqTe3rJR56Ac7g= +gopkg.in/src-d/go-git.v4 v4.13.1 h1:SRtFyV8Kxc0UP7aCHcijOMQGPxHSmMOPrzulQWolkYE= +gopkg.in/src-d/go-git.v4 v4.13.1/go.mod h1:nx5NYcxdKxq5fpltdHnPa2Exj4Sx0EclMWZQbYDu2z8= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/warnings.v0 v0.1.1/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= +gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= +gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= +gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0/go.mod h1:WDnlLJ4WF5VGsH/HVa3CI79GS0ol3YnhVnKP89i0kNg= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= +gopkg.in/yaml.v2 v2.0.0-20171116090243-287cf08546ab/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= +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.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20190709130402-674ba3eaed22/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ= +gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools v2.1.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= +gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= +gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= +gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= +helm.sh/helm/v3 v3.1.1/go.mod h1:WYsFJuMASa/4XUqLyv54s0U/f3mlAaRErGmyy4z921g= +honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +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= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.2/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3 h1:sXmLre5bzIR6ypkjXCDI3jHPssRhc8KD/Ome589sc3U= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4 h1:UoveltGrhghAA7ePc+e+QYDHXrBps2PqFZiHkGR/xK8= +honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.5/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +istio.io/api v0.0.0-20200512234804-e5412c253ffe/go.mod h1:kyq3g5w42zl/AKlbzDGppYpGMQYMYMyZKeq0/eexML8= +istio.io/client-go v0.0.0-20200513000250-b1d6e9886b7b/go.mod h1:aUDVNCOKom8n53OPEb7JxKucbKVNveDY4WJj7PGQb14= +istio.io/gogo-genproto v0.0.0-20190930162913-45029607206a/go.mod h1:OzpAts7jljZceG4Vqi5/zXy/pOg1b209T3jb7Nv5wIs= +istio.io/gogo-genproto v0.0.0-20191029161641-f7d19ec0141d/go.mod h1:OzpAts7jljZceG4Vqi5/zXy/pOg1b209T3jb7Nv5wIs= +k8s.io/api v0.0.0-20180904230853-4e7be11eab3f/go.mod h1:iuAfoD4hCxJ8Onx9kaTIt30j7jUFS00AXQi6QMi99vA= +k8s.io/api v0.0.0-20181018013834-843ad2d9b9ae/go.mod h1:iuAfoD4hCxJ8Onx9kaTIt30j7jUFS00AXQi6QMi99vA= +k8s.io/api v0.0.0-20190918195907-bd6ac527cfd2/go.mod h1:AOxZTnaXR/xiarlQL0JUfwQPxjmKDvVYoRp58cA7lUo= +k8s.io/api v0.16.4/go.mod h1:AtzMnsR45tccQss5q8RnF+W8L81DH6XwXwo/joEx9u0= +k8s.io/api v0.17.0/go.mod h1:npsyOePkeP0CPwyGfXDHxvypiYMJxBWAMpQxCaJ4ZxI= +k8s.io/api v0.17.2/go.mod h1:BS9fjjLc4CMuqfSO8vgbHPKMt5+SF0ET6u/RVDihTo4= +k8s.io/api v0.17.3/go.mod h1:YZ0OTkuw7ipbe305fMpIdf3GLXZKRigjtZaV5gzC2J0= +k8s.io/api v0.17.4/go.mod h1:5qxx6vjmwUVG2nHQTKGlLts8Tbok8PzHl4vHtVFuZCA= +k8s.io/api v0.17.6 h1:S6qZSkjdOU0N/TYBZKoR1o7YVSiWMGFU0XXDoqs2ioA= +k8s.io/api v0.17.6/go.mod h1:1jKVwkj0UZ4huak/yRt3MFfU5wc32+B41SkNN5HhyFg= +k8s.io/api v0.18.0/go.mod h1:q2HRQkfDzHMBZL9l/y9rH63PkQl4vae0xRT+8prbrK8= +k8s.io/api v0.18.1/go.mod h1:3My4jorQWzSs5a+l7Ge6JBbIxChLnY8HnuT58ZWolss= +k8s.io/api v0.18.4/go.mod h1:lOIQAKYgai1+vz9J7YcDZwC26Z0zQewYOGWdyIPUUQ4= +k8s.io/api v0.18.7-rc.0/go.mod h1:v6x7KyKMJ7W/BbG7E9olOQshfszuXKKsxfnjaq+ylrk= +k8s.io/api v0.18.8 h1:aIKUzJPb96f3fKec2lxtY7acZC9gQNDLVhfSGpxBAC4= +k8s.io/api v0.18.8/go.mod h1:d/CXqwWv+Z2XEG1LgceeDmHQwpUJhROPx16SlxJgERY= +k8s.io/api v0.19.2 h1:q+/krnHWKsL7OBZg/rxnycsl9569Pud76UJ77MvKXms= +k8s.io/api v0.19.2/go.mod h1:IQpK0zFQ1xc5iNIQPqzgoOwuFugaYHK4iCknlAQP9nI= +k8s.io/apiextensions-apiserver v0.0.0-20190918201827-3de75813f604/go.mod h1:7H8sjDlWQu89yWB3FhZfsLyRCRLuoXoCoY5qtwW1q6I= +k8s.io/apiextensions-apiserver v0.16.4/go.mod h1:HYQwjujEkXmQNhap2C9YDdIVOSskGZ3et0Mvjcyjbto= +k8s.io/apiextensions-apiserver v0.17.2/go.mod h1:4KdMpjkEjjDI2pPfBA15OscyNldHWdBCfsWMDWAmSTs= +k8s.io/apiextensions-apiserver v0.17.6/go.mod h1:Z3CHLP3Tha+Rbav7JR3S+ye427UaJkHBomK2c4XtZ3A= +k8s.io/apiextensions-apiserver v0.18.4/go.mod h1:NYeyeYq4SIpFlPxSAB6jHPIdvu3hL0pc36wuRChybio= +k8s.io/apiextensions-apiserver v0.18.8/go.mod h1:7f4ySEkkvifIr4+BRrRWriKKIJjPyg9mb/p63dJKnlM= +k8s.io/apimachinery v0.0.0-20180904193909-def12e63c512/go.mod h1:ccL7Eh7zubPUSh9A3USN90/OzHNSVN6zxzde07TDCL0= +k8s.io/apimachinery v0.0.0-20181015213631-60666be32c5d/go.mod h1:ccL7Eh7zubPUSh9A3USN90/OzHNSVN6zxzde07TDCL0= +k8s.io/apimachinery v0.0.0-20190703205208-4cfb76a8bf76/go.mod h1:M2fZgZL9DbLfeJaPBCDqSqNsdsmLN+V29knYJnIXlMA= +k8s.io/apimachinery v0.0.0-20190816221834-a9f1d8a9c101/go.mod h1:ccL7Eh7zubPUSh9A3USN90/OzHNSVN6zxzde07TDCL0= +k8s.io/apimachinery v0.0.0-20190817020851-f2f3a405f61d/go.mod h1:3jediapYqJ2w1BFw7lAZPCx7scubsTfosqHkhXCWJKw= +k8s.io/apimachinery v0.16.4/go.mod h1:llRdnznGEAqC3DcNm6yEj472xaFVfLM7hnYofMb12tQ= +k8s.io/apimachinery v0.16.5-beta.1/go.mod h1:llRdnznGEAqC3DcNm6yEj472xaFVfLM7hnYofMb12tQ= +k8s.io/apimachinery v0.17.0/go.mod h1:b9qmWdKlLuU9EBh+06BtLcSf/Mu89rWL33naRxs1uZg= +k8s.io/apimachinery v0.17.1/go.mod h1:b9qmWdKlLuU9EBh+06BtLcSf/Mu89rWL33naRxs1uZg= +k8s.io/apimachinery v0.17.2/go.mod h1:b9qmWdKlLuU9EBh+06BtLcSf/Mu89rWL33naRxs1uZg= +k8s.io/apimachinery v0.17.3/go.mod h1:gxLnyZcGNdZTCLnq3fgzyg2A5BVCHTNDFrw8AmuJ+0g= +k8s.io/apimachinery v0.17.4/go.mod h1:gxLnyZcGNdZTCLnq3fgzyg2A5BVCHTNDFrw8AmuJ+0g= +k8s.io/apimachinery v0.17.6 h1:P0MNfucrmKLPsOSRbhDuG0Tplrpg7hVY4fJHh5sUIUw= +k8s.io/apimachinery v0.17.6/go.mod h1:Lg8zZ5iC/O8UjCqW6DNhcQG2m4TdjF9kwG3891OWbbA= +k8s.io/apimachinery v0.18.0/go.mod h1:9SnR/e11v5IbyPCGbvJViimtJ0SwHG4nfZFjU77ftcA= +k8s.io/apimachinery v0.18.1/go.mod h1:9SnR/e11v5IbyPCGbvJViimtJ0SwHG4nfZFjU77ftcA= +k8s.io/apimachinery v0.18.4/go.mod h1:OaXp26zu/5J7p0f92ASynJa1pZo06YlV9fG7BoWbCko= +k8s.io/apimachinery v0.18.5/go.mod h1:OaXp26zu/5J7p0f92ASynJa1pZo06YlV9fG7BoWbCko= +k8s.io/apimachinery v0.18.7-rc.0/go.mod h1:OaXp26zu/5J7p0f92ASynJa1pZo06YlV9fG7BoWbCko= +k8s.io/apimachinery v0.18.8 h1:jimPrycCqgx2QPearX3to1JePz7wSbVLq+7PdBTTwQ0= +k8s.io/apimachinery v0.18.8/go.mod h1:6sQd+iHEqmOtALqOFjSWp2KZ9F0wlU/nWm0ZgsYWMig= +k8s.io/apimachinery v0.19.0 h1:gjKnAda/HZp5k4xQYjL0K/Yb66IvNqjthCb03QlKpaQ= +k8s.io/apimachinery v0.19.0/go.mod h1:DnPGDnARWFvYa3pMHgSxtbZb7gpzzAZ1pTfaUNDVlmA= +k8s.io/apimachinery v0.19.2 h1:5Gy9vQpAGTKHPVOh5c4plE274X8D/6cuEiTO2zve7tc= +k8s.io/apimachinery v0.19.2/go.mod h1:DnPGDnARWFvYa3pMHgSxtbZb7gpzzAZ1pTfaUNDVlmA= +k8s.io/apiserver v0.0.0-20190918200908-1e17798da8c1/go.mod h1:4FuDU+iKPjdsdQSN3GsEKZLB/feQsj1y9dhhBDVV2Ns= +k8s.io/apiserver v0.16.4/go.mod h1:kbLJOak655g6W7C+muqu1F76u9wnEycfKMqbVaXIdAc= +k8s.io/apiserver v0.17.0/go.mod h1:ABM+9x/prjINN6iiffRVNCBR2Wk7uY4z+EtEGZD48cg= +k8s.io/apiserver v0.17.2/go.mod h1:lBmw/TtQdtxvrTk0e2cgtOxHizXI+d0mmGQURIHQZlo= +k8s.io/apiserver v0.17.4/go.mod h1:5ZDQ6Xr5MNBxyi3iUZXS84QOhZl+W7Oq2us/29c0j9I= +k8s.io/apiserver v0.17.6/go.mod h1:sAYqm8hUDNA9aj/TzqwsJoExWrxprKv0tqs/z88qym0= +k8s.io/apiserver v0.18.4/go.mod h1:q+zoFct5ABNnYkGIaGQ3bcbUNdmPyOCoEBcg51LChY8= +k8s.io/apiserver v0.18.8/go.mod h1:12u5FuGql8Cc497ORNj79rhPdiXQC4bf53X/skR/1YM= +k8s.io/cli-runtime v0.17.2/go.mod h1:aa8t9ziyQdbkuizkNLAw3qe3srSyWh9zlSB7zTqRNPI= +k8s.io/cli-runtime v0.17.3/go.mod h1:X7idckYphH4SZflgNpOOViSxetiMj6xI0viMAjM81TA= +k8s.io/client-go v0.0.0-20180910083459-2cefa64ff137/go.mod h1:7vJpHMYJwNQCWgzmNV+VYUl1zCObLyodBc8nIyt8L5s= +k8s.io/client-go v0.0.0-20190918200256-06eb1244587a/go.mod h1:3YAcTbI2ArBRmhHns5vlHRX8YQqvkVYpz+U/N5i1mVU= +k8s.io/client-go v0.16.4/go.mod h1:ZgxhFDxSnoKY0J0U2/Y1C8obKDdlhGPZwA7oHH863Ok= +k8s.io/client-go v0.17.0/go.mod h1:TYgR6EUHs6k45hb6KWjVD6jFZvJV4gHDikv/It0xz+k= +k8s.io/client-go v0.17.2/go.mod h1:QAzRgsa0C2xl4/eVpeVAZMvikCn8Nm81yqVx3Kk9XYI= +k8s.io/client-go v0.17.3/go.mod h1:cLXlTMtWHkuK4tD360KpWz2gG2KtdWEr/OT02i3emRQ= +k8s.io/client-go v0.17.4/go.mod h1:ouF6o5pz3is8qU0/qYL2RnoxOPqgfuidYLowytyLJmc= +k8s.io/client-go v0.17.6 h1:W/JkbAcIZUPb9vENRTC75ymjQQO3qEJAZyYhOIEOifM= +k8s.io/client-go v0.17.6/go.mod h1:tX5eAbQR/Kbqv+5R93rzHQoyRnPjjW2mm9i0lXnW218= +k8s.io/client-go v0.18.1/go.mod h1:iCikYRiXOj/yRRFE/aWqrpPtDt4P2JVWhtHkmESTcfY= +k8s.io/client-go v0.18.4/go.mod h1:f5sXwL4yAZRkAtzOxRWUhA/N8XzGCb+nPZI8PfobZ9g= +k8s.io/client-go v0.18.8 h1:SdbLpIxk5j5YbFr1b7fq8S7mDgDjYmUxSbszyoesoDM= +k8s.io/client-go v0.18.8/go.mod h1:HqFqMllQ5NnQJNwjro9k5zMyfhZlOwpuTLVrxjkYSxU= +k8s.io/client-go v0.19.2 h1:gMJuU3xJZs86L1oQ99R4EViAADUPMHHtS9jFshasHSc= +k8s.io/client-go v0.19.2/go.mod h1:S5wPhCqyDNAlzM9CnEdgTGV4OqhsW3jGO1UM1epwfJA= +k8s.io/client-go v9.0.0+incompatible/go.mod h1:7vJpHMYJwNQCWgzmNV+VYUl1zCObLyodBc8nIyt8L5s= +k8s.io/client-go v11.0.1-0.20190805182717-6502b5e7b1b5+incompatible h1:A5pdeNsAyGjohGD5QrSFEto0ndr0yDWnbgZIFWvNHp0= +k8s.io/client-go v11.0.1-0.20190805182717-6502b5e7b1b5+incompatible/go.mod h1:7vJpHMYJwNQCWgzmNV+VYUl1zCObLyodBc8nIyt8L5s= +k8s.io/cloud-provider v0.17.0/go.mod h1:Ze4c3w2C0bRsjkBUoHpFi+qWe3ob1wI2/7cUn+YQIDE= +k8s.io/cloud-provider v0.17.4/go.mod h1:XEjKDzfD+b9MTLXQFlDGkk6Ho8SGMpaU8Uugx/KNK9U= +k8s.io/code-generator v0.0.0-20190612205613-18da4a14b22b/go.mod h1:G8bQwmHm2eafm5bgtX67XDZQ8CWKSGu9DekI+yN4Y5I= +k8s.io/code-generator v0.0.0-20190831074504-732c9ca86353/go.mod h1:V5BD6M4CyaN5m+VthcclXWsVcT1Hu+glwa1bi3MIsyE= +k8s.io/code-generator v0.16.4/go.mod h1:mJUgkl06XV4kstAnLHAIzJPVCOzVR+ZcfPIv4fUsFCY= +k8s.io/code-generator v0.17.1/go.mod h1:DVmfPQgxQENqDIzVR2ddLXMH34qeszkKSdH/N+s+38s= +k8s.io/code-generator v0.17.2/go.mod h1:DVmfPQgxQENqDIzVR2ddLXMH34qeszkKSdH/N+s+38s= +k8s.io/code-generator v0.17.3/go.mod h1:l8BLVwASXQZTo2xamW5mQNFCe1XPiAesVq7Y1t7PiQQ= +k8s.io/code-generator v0.17.6/go.mod h1:iiHz51+oTx+Z9D0vB3CH3O4HDDPWrvZyUgUYaIE9h9M= +k8s.io/code-generator v0.18.0/go.mod h1:+UHX5rSbxmR8kzS+FAv7um6dtYrZokQvjHpDSYRVkTc= +k8s.io/code-generator v0.18.4/go.mod h1:TgNEVx9hCyPGpdtCWA34olQYLkh3ok9ar7XfSsr8b6c= +k8s.io/code-generator v0.18.6/go.mod h1:TgNEVx9hCyPGpdtCWA34olQYLkh3ok9ar7XfSsr8b6c= +k8s.io/code-generator v0.18.8/go.mod h1:TgNEVx9hCyPGpdtCWA34olQYLkh3ok9ar7XfSsr8b6c= +k8s.io/component-base v0.0.0-20190918200425-ed2f0867c778/go.mod h1:DFWQCXgXVLiWtzFaS17KxHdlUeUymP7FLxZSkmL9/jU= +k8s.io/component-base v0.16.4/go.mod h1:GYQ+4hlkEwdlpAp59Ztc4gYuFhdoZqiAJD1unYDJ3FM= +k8s.io/component-base v0.17.0/go.mod h1:rKuRAokNMY2nn2A6LP/MiwpoaMRHpfRnrPaUJJj1Yoc= +k8s.io/component-base v0.17.2/go.mod h1:zMPW3g5aH7cHJpKYQ/ZsGMcgbsA/VyhEugF3QT1awLs= +k8s.io/component-base v0.17.4/go.mod h1:5BRqHMbbQPm2kKu35v3G+CpVq4K0RJKC7TRioF0I9lE= +k8s.io/component-base v0.17.6/go.mod h1:jgRLWl0B0rOzFNtxQ9E4BphPmDqoMafujdau6AdG2Xo= +k8s.io/component-base v0.18.4/go.mod h1:7jr/Ef5PGmKwQhyAz/pjByxJbC58mhKAhiaDu0vXfPk= +k8s.io/component-base v0.18.8/go.mod h1:00frPRDas29rx58pPCxNkhUfPbwajlyyvu8ruNgSErU= +k8s.io/csi-translation-lib v0.17.0/go.mod h1:HEF7MEz7pOLJCnxabi45IPkhSsE/KmxPQksuCrHKWls= +k8s.io/csi-translation-lib v0.17.4/go.mod h1:CsxmjwxEI0tTNMzffIAcgR9lX4wOh6AKHdxQrT7L0oo= +k8s.io/gengo v0.0.0-20190116091435-f8a0810f38af/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/gengo v0.0.0-20190306031000-7a1b7fb0289f/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/gengo v0.0.0-20190822140433-26a664648505/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/gengo v0.0.0-20191108084044-e500ee069b5c/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/gengo v0.0.0-20200114144118-36b2048a9120/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/gengo v0.0.0-20200205140755-e0e292d8aa12/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/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 v0.3.1/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= +k8s.io/klog v0.3.3/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= +k8s.io/klog v0.4.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= +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/klog/v2 v2.0.0 h1:Foj74zO6RbjjP4hBEKjnYtjjAhGg4jNynUdYF6fJrok= +k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= +k8s.io/klog/v2 v2.2.0 h1:XRvcwJozkgZ1UQJmfMGpvRthQHOvihEhYtDfAaxMz/A= +k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= +k8s.io/kube-openapi v0.0.0-20180731170545-e3762e86a74c/go.mod h1:BXM9ceUBTj2QnfH2MK1odQs778ajze1RxcmP6S8RVVc= +k8s.io/kube-openapi v0.0.0-20190228160746-b3a7cee44a30/go.mod h1:BXM9ceUBTj2QnfH2MK1odQs778ajze1RxcmP6S8RVVc= +k8s.io/kube-openapi v0.0.0-20190816220812-743ec37842bf/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E= +k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E= +k8s.io/kube-openapi v0.0.0-20200121204235-bf4fb3bd569c/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E= +k8s.io/kube-openapi v0.0.0-20200410145947-61e04a5be9a6 h1:Oh3Mzx5pJ+yIumsAD0MOECPVeXsVot0UkiaCGVyfGQY= +k8s.io/kube-openapi v0.0.0-20200410145947-61e04a5be9a6/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E= +k8s.io/kube-openapi v0.0.0-20200410145947-bcb3869e6f29 h1:NeQXVJ2XFSkRoPzRo8AId01ZER+j8oV4SZADT4iBOXQ= +k8s.io/kube-openapi v0.0.0-20200410145947-bcb3869e6f29/go.mod h1:F+5wygcW0wmRTnM3cOgIqGivxkwSWIWT5YdsDbeAOaU= +k8s.io/kube-openapi v0.0.0-20200805222855-6aeccd4b50c6 h1:+WnxoVtG8TMiudHBSEtrVL1egv36TkkJm+bA8AxicmQ= +k8s.io/kube-openapi v0.0.0-20200805222855-6aeccd4b50c6/go.mod h1:UuqjUnNftUyPE5H64/qeyjQoUZhGpeFDVdxjTeEVN2o= +k8s.io/kubectl v0.17.2/go.mod h1:y4rfLV0n6aPmvbRCqZQjvOp3ezxsFgpqL+zF5jH/lxk= +k8s.io/kubernetes v1.11.10/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk= +k8s.io/kubernetes v1.13.0/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk= +k8s.io/kubernetes v1.14.7/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk= +k8s.io/legacy-cloud-providers v0.17.0/go.mod h1:DdzaepJ3RtRy+e5YhNtrCYwlgyK87j/5+Yfp0L9Syp8= +k8s.io/legacy-cloud-providers v0.17.4/go.mod h1:FikRNoD64ECjkxO36gkDgJeiQWwyZTuBkhu+yxOc1Js= +k8s.io/metrics v0.17.2/go.mod h1:3TkNHET4ROd+NfzNxkjoVfQ0Ob4iZnaHmSEA4vYpwLw= +k8s.io/test-infra v0.0.0-20181019233642-2e10a0bbe9b3/go.mod h1:2NzXB13Ji0nqpyublHeiPC4FZwU0TknfvyaaNfl/BTA= +k8s.io/test-infra v0.0.0-20191212060232-70b0b49fe247/go.mod h1:d8SKryJBXAwfCFVL4wieRez47J2NOOAb9d029sWLseQ= +k8s.io/test-infra v0.0.0-20200407001919-bc7f71ef65b8/go.mod h1:/WpJWcaDvuykB322WXP4kJbX8IpalOzuPxA62GpwkJk= +k8s.io/test-infra v0.0.0-20200514184223-ba32c8aae783/go.mod h1:bW6thaPZfL2hW7ecjx2WYwlP9KQLM47/xIJyttkVk5s= +k8s.io/test-infra v0.0.0-20200617221206-ea73eaeab7ff/go.mod h1:L3+cRvwftUq8IW1TrHji5m3msnc4uck/7LsE/GR/aZk= +k8s.io/test-infra v0.0.0-20200630233406-1dca6122872e/go.mod h1:L3+cRvwftUq8IW1TrHji5m3msnc4uck/7LsE/GR/aZk= +k8s.io/test-infra v0.0.0-20200803112140-d8aa4e063646/go.mod h1:rtUd2cOFwT0aBma1ld6W40F7PuVVw4ELLSFlz9ZEmv8= +k8s.io/test-infra v0.0.0-20200828131253-b23899a92dfa/go.mod h1:exGUBhfuK+dvNp2knbElr498c8UY2UN00oKgfhs7Llo= +k8s.io/utils v0.0.0-20181019225348-5e321f9a457c/go.mod h1:8k8uAuAQ0rXslZKaEWd0c3oVhZz7sSzSiPnVZayjIX0= +k8s.io/utils v0.0.0-20190221042446-c2654d5206da/go.mod h1:8k8uAuAQ0rXslZKaEWd0c3oVhZz7sSzSiPnVZayjIX0= +k8s.io/utils v0.0.0-20190506122338-8fab8cb257d5/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= +k8s.io/utils v0.0.0-20190801114015-581e00157fb1/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= +k8s.io/utils v0.0.0-20190907131718-3d4f5b7dea0b/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= +k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= +k8s.io/utils v0.0.0-20200124190032-861946025e34 h1:HjlUD6M0K3P8nRXmr2B9o4F9dUy9TCj/aEpReeyi6+k= +k8s.io/utils v0.0.0-20200124190032-861946025e34/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= +k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= +k8s.io/utils v0.0.0-20200603063816-c1c6865ac451 h1:v8ud2Up6QK1lNOKFgiIVrZdMg7MpmSnvtrOieolJKoE= +k8s.io/utils v0.0.0-20200603063816-c1c6865ac451/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/utils v0.0.0-20200729134348-d5654de09c73 h1:uJmqzgNWG7XyClnU/mLPBWwfKKF1K8Hf8whTseBgJcg= +k8s.io/utils v0.0.0-20200729134348-d5654de09c73/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +knative.dev/caching v0.0.0-20190719140829-2032732871ff/go.mod h1:dHXFU6CGlLlbzaWc32g80cR92iuBSpsslDNBWI8C7eg= +knative.dev/caching v0.0.0-20200116200605-67bca2c83dfa/go.mod h1:dHXFU6CGlLlbzaWc32g80cR92iuBSpsslDNBWI8C7eg= +knative.dev/caching v0.0.0-20200630172829-a78409990d76/go.mod h1:iyrTBBqVs1H+bmj+mqyGEgNiLBzuGsY1LslIayGy0OE= +knative.dev/caching v0.0.0-20200824162048-b1979a3a7550/go.mod h1:9UKPHvHm1XlyWf2hXNKWCT90EEkRUiyn9lXod7CN2PY= +knative.dev/eventing-contrib v0.6.1-0.20190723221543-5ce18048c08b/go.mod h1:SnXZgSGgMSMLNFTwTnpaOH7hXDzTFtw0J8OmHflNx3g= +knative.dev/eventing-contrib v0.11.2/go.mod h1:SnXZgSGgMSMLNFTwTnpaOH7hXDzTFtw0J8OmHflNx3g= +knative.dev/networking v0.0.0-20200630191330-5080f859c17d h1:/U/lrkoEsrnDc3LHpaKHhy0uRVXpxOpH8eGVdDltsLE= +knative.dev/networking v0.0.0-20200630191330-5080f859c17d/go.mod h1:76Bt5r+xMgNrjwIjSvCvuQwbYG23cTFDIDrxU1ECA54= +knative.dev/networking v0.0.0-20200817055406-2b6d120d60b8 h1:Js1L84C4Q0Xw0oWHLE9iVW3rWq5VCcsr3dJ/6Zco1tI= +knative.dev/networking v0.0.0-20200817055406-2b6d120d60b8/go.mod h1:ZewGJAElO4qPOeZTKuLIO3NQNGAkqcQVu64gHOSiPPg= +knative.dev/pkg v0.0.0-20191101194912-56c2594e4f11/go.mod h1:pgODObA1dTyhNoFxPZTTjNWfx6F0aKsKzn+vaT9XO/Q= +knative.dev/pkg v0.0.0-20191111150521-6d806b998379/go.mod h1:pgODObA1dTyhNoFxPZTTjNWfx6F0aKsKzn+vaT9XO/Q= +knative.dev/pkg v0.0.0-20200207155214-fef852970f43/go.mod h1:pgODObA1dTyhNoFxPZTTjNWfx6F0aKsKzn+vaT9XO/Q= +knative.dev/pkg v0.0.0-20200428194351-90fc61bae7f7/go.mod h1:o+e8OVEJKIuvXPsGVPIautjXgs05xbos7G+QMRjuUps= +knative.dev/pkg v0.0.0-20200505191044-3da93ebb24c2/go.mod h1:Q6sL35DdGs8hIQZKdaCXJGgY8f90BmNBKSb8z6d/BTM= +knative.dev/pkg v0.0.0-20200515002500-16d7b963416f/go.mod h1:tMOHGbxtRz8zYFGEGpV/bpoTEM1o89MwYFC4YJXl3GY= +knative.dev/pkg v0.0.0-20200528142800-1c6815d7e4c9/go.mod h1:QgNZTxnwpB/oSpNcfnLVlw+WpEwwyKAvJlvR3hgeltA= +knative.dev/pkg v0.0.0-20200630170034-2c1a029eb97f/go.mod h1:7T15JzvjKXWnvIKcohz4brrsVq8jvwAcJwWY9xigAc0= +knative.dev/pkg v0.0.0-20200702222342-ea4d6e985ba0 h1:+k2ADqygEgy5BIEahUUEgdY3LbQkaRxbObIO1ZjQswE= +knative.dev/pkg v0.0.0-20200702222342-ea4d6e985ba0/go.mod h1:7T15JzvjKXWnvIKcohz4brrsVq8jvwAcJwWY9xigAc0= +knative.dev/pkg v0.0.0-20200711004937-22502028e31a/go.mod h1:AqAJV6rYi8IGikDjJ/9ZQd9qKdkXVlesVnVjwx62YB8= +knative.dev/pkg v0.0.0-20200811165506-f6ed1766e8ee/go.mod h1:udIbxBS/SJCL4sqnCG8HZArez9HjWmeqJCaVJP/h32I= +knative.dev/pkg v0.0.0-20200812224206-44c860147a87/go.mod h1:udIbxBS/SJCL4sqnCG8HZArez9HjWmeqJCaVJP/h32I= +knative.dev/pkg v0.0.0-20200824160247-5343c1d19369 h1:1hf89VqyCXYwYUueJ+zMrbvbm9oJy46O8cdWkrWFLdQ= +knative.dev/pkg v0.0.0-20200824160247-5343c1d19369/go.mod h1:7Ezp2dJ/stJ4tyrPJ5Loetb+iiwiXNAt+YLrtzE/y4E= +knative.dev/serving v0.16.0 h1:vtYJRsCHSl1PkyXDoDTJ0ksJIlAEEbxyBHqURbbgC5g= +knative.dev/serving v0.16.0/go.mod h1:XG6NOSbtstohsGGl0UYcTazPDMLWDk8W8F0Cd+W9ioI= +knative.dev/serving v0.17.2 h1:5sHdaWhMdoZW+1VKCxuJODcXZCcNSCK/lOU/+ypWkxk= +knative.dev/serving v0.17.2/go.mod h1:uiEM7RmJkA12Ha9VaihrF7kxqCy5faHhQXfYg5isLEQ= +knative.dev/test-infra v0.0.0-20200407185800-1b88cb3b45a5/go.mod h1:xcdUkMJrLlBswIZqL5zCuBFOC22WIPMQoVX1L35i0vQ= +knative.dev/test-infra v0.0.0-20200505052144-5ea2f705bb55/go.mod h1:WqF1Azka+FxPZ20keR2zCNtiQA1MP9ZB4BH4HuI+SIU= +knative.dev/test-infra v0.0.0-20200513011557-d03429a76034/go.mod h1:aMif0KXL4g19YCYwsy4Ocjjz5xgPlseYV+B95Oo4JGE= +knative.dev/test-infra v0.0.0-20200519015156-82551620b0a9/go.mod h1:A5b2OAXTOeHT3hHhVQm3dmtbuWvIDP7qzgtqxA3/2pE= +knative.dev/test-infra v0.0.0-20200630141629-15f40fe97047/go.mod h1:30tMsI1VXrG2m4ut7CFZbLg1VbcRsslPfGU+GWILm6E= +knative.dev/test-infra v0.0.0-20200707183444-aed09e56ddc7/go.mod h1:RjYAhXnZqeHw9+B0zsbqSPlae0lCvjekO/nw5ZMpLCs= +knative.dev/test-infra v0.0.0-20200811030605-72f8c9f3e933/go.mod h1:Pmg2c7Z7q7BGFUV/GOpU5BlrD3ePJft4MPqx8AYBplc= +knative.dev/test-infra v0.0.0-20200813220834-388e55a496cf/go.mod h1:Pmg2c7Z7q7BGFUV/GOpU5BlrD3ePJft4MPqx8AYBplc= +knative.dev/test-infra v0.0.0-20200828171708-f68cb78c80a9/go.mod h1:0uZ4scq51k4xUTJe8zK+wnODCEM+v7pKM6iTKk0Oqo8= +modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw= +modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk= +modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k= +modernc.org/strutil v1.0.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs= +modernc.org/xc v1.0.0/go.mod h1:mRNCo0bvLjGhHO9WsyuKVU4q0ceiDDDoEeWDJHrNx8I= +mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed/go.mod h1:Xkxe497xwlCKkIaQYRfC7CSLworTXY9RMqwhhCm+8Nc= +mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b/go.mod h1:2odslEg/xrtNQqCYg2/jCoyKnw3vv5biOc3JnIcYfL4= +mvdan.cc/unparam v0.0.0-20190720180237-d51796306d8f/go.mod h1:4G1h5nDURzA3bwVMZIVpwbkw+04kSxk3rAtzlimaUJw= +mvdan.cc/unparam v0.0.0-20200501210554-b37ab49443f7/go.mod h1:HGC5lll35J70Y5v7vCGb9oLhHoScFwkHDJm/05RdSTc= +mvdan.cc/xurls/v2 v2.0.0/go.mod h1:2/webFPYOXN9jp/lzuj0zuAVlF+9g4KPFJANH1oJhRU= +pack.ag/amqp v0.11.0/go.mod h1:4/cbmt4EJXSKlG6LCfWHoqmN0uFdy5i/+YFz+fTfhV4= +pack.ag/amqp v0.11.2/go.mod h1:4/cbmt4EJXSKlG6LCfWHoqmN0uFdy5i/+YFz+fTfhV4= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/letsencrypt v0.0.3/go.mod h1:buyQKZ6IXrRnB7TdkHP0RyEybLx18HHyOSoTyoOLqNY= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.7/go.mod h1:PHgbrJT7lCHcxMU+mDHEm+nx46H4zuuHZkDP6icnhu0= +sigs.k8s.io/boskos v0.0.0-20200526191642-45fc818e2d00/go.mod h1:L1ubP7d1CCMSQSjKiZv6dGbh7b4kfoG+dFPj8cfYDnI= +sigs.k8s.io/boskos v0.0.0-20200530174753-71e795271860/go.mod h1:L1ubP7d1CCMSQSjKiZv6dGbh7b4kfoG+dFPj8cfYDnI= +sigs.k8s.io/boskos v0.0.0-20200617235605-f289ba6555ba/go.mod h1:ZO5RV+VxJS9mb6DvZ1yAjywoyq/wQ8b0vDoZxcIA5kE= +sigs.k8s.io/boskos v0.0.0-20200729174948-794df80db9c9/go.mod h1:ZO5RV+VxJS9mb6DvZ1yAjywoyq/wQ8b0vDoZxcIA5kE= +sigs.k8s.io/boskos v0.0.0-20200819010710-984516eae7e8/go.mod h1:ZO5RV+VxJS9mb6DvZ1yAjywoyq/wQ8b0vDoZxcIA5kE= +sigs.k8s.io/controller-runtime v0.3.0/go.mod h1:Cw6PkEg0Sa7dAYovGT4R0tRkGhHXpYijwNxYhAnAZZk= +sigs.k8s.io/controller-runtime v0.5.0/go.mod h1:REiJzC7Y00U+2YkMbT8wxgrsX5USpXKGhb2sCtAXiT8= +sigs.k8s.io/controller-runtime v0.5.4/go.mod h1:JZUwSMVbxDupo0lTJSSFP5pimEyxGynROImSsqIOx1A= +sigs.k8s.io/controller-runtime v0.6.1/go.mod h1:XRYBPdbf5XJu9kpS84VJiZ7h/u1hF3gEORz0efEja7A= +sigs.k8s.io/kustomize v2.0.3+incompatible/go.mod h1:MkjgH3RdOWrievjo6c9T245dYlB5QeXV4WCbnt/PEpU= +sigs.k8s.io/structured-merge-diff v0.0.0-20190302045857-e85c7b244fd2/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= +sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= +sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06 h1:zD2IemQ4LmOcAumeiyDWXKUI2SO0NYDe3H6QGvPOVgU= +sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06/go.mod h1:/ULNhyfzRopfcjskuui0cTITekDduZ7ycKN3oUT9R18= +sigs.k8s.io/structured-merge-diff v1.0.1 h1:LOs1LZWMsz1xs77Phr/pkB4LFaavH7IVq/3+WTN9XTA= +sigs.k8s.io/structured-merge-diff v1.0.1/go.mod h1:IIgPezJWb76P0hotTxzDbWsMYB8APh18qZnxkomBpxA= +sigs.k8s.io/structured-merge-diff/v2 v2.0.1/go.mod h1:Wb7vfKAodbKgf6tn1Kl0VvGj7mRH6DGaRcixXEJXTsE= +sigs.k8s.io/structured-merge-diff/v3 v3.0.0-20200116222232-67a7b8c61874/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= +sigs.k8s.io/structured-merge-diff/v3 v3.0.0/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= +sigs.k8s.io/structured-merge-diff/v3 v3.0.1-0.20200706213357-43c19bbb7fba h1:AAbnc5KQuTWKuh2QSnyghKIOTFzB0Jayv7/OFDn3Cy4= +sigs.k8s.io/structured-merge-diff/v3 v3.0.1-0.20200706213357-43c19bbb7fba/go.mod h1:V06abazjHneE37ZdSY/UUwPVgcJMKI/jU5XGUjgIKoc= +sigs.k8s.io/structured-merge-diff/v4 v4.0.1 h1:YXTMot5Qz/X1iBRJhAt+vI+HVttY0WkSqqhKxQ0xVbA= +sigs.k8s.io/structured-merge-diff/v4 v4.0.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/testing_frameworks v0.1.1/go.mod h1:VVBKrHmJ6Ekkfz284YKhQePcdycOzNH9qL6ht1zEr/U= +sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= +sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= +sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= +sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0= +sourcegraph.com/sqs/pbtypes v1.0.0/go.mod h1:3AciMUv4qUuRHRHhOG4TZOB+72GdPVz5k+c648qsFS4= +vbom.ml/util v0.0.0-20160121211510-db5cfe13f5cc/go.mod h1:so/NYdZXCz+E3ZpW0uAoCj6uzU2+8OWDFv/HxUSs7kI= +vbom.ml/util v0.0.0-20180919145318-efcd4e0f9787/go.mod h1:so/NYdZXCz+E3ZpW0uAoCj6uzU2+8OWDFv/HxUSs7kI= diff --git a/imgs/arch.png b/imgs/arch.png new file mode 100644 index 0000000000000000000000000000000000000000..188d6bf13bf313741203f3d7c886129a14d44fca GIT binary patch literal 567493 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

=@Zp#p_FH$9~~Tc~~S>WuT9T&S3Ge^#mNo zY&tK5)<@FCu~|LUl>!RYdf!6xG<|4^PTvRzn?$f=>jaR+mXF@AWNW!v9)5h%7(haB z5lS)E^QP^&k0~9>?Wwls8XE#inIbbm`ZIxzC!74>YL%u>AsP}N>8{}I1m?yLshHXY zq{IB{y9VH}C4;(T{q+HLTLNd#4|c=bP7UBY3L&J<(}zRjg}b6zum$^Qi+W&fN^p;h zu+xVPmN9=Q|9@eVBKOf;ML9{I*Co$U_Btlj%DRtGK6kgK z&8A+&3iV~?o?`=bdE7@;eQ zBy9PoDx))s?DQEVNPrgOQH&io;h+g|H_izpr)04R?SvPISRukf^~Gmc@jT+2B>kQx z`dIR-u8oyuBnW!Cv65v|umQ218HUl3IAm z%KpG=CU9d<_g20?Vy3=BPfzbE?6CmN?LCOlaRJ4;E_1Fa6e|Hg+o!3Ghtr-C%-507 zhvhIL$mpZVhxIa9KRj_#R5-(v9I7b14un8nxwQQek4OK5%YK;@ackG}pB}fJ&huWG zN3U><-+$r0Zq^|s2;v2Dw7oNhHyhl8-QQjifAs*pv8PEAFy7bg=##EI28$vm7K^%u zFA`fLeP;VT?vNMp%x@hJ3)uBUM z(E)6jw}-dhjD#UYlqZ$GiYXsqmD5mf!^70}u^;N+6FiG}h|5@_yvm~x6rpzjCH2Og zb@hmBbd?H*_%b}3(r_~$`u=$-KuY(PBw+e_n&wtV-IqfhK3uHNzjb&85s5_*XC(*9 zAS`kn|`tHvPLCFyfEV5cHUaFG;^8%>Sp{4!=_o zmB6D$V0nJl=EjT$BUfB%g&Y^3qgu9n!`_|wI9Z`>LpyvsLxW(bzG7xnFWPLf7 zntpaRSxV?ll9ON%lLI6!L%((sM6hf~lkSwFh3VZresq!|IxC z@9X7gZ@k+`Y*lYZ@q2JH%_8m&VS-SGKUzW;4$tzh0wGPLI$w@w z#N9_NgUY#OmdLvn!>HO`cf494fx>)O)#wRws&9h|#+4-#TNd}T_nw|&D4k_P%yOc2 zYV67{(l?U%TZtT%0A>!G4jdBTCbyR*oRVIq16t^<;oqLx24M;iq<^ssxD_YSs}zdz(n;Kz*51xCcB`Mzu`qS z^x&F@v{bfcHa4f3=V`)T4oe##MeInvX@FdH3)x!@2#C*U@8?58*g!f3ur~I$1DU?q zK}936iol^nf>lEJ{fFWRuOW-dB_59z9@n$;^x79?=M)aDS0x&QFCz+j0^h!PFMEf3 z7pO;1r+dO5D^vFqPnKg>(`}K>OS@pCUFyoT0Nf&QtK;ikK82xw6s>K;^f?$LenWpm z(w-AWP=7?|l-_TYW4g8_5$=yj;wuUmW?~|wUBz`f-4(}5OMxJ; zNQB|uofV-S@ltAhG3Ik&jTX!_p$1syQM@_{H1GrF#0|IaTL@kz(kl{q9N)>HOeMP5 zw&(%k`}g087~Z^DB1riDoo$5-`FOnv`oBY9j|XuTBen{ALIjpc@^NZD`VEt7Rtzsq zuN|;KpopbTmF-GBmM4p`kT-H(aWb(*Zg;F_BDIc-4>%ebLv|GpUmq9gwG`TFBaa9N zMYAM}_oFXr^&P)K!RQFm`R#bX7x8Ts{HtmBvwxuW^<}?N!y=3>bInifwOr(;K_Vd0J)m5!t1x_|)C8LK%kBJs7D) z{|qe6`mH`MDu^xku6eK4UdL}2Lf3X&oo46+?ynV=J06b1%P)I4iws_AjjrmeT)rh0 zk=s`b^1s)hQ%VZBLgvAWxTsVjU09pS8Wcu2sW^5(N3Ag;QBS)$EbstlUqu5GAt%+| zngc@dC7?s(vpv2zzZ%?Ei^D|B2Umj7w-*^+HuCwOkkNnnv;Pe_nn?i=8F0bspRr6t zhNuL5ELtT^9{yMrk3fiD$s(NmlcHY_@_g1xfd6+b5KdAUEp-l=@jki395?}}<28&& zYlR?u;C7{a!+vcXO$uhFaKcUjprhO;j`_P@naY@mRF=uXce-hJkhE~I{)gl1p=bu& zHX!lN17|@I26#RqZleSlK`e|FNYYo=MNPu7@76RS1Aru$yKb8jq`XgM71#GA@;WC_ zq;%?Go0d)31L(*I_pHyfYJbpMzwfwz zKZoDHN_~Rn(&HV!2gA+pUruwwM>1R~^o~QylAz!1=KZu=-h^kVaj)Dz8mY{_MbiUE zfj#n2+3xoiae5*ikFg9SVrX$3>m(8l@EEs+bUkj@ZlU-HISRUN-^}}1P1WclzhLAu zpQy0PpC5+?uLr!QNVEgtxH?&Fzv`k*U(OFv`4B1hIT#x{UjbH?~!ZCAe#X_`iwEO%jUOaj*& z+v83oX=vom^rCIULjzz;k7MM~$iq`cGXEbky#B+(@~c2nA7m6)kl@nuH@>LvE6OTR zYxa%-+HgA5Z#I|{W|sK#F*007CD^Y!nh)-M_Ck6+BGlJh6MqX%vK~l;N+FM8jPT8b zdYbL?>)gCEf=1$`TcHFRvad@3g}H9J?6rejC*5^$Iu)?xayxd?2wI^ij4ty5|JQ&z zkLSO}rMUkZ5dKjelC>xL!Sj?#MJ%e^s&Nqj3cHJU%a{|ktsFDtQo*oNCMzxVZ{YR6co4x7u3f{ji z+O)JgK8u#Z)IC0jpVW$}Z`9MOMa}rc%2_9K{cFrI;`al0OB*;|5g%?@7XYvH^R5fS zvhNb4(TJtY9ms#a#(rhK9_sREsL4GbMzsdaW4TndJ;}0J8d|6-Do*P)I4<_ZhLnpd zxZ!Q~vf)Sf{eUK1dL_MsOh0>_==`ZQh+_xDYbT4VYKhaiWvoT^LFe$u1$Gt#!LLcR zY@%Ps@~HxR#d=|C&mnylsKpKpA3M<*5liar}OfFn#0Wmj=L=s;4v1{xO0`)mTBRqib_ z!+!6wVa+MbH|u+`PA(KFH}Ce%^ZW&PlS~!aDw1*hAD`}DlOY2)07}G3vRy&QZQLo_ zbd7-Vo*XOsC{vnKPKwLUf!9@)y$@ni0}p8Ta~+Wk6;uTvLPE%RdI>+(^qy1tC8v9n=ZWzR}+3C4MpA_Q%I=V9IhLS$yaU%I( z=4`+>$9H8r&CBm0Xv;(KsL)<9`9Zv*cHnfTG-0&d0k5tpV#(R-c0oh;M_U3?q^Q^& z1ZGP}moPZm(x3ifWFL`*xfrQL4TJGL7U8GDq(bz z)`GOTBP{~8>U+9DtwvN&xBXlsSTPU-m4CfYO;!XfJCGV3xw$r!Y-_Q*iB zHFI$CccS_s4gQ{8-#q6*O5Ov(OF6ipJFVmBiqnwejR$hZZ-% z{iNrgxb3IcnRZTf%*4lc^+w(qHdbuqB-uBN4;PW%GZNX{qVJU<`n`bsk87480J%^< z26r=xrZEt1i*x*R#%(Z?I%77HX)YNc^{FT_qOY&`QoJfwt<3LZxWyD+OsJcEes*3_ z^uA2XPw@%AorU!|UmlgA8qs9VX(_AW>&y$(02i?ij-AE(G?bo|{y8Nx;G)GK7Ljvj z_ryXOBqMwoD%2iSPp%TiLHTTv>=5953OyYMGD4=3r8CdH|4#K+lcFzW2w7w>;9?vI z9{!;7YflEqsJ!+fNx5ycDwtO`h?zD1P={{QnaQV z@wx39nhjCpN?t9P^shl$-0@a&d`VzITi10P!1Jr1kOX_|tB!h8xX-}vDCs+n-bboR%Wz;-iP``J;`W`_9{@o?3NtB2!?$?hyhM81mbP~O*`)ptTPsZr z44Z1{cX{Zs{aR>du^pcNc*VYQWI|@gJQ(30PgIlX>cc-ZaGZXYq!hOti@dcSZY~$4Ww0p#-wK(yn>@ zR#_qie91iw9P)s(^#E~Z7jwqYNo0E;6o0CaXq{$F8e5ARF>ED@#tBxJVKD!7c;I%M zBZE#eF6@}ue(Q|vWx1B9y0<)VtC;L3blt??;~zqDNVxDcGDHRQ*{Hgq2_w1=#C7O? zaLDHCg`@(K?~3h_G7=dO_rafVcVRW=oA0XHYou~?3G}}&7Xp#V*0@MV8Xvz(6%``# z1U6o>^Iixt-=Y3{2N(wyz51Lr&KvzfRlukm`+#+HHw)1I5eLiO0jOP0U!>{z#A~c; zAWOvw*^Kt(BZK5lRD_YmC@yOOXKlX_#0&dRgwBsl!~2l>=pg?mc!GdaJ2=B}qO1yY z9dF|n#6a(O$o>C2MGjfX=P}mtG5gCUOX7Kn zlJCJ}aR=3V_MQJDGlCX|<<4s}xnHlX9(4>g$RP-(rMA;GZ>lzyEjO8NNLKHk#Ldi% zc&>N6G0gTrM+gOvl^%5*p4~{QIWi^EMc?dxTIEgVprLQb`|YHBe=}VA%xcod%5Y)# zUHJjqzlH{pDvUaC+VvJPjNg|~68312hjS2_AfBs}%8qHS$9(JqAg=+nZR(|8)ku@3 zA}xYBT5jpak!fOxJHgVMtK$z z)Ou3h9686cXqy1lbnSJ~a`R;>PGq>u3~k>D^x^gZjeHOKvP&ekQDHwb&G69AzwC@J z(y-2PQD%3&ye|=sV6KvI@cfT_1)r^VdCW9K=(3i>7W8ah5WT|19W)IJJrcFg+Ep+; zZ0VdrsqVe+xmlazT11>_P^?#5>Qu@TfL1F$py?QPCcViL}H(k-76ojNtuy_Nq2@7v8e7 zU+Uv8_vDn~DC4c>u3$#)LG))t?*eq0T)>lVv!ei9)IB`38ZTwO`L%Y0-HY;lD-(^)Fazemq?=VcO7Aw_h4vC*HAeS-pC+rj3wp7KLNUm%k2xd$(&}H_#^!xIm ziMwA?hfau?Iy*LABuV%RJ-j0ev_g#>fnTPj^4hw{)EuUkSL1&Q!WaGbldKrJVng8QJ{>P~%QhIy4 zae3dw>s2y2tXo60r*qO3)Z%{R4Th6dntN_)lr~t~l?guNjlY)fdkdfcNI%*Bl)h#& zxfos)|K{ZU`YGrqy0+d_Q|V=Rp%bi-S5i!AoHQ^1K{#oD`()tkcwx|CKk8@4XjS)F z{NGDfnKsQ=HHcj0Diy*pRVPK5Ax&F!t^0PQw8(BK&-5~RI_d|yBb9qDdrpGyL1pbB zU6bBqiI7y`M^|Mg3@AuBUY`0;t@<#tPBwKLHA08Nm;_ z>y!fR;znq!Q$-j@Bj*GB-yk!6kVXNtDr9)zAPH680$4{oK9Go_40k8KEw${;^1PYi zy9!)4Z=0ka{p;`--R!YazO<3g?nG+{;RYAez-~wCCB9shB%edDR-r_UA>eeZx(O7> z41q!z8PDC~UI6;dX)|Rs<%mX&h4^rVj*PZAj$>36y3T~iJsG?d<4WivYv`&{8nz%= zuZ2@JZW#e?rB2gGxPFI4`GURXGMm)Fy4PM#>z7(7E86%*Oo*gmV;QfbN z=Rfxlz-H4Lh3~LNGVodfw0{-F&@A0o<=5iL-sa^*rX%Is%^?O@$vc~ z`{;SZw;3@1I{rDz(b)c=@n3V2pDm$M92w$Uq-Azm51u8iN8DOMzL7cl8WTq}YGVf^ zEkhd5V3RGDhXy@i|I;3}j@L-Ow(lrycN)An$^j`LMC`0XN()|}^1UreVJ8uU|Dh^f zpaI#H=sj*mcYj)yf(#TwPQ$2dnB`Gdsie~~d|f}kWoN@QBhY4dCfJ|5tY&k5&Fox| z4dOd?fsk_7mLx#03l`P7m=AQZnxYZOlU}T2R|F}xwIn3+McnX12CmXhgb3<@7PS8R zFd&}x;20;tiK$BJrFkfnJ9*jlW zd^yOYN-mMJi`16V3;#0>fQ9A(IHXa-wW+Al!au(emID|kPIb4)4q+6f)q{Yckqa6$ zN8+4stU-WMZZ&*Z0oOQn4zd9#Nqzte&=ZXoC)QW3uj7dwZS9xfl_gN60{Cx!3oakq)a7C+W6vh{I=1n(;Z`eWR9`rN?7Cs(RQCL}rN4NpvYX zHVJP5qs{F4czLK;e!}aeo4=EZnaoI@^8adfe>uU*9Un#LCvt#s)Iw#*Igjmodh2MO z0MmykVy@AKpDf#(^Ad&T)~X?^p>5`lEd?{#LKYrBihjnJO->>K&Ck)1X@WoVQX$UJ zGHei}_8f?AqH?HwtQn#(ePdbNi_Cz>tc{9~=@N65k#KD=Cmbp1%!4&0Go=SSEOJ^{ zD*1>jo2PG!K<{Y;-=={%HF}-JCx3SG6z}5|a}dz?j=YrvkPdfV7x0actxtveEpA1mjvQUnQEnTB$dXZv2|1ciu%; z`{CQB<4XLrQ>|=0(O|H2NYL#AfAkVxRMeZ)GLbhIg&S#Dwc`)r2_ZMQx{dYaXi*5L|8GA0QpK7i?KbT+%x!KAU){B!%HBXObd&*1h>|*Yt<${f3sz+)epnHqD*KI_CypL7{ z75QN#djT->`aP9NhU((E&-4NUdMzz2wCwCE;1|pkBr$SYf#8~3n3$N4Vr^Vh)zxE* zKe1d%(n*=>$NF)%m1FxxWI}?KMzR$-H>auTAsCt%Kmhe9aAvLnd|(@qmcS;f7#iB^ zU;k@|spLBphiNL6)^W8d02@Q(F}FX> z{W9X9>sA8MB9fTbZ_>tGw3n({xH2l$k>H0W<@?9StP<*U$y?GECO0~Nj7v%W4r%(^ z8gL0r-4)RuF4K0LpqDRsD=tzVscCC70_hh8DJQG%OZ~1Juq$a=Tjw`%;D$jLEh{7Q z>az9T^v(At0jp(Y?1HI1Xclm!528NU^15$JiWza?|Lx-mD=HDS^Skd|(-FR^XgEIt zX#`s211_}IWMi~4#`FxKpayheSeUZR-#}TwGazJmuzJC0TIP=x{Kr$$Pi_J&D;>|Y zn`x2(Ib5x=1E+m;kOkWR+si<{Y?1F*x3}ujwb?Nve0i?k6O(KwZNXg-;lH9NS>=y6 zX=A^NJ^94}wf`q4H+GPm%PcjJO|uNA|YgErq7-+os7^L@x`GO(PgqdFR7d zUUH^oR~Z~=Qbu^K=GyZzoO=rq5D+oErD-N0xpA}J|5=#ShY%Sy2{r=tNVkzy@V!>|G{U|%HN+?iX3v@U@w}3IGL=Y&KR6qa3ub@;C<0N z2>jrD=>~WuGc!}HFY91!R53jx!;=8@Aoj1HY6`~O)^7`@!cCI+_oDjypP-->!IPpu z>ztHsn#8znU^*+>K4KFx$JWm4srz9(^`k6xb($J`)wQnavq}|JL*_OFB1*SJx6H{^ z+S$2sFAO6#^5Yk?OoE%CH=>vxUfzp+yhyqth4%5;wN>u+YPK-8_D~0J+KKl2zrSn& z#aW=k;$g7Vu${RWssq;<&>}C15!#Xa$4i__6>)d3Wznlq0v#rYcBOSJ(Y0&X^Xm`I z%rY~xv#ThJ`hzM$cEhUnUHpxXvrhcxJ*(3kx zes{E^;xF#DHa0ek!oPkhCSgGpzXgY%4PhU~e<)DA>}>;*AJ zz{WtAdfs+ie#a@ zh=+1dI@p-gb4q;5vGwQ4$=bzfkH=Tu;uP15-iwY^%|w%Wp`ts=aGo#E?MFicW|d{otGDD=_(T_z?OApB)&A#&WTKTY&e?0~xc1W2fXV9cIc(o|QMc5|z- zYA7sZA%&<{D;?Jm+ThJ2wQ+jnZ(k-yeX6-aUVM-h7Z)d^rKbL8Ws4r?}Z(29I^z1!2vaVNIyws&`<^6gyUZRp3>uqoI zvnyZHNFL&GbIKt0Q5f$|v7*y?A{q&3UIYfnI6kP`Q(V8}z;=~jcFXm(6ywhb0u1Au zMA((>q@%nMmmHM6yy}M-X>hq8&Nn$D5V5b`*~kaFrafa~^$$PaE$^50vbMI?MjPo9 z5ezh{d`pnT6l=W@SPEI0d3+`THVUFN;3kvC>|NB&j#n>XQm8-(2?xe(TgWt3Cgd=K5)f4Mmsm-&+ygrv$o0vX@^;kU2Osj>*QDPDF;_R$uOrFkb^%57o)ox5PZQLdxA`D&MNqv^ zGw$L*Kj=+ak%cjZ-&F>@pcGYuk;~@L!m&g0Q{bU%j#$~Uf?~864RmpSy|qg69tr2*fc1BV(k${{u!AmY6SJ2=emsu4?H@dWeg^AfamBy(%V+f0Oh9 z-LqlV0F3Zi~o~a%AXk%(}i`ac>!zl{RbYy7SD%-f(Xcn8K0dT z#UE7Ln`}BpbLbK!`gwtvdKS9Xhxg0s0lu5?tBC*v6{43$j z6ZnyDZwO#NZvS@=17~{^Kjy3#+14DigvXZeVnJ(}bCfG6B}f1FgM@=)w=~zPtQ}!58T8hOGFA$zJh;X2ks4GdT4dWX{!Av26wRf zpG8rmng-s(N4pH;SMdmD`7KZGb>(_V^oaiB2-Xk1fG(xK5mZ_)n0kQ(i-v>^Rg5G6 zTayFe=N*f)fX zO-v>FL`u#qMon|HQ>gLwBHc>7kXwE|RFV8mN4h9KrEINNuUytR#3Z)O&>{!U&rbFv zI=Z`MhU2WgLdB)r_**VXnTmeVs6$=CIIx&>xz!jM=C9%}Kx%R7xU%mc7&3T!l#Lmaf zl9e=ZLebq4DK>*T9GHH}m$)7l!pwYF2fB8}c>v>Y6Rd8w_ft(`Dluc;ZB z-~8>Jr1mS8x{&Gu%{RTfyL-y?DU28jKp(Pz6)iQ@aB~j}?;$#9*BVaG4;wWlDt7Q5 z+7MVLGs}+5>(#(d0P?r9^-{4>I+mwdWbMvR(c)=ryCj5X|Tk_@f zIpdu254z528t&{WsHtbfDta0;wcUdQ2PrQmCY24EDH&OqA}8KUSgEz--lluxC!3c0 z@*b(6W18G`KDmIswSwnd4NOG_o`m^Dnxot|nKUQyE?veYkI2tw+9zR#VPA?nHHSSe(&L)O>XY4eo3SEBBWlrrwI7CP0U zeAmpoHYXJ&r8E+1(I?O4Uwa)N#AddN)k}r&x~ceAXGTQe-!buzz?{GBiGoXcHJJ+i za-fvHUFiEqSG7p(Krk^nD)}IWCtLa1B`Gzx*GwE*BX*rp1a!PMx$mOQ>07sB zXb`Ia1{B?5N28s)qV07iQGo z9}}9L@ISjSBRZKQBeB6@g8SR~3dce|G%Kt5ieVd@4rtT|z9p!r*yI6e=^P>=;q$lT zRdjunx(_rzWf#?!c`RsX*IOmocJ*pLc;m=7mWxIy)Ar?NiJvd}o7nA#m|pWShe=k^ z5}$@jGibS)RH!Yja_#YdU7&lYd_QJsiNx6ACw;iBeMtU5}z$8_kiG zFb^=$dx4QB>dxVxmVFDA-eO`=hH^oh)XQPf;GW=^+B*S`AOfag20Vom1jHi0$G`w{ zQdnoF)Jg%G^uY0euGQryYE{=7%aJ1VqNie$sT=6B zP~iUDRDPTC7q;>?&|j`VrPT+Ur|QI~?k9hJ_m3Z2jzVhy7ZNhrY=SHK1)t(KegH!k zGouxv;EKA671pIU#%XJy1&D-OT-Ck|4o-e64fU-~GY#XD5Q20jqypQH;N8EMnh4?S z2dvAe|7qCs6-1$`q()i1a1rLYYXtYuh%9fQ5e1Z_bD)zS2|pMK(=Rh#!_}^K|Bz|1 z9+57%sG{vG;!csTeDn3OMmS&5uM;I6QHDXc5`#;)q|}4AL*jni3Xrl?D#^y`lfpPZ zM_IKm7khrGi!C}pO76+)FxS1y{e~3hF6_hlZr!7(bv^)6A*c zS^kwGO0<~U`Z4K}y%_!_bqx*1AN@js(_vrjNZX&$lwe|EeR*)pc0_FI>eZ_g4^?2^ zhTvYk09>-$#&h)ud*|{YuFH&bN}tM`Yu}1uM#sc6gz%TBwdMD-Z$9?gHhM;of%sJB zoMbk*WOv8v+`IG34W0JeHxpwIv+!3aC}_^27h>rPMIC!uud;i!Jl;R`tX$e!$KLx0 z`xs4YV5?_K$>K0*@wds)m3kYl7x_f2sYkQeos{Q=fq?;4qef)2W&s!Jar9yr{`XHK z+o@_0!1N#eSjZ|Y>@oI1TEuI?|86#vtBkulPLI5UOXuYtOgNMD6gzy3jMAU$?V}*Y zmx^FUU8t$-KF;HW7a%^fdZ=%1B|$zy4Vks<3kx*g!R{n>uX>hf z1OQ1$5x?M%`H*GcCK{UB)`i>+(xZNU>MQOzKAH4Lo1 zSkmYKnVDA0v+;vI*u9x0B}!OWSZL9S4~y+w z=3NwL)baO!7?Z<<(Kb7rtBf5*P5rSG8w)2QfAwNiLNv3iMp68F^3%M6B0^!}8Sc~d zmCggCw@W7x{wz;Uvi zTomnx4bKR7N>%nO$hAOpCkry0^&zY5y$jpmK;~0T9$lPkmw4w%Ym5KKZxZ35ZgM5w za(hWc?cU*Z&jx))^m8ux4M~Z>o!LJos=urJvI5%a2UUx)YXr-yXce83&Mn(d(IU~% z2vTUGa#hnaCf<86PHHmhx{`E%sU$74waYfM9nYKBt(&dD2-B%+*DAHsK)q#1cQYtF zIFeMgo!Ozwh)xJA{vubU-6Jb&>loiAYC1XVnBz-}4mqXTr!l(&UkyA#xERiros$`I)Rgx64>ImQ&<4~wQ%q=NVd-dwD>&qe;Vmad6v8BR+eJxj+ z{fUU-3I*}qW>LSYuo&Ds-51|%>-*zl&#+Zov&Fee(A!>lIp5^!?}OD{d?|T(V)B22 zmHp8eNd6nQO%jPW0E^KHcKQ1u=(~eJJViV8@<}ockymQF!MrI8qHf)Zz);$t(j4LvQ7wJ`| ziL7mKJB#bc89QefZ8YyjrllDLX-r2%9UsJdU%VvSSV8lJ$KCf;a5VMeXX!+*%(r=> zo_B6=S^91c63~ft_l#wW%LvJ^SPf$oy zM>+}2$ou?8IL9X^HZaRc;a8K+aJ`DSpCt6@_c7=1RsOF}I{W(Kea_Yl9Nv0KgMa_w(~9ymEe*S`x0%0GcS zJJ_7c5u6kuAG|4GZAf?Vtps6RCxfEIk01wj6tCn(e%M|Nqm42#HMsPDrX2#o!fGnOtd4P?8 zgpww@Jwzil{4|y!Pr9spcgRi2gmRH9FH3GMm7D3Ew!HjhgzFE3pB`O0U1O;^bxc(|Gy(z?xOTy647>FrNBHlYdl}-yRwA>$CW%$cqDZ?)q#; z@Gd;Gw9GwtYSzO{_9K-y{05f{GP;-#gsAet%y;g@0@J9AmqCcTe5^5bPqIvg0z8$@?1prKrEZe`Zyc1_%2mC))X0 zQAxpjcPgyZ(#Z<&Nk~SRM3`7-=woB2=|tFVc-l=W31sFN81E8|r{=Z6s*rge6UBrn z%_#F^M00*|!6D~WqWbY8#Xh1t#l`cOvJlU9tVDEYXJ=1YS(zp%C0g)D%Xjrmso_;IeXr;5kn=AF{g(&L0#FHDyA50*npU$MPMd?G;~ z7_e+_#JtbgG?fT-K!%WQ&vuTgbO>!I*8H*YqO+4hT0ubr`!S}+ zJYI0LB-8A;(Hvg16U3bnP+om|P5Q^_0ndy#njeGpU#C~=;lVQqMj#opI ziZ>G*zxFz%E6&v(8q&IN57iMbcJyLt_$Jw(1gEE)X8mfSVK*DIBo#6V$!u@yZWF#cGAN;|1Rp4+xJPSnclTg*asX9B%kY(o`Q9FZ%N1Y zOF16Qj?r)nqKX1YgibO?`Z}F}bFKE~z6+92Zay$o?Me2;Hi8N9SPSkjk8Ilu`TVBl z5DYb=PTScDwl_;7hvEpAo)on}^Z$-#aw7ZT^Zk>VUkzNVa7(NsNRcbxcTvkAFVxI8 z6N09xcmc#7cD3O5s*qZa2wA;2@^bFZ4mf*UWnRCUiG%jV5-;kgsC0_i$dG%&Zzd5y z3Z3)qKw+up6Hc>v7ep}y^pO{Cj(+l&@nHi)Qeo=8taC5?jYVaT3Q5rwtw(>80C&L&0DP1M@wEaP7wr#hy zFk0rilmN$w%dzP4G(2Z0_!3+FwuRshu9X^UaGZVJiQ$QP%-gV`Au~SHUb#gSdTD>u zi|B~Ux#e$se1|A=HB!SI&2|HZqiP+BzA>YyguW^$cp>#YO;ulTx98{1hnX{lOIIi} z@7!%TpZR5t9i%X|J}37vrt+4Y&}UxrfK}IgF>&$LE=jGV@q*j$*g4qEz@o4Nx<4t{ zXf_*~`p&UmpA2r9LA=sVXyUR5sE)o7R`w&%UPg!UEm>ABtG_G4UtHScjH){h=^8+G z*WFk#Qe12k{0gCdt<5TW11u*8qYR}HA3h)YnKCZ!cPa+ewZsHwT~F{_7vqx;ifqSI zbgEX0-{fdWIipLO1enNZbJB~c|FZ|#f4z0 zibXI&4v`7kl{YydMZTFlp%d-ZuA$#|K=73y#Bt&|Wy}Uxm|y4WV>GwOrXw3xqg1NY zhI_qJT#sC#Y+<*W;a_6^gUeRD**`p^KD&P@^}@zSxFtMm#_JDu3m7VLtQR4kk=I&` z%9RWaS$%$fGOU=*k|Skt=9=Z%2=_V7`1<(c72Nup+V!q)h1~f3zh?(hdPtogR5z}; z;%QD?B_(AFDHrLh(=Cx*zIKTchkW19}8sVK!t^}Z}fZc4lWj(e(DWJih` zu1A6CCRq;NgXqOAFf-O~!rG zSmPDWIfYU)>ETyM`BWO-sU*fsW2Dn;#O2bLHL9SJFIM%faE{(V&g&%#UT(*I{Tu zrMvxk_V$fr8j}26rPQY^g|dlU_>>`VHxX?DhijNz%6<7u1uwGG($cuKB@56yA<5Iq z=Gp66_S>Y&u3};}-qYK@X1Y8q*eQ;=mrf(tt%DeW9pI;}S!E80(-c@5Oq8$P zeRow!LwVqlGm(xCUj=K2>KiuiA94=8% zay81T?oS0nyDE~4C|zC5aioNjojn;6U1{FZ>FP3J*pB?eT4NGaSL~$%;+d+k7eoJ^ zu>Siez*Yz>iS(P0+>5`W$R5bt#NiuzVFkinuewRLoK_W}q~Fqt=y+OFfRc1`4ij@e z?HAKCGZYk*Vv;$opT=irU^^kQZF$0_rlGM~d9jf6I%O6dik^Pov%x%Cqmz6vkG5b% z+8v?esj;Si_bax&Z^y;Qx`lO0PiUK-q1DNseHZ>Uu+FbSvPFl);fo)neP}FbQjIL1 zza_xIK|?r?jg4J7ntV_vaPysdlQ*iHw#RB-ju|93L62h+JIqem=#G?Xe@eH{5UG3D ze1eCzjoh%JAv*wZ}r0f05 z<+_Xq%a=5e-mU52g-CyWmR7R%lwf&tmwy}=%W+7oC@wrUWfco;R{T;R{R3zDqV+L# z7UAO0F|3V-cM4)hGx9I)%Mha3Kg6eWr#@Zh>>8a>yp*#a?{F(nM(dq{ilL8Ee*U4f zRoA2O#8LxyK^?luYTLM1UY`7FR^n~mT<)4_=u#I4znDP>IPobW<3TfFaW~C~w0i2R zsOV_A`}cJ`nf-OG+~~VMeTqLl6{uIbjQv~#s-{%K88<4iy}eRrf_=VJ zA4A9`%|>S&$4f~mmfU8v^@KL@+#a_rn@#KEF%a`T1&Xy0W;R6!csmwM;7rmqz%{?W z{Wvf@{8Quc=XYu>BI5M?)(t;|5ScK0QHM}xJBIA0Cb94;FB-NENf+G2!G);B{7RFG z40h+pr{pPADuWX7h3z7j!(g<)vLhN6#I?U)dV6@VWB%8t{rBa3EVBkwVzn>n5UmeF z&Wd}+KMboB7Q0_%WMuG6i+LenVe_ywW3%gf0}wB-V=z=CG>D=dx1wcjy*4}@P{jjheE|af@=F?AitkR_5qs=Y zQ&Y(-c{AbLk-^qUuZnP<`il`I^eI~N6Ls~`>^iAo-k^5F3!qeiz(`{reVj^$XIhApQ0E>{3EcBPB-K@*hB3;ONYI zg1{0|*@Y?CxHw2YYxYCo#G7^XG37;F-NiQo6h1*3!P_R4k=Ich2b;{$4&12n+$V8K zGaOXfnz@4WjdsDMIyY^2WYe?ESdsh2G7@%nnbrN(O45uc;>GfcF9AK)B_c9L`3;(5 z;eI%s8$o~;asYXlY$s`i6yO}jXCCEfew{YT>M^Y(1V(;qd@7)H&zAk#;kG{ zyJ6nqwj97vP=olKJx5f*VUf}Uno{|tmnze^(+e1hF`OKBP9HvO0Y2i)@iIr8nhr#P zP+EZhqLi%8{!JJ{kmRQdU%&I(t@11C8jX6CxG7C3r{Ata#%!(h`fS?N=EJEk@JG{W z=j5@Y>2360(qrmXIfLl|L;)bKh~B1-z{qJ8p_E@3V&OmSfzMSir}{U zPabfDjE*iYMVVGrcP)#gkq^01+S-}{h%}AjEUnWc%(ki=egrV`J@*H|tL^5DX`lmq z2xc-%qSE2jkCU&@fyLM|&w`Zo5BT^Jfbyr_c_c4yi!>baEYQx(*|_G#jB};ggkI;8 z$kUFlA^e%hwSjIX16!E%IK$dwP(s%a_PasP$u1s3^Y4~Ht}(&Q39bNhN{I71NDcb| zJm8?4hCfOQzNa|N4icio^xCw+U8DRBB-yiY4of>Wl?yv-hxhe2&{FpY&@NuIKV5XI zv9`Y+={w<-{Ej;aQ>xziyC*XO=qYTk>-w~8Ggr8boG~`QXy5K$(17GpHYhq;z17%Q z@D;Ui04&03S36$V3T0_ei?Syy85N*e37abNwYQa$DO`m(?o^FdQv7|ek)Q_~2_sH- zHx1$GI2HnW2e(H%*lQ033f zX&veQ@R@**kfQ$l22~>h2uvx9tvFH8QZFfKXe5>Y80K20oEQB89O%K0$NLkF7%6EV z6rXLTv$4i1zl-dTjMSfz zwuMkO0QG6ZCx6&iB>q;UhzF$j`d(FA(i>n=+E!q!j@2s`-7DjEY;myE^q~#~&6x<6 z?0IDzo^f3}ne@W~Qdk$juFQNzd~fU7M*#g4_!32xy)?TZs53rCh~n(nR^;VP+eD!o z)C4lYZipTD*HQf|2ncueUf>&e_tR?I8{3_tx&LHp_2H7&>m&0TuQLccJulI}m+v4K z)q+!zla>y7@d#SKO0S*HhXCN9(Rct1{d%1S-n(t_JFvw!SkOQTwQF2QVkHUjo8vJU zg9UZbMTPIQw4Uu`q_rTMTXe55_M$`ns@NCO5-1bUXS?3Ep^c2kCS?h5RQ{<7+Ks9g0$2f52%ow5t`&`jU8QaZ1dl-o(^ zByfEx+#MGXnS{eUSA5^L>S-`v@t}^!`{31;ii%9e+moxDNebR zRkBp#hslnN2#bY&m9|yyx;=**f{0Hv86x7 z=vSWmnb_7%Ojj>%e8Bhp|Rrn zQrt=L0r&5}WeI;jcE{o{>6E{xS}VOfGd98W;Imi>J0xG}K9Zj!%MQ;#)*67W&E!GlE{%m?3?SRGedvxUs9L1lieL z(y}sLE^rcd(c&5!NtXmL zV)5Dppa;HO2|i%~3wW^hlYv`a*M&+N7APz|$B;Md@64bans*3jSO#2WlOtOQ4EQ|z|#vusR?cGvrYK=m>PP3 z?Az1J#S^e$ky#Lri^E5=tIR;CkgxnWSEx+R8to21V_TpFn>J$fRCwJ;|MI0;11qa- zcBbD`42;R7G=l-8geXjHQbD($MFq<>%9Yq0efjbRAJedr5I^R^45T1fErExhK{glqlIUM|CHd#hRqnJr67ov z4n+yInY67?5%w|1({W=7Dx^6yXAj^y(cQ&}EMD-q;yP{+k@)k>k$b@qkHU{LGHapG zbIAUMURj$xsHEW73jGF#r9dM^GcZ zd5?G!T8>hDrrX($OYp#rhFL1sXokx_h_dA|)L64mz4`aBvJl(Cce|r7-mn8IQ|`<~ zMqtL|>qJ9;fQ=d}zw248FAjvzTT=FGe<&F0FB34S!lq``t5T`1-;y^@h`|nfS=^j9 z#md_KWYM#%-23kCYgLZ);MGaegpf{tPW=&8@pN1C#wO0j*6yAR8VlSr_43S3qfNCA zZy{^efqr|^QlUhi(?m!NQARnS*sTk(R2sd~KzSKHe zDa9ZIPE@$e#6%O;HAc48lD4OP{r$4J)hX}~DT;T1vcgKQ_OXl3_f(NX46Q20R#d0b z0M!t?l*kBfjE9DX#-c<5*bZhkVFM^wl)9fa-czxsWRv&x^+5-NH@~wUOUvd(OPxWr zv?uqLWr+wDtu29`{42!cFp_XW(>*YNn@HkKpcFUDDKw!{$j+bHlGN z1N(*?nLw$dfV0bZ!Zeo*GsdgY@yyM)3YUC6$Ed^abD?-xI0cOhPqtT>WF>j0%UGb} zBM8iL41*a6Yv7k4fy*f`o24mf4I>AV`v+a%i#C5Do=flW~?l>X4vy@km z=fj^u5z8FT%iXz9(9DeHzzhg?6pFNPX;3EepkWpoF16g+VZe7oi&dyy*Q{^<{zWu` zYyoc*!5-`8XrCFEz+a24kDgFV6GUbh-31Y@z8gsg3+(VU67)6h&o!^sc5z7<;?}9Z z>Z@ib5{taAKV*rG(s45VJ@X|#U6TfxIB^Y?Os`h7P%7V8y+E~xfi$e*<;`^iiebj= zi&Q*Rd&$BKr%xFU8>pOycWy`F^uoeos1@%d=^9bRiNe78mb#7tEg&;)kVrX&U*cn+ zA8HJ+Z4J4pBS}&ZC9@?1gubG|MZYiwX#loXmjoF~CRJW;zHf(*6PU$YIb!#UVQyu= zM+oz&Brs?GRmC=Y$VF$@{aHPq!c=Gi1@moJ`UF(10}PMT-dqz7(rqcH5*-|{2r-f= zirT=TJ~cD5U}oFauO;UDbWEyJ9yNIZOmJEaoCYj-@rHqH^L?u8f?z72VZde5)Vm*J z_+8(8SU$G!@BP}uXYhet``Rl`K>s2bZ=3)@`qqc_R7G?Dumr)$=b;@Nhm`WHYFs`8 zkG5(&E*=wy5j5}d&&jFVsC#JmIn_L5q-3=$!W6g{&5;z0BMDYz0)x-yr%!UdN$>tP z&ipkG{mF%D;4{Z$fPN>7$PC2#6IX}x)Tg7rtQx_n{Qb%us@T)gd*kC3;m!^INQbU> zzM4-e0VXPgb4H}npHMGvxEp3`y-)~4uKo(pI+WIy2W@OA1q2qY5oFohUBGr|ugQJ! zl6V#<)svyd-+r0N-(V!fHtALhVgMGb(*iA#kmKe$pN=QYZ`%+gAAH&z7jsROgiavR zM3vn&o4_jKVg+843<5NfCTXNbR489{pMmOcLE%}D#3ihAm$jmnR*HB0-VPYOj9Q+> zslfEMnRPhIy1qnj-QsP?&F$VDq%?Qy=zc)a?7jaH(S{3+4qZv+1RW&@dN29F+P+qw zUg$qN?g0S!N(0Wxw1PT(cfjk@HY+YItyTQ37SIqWpnMU!_18OA)Rj^cR@K!#{!pfY z!T^QrDF?!6*aw%mK{9dKH`z}~V@qRjfDl25O9r};T8JbW7+{STGKJ(!tnksz*BD1|Nc__)jgq6igC;rMgX@cOB;TrboDGE)znkr zYxB2vI_g0L$TtoIu({d(mX-miO*Y)_2rnwz1A}=LkGp!X=+uV6eMJZydl!Jiv`((Rp`1-9+30uV808EEUSJR`=h(csp*K z4|0uw`Sj9BEx%Mt;~Oe}*w;5>-*B0y-5h-4Wg+yca5Val210gTiLO+?4N#)~knX28 z{DR-k?u0>oBNJKMcqeSzcFV~cX&i-|@{~lfmrNeB4I+r<}rfkrGm+beE2CQD}dt4v} z7zdCWGxhu)H#Zng9E$Y8nuBQ0X?dqi?|Q4s$REz*!!An1@BT2t|Ykvq+jP? z;&k8)4><&Z#mB0fCUYcyzZsK_Fm{-6yu* zT_=}RzCx3pXrBM+lhrFX%mgIX+(?NNO~+H!O=1RNSjvq}P1cbpTY3WYw!$O&KS#iO zlGJg3WN!s$8;ci5!sj6B`QlwcE52bD>T%iIDe=YUTMu4?iHz|nu|JzT5v(IqFcmb* zJ2<+=!7f_^f0qFn?KK#~TIp2DDVj+an3$T?7j%-ks;TAUaZcYII-*2;#5~o~eqz%$ ze++jYsj|Vi6bd7THt4VQgzVE=9m?1YPf&2MbxCXpLxF*&|7C!QNL(P##Yxt;S3s63 zv*tmp_%x1)Pt-t7U%xOSROTxvhTj5sLavC!$3G$OYJqAo@cde>jD-OaxgjhWm>d>s zhw7tj%hfy9VC5W&PHQs1)1=3I>dARv;(2Hv!7l1ImUJunqmmi9vH3YxK0FfXkNOzz zE3sSpKKX!ikLSe`@SpMXliKT+D$w>i$t7$|JZFwny}PcSCYU1)p{w=i{8d{1OKz3@ z87Ame3U7TDzBCdSwHmM$cA*VRwGctaEVh!v(~wwS5W@l8%nbl7&+N7fI8HgWB?zT~ zjYO3zhPai4^V0@(j!iYZpZF)0N)0o-&IeRAG|bXS4;a|Dk$OHxcY}w+B=ztc%y2tJ z*a<*M&=C?6UdmN}+*9q+GKbbz{>PHp^sOa|={zG_G5|`&*>-8?LMQkvbMh2E9FoM|mW?x@2oo(0mx|;8;fYTTyx;jP)c_P!3w)-k>m`bYLc0Ot$BjK{GsFiuw1;R8WZ87lW78f zwUdk7Wi(vzTe5_w9ExZ(v^-}Qnnd{ymggl73VuO|Sx_0c_Ay~@9~m)^%@p2Y`|Z90 zv{eqPt>p`1Q|1yGByDWiF@ulvJb zNH`QfgH7Pd$<0;0JbCOBa<#Bv(`75Y1^cXhs-Mwv3G@RVv~J?_qe!&_m@f#g3?}f( z%P1#q4)h-<%nV1qYYOQ*lV{okPxiT_S`Nfy31f&8)5Nga5`Z}a!nw5yC7V#x2R)~x zX&G)GLi^4yx+@Sho^ohgYUznL?S2Q-a%$l0o4}EDc4nob1;M(~%Npk7zO=HxF;s0Y zA=+LhY!#u0kq4d_S~~vsxzyb>G_vlZPu{G=BqHa> zu4Us@$Ud-+O@Fh~+;~=ng?HuXhluW#h3R06uxL#k{rA`Nud;j>1$I~uj9lEECffb093K7RRzplk+5!)(}^w<_$~xWGH}d36c; zZdFzRSl22xY2OuKdIdHe6;R3N24^7I%a2yjPusn} z`t~YH#Z_i(<>fK|0{)8fUn`eosIhMOD7;!^ImC}Lh+R^4H{}e&P2%HZ+$a(@>lMh^V&-#yxer7E?vzoYL+u zKSf2@vhu!lcN`oXR80^erlsbRNN!VqUElR#0w7{cwuiOf6(K4FKw<2yK!B8lBWX(} z?ums-UM$fhW+k98)n@R?e4@g>HN$a3EmhE?@|^t_J*bWAP|(MwC%XtR7-k!JMlCSV z1GYo1-1z6&}FRunw)QeSPPxz;f zsfb}3Ow7!6e0?m-iyL59t!o!QeT%eR`*wOEpoEf-Z*E$LUr1!8@kP@wY;8a`wA3{K zvm$%6Ad69i(mE|ft>IAQplF1W6J$XcgJ=C6I5T|w6M8EO(BnW#`4eYFUAn~CMH4=< zC=K!SQ%nr60>6!8RTZlz(o*ryeW5We%?7r~be|7rcHp4%4ghJ6{pzrUu!LmfCUoc` zt!v0~1^h)5-+^ZeW8lD+e2K7xbPqoA-fpq}HJBHc#sEg{4-kc_%Q>+acUyLRQ2=Bq z(*KsF(5~GquL^ypfxL$MA_;@Tp!Kn<`zgBOEdkY&&E`Dyyw?2dm5Ka8;D4nkj$x_| z<97H;pZ2jWSCAr@sZEX|_Y1mK&|U@J4?ruYuabWg7)+=oe*=a`eTrTt&m+U50VV2< zPNn~Mauz*wAm5DaYiaWwLPU!}soYM^$jHT~sKT7rla-UxDDU&tMkp;8rl_mqZms|@ zH?@^yIt$ndt-7Di&FAlHWnRB9QYroR?c2qxZ1k{{%2;GEoCP>ooL*Lk=_sjpZYBX2 z* zD+D_yv#Hcy$1T@RVbS5@)w606B0mr|*Lo zG_kEsN$qe{%hsOVAPW^i8uOyFll8Ll@Qt*uV?EK%(dYU3y%nBg{+14wtiS$`o3Wua z=ES6tj^|6*9&5B9Tug0)fX>s64OI51sMpmFd+*#grepGre80ZrW!(Bf37hr#D#ed| z3s%m(T_x-A14;bywuB${-c!vN<mS6N_84Wt68XFUkuQbJ10J%oJat%v5{5{1kAz^6GG@S90LCA z<5HPtx)*dl0V~Q@YN*~Tf!*2pVh}4a%Vk-}c3+K<)1=6&?vz=()*=qCL$U}_IxJUS zL1F7HZT+`7eM))~-&PXWJ0Sn>c54D8wEXgN4YaDCD2kaN>rVH}&;=D!kcQ-i2FCi8T13VYNX<8ho;4!*oroE?1{HdEc%O&0>NIaqviXmP^| zMl62~ZT@O&!M5TBEWr$DhH&xltTr_$DJj1!!n91N*n`ea*Jen@HAr$-UuKqt#Qn_z z;Q2fydikTaZ3Qp<#$7qMN9cv%v>n6=s_l0N9Q4CH9TBLk&-08>w&2p5O6N9sxM(VYq^V7pHqC~%PMI=iREt@GwW!=H1~y8Q2>=VFficQ zgo?QWm9*S;Hu8a_SH#=`pkHfzuVKElHmX%;g?yPPc>aUhqXI2ROPBFfw}M%Swf;X_ zn(RWXY?$IgA;-&xAslwWCQ&U|EbIVErG42Q;TyYPuj>m=#zmcC1Xf!GD_o~*WXo~6 z1hgkKzO+dG*9>Z?PMDQNsArh1h_7(Y&z)#_c{RzQ*!_e{HQDI-9UnyCFM9s5UZ2P z19}O@stLR4ODj~>%$Rt{<#cXQQIW+S?t;R!4$We{nVh0xE1y*<(7>-t=N$J-&uo#--Q` zQ&Af+G89-&>z}l*IWn=aDZ2$j}klOWdI~w1j2T!*-^_(8D<9{G@{(IB#-+$;_r-SKv2d-#~x2)SChCv67o6*(@ zGpShMwya@UAq9)|vshCp7u30H8{E=fRgIe%lU8~}S($3`%x@3?qmKupw)tv4Hwp(D zrRwH!b|&-BE2(EP)yJcU_(Nbnuse^?3~Bi!kW0x78_(-zDwsir9rNoXQ+;{Pw;BNB zo3@g4eu2;}N5~Lb+z^N$D~bUD&JrC7oealuPmd$jA(!2|#}XJq`EA045SGK=ZV>Yl zb6>s%Z<+&Pl6zx-zxj`H z&YJxBpgK_tVV|0dLrx(hM&Iw6VLUuWKU+cl=H@#5WUMA5e4A*bn-Vqp~^O(#STEu0T?woS=pZvjUBhs6(;>0-z~)5o*++q&Xj2aiQ7yKGyu7yjTACVH3WIPh#RYwEgxeRz5z8yAQ5&9^-* zD~2DLxkSKC+G2C1nsY1FvIIn@;V)DxT3V*s%>v2G*4=M5i@JDC4UKOs7c4)^E28SN zSA;x2nf8P{gZ6jRql&NIyrr(Hatx4@;_`pCq52lm@FaFn?Y&zKFKPx58%JRU-*eXu9$g$Y#+H#{QOCkQ8TbHMXM$LF_a6etvn6FPHj4fm2d|Y z|N5l=^HT?Zb|65>|N2#X<~;D+&9|`!+JS1*@=&x8MZVI}JgFHuv7ojU^-GI5rpjTi ztE-6vfqn8Xns=$%LQFOAXPls01c}JV)Ge-v5*2G&872ZGxEQtj(q!mch(A!&)mQWE z%5_yj}Au~hCVf2|DMI{Q#&EDB#mtYSufiht&jR=f%V_}2LDX?&I@0|D>cyMFFTV5`OD8A0iZnww8lM20#5_b;_<6L$e@RM(YZ-_ruOyvnX;+tm7`Ls*>}3 zEH1Xh!s@C4_7z!c4^R9`JQV*JEFyJ%4wZm}rfZ$BoR$-k zP;#`1iJANtY__hvp8#-QYk-o#+K5jUwkEa*Xkp1mi@s-mK^_LqPQbC~1VX9?U+rY% z1-&*O48x+X)uaj(I`#wd25#Mu{$BZ zNm%Bozvz>#_N$ea1!EipadO|gI3Vs(izr_6M@>+Gg5_?^GmC{-EftstyOa}*nm_Jg zFWY%)&ReW@`dgO4fvd~w$oa|9h1ThXCe=$?>9@|QXfx<#fZn2Af5H&&Dy&Zh5-By^ zB|Ztg48+Nb9N-XaiB@WUr9xWsuXosAzxsVg8O{>XC-XWLn>?=^I0HIt?$-yUKLELR zp?deN(yKns5hmCVr=-t5fBu{#MMFpTu7IOU0QK;VH5Jg)*1U{PN=&4IreX&%=6yIu zaLX$C_RZ=8bC6Bu>5u6GgLD-8Q!m3w61{(X*)k{}uUv6mDYV_WUqbF33-8LEVj3Q| zm9m6&9SnT?L4Hzh)UXe@`jbv5q8latz$weRiDU`7SLc=LrCvh$N?;_pt+9BD&JCsq zsXVr6!e+(Z+@M_ZIFScvG96QwUv&25uB3a!|0sz6=a`i%0i;Ly1H$|RnKF#g)6GiU zem?ku@`vowl?>KL??)Zl6h@V3n_)rn`D6rGRkkx!H8gSVnF#-SSMHZ2iKGHfQ$fm2 z(IEnWh9FwI8L62`DPPG27Vq9{k_?!4YKN<<`-sRhl#iu&<|j}GJhxS1P^iq00s5>` zdMS!g{}hzWSavZiQqnT_uDl6Qcv6iC{*JU-L|@#l*UKvh+Feub9onNd6md|Jndl-R zurqi9<8OR&GCi<^-x7(lv&46Qd)i8GcL^f^24OT&(N6r)V&to1P?rtvj^`aE@NdD?3FLsgeLSL0gTc%HhI$jF{5rzaQ$8-4!1B`HTemDo#! zNG4_bdlp`rgs!AV^e2DWZ2^l0dbX~o=FG4wDGl!ORxl~&Y3e+i%qCs5D^Ka?>lDIc zYA=htVX@C|uCK85X+^D6xodr8B6xE$GDy_NUMv@YciF4G`~(w_XISlZ;}m)%smJ2d z?TG~^h`TO~;t=VFSPC_5MMRp7W#+Y!KO%Vxv80O11MO zrP;n+UQELkPE4q7YIwh3V8Cp=DhJIZ2wF};#p$>1(y%#X(+i|f3!rBJUKjDHZrzRt z5Tt%CQB()?Ll|hWUY}uD8>NDNZI*bDO5!cz~9whe7G0 zMSNC0Y!DZlo^Bnt;q}qXtiaN&)EBJVQwlgHASec;zkn$r5fIiU`wi{LXKv_~GAz=L zZD@GDrUe5eXQ~tz*x7>KvJ(|<`9`-d{J3Gjh*q?k(_x{&&klPW*Z0Hv$POsbCcm#f zKDf@exK?;wExUT?qYAPgue2?$PeK8EqcNP#;(oHbOCQF#mqm~OQ#OhuUn=Zazq77k4o@Z3yTFFyh@iC5dlvZso2(9yA@e^qq#64r9lqB-y`|37LUQd$_tF>w9azZ(X) zeOl-O^|LDkwqP&wQ_v4&q{`B6+T`~}pMSBF5jz^fuyArt7z)dTgS;T#*Ztc)ets~M zFQq;3VM~#_&V^fTw1WX?{|#DV>BN_)2JEk01bU#K(=&FeXW9NQjEx25&o7`4bMM#a z;AT(r00o4b1JB(J!@GFmz@Ol^>2@BHhz8vlP6(!pe;Cn_k2bn z4UHMy0s{U96C`_(6zc~nhLc@a$CA-ID18=c1$aSBsotQ_w>zc!beBM{j#`m3k< zucgMCEVhH;)peW=-2o`_E2&^O&=3gAQDXNGFa~!-O5?~i%w?t2%a|5Ehr`l}2AuZl zqsHD%HC1(ev$WmlfY`<1kuL)am;9UO^iactf%wttqmO!JWmuma0*V5l1C+8>y#Fx5 zy>QR9aaDwvcQq}UF-=87C%lG4ya#2xfu-l@`nNW~m(VGcdIP!qY^|accuqEj+YLgS zKCfBT=)Hf2fsx$VNx>=#CQVcKoxdBN!TQ6d*=~%@Pyl!&t&V$EwNr$xXGP7du&~cY zp`d{!Wqb{9cuZyre^HPDp|*gD)GgjC$6LPes3)$LhejEjuQqSiBdfaq^@92PS6%Cah2yB)`anV!5S+-4I!4m^Bm#)|%Wb+zFLbRu zPJRs}yxt_-^F{zm{TKczqfDLq573C7&xfjaAo=ST(5`T`A?w8&Y;{n>T5Dh)8vbUU zslL0PP9yj)_2LKUyQgpZyDK!qZY98#@ot8sEV8(nn8JsH>zxM>^9+E@h!eZ2FHTtv z58HUppIgL4U=Dy7NwBvj^+Z?VTSxFVI2i;&e_IcG&GV0@7fM0VLO`_T1oY2omsM@D zT$`Q!LK@vP)NOg@_N3tbga5Dh&#|Z<*VpBB#%c_qc$f!{lX4j2v3B{J)5Wd$I@`jR zyrfJ9mgHs$*SCma71$Iv*NE~pc%6KkLUJaP1+S|Oy5I-}O~QuN(L@*-2b@3xb}`~e zPBpmI8JUewaSW~4non~1zRE8AAq@W)W@%3 z>h@M}AqqZ#*u0gEn*l?juO;Hb#1w!9OZD2`)ic+RE*;o(q*LCWVZ@o8O&b54heUck ziyDc~Or>7EYg8H)Fb%mTLVb}b;3+=Tx6S^yeCDsR6$Z6dVeRqZh(2JH~mVshE z8M0jd#oY>^xF{6m!1-%V^@kmZi!LgWM~_|D;4ljex;t@CWIQjAlYu)2^tUQ zRk)#-NBSl+8T~(;ys+4(?66wqA^_QdkghS(O&udhWoc>Y1mc%dX?dVFkG2BZ0S(=hqs3~9zFXB&F9R7el7S!ukwtK-}>1K>$zrh zf{iOBkR`X7iUB2hEZ7}4Oj~4_O56rlzCwgfUfwh(rZvQ`x{?9&?k2|ion&eV8Hl4Zq`dzRbt4mhi~rmyhi2Qr;r6$Np=h=@`1_wi}pD3RoUZ8$zitnwAxpO0Qt zT*n~T4D8a1Zm)g-pcfldnwEL$w~LG>#Ye&9|2?zK^J?(jRx?S0Y()FLhUd%b6J^h= zDv;r!_Edw98r|GYR{To}!PBQUmJ%l`ZM494Qz#=DbkN$~?!)v#YX|l!BqWf(JtybP zd`y1iwp0k0@kC*Idiu7gqGa|=3#O!^Vlsfi&AfZ3nV)t=74}{#m2Xk6LD2Y@gX&UX zDU;taP{+@lclG$f2g2pMdS&!JQ%tx=PE#j8$Y0Ms|2b9EA3vER$5dhsXsLMfm8PLV zp&_zGMhEhpH9Z031RVdmi~jmmRFmrT&!n=oV-Fd(vK=19FTbC#D<ZS%%(gbEZj_wtIzL9k8Gcb%Tc9&Li!ctFvgKOY--LLPysgohO; z4hldI?MO}v=K6>D-Wnw8>aFRBd;-t}EFh7{K3(UG?CPrHQJ3W2thPx`O0@PYx#O;n zMXo?Gbt4I%e6m{*s2Mw&0J16pFv{dX41M~F80K~~3@W1SYJ1yj_b|WfVJ5dl0SgC* z$`yK}RlP$IN8Tk69hzhV7S(Y1(VXW=jyo?z{#DQ|r}|x#dbu8RL!{w!GejfUzs_$V zMrYhn-55^O%_qi{^b%u6@=>q&B~xr|Nt2$U{5n}=xrflp8=d&8>JTwn`^?cpE}M@H z%|R1aZ7dUAf6iyvEeT>FVu4J}0v28Hx>M?7!MRsrooU1&D|5m-+Ha0L1aQ=0X%ut; zreJ`~ASbJs2vYUr$+tX+(Z1#6L;Nz3ciWV(_i zd1coXM2lyAkm!d>mK0f?Vfs`1rn`sQbkvdS7lv=ELj4x*5Ofe&%}p4eCrHH21F1(T zs-+k?o3ql$%wsCC+A2Ajm4D3VBTP%$a7uW#{bKb8@xPj+zkXdq!S2ks0MJxss0GB7 z8EP+j67&kJ_Zy!Quy=B1f`RSh)LZ4xK-M!kQHckCA`8Y)1$(4X zt$v@Hp=6~9*X=LXS z?pceRxcQbRy&GKSqf;lsqe*Bg$h|FQhQL8(Hm--Y1CHS-&6DHH^~ZTn42q_S7O$(> zSFh10BAwpb{#j_LpXEU^@66}y^6R?%3WJaM;&20w=Q%;+^PI2(h9XY&pyuZ(kPi8-udAwW3$&Y&(zcMDgKS}Sk{;E(@W_jlo+uN@x zG=n~Ng#7v!nGENa)?94u*)F5$c-FidG&tznd`cQ zJ1>(!mqkN{D{<7@14&VY|M^){qM?A@Qxe=K`pv4`iNhwyXjTG$+q;uh`FPVkOA&5E z6Z)oB>>IWT^$a;GV(gnKb4V!i;g1I)mp`3)0xlMF9@tpvL@g#b=9#rq8}En6U3vEL zvqCt9h5gwC3Mi>`YXLs%hp3|_hHp_?;73Wu!YR7?RPQ_z$$_GV1`HeoYC)-(ZWUkO zj`TvUUh+Ubj`1RRk&kDnp1N*ZI0o0j$O$ogC*jh>7w&~KDoPv49Ewc2iM^6EY#iar zCW?iVO7a`bt86SR;!0`SxSzMTw^>u)_a^o}n9|?B`P7_LIBVl>}8;!l>euDYnJ!Y#fOtI!j=`@ecqb1 z6lW=p!x{AuZHvQ*ZK?nK^#1kdHEEpe?BCI@tvwIh_74TNlaIF*k5*aNz4V9PC!Sd? zsZMz`+5Pg@v1}`TH=(}Qp|*Ww_K=gC%#(SQoPZAfN+mkPHxFyB4M$JN)uhokH#b>% zZ<;G0{E!^-+nl6>*5JF$lz24q-Rbu~)^yspbe8O4Mh^ZwETEpQTm2H?;25vwe0Vso zit!%SyR1&Gd*6YB1~tDzqED{TA<4cs$w|{HzdS+hc{KKTH)hMsyTZw6Lv0u?PC{;1 zNCo0#;9TMS7cbtKwtTk(6Tiz**Y-)&iV?_pW@tm}7OPU&&3xAV{PwhF>*G+z-B7(M zGI{KvbRmt7b>Kb5}lo338kuGZ5=CSGXkmvmdtMFmwZyF42_ zDARz$CjU6}yaM_luAB>Tbo>_R*i?PZ+wzz{ec?(y^u?f7XSAi?(Nga}4l4MlI~C#L zN8zv<5mDV31r%@R<#QZ9x;ym?U-T6oF5NhyP%4U?Karvyoz?G&b;2e^rGb;O$!?g8 zCLyR!khz*~qeow8`;IYR71)D^KC`HsB4FWrQ`qBjIc&+COnmTXf93A8zFTBeR8#Tt zOy>J;@)8E@v+tx2*|Mp-KjQLSK&yS{P&imV56h%YhvpSRx!#D}uzbe(c z^)c(Mn>=|UcjuG1O3o!0CXO)~-F~;l*0PmewHEcs_nh9hdfseNZ%p`pu;T8M5a?Eq z=@t{{mCH+vVOQNB!R_+peoFaXO-Jk#1}5Z(jBs^M=Pz}Bpr}z5z1_g?*!`6}3+h0Z z>r+F)L+h^lkWLr%@+cU4*{#_<_$h^;tNTMdhT-N3e#W&yeF^Jb)Q^(clE7je z{p)W0C3}XI>V8c+_GOSu|6=c8vEzQREH5w5u`Ye*Sxe%!@Kw{8Zq=yH&*|wc6Va14 zJ?O)^rbOY;qE}*bHOJu?>YG&?Z+GMQfGm6pd*zDNr&+Ll>U!Akv^`AddE&Wh{rFqt zak9~ES#Z)UnpB|PZr;wbhWKH0>*7G@YH2fGJpJZW>-5Bvl@X%&+G3htBk$E#*S&<8a!E^UNKMu$^v3?)HJm=Z{3{5BbF<;e7U&m=X zNwk5;`z&SOJ|%sEhI8CKnd@^jeLqBa;V>Z%0mqLWLU)~vo?GzrM-MIN^EvBc5gVbx zBG_?_y2k0@qjrmd9@ zLeg6KpRpZ@%kSRtS49(9!Lb zz6r_?@$uYYQ{H^io6jcVym0)=2L^6}nAiH@)5Rfthityz)La%b&lDUMChY(EGiQpx z@Yd^39(f%!Hc9wT4n~=e>%zD6yUZ(K(Q$rTa3tv7s? zv14Do!U+QxfHuA#f(%yT=+DpY{wP1zLRbx$qrUJtc6-aLSS>=`oP6%I*x`KPCM6hd zzb_{bJmBuUjq=iqnz(Tq`HoEXPEI<+MHf1JJMO3T??1O)l-b*Q>Wz$zEn?htVl=K| zxwW5eZ^7POI^CR`x(b7!7ndHp^AFu0Zhq!S5Ze`ghJNu5Em)1q73%dKt!}J69o8#g zUc0$-d>hD{eq~BTPXD9?niI+aPz&HtesBRbNIj&AtiY%pG+g%OPP1*RtiC&{E9RfSAUTai^&b!N$anl3^hy%ML*_p2rl zIrK0SC-kU20r}|I82OMrC~svn=)%QSn~E$rWlC5(M1O+)Sz%4h5bg0Hf`L3uB)*8( zbr@v);@1GqF{4;w6oLIHn>ZhbP?*TIn+W!;*Ab)%=e{}Bxfa`+&yI7gm+i$(-#qZS z?@!aCj1CXaU0(-5s&_Z~(2gStfHY`fc(@kFh2hAip^_XpzmH{_G$74BM(J8KHm+hO z#6-Jwnj&t41$e69a%~j4=$7&%QJrY|ZLIO_^gU0>dQ4%aka?ECOB;L7A?s53oh1#l z#ZB|>^mmR6R=NvHf4{Q+zKreg{PnMc^&M72I}UVDs%dGK^~bPdzUx+FE;g$KV~iU; z8PynydAyEkDV(u)hTa+#4az>}2|5cI;i|2uDSHS^4H*9Rw*~f`!laM%;DTPZr#O=C zU&Ub{wxuKCJ|0^wO_{rBo^304too-?S&IgTOTWZs%b-deDe6@bpr+*im@Pj9? zExlaKeHEpzbhiDn&UTV6Rs04Vl7{qW*2^9%2|X{1KvCnX)sSJI;xZWeOO?|~)8*5+ z9pA}9l*-UwmD7LLov;1$6W`R%eY4>Z7P8kD?;d`YPtLJ!VPW5Kapf|f`9LPn>iaWV zOq9Rbx8e(5_3GuxQDA1RFuE7D)?p9GO{PS8#$RQcXS-OoiO-jDo!_*+Zn!zAfKDc8 zQmFK$8jAG*@dllcz+*YFqy5Ioj{cj;eV%)eLb@H>rV#l+o8+hRE5jA4?FMAH3W&~i--?q&PaaUNO0H-WJNfC-i<;D z^ZQ?amQ3L6Jr@@bBlPcb+aSv)^3eK=Zm*^^ncgwXqJ&>zM;?8boX5S{rGu(XQxtHpiOFvs(JHk#y>5%h+zZ@uxP zf8y(UT_XbFGXCcG3Hpy&+C#7lwf<}^6mkOURnSv=Uj~X?2Won^P0k?;oBS~*hoq=r zc6=VRyB0{^*|fjwx1WO+k|zZGdJ#UqsL89!KHat)5&ijG;q~>*!>cd_+I(ML`95A9 zH>d8&DR$bt@V%e)wFR|f$5N}?#k~^e!n2*_{mz%v|M3O{RVbhTA}{AJbdgG;ha&}p z7PyJwyWEk&q{GaXm^t3IW8BN*hPLsC6LO#Q`vv8;A)kx;lUnkJ@`gELGWT%Opp;tD zn;+D}1m^M*|A(}XOWkp5Q!-6D=8LxUaok;P2@_6M|5V%DM>$ZE^QhvO7ZU8L8YVCJ?HebZW@|A%uH{^UbHl zjN-sf-H!OG^9T-b;Ds3FxAp20AuNeA$L z`DrH%KRve>J_`Cgj|9lqwRG+C*1IiYo%>A%v>MJkcfET4h9v$Sr=@Pc0K?@Q8R7Y= zAI!{Ry_+rtSn7mBhgh08rp)taRlM7o7y6rnzfA*~36`r0&X629Nrr|ahOjx($260E zGm^zz2?#Om-MG4SY4)YFgaDVqK_TIl2lkOA``#F20=5Bn810k*)(rWpBi0S1?Dw;a zE}TJ!5ks7A6n?wdgri?LDa;|+Q2=UwBS;Cs3Cx*431c`{e81;@!ll){-7zgq!~6C` zFW@1k;uOqS=q?UOesAbLy_PtfZo33_ zFcp9LEbb_NNh@w1gF(Ks(6iWh0YjXYf83k9VNd`HGe+FeW^#P`%IrLaWZezpkfBsP z!aXaOL;O9{>vZ=DpRN_^)*bm)TdQFGfvv~Q+Y5}Yi$*@}xha0LY`86A_oFKM+&ODA zy+29GrUo&CzDu3K`5COpk;cJdRWCX4n|6=(a@^+|n61M~h4{1GBW&}lJi_*h=;PXf zn9ZQM+iaCzJp%nQX5hD%x0hL;0%uQs9$&$Z6~jwQl9@jXRlqJ?*c z^woLD`9?(T+0?1`DlgM;@A2<*7zN_7C@CUtKu_30vhxRr&ve61tve$(6=cDSKo<@| z4#PLUgrn{rn^}b?{$S|Sp{l+AA3*;BR25i1ByB6#nIq-}WWH%LNc8nTwp}KG*VP#q z7*0P^{(4is34Nzm1_^nZ25pc1sop+uC)LX)kwIX6@g2MQ(lpa;?fWk9VTueEJWV`& z!aNQzh4&DpDW`E4GS^{VH_Qb|m+!2AVicjw=hNf5@WyBPGJBa3Rcs*eDa@raiUuD| zoK)v(@SFGQ?Csy&+keLTe{Qt|`A6s7#f4j^=V9vOM&{k7vtG!^#CBhYVu1 zzhI38#_Pcq)=ZRKa`yiIE7sQ5hAnuFBXJroF6YX;W&X}^@J~-~@DE|JImF4{e$3j& zW_@6D-B*lE*!zo;;>T~z)9B66Ue|e+d->Kzu%*H`{lA!HQz-F?HO}Y2k`ug+6y!KS;b` zJo*_0zH!WDSZyHiOgUrS7yW~L*;>ob`>TUfm>JU0A_T(4?`)jqA>?(G-o3}}(q4r( zd)nAZ@!tEhAJhnAishwxl+V~t4^HZMd|`O7z(kjVfB|Km|4qu^1S#%iTF`L zSNp2JiePdfW~PIm{Jt}3*2CW(Q~%|;cEkX%rpN@^!x`|)PMI@+aNMf zqGJ#vyCc8`=SOM$y3oVqBnL9^S(^#(gr3tcuKQ5QrEw7!;k~cFt7V1GO;4NgD~Z83 zM*#*i6|{~qkZM?QmTHN7oIb&ah2C6y8axY}87C&pU|aD78w-RqO|}~aP|b7w<@=O} zEr2?lJa61EQn_9Q@s(P@Ak0$W#OU0=B14|O6V`NoQWQhc2%G+}4wTle&0)`A$>hj% za%*?wSxzmxw8|aVaum~P4V^zxk_|Z73L@ukHWA(+8q$lhj3A6~YD$f_;-@2KC0bj* zBq*aDQ|Guq^<~KzLoHm-B5U0_h+@I}&-u_laUFIHlz^Y{ima}ZF=a$K*_Y0O(JU*; z&r8XAIyzan65j4>2DPjvb<0_dnI~(2jUjbJ(mn@nqXtI;9QiknTN2Ajckg_`U%F zwrB~&L#^`^zasSIc{=2^}X25dX<9MBngx*Q4AE}1k<*oVkd)5^v zs>7q{Rhgq16O{3KWxB4+fH$DL_XF6Scw}S1Ri-lc<({W&JJMX^P$JD{+c%bdrY}aN zo(lEo46_34Z5gqUSK_3kyj^X-3T>}uLEJ%!*88)3+z``c!)X**WYI>E%&a^`Etu6` zCmgbNU@g}=vbz!@K%Fa}M|>#Dm}SMh+%$`kum)FMUBxHn#%tK=BlIdMEyec>Gug$} zjvTN|-HsPM&Q6Zy@BUT)rx$Z!#8k5&trImoe_|-3(hsdh>BrBi(cmV-I>vQPc|>HO z9~83l3T5!Xf+k7Bdqro)e8RoX^!Fv0b2V+s#C23!4Ov!^*t|*|{Y-`EoGZq%xC(~3 z0zT7XF6Ej$e_RiEQcYOlGaj%kIc$HQs8q&Al0dtMe2M4X*YKUFeWTMmC0sKSG^hJS zR8m-se*5jV9X_qlo)6k!N}iy1e6FNx&+PJ26y^9NR!@Y)dF{Ei(C3oaianjXl$(Ho z7V_O=@6C72zZz_oK(K{?eqmdNyk-br5IV=Cy0%7fI=L{O@nJ6oUK6a&r?1dL%`Y#^ zmRI}9#|3&lY{>0Y_&ftcko|Z#8T!bIHR;}1#(F+*%yP1~r|m3o;Md^FSWgOZgbG6r zhp52d@#orN%mP)5vWKrrlw-X2fWh+pMn19p)?hkna>1`QG0~65I5>|XNcfk?F`tw0 zW$3s|1X|axwlM(ZMSpSA#)i^T!O1a(BcG_lr_+jn=|Vk8<#0|h@#a6$;6#9MquRCA zl_uapDy?bWO?jLvWe{S8vMe{48ul6zQwlD%mWWw7i=fB z_h9O2@I2FZv}vCe`HS5a`&!FAdE$fQ&HXgJ@#6fP`}gGHZ*3p%Zk@`iR-H);koru& z2KBIDefk+Jd@$sMB>fWSp9rh}`72>cu)}Nx0i>PKJ3%FZ5;dp*NeOJeP^$ziNxr~| zYgzw#E=!~OIInY(Wvt(tV4(rTVv*FeO9_q?WxAh3L!>X9;4F9I%4jdHgLw()RB1B- z!~pp%`WZ+e>&|$w{V8vTutG7S!spk_wcdsUHNe_boMxLD+Ybjv5np#PB^ptR604NH zlqO1zm2?M1h!P}3cN?8$>!8X$8S=&lr-IJ1Ki7x-#mDEE23wp?@U#0guH7iAu^$Dt z%NkF-?vCCdK`kp7onp-6BjKQWRNEF6=hg^6;tV(fR#1wAp{*6OG`FjErszf8Q5E z&tA-V{7<1RteT;rTX?s=gZPvQo~8jCPDN~+)e2W0yMV26I+)*L{fqmk^3>kRm#4-= zIyAm$J23}>xJY&iR9)E-m(S!|q$@4{@Hig~ue`Na>T4UM{Z$7r-E5A{=XM=uU^H&EL7){gbAW3J$r^Kp3S zfVL<~rDmP!r}(r2CYlKjOGj&JbZW3=itQZBckyE<4y_T`WRl?d1i}hXu_h!S>HPCO z6r!0PZOY3n>R>Ze&W?;-MN0sg^qmv3;2KdwIaVHEBf$`qt7@NEe<&amaZ9Wbfpdl4 z>OBAD2tuj^18Ip2b+^(V<6aCRG1UK zFc0Up3IoPiQGE*BbDuw>jNNdB1HVTo6xq&R=pvu2&5Fn-iTv#X-bIzk&DLvZzc1Ay z!kkm(Vf`UxdHI;ajbK*+p~4%PQ5fg@l-(K>@ZiWganaV4D6+zqsY+SKz;-2Xlmyln zAaX^KF+Nf?wTeIzG5lG{@p-UOLM->1o- ze*Mtev_Nsu5$CO1jlRHVluw#l&@>GebX1PA?Y0~kD~43&s*g6OY304$y{(g^W08E) z3;z)@v=Sgv?WE>e7buE*QIn&K*)a}=YR5|mt5YI6^`78 zi3HsMp-vo5MWT53+bHJZr}QXvEF%rEpN6G^DDn~e`{MNqp{r6=M=XweIgDf9cx2Z;x93yt^Pc!uHD?JyJ zWOCug&Fm`8+Bej8wRAjsoo~6iQ}dcz154VyQZ+R=gWx_X(8Whe)paKx*%>a*V>bn; zoHWIpi(3YXa_Pu2%?YJc>aq!VE5s@Y@pD@w0F~{v9%?h~V!nsQ)gR{X4IR_sg^FrO zrea8!bR0_MBY7vY-uM-Y+uGQ8+deN7qhc)^-#!XapB1dq4bOh`%9A_Gm6oy5*z6F;Ao`Et2HSg^wZM3OsTRKar z2+=cFQ6K02{j~8)))(#Nup#OAjn6D}jUuTv94Z_Vy7FycNG(fij)JwLo859?7)Xnm z)J(6t;k@#t%aSwV0g(9Mu2x@!7=(k9aQ91_Jo$nBZ;1N;Q~vO;A6}G)1<@9qxnDF5 zO7Q8Tc|YLV!?@9+5*?Ups*&9yXVf^dnxdj)4D|KguM!fNk%2Oc$~rm~G9_HcCnpWC zAvm$X3oT|lo<4JN%iL{+v9fpv~5O4cV6vK?%A$c_Td z+-V6^;r*WB!DH?5$mh2zl zmSltJ1fBF%hX*0dq=g?m)RioPYI-_5KPQosHR8s^uw%W>#x(zG-}kCLa5@!SmeEsF zx9nOTI`GlGedW@y5)F8RSL*arw)!+mN)lGU>Lr*R|89VSn^x?Lv9L$tJmS${$g!1S zfwKH$zHobeP}9lNs;`1SY;PXimx@*MBvKa%sheB&Kj1^`G-v@KiQ}f<>GC}Wu2sQY zL;nFL_(xTQ|3D9>)v(muDI>iVH;kO-8w!ac{R+xGQ@--*z(A={kBB{t?`~~t`(8>r zMtAeT96e`+&Cr2BmHY-BTwgy06G~XiCR0Fu{pwMY5Y$%FcK9c8Pum81_i?|Ravux6YN+J3Yv0>a*u8~y z-a)6Q)f5;slmkZ(JV4?spm#?zNP}_v{Wpi6uj1rnvNAo-*7SsZe}L8l&es=KS6934 zj~+$i8rFH|%y>rM4v@(+D8|^~_~*^zGz{*22nr4y?O})chuPY;B<<&D);VSoT=M0Y zHsDBipK!|1#ENIzc+I;n8xtw4>U2hsA_KKXI9U6q#uPjZTzx(Wi`Ho}{pD$-qTEaz>v{EpGakvOnZ7JRGW(5-aqgwTX5gCvj|#=C*2FbL0NImedCR4`oRT1K>L&pDsRTyos`` zH+6vq?N#s8kj#xxEcC_*sY)`~FyxN4*`5N`g|-i5;Ad)m5$0|F8vF>$hp8X!811S! zu$MwZvjTVH&~;d;thg2UczLa8X|q!NJ(sO*4pNeE!`Z?SXppJ$J`AP~IYW%(*{xz3 zT;&`c9oI558(Twu_n;$|_DPSNt>Qvur%G$KYtk3^6!AxaO`vV}*3xKV++#?4>UM+yp=mzLD0qo6{AmO!p62fn;US#0&h(vOY!G5+!hu`>B{d1-=>CVIxVfB85y76>@0|N zk0$dmQ@V9z;tc$P07n3QFDyCZjlV)ja0?9gfT{gl-`Zvr1jnhln6c41Ez-vJ9l6rH zM&BK0RPP(#gY>mLF0sqX@;OdEiy(BcV5q(&8^UV@GQ~oo*zruOmL^+(7&ki}Wg}3J z+DeAM_6Xpxm!4t4==7IGDa8hCzy_BuZj1(@POJDE212fz@33Jb9ysc6bX5q)X6aVU z!FLg04#jo76eU#`i0)EDbdT-`Y!oPUAkj=FRp!@g+g49isao}B^9>uqiYmSj%qx%$ zTMy+Kd*K}O`TeYMte7`ka3l11(^Pg1Kv3i^<~t`CurO)MYjqKvcF5oAwI|OrzJti7pH)l+g<63N_BHQnu z!aYx%tQP`f`+U6hbwup3fpX|JUwM7{a8vRky(e10|4=dYcVN)}gQD7Q{)DERq#Xai z1e{7u7G;qR{d-$?_ZgT)rJk_IK3i(SCDt1d_e-WY4N!YaAE{~*en(el~IOn3#i+gzAq1h1+U#IdkP%AcgY5?wn}Nee#G8>p`xC-P?0&!aXi7>jbODJnYchUD|UG z1{5$o1N&br475$4I8scw<-Yv-L;9OP?#FLZ_pwoz{qxALX=!P1VZ!&-<)#BF^7%4K zRO|x0Y5UiXFh*HdfGpZHQZpMkFoBd}I?E*KCWeC|$p@}rZmAkKAcz3DZ>shSQPHSz z+Z!!$j)-M^5EU$d@LaVoDKi@3{}Yv-Y^9Ib!{IHq`Hv4qC|~ z!2$KYRODmPqa)03e``GsT-hS}pkU+EAC2_L21}m4qJ%s6T6MPgAAU>!x|kD{&R)_p zfm&8ck1VFBRHZ4e{6i0lS%o3tiOO?h_uR1P)ViE|KS-Zzq}y-(G!^_z)Uq;+R20Lu zr7tO8jRxH1=KAzKNwO(>-cYtXK}|E%k#KYBOZOb=Z=C~O8$XEC%wZHrf%n;QZodj0U^3Z0GMFCUq@bcjV}dg8hjfI`g^w@4Y4+;A6#yi$6Di|{uIrY&&!7!ti{PYDM9g^# zW|%B;%hd?VDH&?7QI!)Sy1nLONjR)YRGIAXq-9b<&wT)S<2Asb5#Q46VP;HUH7&LY zqenZw00+LOwKoMk4i1Qql}tD-3pEO-ls(p-J&6?;l>M%G{c6}Dz^>giYv{nyop0~R zHt5XNAx~U@lEy3#7ZR%wxIN?Py=<*v$66ACcf`jwfI02Jj08R+L8L3!HYzA+Vw^N= zu9!4wW!vp!p)27&vXa*T>o(x*kNZy8WYyI3gn?gzfewJB=%Dp}`DDKUYlBMZ+?yr?Uo%EMtQbeM>;w>)CTs3|J@6Ksx5L= ztFuD{8GCl4dQe~G#YFB2N9H%H&#&mFXMc9>fY$%Y}p;~1}G0>F;59to{& z*?oM+{FaZ{r9g7wwke@)Y#mvmu8vM2>f=c2$XXS@;!+;othLn80R*~uzPt~sUg$-q zFCHjRe~2$mp1CDJA7ok5nwql8^Ft%4w?*tjFp8KNsct0Rke-~oAIQQTtOxp!a*vPO z;tUrleHPicQ5V0Jd8=(6p`$lqVa?@a;(PmEl%Lz$O4B4NaM;^dMEB>IM|i*5>jO8; z$OZv*uy;oTIVW!oA2_U4ZqI&-K(6!QiilTZ{DbZ`IsIq+YvHiSEfmT_p*mvMA z(8_3n9ytsNH9f+k$ydspWG43L3 zDdXO0G=cP~MCa`lJK7sv(%%tiSSKf1o#ZCnEq#j*9Z+i8tJ*Wm{Q2}Wr5Ye;ZKTsn zjg_=|e;*#?q>xU4mUG2F*m!Uk_tW%WqZ5I$aP0HcPB;ljGlcur1 zD-f`Z^PQ_TBT%IwfS7{dafXfSSIJq)?v`cfsPI=R(Ea9{Hu0PVxWHgY!@7J< z!VS==TXb&&UzwT@3T15Vk=L}%ov@0}tCILQIRoMlkNmaY+q=!8!QKOtDwDd{+&cJ& zIvd%fP@i!!%%;8q<>UBaQl0bfBFTv25qJgqK^Q*GTv`l&m0{_84=Vy0c}vXYuO_^R zLM(4`l-2zv#tfu{wNCH}3m*?8cwb^4mk|PTz7NFh+`_y}U?PLXOe%L_W%^RgJ$J!` z!6WktZEvwP+!l)nHyDkqmq>0)O$jNmZ@0BFS>l-7ccjy5cBUhUdg&F$5LH@aNIZiv z6V3-RGcISQG8I&$7+e^d+F?|JvproSHf8@3-+3&YHbetS2 zCuGA$7lw;|Y!8B%5YylJv!y9*>KGS;HM?`csmai zh=iaB;gwP%J1d6S-w;=E?hpm?&8<2a#XUfl8&axu4~HV3e~wuwpve7?a-aVoUjCbl zGdh@n<*c-%7P6rVpN@YN{?%X5s!16SHo($#tC&7b4lRZj6af;OE%udTb3^93+YBk} zzAnSmf7{^|H&V@whgu7KyOBC!l6*IK(j&?haDDIR*wy#b_LGDwbNbV5M%??;Q{}E|mvGTS*f!#0WN<>7nK7MAgHY9w*8G9Q z#eW>3GH0+k=wbBW^l1QZmp0mgns_`BauZhVQLq0Nr%@6an7<18{^7&skJ>vyXZl#D zwi4~XSY?gvbppV~Qb0$;=H7S{!i^E-iMW{wcaI-j!P+K}5lZo-Q(1A{x;mJO-vk}> zA(@z0D6dB$lw>|C87FauQeTQ*n`Ho!i0~}L>#C6*R@aWC!;O9;6&BSf?_qXx z0}dAXu;`I&4mP*Y@ZjU=3}vb8dAsn^j~TCFOEd^%D5T@Xd`bEJxY3ub(fRdSmbscx z281p(V(hy~CjcCiI(76@|N2u8ClcIHHVf~2{4~8@`(IT0S39DXvu!;%LhI@BQ5Eb!CnfM?D`~5P;>(1+A ze8G9R965GqGoPs7C63ZjC>RXc411{umOFj}^$3yr1cZ*F8zmC_3 zZcaWO{bho`njS{*SJPKKOPjugFL(jaD^hD%HYJ3{kMb&teaO#mQ3oT#fm^x&agjH- zcX!K1KKac(Jv|du8y7bLxYWYjM9>4!*GLd)HQpjl=mJRu+eAc==lmom!HE`< zP<}(BW~FY=i~DlPuNS&e0I`JOAR>!i0(XaS_3n+1JoS;slW7IJfcfCL;or5z`e~L& z9ACzMIV3E0#0bhuqst^c7soaI^N=vchEew1zW&nxpjKsT2lR% zU$0@ryVhgdhHm`|UR~Xcg21Zq(M;fI^?u2Gr84$hPF*UZMt2lDY4oTGZuIyAfvG#3 zg{%4F5=wWn*?jJCzXVxoJKmF3f$<;?m8n(S1CC|1tYM=M8Kj(IXvRi~tNfFX%o=7S z-;Ww>KSS)+tSb(dO~!O_QoKLZ9O3>ytiu0>dH9ddEKU3&h4xEIde$!y_;8s%AhmUM zIeK_pwRYu21cpWC>a&7lwq-|ffPsSUyA596-h4V9QX7o@!2yTAFoeYon%QPzR|w>p zL0^6)`H&8QEvhJjddw`YefQlBGkI*cs# z5z>F1VI;^(}a^NJcOK!X?YEpcbj82F{1|4Kq4G1%!g@?sA|Zd zL+;&Amok^dh1A=>yrb4-VC9=LA&R33CqQU%zczjR5VeMcJdCR*0&6caj=gmrzRm#B z*}r`GymY%C_&$INsXMT3R_vlb+^Px7XJthE1UkI)haLQtphAv@UkiQ1PNMU%L{Wq#NqD z$^e0>`8lw12Kf%PpN{X)!HO-*Kb4vfvUAuJHL~H@~#R zHe|{F_lJ&Z=s!_e`vq_(IW5O?tHYv{U{@9z#?ExMOn&rC}Uela)JR8(bD%gwA> z%~_o3R6k9rFc8eUP(d@aj8U=9tV>W-F_!7LSjeP7FDaZv)L+w)%)cmY+ts zb=Uw6W37t59~7)k;+nGZ0@EX6WgziiS`ELxLoCcfz{z{n(a9Ejb?%>)d!yI6v7`R{ zH~;9rCqw!lKF~l6!@#-NGyd313~(yNA3wVBTCrlhTCJ2=8rgFPiMCQZ87jr_Emgd9 z9|w!NbvCOuM_CTCD300jzF@1?q9&U!_BP{iQJJJVWHtzwfZwW+xsw7#F$s7{vHAZr z&0@ElZAD0~P?InhPX91e!2*1~kTNwRt*M9fw~Wxr3)W)DK{O%Lae4|BnGFsaGnhU| zn`L`>`Q$L|hc!J=!%9&GSt!jz&LA>y)*b7+EKce~Kg}YP|`RDx@z|2zzucSpfU3~ zLnM6d=49@f&;%|0{l{Rl-=l*7tF~4){6V&DpN;cab-B}| z;3r=pT7dCT`O>OZHpM=f;)3Bzi&*H2hr07FEYwO-5vg;e0g?fqrzrx=MbJLnxa#gHHW`s(y?VYGT`5 zra^-l*A$-6Gc4X_ah@!I|E%HX)SIRgjwlAkmbZ2NsNy(5+3xeR84WuzNVTMmDj0Th z8clW)JXSCnuovc-z}FDA=*W_Sy0)m5QtsNbhEYWfbyb{0CB*j=F&#O|yZAn0@YXL5 z>}}ZWyYo>-EcLEZ*cs}4cKZ16S}s8#lD_o5D^|_|DC3k#v~ILVw3kKK@uUYM(Y!_` zQ%1W}7sj`Yl0BO;w9`8uFI}R8(L@#zO5K$pJ{L{#xum~F8o}BVf$;oib*H3)EG_i# z{5dc7kWulEOXJzEnPJilS=pF0>oI>BCj_0_Hzh@)3_K9e0rSkz7kCMg?AVF=SmO>Y zjRwQwzIm5}@d|1z=7DOCvc!jAw5(I&QaL3?jU|d8m&)8n#5Wim6`_1v(x&_DQ$H##h~b?&QH(n8VT zRMbC4Hm?KjZB0K?a?4?XIT5oix91mi331JsBrLfVZnqO`*z%1Vi;6@ufpl!B#F5;n zR-`K7Rl*d!jI3(v`kVaDIx6XA4>+s0Eg(0NRhK*!glF$kVaK3uYy({;$;r?_4Lw{n z5@;FhxH?i3Gw=qWkmY*~9=i~YiWh|90S+jZNTE$lf~2|Sl^RhW8>@!q?hamvTG$vR zvbr!ef9wy{IUL)zWN?6;*DIIqMI4`-m$I~YMu*E7vFGfIe(uOA-OLrvYdM$it5@x( z5ofv2v1G&^%Hl);+=EY2Ysc`)}-qC;d|TRSt1iF;t+UzfP@q2+QZI%kTR3r zRG0Mqq0aG&95>NA)$Sz9tv%@8Cg{YGF>+@%X1Bz)t)Ocj4x1T{nmJCBqprT)ld04o zY!PRdI^KXS%Vz)df+vfLpIs=dGJC4sBmH;{B71}zZ5I#_aM~-8JV>?JEuamta%G_v z9cN8K+wk-$;cXv zk%?w!dFn9Aci$2&OyLn^dI}{nTX1&$fJZ15z)2U%kHib511!g``nxL-;#h272pq|z zejNkEv!Ae55YeS7Ba;VOk)%Nbd6u_beFo0f7tNBbxf{Hyuy^~(bm(U(G0ow% z_h|KreRm-$R;`r$=6|SKk#EFAgJ>6QRl$0^A@Blh%@wOIxx$Wa#f9j6z-a&nz#Igl zC#<#%@_|}(Psg@wD~qiM)e+-lh_f2rE-lVC)QOG5%Hu7Lq+Snw;p*9p@4dVRsMK?` zT$SgNSqEqxho$7?nA6Ha(?1pGpK<`D==6I9_tay^2>E?=5-AT*21|-IDA1aCn7F#m z4`WwFl0s5;ib5lm@2BrXlDw=1Z4yA;1wC)2X6*GHJ0Uw8A zG6)m2_tJ+WX3=E$wG`-~UC}XKJLP~K2lTrUzjL>UZ%3kqVr!)Fxx$I{VqKTz0LruZ z9d7aS!=0BWZk$!(IDDI9c)iabqaUAshPvVZTM4a=;7_krRKYEN7&@|Q?~>x0U5l{B zdzfiyDU3PH`Zy~uVZSzIFx3j<<{>6|)0$c#m}j#R9tj`x|>Xh{`K?O3oCWLs;#rY6Le4uQaHn(@6Si@f-r`zSdN zlq{C>pgqUS86p!^Xu=*A$(1BXEoy`ILo_ z-I-K{kM`fgNnLt%nhGY{yoT!8Pr;CliG5OWo?NHuoBshx{&(Q>8+PS(PnSEl)n1eg z>lC|g)a*%DhMS2IZ%#AI*>W{Ir2C77iI|uvQVIa&$#Ii}NiyQA2X=wjd&#cbJN?RvRXI81!fTd)W2;x`zXpo` z^1fUA)9tE+(3OtInDVxEb(g`c4Y%wck@ zv=IH(V7}@by7%N>+}KreFZ2~{oE+U3#(*sPQ;;6cx)}&3$HMe$_tJ)j4GKN(o7i!C zEHlGYHT-Y6s8EAwELi5>YGynTvslV9CQC0;7W$YPl0ojof?t#T4g9i5)kq>f+=GVV zW$x?n@~?cq-L`JcD917=`VyL^c=G{VLKZ+1>lK)!1Vqg8A83 zz5hjOJd-r!N8Z6B!Y{a{_pRLk!Rk^qb)Wf>vJDZGqgO4I|4?523Kw-_t5 zK9o(kk1=_bg9D`~fv*}t(1s!%dh3hySFWdFbc=~#y(9hgA3_rioAMGJ%C1_q|4bxV z+eXN?ht;wX`YJ`xMv<@Z<=>&n{Rt#~kM85yu9$Sj4v46-*<(PdZPBncLM;CCc5tx4 zmi`0w^pB*ThoHo^6bv7(hrqT^SaE)f;RyHRE%crxVcOJ>PrEG_l^=Ufd0z0SstM-I+T%7pwFE4xI$@f z?GqGAh%>`AF112LOdMtiZ$OUo4xK>w*h#CctH)XCh22_Gr&F15x|u!iCx_11>?v4{ zk(9EqAty&~u>w|4)b;VX!^atNh0&PA%DVpTuMVS`Kf?5H#={HfQG}nn$oLYXQm%K@ z^VVqYhBu@~C2yNtn`)*lZ9a#BucG_qwIdxsky^i&O+B_a@l@&xy#h1RU%&h~s zYRBit(FptW&vT318I>VN-khDIsu zSS0nx_7-Lh#dJZ@O>(Apy;XGHHLUXQ#T*h8poD#CkstPwB)oCe*LiKf?Ew@tDmf-3 z6bozXR{#}6Ibc_FS4ThEL@nMJn`1(nPB@krOm^@B+ivZw=aD1eTi9bt^xNH9?|N!v zv3kK7ivxmqECw0>V<>**$B5M#&LtS5 z0TK^p@X8R^f2qiH4D{c~Ou5zgG;q7{V;Jo2TccEVAq`b8r`B zgqPD)yQRN>o><)e4nEPiU2d;vAl$2M5p!!*Wn2DYjsuoHj;g`gEukrYaa2Q1Um0W; zC$o&`#ev@H6_$k9^Y?S^ikH)6?_EVlStaHg%* zI0V_rb1M#+95QkwFTUH>GpWqTphd;xmx{qpl}uCc^{XM1K-7=q^dQrpA0CyLx??bE z_}W8%nG8WB7qDXe-F2UrxcK;D-Oz9DB)*6L@We$Oo*Vha;3=u}Pp&3Qc>Ge5y-DL{ zobv4`1yCYGjSxQ)95S2*-Bh_xUc{e4FOTZ79|cnqfQ zj}hvG0wHU&wOPXNz_-m{y?+Bpq2nybup>}dp?7)HiSwa#g8(t+B@)Kcu?b}pY{I(K ziw@hSrY7J3iXb>591GW>%dY9eGN-a}k#t|seTSZz!J3bs-?FjqmP{!v{z=c{SqrRf zz3xmN?r`rj`R(CZX<`!RHVc7H{przul+(C11nbc=I*>prC^1S@9E7}b(U)E3>SkOW z_2X@5i)G%Blg`03l6QpHWea5J;!rR*Te9Y`qwGeMSWZabt3!Rrp2EpQye$CT;+g`?E!ca64A~2+Y<8>b;sFecaGpq9~&-$GDN| zF$bjUFxjX9%|ET-l9PGXIC(rt#d_WBpu9%H-g=16T6c({^5w+{qQIH6A}i!pZ(d?_ zDXS*%QfCkrSh9)xK7kDy0pO(iT;KdV{`fxuC7)Me_TI~5IrPySa;=z9C`s#U_Ig!mS6d#Pbj5&%61N zH;vrT%l?P8fq)lWl$Ba+nxi?N;$xtM8U$Z@Wk2*u9mopR`uo>sV3IXo9+nV@1P}Df zV(4St-K$BXdU}1}boV%0HXzP6{@0Y+8}3i`{Eey-4GOC(qByvZv?Q{>F0$C{p-%W# zTnmK`mzS42xw%bqW4+COuW4z?xJxzmhV5*n87wDHYG_=mZRq|U(~dWfQ%cjUSjEDG zIiR73l|xZ2jFCEHTq`Sjz?nB!ZJpXc5ik=fF~ipQ)~i0) zs?&QfVN#nt{`=&cBS#LmSUJqo^M+~5QHBF*Qzr(hqHrNxLjivBEHsN*J|V#f^bZD- zSyYSH-abn~jF^IbOtHUe_MU4tdswks#2i;U=JINIg#@9gEX}R>gLDj3wO$|Z3(;%o zvxuY%b=h7|j|9BxUkTPC>olLXIaI_LZX4`f_~0Tqyd$3bMVH`!U@B$5-=l(+0=hBj zd&R;?$wkZ@@4*G7G2ktb&AWSaE1>F*RZ$m6x_U7CAu9CNwlBkC!bzU!<>Q-Nc@sB^ z#voK>HK6bFdOktlaU#bFEn~seKiLfrTQ~9y4)?PMYA!=oekrYtbs zyshatTK@G*Y{&Cti3Vt7T~JKWD)GNOzEHk!z8e9a0l_} zrX=dNZtnvzG^XW2GEBLux<%>I)3J|kWD`+09-o+S9APKdwl+zoyrC?P2F zI^!*kP&KL1Ox@WG9rZoPbq8wt8TW-YG&1z^M~`wqpol}7N88f6dY{0EX;c(+{7v}NE z)LML?f+{LMy15A9j~awXs_HjdRAV}$Uj|pEe7ki{8GO=S2E1Cg%IR;zcZKS{0I9mr zU~GWK77i?&(BYhs+37oVn=Z^Q+ud8n53LG86P~ZPvZGx&C^lwo>IJ+8&OXm#lb{WY z<|?il+K+~B#p1iw@e)uXFnCw9QnXCkHd|4WKtEAjJ-z-Tq_Whi_-Ekq2?xB@8k!DS ze#1-|7i*r>*mS#sHaTg_(NnWl(-pyIQMbT!-t*QPzBQzgySy&;J>52U|Ws$A+q zls|5FXKL}6n>+WhWM$QKy>Youpv?@~W=10ubxg5{G2&ML+1qe`@zwobGx0Ft1enT4 z_}JH>nLqT!9)dDnkax#`xtg&1ZY;Tw=g8>0^r*(=nzUHhsDPI8g5KTXC?_Kczysz3 zPPo@(99TA;2^FLWvj>u~^Am)b8)@(f3GJ(A>Z)}2u<`~j=&=zP!heB@i>cq;bovMQ z`>(mG+zi8{jDnA2XjgU5LkZtAMcUx%jqNf`HxBA0)%#@HJBy7zA?26uh++#b5JHBl z(3S}FgxbCjQXca=-eat~3b#gZ^At8lA?hVQz%-bP~6>};&!uk*L$A3*ShEI_bfi}gpe=!&pGBC zKN(|8*dB?(NM=N8Qij)Dtxsf#dvgKdqP~y@xs`}M%^RfU$Ae&Dl zn|NCHg#`pTe`v#7&AOUapVc)alyaDDc?@bsU=&KA)UZu2)TZ2Qls03P?~|b!@tstE z{vECV9U}kl-ghLzT9znsS~B8Gth=kue{;D(S8|+Ku4{gmjWnQxwpPcsSlKHB*<#!y z8(#puV9XB*1l?v>$grp zO-WLxLUu^9(F$qGEIT>2`Bdp$UZV?QTR9I(KIkl^BfS(fLT)Z_&fnwTy`h7;56E(g|mPNR5H5^ z8WbNi{lTR+%kGO@9#(5gf0^=GA&1%6xSR-)VN2GFSbv~D@Uhm9xV)OIz@=Yen<4!FAO{LIF*Yh*hg#`2}wn|NW~-}X$&gu&)Jl>T|QbK3HdX9KV%;{@`z`#Gxs=Zn$>hGj*e;4 zLq>6te+gpxfRYrTGfm)XOaX5#$!%g{YLOHi9-fpwZBAv3{}E{g5d?3O-hCBs z6#>oD+Xcm6mHSeo!90Xy1#n-lVJEQUmQ)n7gnbXku2f_t7k z&jT+{3ltdgh7O#uQ1~vtq9$v=v%^?|twT%Ea0Qx^d^8Pyr)kxIm?!UCg_~X@@FM;m&N`Re<7KF;pjHxMAmAd{NuZ z{i(v3=&$t-IiSp!Iq)PLA!H{Ic)UhEX&btQRPa6#k?uH!wx)7Rk<=g)ypJ_Y==z zr`NPHQA?`dRyo5NE;Cb5^UNDg3D`f=Lg$&E_6#8Do6Qr$S~#}S*TCl!Q!AOmQD!QV zovT~;WfoX=I6bw&v3Bx+R@dhA^xHGsEX$K1VIFx}@ha_(px*9-Mr3c7eS{*sk!;ro zN^1!!5LpXRp}`#H-l2GcQ=;7Ol`n=jC;=5a>rWKZQ2$_@hZlX!zn|c1n%Q6f@YIKxmcAM6qkMPFW^{l`P>G>lPee>s* zp1?)TBmEqTt>$QX9Yg#qD<2*<)r`oF&=Y4TXG#8Fj1e+RVjg?;xxUL-H9o&k%w8=9 zhar7n{O$ZN;YYwGFKwdG2>qBMnzkC5m}YA-Jvu5Tles=led2k~CKhsDFIm~QzD_*` zESNsiLG^uQ-)Ay)16=Uiz5~er$g^@~ixRTbqa~2h8>~5wgo+WCHgFaJBe;SM}w-NHBzv!I)m(!PA+cn73xc+i|u%@ni z#~N$*%qON>2o0C84U@gT*3t(jgtTlA<#VY5)Eg7rlr z3jbWy_QtJqfRZ!{^ykwEs4(RC3HN)A4>NJK=fCpA)V-ZWQY_we`|2!Jt4DK)Ss>;q?-X!LRB@R8k-wYu2(cv=tgf6Uc0D9f;QOeE*bDv4Jqm+3k2(U#bZm|A z74cA=Hd`rP7l=lxLq;RkS1GC9q2rWmV3liv`OioNBWXy8#W%KPa}R|?WpWR~oWRaB z|KcnHCM1l_U(;xg@D|X)trXz^+p%|Z12~K|s8$wa#Ctj6nqQg^*0I5YEnK1Urlid1 z&yQ_@h_U@HfbZd|ck#Ja-H6gWazZn_hjX*gez|~EQdnRb{ri@W=B@8glg1z@yK=p; z^4*nLLILP@=%aF3>OGej>EHUcsf$_P%1b1zr{IQztpHh1-aV^Zih2@mQd(EXX;Q+I zL~C8OgP9^$p_?QZ2|rr z;RM+_)XcIsT#C3vO#%yYFZ8CTWRB)Pl(q^@S){p|CoqGzUW6`qsTUjEXG{y=ni~o1 z44dB@4w%{L%=pd8%PPA>{)2Lu4s3vNOIojX?JChx_EmRzr`M&TB#fY=2u6oI z-&K+sjg|e(1Ca3=6Gkh`Rm}@TgUqsJfw|K^e^7&yf;0a5%+Wpqb)TC*l*u_OFf?(y z)YLn*tnEugZv->hMhsmBD6qVOnwYhG%@QAt4Yy6pd8PFv?6}Qku||YeI6`e55Qzv> z&tr>s@B1cdm&~~kwu(>0(&XvG|3asVJsm`wAzG=v!JEQs<2w4otdc@Fd!QFJY14oG zE@}GJ=jx&PP>aW@kcFjIb0I0v!E~*Ykn8(qFgtjKk70JD)Eu)dg@M0E)G~VE`R1AvSZ?~hamn6(e?@>|+Xw2jB5CB>%`>IyZZXw91cI%!lRF|2pw2*ik_KHSE2LrG`C- z3J^0BVgTh#U7RFnEzOvW{}<`a&5a5p4uf^$Y`6vOKCQM~-q`m3dhRh{qCBEo$#>(W zNn&WmYs%xDmm3;H*GW@|ETh_i@%_9e{hYfKvJms3#OoXv>Ys7UaBfF~Ft082~exQx-wu z4&|kkeq6WdR5|sTIpeb=u<`N-3`1Y$|N1G~kQSXO*e&DHM8lO~--tze8X~kXV}X!6 zvyc$=mY=<)YO=Ah1+4WduO6>-K|~1MbU)4z8nW4-b)n(+OL)6qk^79lT& z49S7r)sL=AYWK0G;Mz!FLfZ6u8XZUlXz5S)ZHp6hWbtAj*jQ`rBEZ{>JO5@Vg_ zJ?HmQuX$=NT_UkFZ{-9b&d#i7YoQ+VNNR`Q9ICWg0?FZ&iyhY%J_=HcMko`+ zGM75bKY#fS5W>C+0hNn*|mJ#5%n^yXT;o{&i!Q_kn-u99riJiFc0ZEXh;2 zXnXz7ibI+F5Eg$R%N-GmZRBaKh+Gm|cfs3kI959LY-unpLJca0vI!G6Vg77fPgT=S zLMxj>B|U(7rVcq*7@~G&FKfx}p5|U2NOQ(#w99G4{VVP}vN5%1L5EU1*^F2L-E_vC z>A|?<$yNpJeox@Q5kj`x0Us62u-X5kKc51VEg;5@BX6=U@w>Tx(>RPu2D&=mcvj&I z_%TQ;T*WSN0(Lm!pLT6!xazUR#;_e+jZCA1DtbZ$Bb=&8f2@Q;xk+UAbuzoZ4)M*8 z#(%vSrf$Mh@#X|XUN?NqMuS5++tfF;?=u-PqqPKu&yt1`{3IM+@Na)nFLaN_pr8|F ze;OYS1tkY&NCvi)pOI=Of81gx36rKfE8r3-(A|5_tYNFF#Vj96huXKvb`8WmM~4~v zpMOx&b}3{0N~@n}0_l|-OSd+4qno|*$AEI(x91~JN}!@mOo&)kv|-b0Z+TgFJL@QB#Er)^T? z+^I(BwBsD@2g&d3(p**)A=jLb$$DIljx}}JwC%>CGd4WjX-iu@_oou`R7hDFbBWPX zBzy!qA6S(?-8GQf24;5=wWX2X*GCMKmXUF~KE(`HxTjAXUL1=()NjriBRqHJ|sufx$!8j zj82{}fWCb?G}1w5n>sh>wy;V>77a6g1!pYs;%%}ga7eM&TrAU~z%&SqFC@lTG zwcLk468;W-6ea`COMSfpZ^{aBlq5$=AVo03=j%f``UqAns_K|RRSC=Na zudwCU{egAgZ$vU*cD{!X;Qc2TXM+y{fTb;Bbt+T(xbv*Ty&ce+v=?jlQTNkj+x@J1 zXDMdEq_uuU8e2&%g5#=z!h_h;2|)hnIY*`>MB=CvSZMiM&%}*|(>;;MdK#r~5NKbq z*Jo)n)sbf-0q}zTY|YX8zHii*@9FGR_CkAQ@+xJn#RNO#J7ED;f|HdU6tB#4HC+*;`8ABiWOQGKs-oa8&Syzz1}! zz+C`hUblBmtAn*d13V&#MZmsjg-tM1B9^jcTD8X2@T`}{+CBf}jwCT0!D6QN%HFds zz@V4tKkmcM2d`e8tp%>O9ztDzxz@52UiBqu6O{`6Nyzrw(A)dgrgRy zwg;klk9Q)$85hP%{P*IV;?GsRX|~C%l-N4Fwe{yzv7c|z>6~{UsLgIi zU!LqJ*}_MfXEl9!j~6b=pWHz*$DNb&CephxkTE@G00)DnO)t?JhsIfYHB>t;yBZEL zG>|rTd^WWf;MwI(NXQO$4@_{fBPJMf4&-k ze2S#dcEvbgbkDsDB%6q!(zlxHTx{6pBumc^tDhmtYOa?gk0LBNAvZiz$=sINNL4l+ z#Q5=Gs!Un!cljo zKb6Ti>SN8ODrdiqK_k;Dq$35!Grc&H6)yOkUKI7pp6@be2O+m7QsxCM*&e;9?$S)9 zWKfwp5v+G%>1*O^{{IL481Ovc(~@9#QLmJsJq67U|6Ra~i^a}(Ps#t#cVdz|z!UTH zFVb}9w&Tl!_S@%i6DaEV>mRqWr*ZeV$xiHTQja??go!h)Tcs=U@dmbnmpk7kJo>(@ z%&`B4zmzoHK#Ilux$I9k<&6x7Q{Fw|Z*9T1oUbqp{d1=g7BW3qrRjvQ^LYowEQPBIf2h!e##km5F9`KiV=m`EmVv;z|=N&r?DgKqk z!}?7-A$y-XF2B9=4R>3+QZ~bi0iQ7w?lTGc`|~Aod_w7|kw@ydsCVkWmseXDky=z& z*fi^7i8umnF6(HZ-6rLF5YE~7h$LlzVk-C73%z=KF(V_gn_CuBGc!bZyA>2m1jcJ3 zgp_2uiAiSp$vP{}O-WTSsw$y4nlXGv_jIE(-QG+XI?-e~{zX|^hp31w!lS(d+Q zVGtwF$VFSINnuorLH-#`hOQ7q9f7JPL9bbK_vGm;f76e}nP^GINPlKQ!@NPAW*AUM z<~qQnN0aS=x-W`bC@jV_;x%rsDOQBVDu~@EO1KRCktoNVE?JHb9FLN^Z}>4Vld~T2 zNXlcVjK!S27301P)BILXjXP12C%xSEy@Pn(HHefib0`1FJ4nLzl_B@i*U72_gQ)nW zkVB;=mfANvs=%x#Lx@3V*Ozm%MkIgd_e%5;+HXHCwH@?4K3Hb<9NqV@%)9b2{x=OC ze#bcc_as69;o2QzuTu7}A|x0`|6ouN;nN zU#_@laWM@NZJO2;0qAwitnkS^g<{7vklvhx*N(0NeGW~zFwP&=3IvHHd~Y>te2(Ad z);Z{`;ud-SPQGJ0#-v+AOMk$1-{p_U)bS{`i!J@(A8h?L2l@0H9G}8x3=g9e>X&_% zV}qjDmeFM((^ zvd0+*c4;P+4FKjDkA`H^c#@HN`S@ayJGsW8r=_v?eP&NTN%w$Hx5v9HTe!Ktc{*J< z={bzVHIdCMNnc$$wYF#4%$2|X`^8`r+%YFJvX*y5)_!m(eA}AC>)Ay1!quVapi2Ee z@xUdn2*GZzs2;EVL=PskVoIXMuEU%R>oBiTw;NFGbms_6Z8Pj>Kbs`v?}_1;S+0cE zg49&Tvni`?KRSQ8lg{dK@Akib!#^S^^l`r)+$3P|QDjm$^8mdek04cNPbB&-^N!Dy zTZr0kGd_&9M^*MWX|eMM^YqK~Gj7RygiU5M%ID6i$qsnAnCU3W+zyNTb(NLR@bU4N zT?ydsAAC|$Cxo;LbS*@jP498cnxyT5>S{o1>t5PiY@+#={Knwgtkod>1H&f<`fTUX zzCL>Ru(Bv8)CgL7dP0)S4$N|NSTvPU7Cj0ZkZ+Xfnv2v~HDi!`VJ6s2@71W;i%Swv zy&HMr5Li1wilv;6!w#fki$f7w(1_bTgc1R;D+-;bZsS|4OIPd|O0TuxaK2@!Cp?HN ziROw3Q%G1>BiG0~E(G;bXHwDwrjtYq2ZW~=O`BU)1A5nhbZjC9DROI61s=j8ZWbEEi>l9NW!*xKc5Uv@<@0DK8PLxTG?SAuopUV_TRad}|XI`#FP~A7( zO?c^29^|Rw6j`FzI{6$x%eFo`Vbe)nJUjM&6}PT`mcaCu>VqZtdXfX*a^CE)OT^z@ z%Q9#52IpU2LYp0qHs26e{K%URLCB@1D}tj=OVz>z=haG^$-_L*Q@WlJ!Lyf(p7$>LyndwDjNL-A5h_(A z_VO+l_})Xs&FKo zWh-xnJ%ROZJ~zA6X09g;=A#uZI_V-mE*{)^8`YZwDoNEkmjb}$U24d#QpSr+&f+;wLHiBg}w?F+}XOXDOY-9OY3vqj7Cd}T4n~q6k3Bgw*te> z(4A8C#}4Qc;R13KKg~6aJL01)yLJ2~{q1%Th)qeBVVrF=*3KT)PGm@DPeaW*12c7w zDW`eMcVG969C4`Sg#4 z@XVY1N0JQB-9qW>$X}`J)-MIFuwquHqkf=AWO64lja5e6%d60vlbg^In(9rt)#beY zl-}6@Qfw(Ay!CPt=jKt-S{Mue`+g#%J2rY;6*!aY&?LP3Fe3Ef@mKrZddtV+&i~3< z{@*W*xiF9Ei~8GtF%}s;(po>u-yt@$7gob^{hl59*2Xsc7xjnd@lgWRKdKqm){0_z zts4y`ryRt+zvD){o22S_)Am*<+u#65X#SL$+5xRn83nrP)I-Uh0X>1$s95)~R^jgP ze6I-}p;C%kAH5GtMTu(wxt9(G4>KsBO7~#ulZyY~@z*sXv%bGa4q?vHB$OC7VVvQ{ zm0(M#%q=LC9qlCkB!N0T!cK&9iQ18D+UK{kr$65ka?wlH`u0rjSyz&v6X{y0Qnq^? zEcn|Grz79}s}nNuC==#C(YhWTe3O+{|BR<}R6|UwMx&FATnXfCeXHq~1{h6@K~RcN zJ_mc(*kibgoI4jpVW=udU`6YEc&>q}Nz2NugCI?ZnUjjSu`_&4Cs)_+o)VbL+sy=I z7#(Ghy-ee^1LXi~ske6%1}(7itr?^#R0kD@8QR_>Fj*T7PJ}&tp~a18AXB?_W>lP_ zUV~5fPIZz=i&S-vI4IN0*z^EY3?1pMOQ->y-R3qQhrHEZXa*Tnw-)zIc;`)9r8CR4 zjAZIYlVR_>29?Pagl^;`44f~$1b=hj~oxId?qmR?@ztbiNK0!^?y<;t;QAx!Q z_FF;PpKrqXcrzC_@;w+yAqpusY1J!54sre~d zXU`DxP!}>96oD#DoMCr`Xi1;1tX9)==+6x#)7i4jBjP+sdHsh4T$O~1pZ(6pQ|T&d zMi+RN4238VUdQ>P;19m*yY$%-r`AfG35`9IiU^*K(fK4%6hGjbzs+`ni=o(fbe1HZ z$e;c`(3-%o@JXhUC|7wP_6VK4hq}x=GF|+j5wBWCBzdmPcrPV*sk%`q<$zCMnd}Lt zlw2BL@6K@iXYGDT7Pbf%Y~U$1pN^u+c>HHahS+y&PK5msT<~Vj`*0|Qv zI*9kkfei_)ns`zX_J|wigq@j%IaudH!Z+XOgO;xNOab^EKO^ZIxs-W6Uq8=fjzKDq z%F9UvhYKwW!=ok)`paQiZ_aXKjikRGW+m7N?U$dH3}Z5`?nL??+DAk}{T_=m^g|t$cq^|utU74$`htkxApFRlU)A>zeCOo~jQ?7bW1b%zgV(dP*YGd}6jp<`r}41RH6V%Ls6Cmsq|`)BFFT6#(R2@LLm1AFbi z9cLIjc^(QD@+C~HUs}6(<#@swCx$hd;%_D&HBh>FvQUi=GoEVW13%+5p9fWQqIo{nu#9sC{W*g5vW+q;A>)l_0dL2 z4#gL9I`l(yL9|WUD+O75i-}}ViWLI~ji%f&uNanERSuC;L`jMA#42?JmHL93zB)eP zvhS1N*tftPY)&@8D7iw!%mc>6;=5x|Hf~-#mYC$M8&wl?q(W1=%lq%HD)dqUlaeVu zW;XPo2$dxDvo#<`cTDyiI6ImQ2vm79af{c4(!IlN9&V@(Qj0M=1f_a4Ra$hS#axpvqMYBA{aoqnn z<`y@iY5+l$R?N(;>MG)Iq22W~4Qz238g>2hHC;!GqLrhs zs4?~>PNA)!!@2PF3%jt52FzPk>Yfs5g73)o;GT6IIoriB>Uu;xOxV%fv!iL0aiz@Q zB|ogMSD10#RB17`P6JTSk{ z)4b~WOC#|{)<90Aw=Q)}E1T+DCfi_j=@)EQLwJo9UN87BY-^X*yRv@gmX7gouBb`Y zcz_w9UgEQcKQ&%%vg~uwa3twRm`9h+ZB4K3D}2SC9g}ZUHGUSgBXQc8Ul@>bV4-is4BIz6Q)7Rsrvj@ zXlM)>QQqDtBI5>jQ3gykJUa(jO8{g>-;(WEX!mR^y%lKSLSd0jg$h;h21fr34)6Se zXpl;o#)S7=dPX^-LHmH5Dn6d<4qDP{bOxevLS+U_sgbz!Z+mXZu=`YE1S*L zf@8LhVtf z0uI@p9@vSCJggqOOoFJ9*<3wRRRKzAJuOIjgKc?VaWU|VabiV&`6zfhyk>-ngpJ>j zK7T)}_NRit^9PZinw8f=$%=uf;BH1q)JQ(`@@HDa7dZM;ALl2q^%?sn>k>aZ=c<@; z%|NGWy~#!N(=1R)5^T?HYB#LgWvb;?jSn~r>JLv!K`11ot3wB4cdG&4TyG%o0JugQ z3)FL;(8D6M#8k2htODcDSH9zWuXzC984wPsfD-zh5(BvH4?s2L5}t4r??e*>43?&4 zkD#fxH5x<7r;No%($bG6CzW~_!$eZuT$E%>;F111$%-T^n>$-g4^twS$n*UeZ&t2t zvWP{ui#nm@;@UwwA*Tg!d`-&P2=az-5vBiCeeBSsbNr28Dbg~@fU^swZO(y(U2 zE@XOVF>qYylH$Ch6|`7O7H+2(^SQ#3FB0~JBht-{!uiM`%*jZ|9iu1|+Ud3S2GJ5m zWk4#CCYC_c|Jf{Xjfw6!jBj0oM)j2B!v~zGB^DQ)qO-R+7P4^+)`a* z4&q#vn3R?uMV6BBHZ_^=ZOkKhOpajfIXecw^x2d8<-6~c%Uxn)Hu>95(2)jblQ=Ea z2j~&bBswI~vjD2@f+95KP*vNpZQ_`1R*1pGsGX}z(_znM39U(0Q@&q%5CZj_vT_-* zArBj-hWLdMs{a_s1)?(lvqpCn!Yycz>}$0}P`+j*gL_}z9x&MRYsPK>AhV_mh#WrhRICby2ivYqgy{La)Oz~`r*$X>MgMXes@D-bYzxH~OAPBP z_%AnW0j4cRC2p^=F@(bQG5nBcUL1-sP1Tw7(oYWaeiOKCEFEZDueTT92v)iZU9=cn zt%xj+N~!5J!Q86+wBoLtT&9m2r63A)JaVoPihxGU%he&FKUIysjH_i_HN?TH>s>^1 z&Z@#LX`%Pi2hqv1!>#8rCb5LrFA)@z13L1Y@vkS*`VN=gJjM24_+vkJ3}MGS*|7*` zXh)u>4N!rYQN92OXtP&-Q2pTFD8Uy>59sGSX5uA$)txx*Ias{%uAx2dWB^>u%g{Mf z+z9;2P3x@q{xX$g!zwL)iD_G@1|>N|vCnQcRNM2}nM!NIX_|3?Aa{Un;_K(?2>c8u zy8HnUH>kN2f+7!9yW~`k`aDW_+7J3v*K7i>dh1_=F87sksp!S2k5=+8${Ox!^jpT# zxx9eyQ68nIn2=rc|E4Z26C(7Eyjo6WA#U2d5jVIR{AAe4^6+iV>U%D35o+S=|FB}; zVNX6R1%?X_9Fa;L54d4PU4p|*lz8Rg4t->S$ipZOOxEsc(Jh4WR-8(iMc4(MNYr>h zYnaPArk$zEGNWvG^xo)sf4+*xk`H~`>GOe+7Ey{Z8_?7M@JbSFY?~kK$}K^;HNVHI zJDP!(8LdJ*4gwO79u!zZWwcPB*-FOn`DN1hx!snkh&{`ynXsn(Yx|_R*zjn4jTs=Z zlcGn4OgeobnCKI2eptA@Y&RBS=%Un0E1++ok_d$vVT62e&PZ#C5ftFbG1zba4va8xDAs6X^z!LELp#`LqY z@5|_@J3^kA9tC-bBor#8PB-y^F<3@@ONIz4Re15L#%|lGdShUk+B!qo30I`RcFYEq z4tGaCdfR(kg{;!bu$l}oG0jz9FR!2l?Rw|EcBA`XhXW_k^Z$+mJ5K3XSp}idd;EAU zSu)C(Ya)*;TDoodcr9`Y>+)A3kK4spWPUd1GO5onebYuivDL!#aIeZ!10{< z@xETgcg5V;j4;eni=o>*!3wRzBOjzz#kMr@AeR$l`+Xp@*dDyiG44y2rlhU?XlG|5%^hzE~7M zr(JzTC?fm{n&jRGJ?LVb=lQbintExFjIOyNIg{~@myL_DMD1Yd3emcPv$r&?+Co># z)}i{fy~5QZ0TEvuyjV_%`LBT!DY_hdMAln=znPiS%n=C_@@0AG4}G=zAmBErHx#P$ zYvm}@_t}!iwUGWkS$h3@hcBN;{5HHQ4mvW1u2wJ>KPdaGKee6vh9tMi(CV^I+;%rV z2XXbp%UP4UJ8XaS5PbOY;K69n{TEF3*FQUk0LZj-;G0S3W5Zi!$|$emVMeFM>r;n| z@Sw=ioHHv%mLiiaFBiOsAJNmr{{;QPs+9eME} z)q$?2Ee)dMPSzz?KBON5?KOO<<{o~GOef<rml zynzjJ^nC90J!ciCGxuqeWy&>SeQNt#4?*)8bg(M$L^7^S4~5#~M$12-s{QNnk+R>1 zAuSn!znXotdk_u1*ARX0>mP_U_z^K)DlT&vdH36;PP(lY(j9iuHIN8a+<)Y2ac&_ixG0->K*de8js-C!moRQEitD7DKdZRHt@lcY(Vu ziKb-)nhqU-vsP9M&1Cbl9Sk9{sT`RYVRt-ip@p9r+6(!cuM!p;(LZArwm3bDSn?*^ zpgJPgBXCxdHt$(tn;oSApd~l-2I(oabUSCRX-Bhaa!*B0PaYIV0s4$cv%XH4yNeM7 z`zwJU0_=x%{ys_gC)=+S9nC0n934!koCT}sY#kc47fSl&(9dRszizQEhK?0GkUuU0 zw!ODWzp?M=eE*^No6C9rR4Q{%5i@{>);REmvj{4Q_P+OwE`z|!u4-G1SB$H%Dgm@=IFc~klE0;%3^W;z&_ ziXT17i(UOS+GLJ%^5?;C#eq~A~**o&UJLcs&oaCpd zZ}!C0bIG2%-tOsa6}>lKzyJ|T&LIv1f;A{u*A&+#3igX2Q#+D+x%X#S$x_fX$!)C9 zFP{Qx)i6@w(A}TqCa1r!B0ectO@^hvoZ&!?tMo>X1*fryru9~WI)u7q5bZDbTaj~^ zuKlv~d35$S65op*(E_Nz+L{=c=S2mEq#+_Y@I-(_zQq+Qh(Yy@^uI zYrn$8KhNXP>Qefp)wJtXuwQ6#p~G(EUx8x@H$r)f4{G}j z*+bMS)lrB6N7hh&`*F)$o!xGa8j$iHxxV?rHpA1^HaqO`qA~xZ(a*cPkwI}m`{|1h zUGZ1#BKKT(4@N@KMpq}j$B`l@R~q8ET@ZyER4EywE!QkR$gmK5UC-5}-C=6PGU%gVi6FB>8BK{C+{jAX zGzGN88d_d(-1qO9^qC-)!H>D*1FDH%Q+=7D-H&i{-3~@{kT<8?_Y{{mH z5FBfkUYq!YcL#kThR|McB_Uaen{|KnFp%=Rl&2F2Kz%fO&NEaJm;2$ zi@Bv#r@D5L-x|WdJXH7(yYoPws zVtZqzn|3st>zXobdU$(g=YCxDJ%bB=Nlb|<9_LjZ-?oi{iWz% zBwpLZwP;{en64UhD^>Uu8J=5*w4V#MRLb{B+7RD{EYtV+Fsa%!ku+MV3fr$a(+G|Q zOVt6bonmQut@nwtK5|(UNvR>L@=4Ck#%^zmy6#z+T^@*E3=8!gE<(pGP;+J* z>1!znS;K#2Y&zKKj%S-KkINat7_{v7y&*YeNvvBK!nePot4bSg*WzjJMEp*pJ#6YL zxi@LWJ+BrG&NRzV|I_;HAl|KDt!MfW)UMIdi-(Wp^_Yp$a_O{~VR^q}elW;81Fu7G zV;?GEIeTi#6e+SShEyND6u<1hqjeUy_S*Kv^V6DbCaP7l#5~#&o6ErwsgBrGnNL4z#%ox{-*K0oatt9to}94F6g(zg!T`wxun#T zq;WWMkO?w?Jeijg2ntdH6&p~GZrAIWGavSLnV`Gz%D@XaqFu8lmyqow%X41?eigP{ zFqi{YlH<&+g;%SlVd1bZr)L&t7IQ9r8>WX(SpPYuB!hZw7kj)fVJ87F=ka7l*$2Un?B;1W%wANu^RZpf zXUq3nQ}Z&sK)zBRH=JY+^Jur>YrK~ImaD_pO=TZMD&&~QMQ6~s&vTxpie7>okX;K? z@{hiG=xS6}lv6e90OK=`y-FbEK`W@l2=;3;8gwup!iglaW0xAc*o3vC*cxWeQTFow zcLF_62#*x|=+q4C03;gYz%WV5l_0v!pmmQ7fNTrIxrNba`(vD)*v0X!I)T`Z5yB4V+fI(c~% z#`|_JAC5&HC`lV^ddE1$YyTRe|1Lh3C?Q0x6nO}@RO4Z$@kVI7VB<9RlyW85QwTVm zf4fr4PortFBU>fAXXVehq4>r>hgUVLq2^jb^S1zyg-V6^PKyYkry!NS|qV_EZ`-=+-w?_l3t;sq|fz?UjKlNk} zDtKnmlBF(2$@++>K#UauwH3!{s?%05*i?bpj>Z)hZ>n!*<61Zs*JD?t#*42LF=BIE1Hh<&drE@XS)6vr@3A$Wj zz#6L}rsk6S8$0uV!FEmZ0DjYTxlmZv>4jIA)+vNCg4}`4Ir0ZyaaZ;hdsN{WmP~Hy zE51y3Y?4fG)zuuSWf2XeUcnSuDz{@Lh|gUP{$tP2FqolaB`&$Key)_LZb448#yp<} zn@G8*zIQ8O_)nkkwK`|Iv0GP)YCk+xfjaWWGPM4~SE#Vr9oK}6BDoj8gZWHC6s&UA z1v?A$LhwXhgRDOWVp^PSZ~6>?f_V6tKS`wn=`Pw9fdEvwoQ=# zx0_e{0CCuWu&4a7x4q-!=Y4T&@%JJ>+Fv)n@G^SOmPDXS*Y%Gt1-QSXztcgFA*6z9 zMI|ULidv0+Qd8;T;MJTBb`@@1ZdzJ#es|;B_wPQ=Qv4O6|JzAb5r{Hgq>-@5|MKz2 zTS;sEAE`d?B*)+UAI9D~Dy}x!9u5Q&BoLqp?(XjH?(XjH?k&~6`{${?ldiA2uKTSWUPSvieUAw$Wq$ZJ^?Ne4`GCSbsMAemB?Gq zTm0{qm|M*!%*Mw7|8U7&&q!*XhzHjrvPI!t`G|B=LKUflLL4NeP^uOF#7(4d`>GIxnzVf_p@P&3gTWqVvsGj@nH9*ap-+Zdq*5jBs+QgJx z7iD%#FiZeuhU{C3Zg=}r<5;rt9q1wWPp^#-2#Z~Y)tI$l-`gh0S!wpQm5U$lgRy!m z*}?P5hUSH5z6h&tTP1NTHO@E^Du|5&U6~OcI4!8bcQUz7k5uK}rg6Ds)El1shlm#P z{ah}#g(FiwbyL)3r`a#Rv5%W7=T_P$KGF&?E*DDWWAs0mHiPI}1Hq&%Qgm%(mjj6& zJPk>?nX?1EelT&XjSOwxh7pL{UvCYj?cY`|Y7Jk>D4jY@p=UeR^fQK?{KJ<=#AQv= zEW1+sgBFtj!p2J=)rv{z*~|+E53{3u?KGXbj^yTdDiW_1wl%TZC{+NIxH41{OH!!8A_E#k{2O3(DuaRMBfe6D1Yi+$4|u)$WI|Cpw^6Cs>e>t(u^w} zkx#b~PpiZ{3`lI14+m|I{r%K@d-t3A{;rfl0Rknm%Sr$SKr-gyTeIZGc%$ZNSS+Nw zyM;#j$?^+q@IcUPlj%A`9#q+(h0(r#hny)g^T(nO`un-PT!=c~jV6`}lfO#2u4nHv z^Il{rs%)Pv-CJLn)oNjCtI+-#2e z5or)5RLuk;+vAz%c~h6SbyTBhuMX+{9&lHmeWdmujgSw*CY`UoI_FF@6cHUqhy>+F zp{}4K`*{Yr&_)N7e6-d%4267K4!-iPtyEev)BEiLX=d+Zk6Hb7D} z5u%%T3-+piG^sDtDXtgVP|aMS=Cs5cXcXtsr6h`1qZs%+5&b9-(~j80C9#14uikBD@dS1^b_PD1@&sTnmYL()}}N{?SZPK%A@{krdXsiRc0cn1v~#G{w8qto0IPw_h=&X7c4Xz zuPU$z{zI6gtCr+qXZvnzTG!1-z0tmsW&EEf`2Y55HYt3&zuetKKNB9IZqlDw(<>Y- z$i7eHCkx^%aui8{XOaJ$%&2!M4pW_Q zRgS*sso+t>#c(g9Oz>_;b-Mcr5^vKH^1M(JQV%lGh-LU97V8KOPq(H_>>R{VkQlOC z<=zZ}EAwL$QlDFeyVVTqA14`1dJ&rAi_#I^l9UWO9ZbxE^~W4v1N8>ksNV^h|1RIg zw(JTi*iQ$vF!Uuo!-D_DpluZF!Yw)2S%HKo@CF86>%E;f2zOE|31uW%gGRNsPrYzv z9or9{H=d?me~2Q8lemeR*Fdo~7Qmuzw!5OOwVo5Oc|hDmn)-J`Ah>zqqG_sI_H!<{ zubbbG9`jzZZ5=lamh?&eCA9>yYS3vRcT#}nI8$Zt`l0i~MWu|sYb1n+N(Cux3%N^R z^;DOX8M<&G<4VhatEMDnsHI#vxi6=sfoUM4sAUkKRv4_#<8=7aWZLbu`7+yL`vt#p zj;CDrFT_BX#h0hlmy+Xd`DmO)%LvXQ^0t@ai)@{?!(f?~4uT?h;3I)upfIR^9YUkk z!qvcqQK-TO&O*Y%^4}&1?J6Jw1Q2%tCFC53f-Pr+dUl#gmrk%*`CmzgD&w_74|-w< zoF}luB)sY-7v%5A=rFN`>6n1IojEq5sB)a1@IMwAOLf^k0^xGcQWoJ+@!YLF(G1Zu zIl_-xLlL|W@P#;+s>cfcn$U=p0MQVH`znV)uE~TDA+j%4qKHf(h8cowY;+ou`Fm0g z!P(SHsfmp2k68kO5^@Vf40gnLXS4LlL7Je)f{>=tv;mpo?8d zZgzZ3eqnM8%P+2#w>}lVe@@LZqlL_P&Ag*%ADx%4az%^xN*# zFu-MbKwXkwwz_KR!^+1%2rH??{}l2-k0OYl1p!DXZF7V`YXY)uuY&ixF2=8*95%=e zaXEf{#;}aAUJj1N^+Xyv)kG=hNV0@rtEyK(=Lt5M?K%J9do2wS3ePTD;K4reB%M+~ zu5pVpnt1Q?OPlY;vznmBwHiW<5&tLiKmI$T-(-CTJ7rSvNMSvRwr&{Ji2Lp!0_Z9V z1X+b3uXlqzc&4WZeEcAkF zxoFe4wNBK-r!%3p?}m95+6lW)PV86XnSs7X$N|$O@~w6__5MB_*l=KdL&eKe((oMG z@d1rwdLCEeL@rjk30kw}|2QHU2o+a|M+bt+hTjmeRQ|w#0Qe>Do|vA6Dd;uG9-iAlkVnH|9UD!#8lX+9@L(@P(<72;0vE(s+S|Om_JzR zd8?DD*G6^!VIEs`MC<5~sm-pE{4$>f2sJdk!OQx(onpZhD+7Rp-538}|mPm5(NPdWQP{e-1F0 zg+<05CYZdB-VJ!npqd{nBi=vbK1D>pdB(S;6A|Olg4#07Ebp^=Cl68(t5%YuP1?}S zzdu;8zjxv&$L0)p?3-?5bzi1B@5=pQPQWi=0g0}ES%mr2w$Z$ zQWzuqCyC-A>rvI;clWXo%P@>&8ZD_%p{%NuCCX7K)3LCGMC|K3d0~;tWQ%mj@i`n2 zguv$rQGF@EL?V5wVS^Ok1NKtK719lXa*8_hXxL7{d+sd=R@Kv#)o)WsiQV5cs5km2 zNLl9U=cU84G!Dv9T6sb=@LdhG>!L&R2{`u%RgHJdfdNDSeD+O5Mm6Gw;L!O8JJ@@9 zJ@N)9c=2tlySO-fBDN~*tgM5B)OBUz?(zSzQru2gc2-&I|EvX}h7a*P(sS|g z@m(iGjCB=#@mTjd3WfS2ihyclN!;s3!JwR9Armh|z^1-Z3{Ify0XKwbOs>oACpw0A zZpcKC%3UbtIVrthRQsDbT+rt$?nEwUW?`{=MOI(_$kN(<2i=7hb%SAAaLOP*Xici% zr(i1=GAGa;(z)XxX5@JY60ZCWGbbmAlt&tS-U$2_EbaWC?dMmO)M!%Q8;j5y=0&IR%-u`i`iE`O^(0k+h5rDKH# z@b*s(bKn}7(SY>2B?O52d&{(M{k{aEuLTT)4aM0~K^_rGMV+x)= z+6vEEj=`!V&l(Gm>No-gObgK=#8`AtX>|CCv_v#nBD0;_!$`NBq$2Q5Dn6{3)ZX<% z$ncL1?D~UYal3%q${Wok%WV1hEO>9c$88$JsPb7^3%w_RDyyneHvKE|eXE0j=^OsZ z!dE|$#@ErMoc@=8HX*(UCp}AeXRaa;>3Y2la+Ek$v;WZ_RmA#H8{hyZZ%V6i<9-q; zC_yF#1mEyF$Oi%ODK)vY_c@Gk+CCqya;o63_8lukMUHrq%KqSV{O|+41u2VX76C`Q z!_T96_OukehmBVHyYM=?tJ^bM8-O%+p(Bd&>$(rub{ms)@b7Y77X}fih=hUV4brs8&r=W0F5>|_RdR*kc4g+e|0v{X~M(k zmIrtnP4i1mt&Vmz#Hs3inHHw7Ff?h@C8e@bq;VpQaN^bW3W=OvT9KnWNEk_}%pxho5zrx3Oc9ej1Jc_%Vm59P@ zvkc4p&b+)fnH^+KiKg`JY}h?b>XmVyZQ zfsf4l#12v24t%`F+f0v9PDQa3LcdVsbOe8`F)Rhaz-X3TEsLEnG_ykpT(Po^7U?nE265({1Pbtyx5^>-=)-d78X$cJ;PJAB zKKBWy$wUOyT8q{1W{${H%ts4xM5;0LQIYo^7zq_%lMdSFV{q6#8pmj+X@boQ>)X*Xe&|=^COn$9nJRa9Ws;7?U^lq zBf$`S(}MOox%9k1)%9?1X0es78|ml!lZpO^JSy^?;UmR926!PE21xlvEIW9JTBx=b zJ^ldYxW6A;Y|WF^0J}N3)WSN+JhE6*&bVlWfQMlTHj}E<@g4~~WjuErO@U73pM$*S zzcmk-R+KBCs4)CBoqaFKj_6g>FQ*U_C5?fyQg(fth`&C=6~s{7`p3zCibADVAS>uz z+nKw|H{2Gfvt0PmOct2O#smDhKt{5#HdKR{E!$;?ugrri zbgu`5mvYjSn8YT}*3UTTpIKmNOUhLX#}ww6Qd@!cBbb6Xu8Z2jvw1#eHkVkQ&E%EM z(oJxDgp2@6nHi-#$hDJ4m)R$M)WJhtzNV>O9{$YJC#)P%Rc>T$E#6=+9AbsR-?#1U zs04#hl+PPi6dMVzkbLBm1e9#EbuYiL&Lk0)Z*oH7*Uy~Qz*db1X%5Iy#onn{6;R6G z{#NbY_{DL|xxT)<{3}0A{=C6hGx=K-91BZ7H1W(kX!sxqC@Lex8=DvFG1xlf}y5!KaIBiAezp%=?&1^uAvyHkbeiZ4K-I}EQ7`O9;6iGWq z0U+U{0LfO=B)=ajM zf9CcnxzE+2WS|<2s)gIT#aU}2tb2bkgeWkjF38v?L9jC8GkbDTf3Ah@wKNYh z;y${S%gJBYO(pmAb~uK?$MYg`DIix%(SXIWkGO zIM?z*b8rYRb}%b#cJ$Wl$z?M5Pa!xMz6{EK%4cH-DtJH$YhFDnb-8P48HxA!kS(^_1ZMPG0o>>oc zTF<@`6r$d7hrYeA>h{0LVu?&RpZ7BJx{!i&oAF?<43oCO@}WCaf6(=ledBPuc-L^+ zcu)aYxj|U88$!Q2+JNNs)QyKo1)&R=hK7j%7 zl4NfS7#Id)S^J}@i)-Bz>mNrx?NBlt(8_=*Y?Yrv*~K{&^&vtzT>iR0Z7gueM@t$DneB`ivO(ChC0XEa}VoT zA3#tzh;^Os2dpqhu`9HY9EUxUA)%odQGytAW3Io&m69W6K3t|2OFhBdWbZRQ$0zz$ zYE`{_JOH76)zCTAS;g5(RqNQt`mSmi%Ci~1HL#dN6(imUPR$^d9K;qdVe&b1Guxt8 zg&*Ng5+uEO3&p9l1$yujBm%>xaT)n|;hHoFBKj8y#nGK%Qvz|g_{jGVYWi#vqQy{I zq4CJ%%u~T(nuG&O3tQt^8A!tXOd1XXRDk(ZgrV@Dm2B>M%P#=)8W|nf3jsW2fv~M& zJ~F;Ix!@->lJE?{p0TJFz zl}fR@=^U&Z!dt-d3M3W!Jr+ zWU)UR3}EN*J%v@}Cgrr9UE#K~?I84yKR8&MfUJTl>){Oj&EnFVw>pojc`n(D(Xv?IPh{4w)3o zaoD}v9m^o*YiZNrj#2?pr6CbPRB1@=PtL*+DoFl_9C+Brn0!Vr&I@i&m{|)XoJ=R| zhm*pl1gyc~USR&O_(Gy22$8?0;7W$QQ{h>hNb()!s1RKTri?OWSjk(Uikf5?0f6k52WIM5hFx!FX7~iU=T!G3V)1W5=3(w&<@-iift7 zAd@zxPm<)+mrwf|X{0kQolnPnmias6b`vQwKnC!$G;&4CV0zUtD|QrmI=r!Wlu~)@X3hvYKBa&6arJYD~fO7dlhWE-W_{x)^rY} zyj}9_)T+0=j^pw#Kxmk#OWM!pslsoZJ>m2^wktcG`fz$QoI^VEA+t_>NSbh~GBO<6 zCCg*95<&83R%myj9WVe3#!MvkTF;D-~!MEzb z??sOcBr*m%fO*w}CZ}Q}@KOZrc!el&CWuze^H)G!7$*pfRkXGIFE-56y6d zoGc-qumfwiUsChk$P&g+CvV1jtU!lRFpUf;T)8UNP$k$_ z4{P6oC5*`lN-@Ij%6zVR1%+YK9NZJhkjji^a>$O5Q{T5edKcFO-|nBBVp~wTkLNZcC|%`)konKUx9^v$y}roeQs*BpHR|`w zdXi^@!}K-h__tcbKI94*v8?9KKfAv%fyDz9?6qEB+b9+J|J{ZV{38W64ui_q8sJi-4Ir4b<8!R`9wsMRNaV!@6eefin4Rf_DtV&DTO*$l z9U>TY3f53Nj^%B}IBwH}%_xxUw+MX!LR)3-^}nRff`7!4Ad1Z`P|R=tVr|oQf;=Fn zANuucRIAX(JO!Q@f<}Q58gZo)qkd6(5!SL_{;GCcPo(rNR}jS_A+b0I!bw%)4>dXw zam7tV^3?KS+nI3(sY0xT0QCC0Q{k`8fSO`>S86FzasU$~)PSM%l%hX)vACm5zBIKe z3606s;HRjmda}Vb{p@`=tYWpYxY+@@qJ@!_sH24NcmpS+aukM>kH_hOf!udU+Q3n` zvLZ`vm(Jak$;NY?=b^Vp$LDd|7ZgZKM6SkjVy|s~)0)ebWosqYvSmQBO^ z>3M#Ybj$)B;t{!0K@Imiu(5kcn$#UGv;P)$Kp($hLA>sq;|d*uzY*>zL>DyE`yW>= zg;ip5)VOPZOt-E{fIx-OmoU9X%NgCc2*+=8utMNnaZTLc3u(Jb@HTvl>3o5I-Izbu zc*s)z{HN{v|0?{eVEH?wU)l!}LhXHr(nP?RP9q#fS@*X5kq*sTk0+6mDW^ESMX3zO z2oozd$>F&JR?`Z-$El4R9rVb)T+h z3oVG>A7!F0uc-#C<+zr6k2PtZx;?@UR1fqIQ;S)WG9J;}D}`yK=`B=!Cr+l^D|ZT~ zAY|kKii6aLL>^;#JP@`;;q~j@h)6<0=-4?zs8$OkGND2>TM#0M$v+(xGb%*b$gPlZ z!Sp3?*=+C#|3K&y!H)0t;Ai-Rq| zG{-yoa~sf9hb!p5C1bKLO8+AqCSp|0Bofj3jakF= zG?G#!#ozC9vVYftP{^66EVZCyq-B1^cl2|&9-X$!-A zzWct=Eg?vlugOXDI*B zY3x9rS!#DW3B+=S7B*N!q!*ZEc;qum@lPi)41SlU&x>*VQc<7vtsD}!3gv^$q5vgs zBxx3W0h)%Elo-pLu~t^XK!QRuf&ek9GYF2oBfuxn)Y~8gsmxV3h{MTc|Kf~VS#T|N zQW5oI{iG|zv>U}SfFgxFKi{o9bwo}piQk7J5=+%$P)0`2!V2Or4-EJj9*>(#Dm2I5 z2-b1vKZo?jg3-1QK$!Eg_zy4G11FM5L!)cdsx48~`q{8Mft3qJvXG`Q8d+X*$Cw zJL?z(Qr-b&k_3JZj*yMT2{0BIx-BuKN`=n1zjr(->c99thAa5;Rq%kaL4P_Mcc0P1 z1yqPGA8c3rO4hTVgTo#@$A^f?YAce7OA;xKgiD>AJN)mOgI#^37p!+&5nR~5sunFC z0~}skC1+h(tmho(H0gRn4Zcs`ZF^s0+WdGQGiJ_<)zCue*F6|!dsJyp!#ZfOHBdEUYU zeF}1hCJ0dSZpcN!QS4aFWv^20!@#yPqq%uMK-nZS^vdW>eC?N%u{V8zWHZ6{2GVe5 z#Yk)8)QebkiIfDY01{)f6n3v)@2;LcPZE;`(rLRW3_)m^Z7wd=ql|GMPp-7X4@J}T zHY@O_=97}f*GvE$t!j%trGDkTmZ7q6UO*|l9}ZGX9(^cD9ht5%1y2ZkLF2rH5sAie zSUw0h94tQcNE{0^5mK6CCHT4EZ|2B~bnKd68Rc!I8>vSWO%CJyA-g$e+qN&=(xxDC z5@LY!tlx?tAG}X$(+#=o%%xEF69=MvTO~9-Od`X3NSN#^WSqWOGh30iq9JV4kbz9R zGKIqKoEIk4LKsyb9lcD^Ap9&CS@MbhD9C=ET)!AOv7u`0M7+ee7 z1R3W}nxNO;Zr=iH5<;iyYTm2fS~(k(FbGSSO6=h%Q|!@uov=&6WB&-rMr&#HL@186 zswuOQk@d3O^{G>fr}*3GGHOg$3OS!fxH%lE`oj$AS_r6CG#2kN5hT^H`t-7Y;pzK} z`O_y^D)Sdf`80Ngm!r`2(N5Z*y5zKwvY<7je?raw`JMvnFToKwd~jb2r4;b#(NW%# zpT=x$Ey7MT1A+qeLKxP%5ccOBr5yU9=_vj-atgUJx~=*dE?*b{BZ%h!-I5OCKOy*I zfW27O=s+Si^+Kn<+kHlwC8at}GQ}nlQSUZdb$CPpv|KbD%};m_X2x)EWHlALPn$$I zxlCJ!b!TXWZ)K1plZetW(?^K6eEyR2h!5T;ifDQvnVFxgL=he`$HL_7l9yM2Im9wI zy#N%8$3;ezRWhf&6OvQjAt9lg^2ORFjnQvQ(R>px93bP_ zV(C*xABHNxkip|iDG{51b27EyH~fnD!wftws2SaUH^}dWWh5qD!f*Z*BP*)=B&^kh zAdlduw;+~gazG(OR%H5OHA8hu)+Ct_zCv3XjhquBh5hcno?F1U05bY)_SmnrAeHC! zB6CfOw-v|0@+^FTzBjF{Opz+FNd#(qM&=-|Vj&WUVWYM^i8J(g)gYGQq+;t*BeFRO zXM7~+N&I1$apmEP2_bFbh)NGo;W5MxY+lO|dx@NaacbT`;pK^E9t~Boarp0?X{yiu z=e*6hFM^b^e%EKLtA4UmU}Q;Z&s*rG1m@kvn!5FX&O6?Ykm{AE`?Ol^#ACoARmZ~x z?0wC$i*DlW?0**7={h2k8#0o|!4&iZ^E8bR)+~<;M)OmtS!h#xFHkuK#ay_jTaSyt z`i7L^J$?~#LuS41Kdks!lMl~56W`2ET>SDuM$T_$KJ+Mg427wsu)c!fA92zD_d3Bt z&=`g)gbFbjKxf8wpAkwEx(k|(t*k>X!AF&LKjV8zCW!!aNC1>D*%>sk+lqk)c7#JY zG65JQ2izAD(dH7z$%A(hiV05B6v-Lv9!ZsoKPtU1023( z1!TxXq?2(;)WX|LDZvISk_#zBK@A|Cm_qM*WuM79;cta1W;-Xsei6#p+Bqz9JZXWB zl>kXpeu`+kC?Lf!USk?aHfHyMkw^RzA)@9w6CUps9KG*gG*P^Dr984S&&Pon?YqV6 zb>(<26q`=~&JvotIK+12#I%{TLPzr9bAk7Z%iP$$V)jdrOcE2KYV2_3oU^JTU;T%& zJ(+LIUTUT^02syG-adE|v(}}jpLdt#*xXIKbMs@1C5qHpPlKq259hDVl4Spf9H9i! zMUpK~O@7Olg5|4ypF?f8`K)S(1K98Wn9VYAyBDobyxsemZxFB78Ez{Ms_%@PC?jJ^&xY4Yf&pIvpHcY7*gFvqSv$@%tmxV_ zE*NAk$b9jLh^2%6I_U6QoEF5&O?QAWKeDL&sG*H8F#yA!AfqIi6)uDNXzvu;}U|j4gONZ^T)0z2u;)*i~W(dAnNtyfxd}INsv8DJy+Z z*YF*(^Mcbiocxu$PeLq)+Z(|UfL_N$tSaC-^YK4}US+=A;d>4MKK(aPSx4t8e=WJ{ z8im%>IsLuD?ABwt27(@NL#wP?xUVGoj?jApjpVMqyQzb~fE)Y3>lBB{Mx9j^QJeF< zznmmxx8?lL;4p*gp*+SNjp31c(yXFVYda`qn1R120m&(#D)h*RW@UI+Euvc8yB_FR zHey!T%ru8&W6T~cxHOyM;b7ma@YoSM2@61Rpse5o2h-QnP3(2_uqyFB7>P8dtoY&s zDyHb6a4;;dD}7++J@T-VyoA+Cl${_cc%60>laBvP3w#}$D50Znz6J>&K1wik!!SR+ zWtB(*GMq6P7sX__`7k>m_)yM>MzjGufE|6Y-HkF>;nYcNi<=at+?g36moJ0>U9~!D zKuCo6Hidw&yo1X=R+|+yPXisZoRi5vt{G=myU|m|uHV$eQ+1qXE`H>=Ym8#YwDgn^ z*=*HqdhC8}+ZXuq)De2h+VNhWgCQ;1)Wy?B{@ep$sMzH^-g3Ru6U5#ikokq}1yjxS zXsp$_Z_&2LTrF(6pFYh_)b84Ln|FmOo1^FoDB{q-*-|%%MvPfeRr4=qqnvAlIoEh znNNTA?efub((C57kHuF#`Ex@({^VTrQI~v(HO)Zh4WaEtKjY29yyq)VuJW28hBIgTEjpzPM1&3 zR!~{XI)b7_IQyTFb6+Ut`E&WmhG7Vd5d6HokiV-(#06-b=59a;s@Ml>l3}<66hNJ- zW+@^rGt$SE1xpzr*NRh&sCSyML0@)^81bsdytS>YacD1Vv5XAwgqYo2m~rH^Ivx%D za;7{dt;hirNCrl&mZdhCt1#^6T2?PdMy*!5{W=_&l#P?Si{^G>j>wBGu#G?N`YKRA z?N=6Y!c)QBZeq)Z-@+Rl-gvjWZ+|dko6F^bcK#GByM1KoI-z~YRlSsI{oQpHLhSz_ zj8>#{HR7nFpNZePiRqgvkE4RfPt9@cLF}RZU-`JCSJP_c0 z1Qg9w0x0{;IpF(g1D|bSgS*3AobiVHdZ?wd^uBH|(i-j@rqDfX@f$^B2^up<%PV~V z>lf|km~Rappq`U8--HMVX9LgDhQhMpV`l7!q1jQax~Yy8Gu-mYAVx&j0#pu!On1)TsTE&BA(p06TEx+n=aLnYN)NNvoN^szY{M zr`ZYBsiN0UmsEqpO}ptS=9`7L;KVA`Lw7K$^ssD%N0N`-+7TbZVo-vS9Je0OBPx00wlP*sK@1DxcpEv6^C{tmt%dy9j(%p4}=;TGF|i&m@j}c|CEY z@2)rv4X^>j7b_fRnbFVio*X!`)<)YK&c1d&eJZ0z^^d0*37%))uRR(~p6m9HwBm~; zvsV{GSA~>xlRw>SNB2m(T6r2tHg4eQrl= z)af)7{?*5!?_I<5vd{b4FMK}jitCN2dp~WvL3r+iy>tj(`QPfYri6O%V*U={m!?2> z!~X9?@IFDWC0qu@-;u^na8g7`|_( zYlK3Ds9xAw(`s9W9Lk!DpvjEn!^05%){2?*p}RtC)vHgvmXKaNeKvCAm<-CX zI#!O5j~>Ls55%1VwqCDN;(+}e6W4Q|n2&>$!ua2GA`tw)h~|#^ z&b02gPHe<<{IbU4U}++FylcU%w%bboGL_aMle)1#h1(JE(f2}Ob#|AR>Syqw@5^f7 z{c$Vq56?BP_dJi;^Lee)n!*kbo&_j>4>bP+B|!qR3}BI`3~^!5B2@P$Ts;$e%)Kyy z?+4HcQ>zo>yf5jBb-4VgwqGa?>Gz$ClH@EPjuPnlxbpZQFD(YcW6|VTt637w;lWW% zmxMnS7ONVQ=q_i&BslkZ4U@1%^BGFPD|i|y?clA2bGA|&XIipJYcZNg0>Pj zb3NHSOJh@1nhtGKD^VAF2dy|#p3s_E`k1i~5p{YIeVc`}0ERUs6K@dkoH=X+FeN!F z|I|;L@=hpgd9Dz@Fm? z_?nZwR5q7$_*mKb)w5+|==U*RvKUDkNNJk|cU+#cFZmaQl zzT>41fP;OCtwWzBYlj%W{@UkSmHIk*7It%5iTg%S>txcgKrS14(An{%|9r|Fvzf(v zMd5WqYC8~e))2W$UH`Y@#{a5Ie2a%t^D3Y|v9`C9V(i{QnVird(xSGBx^#T5?pA9; zx(l{Ifb8GfZTdpNFLxFs@rGyBeriA;LpMQPHy$L4^3#<2(%=Bi6J?{HarwzIh&ESq zSOOd@!b1T2l#F>A%)D74>0F5?(1K%3c$YDC2_);*LmKP8O9m-AAa`&I3LMD6_BKv! zFjL-?M)WmabA4QfqK@pe#g5I76)wMxbOVVXxAauSXC19) zHVcRe>;1o&0T_$nu0H?*?&znhP>^HZhbMb^oUS_lIZuP37wd03wBO$HXgNv0!nJ~$ zOO6T3K}e{DrAP z?3{U#|LgAjqx(V`!56;%Q@8z1{CVQ-8XM~zQ(NBq`?%M0)qJ%XE3P9(EsxLT#F-}j z$tWU7X6WJL{gJoq26gp%R7~gj%|e6zSj1rt#~+&W-`hEVuGk?$t6^bok7{vc^m)x1 zEbT25@-mHIwT7|1>N({A07*>~igt+=L9v@_(bnG^y0vn-#N_2;2S~(*JvZH|P%5U+ zgwZ5XVI4NF-mS(SlmbfoPSiCeVDS*(@fYUcnV9Ba-0dS_OZEBHPm^kMhZJaH!cBFH zdz2v$O?A6xu4(Z-FYp`yFJf#ph{hJ9RulDI-f1v(Xw{@@E#1O%EBRNj7V2q#yciG^ zFg!jB>3u=4OR&A2zHLZ5j-zE@C?R}vBM(K27D9*=wgitU`s!{xqilc1{u~SCX;`O& zNWB`%B_C%vCSHDOjl}V?x~(LxV*Q2j)=Gq z2LqRew%(XX&>8(Xx(xldmR)NveH`9dx}TN)Ha1S94gPd@J`jz~ne62kYyj=+yS{y& zqx(wp_+cQW?X{@%TM>D9j?aK)N`5)4M(EAuM8_33P}+#bj1#u9ZPfOr+WXji<@ywN zYh1IcpY*Kdy{h%8x*0Qw`2Kg(`=2Xz(1>>QE;K4J^fCKrDZzOU?pC(=Hb9`GYNb-E{ATQOI!Ez+y2Wu{XXnc8PFqtY z?Kp#-cyUZ)i<$B`Y126+YJRkD_zP=ZJT;kqZHXf(=Gy?zWn`1XeEt1M=QAwVMa&zb zD9f53T&pkgDyME#$Xxx7=zERp;;f{vxXBI)1!z8(IhVJrS~0Gj*Od#NFBORSPty-1 znAMR~pXt` zo8iLquK1Mqhprtc;v9t4zl^-=I$k$*eH?{dW?$Dfbvy1dmu-A+lI|aJTHd!-FMK0- zDwp~9Zvtg<|MJq(14sGRUx^~avYINK`7m!~3u_VDv{>`P?KotOoGAxdW$IVj>z)0? zwHob^^bXq^oa}0$SJX#Z$6F;7)e@cVBN2|~J=Xlsz5Y~20DiM&_WSrORZ3%}T6LO9 zZ3ArySQ3!>Mt}N;mHeGG#S3skRITZ+;J44{w1cEaYhXNgZOixYa(+tRn#P~sVSnW^ zj%%E38;aUkgI(6F#d#Pw13%7;u5m*B^$!IrAwB%xGtE%cyI=f`iSz_ub*=OT5Y`WO z1z=;2Ld^(b$}4&FB*C;ShL9O|4-FRx@t3i@puypn2l0H0#&Y`jlgP z0_Iwd+jMo8hSUARi?iz&D=P-8`;-s4eRT}7roD|==4mK7GhR%+M|8Nq_C!VDD&jvC zZhcgj-sD|9K!=w)ahaB8EvT%AY+Sn{(&2FX)ZQbjcOUMZYPB3u49A*Vvkz1K`WR9f z!xb~oeP4Fh_P)B+hqJ1AZ%H^ZU=%!>`&?V zMcj7Re%@#Mx@Wt!WLd3kC%x!}sN1qH53&hvzs;#%0VA}oU{9fAcO91@yEeCN%ilX* z=Q~^0UwW3^Rck*%c0MgcemmW3U%rGr_kCa0>2b|aS5ES;DDv-rs~~|zx;xt2njR#s z!a6d>#TFrLk4xz(m4?LGM~jkhz$n;(M?_PFrc6ECk#XCX@i>jq%(P;&Z_1yhCmAWy zG>l!b-xV5w6@`;4!8q|NXt067#Daqo(92$_CfI6o5oiF;E*aN|g4te!Ll`)bC+~`) zlYJ6@zaL5ku*ax8*j8qKvz>Ulgc1HED+8394d#LVTsh zY;(3P)bKtuv_sQ8U&F3a+Bz6_CrK_?{QMx^-%;8JxLKGFp4$DK5x1n0LRDRqrfO=$ z=3HI%Rd<|6=j44@rNV_0fQ?>Pdv1EkslGMfHF076TBeflj3vf&W*bH$y9JZEzO(WZ z-Fo8A5ybpyJI;CQamhu8YbPYA-(7Lh-@bYvZh}A+H61tdR#;In#nDSb@T|DkvN~@t z5S;}jiqaV2w5WdR(MdwYQ*Kx(_~&OROK)_(G`@v6dF*~PuC^FFYWs&3bOk^ytaGZ> zc4pjPrE~(1t6JgD-6uRReof2LmS(>_m#lZ8zV35Z2zVL2Z#AD_`D$*fF^NWNVscz@ z<6d7Vn$6)y`#i*3oqSfF^FJZr|H2NELU?+&fjzAH9ugA& z@^ILdM$ldN%2&#I-w$O`<15Z;n$1BlZ>t>&vG0FAaJisPV;EcMQ3-URB%kq~2G5$n zR_v2AWfV@DHKFnQ;sgB!kO{eP_B~^Zp5)^Kh%_TtV+MX{vZ=Ba-c{@BocXoKc%eW0 z0W>QXlnUexU87ON8HQpx;79`XL z{Po2lk_4Sv`)rI-UVLZ3>{7Vr2Nu>_+wrq4Cmz}u)}eZEpW4Uvv9!LqB^UN*j?C2n}yL5i$N_?0j$DI^IGabZ@>=K(gaHa&Y}rC8wm|VoIG%=fK6Bw z`pi1=k`2kIO`Te0{PoblBbo`L%V@1Wt}eG}#mm%vfghn; zD2kt(NzJ?S%NY7ZljuaqxiBe2=+%JwiCYEGFq1IIxJeI45NMd@4lHjEPZQT#l@D(g z#t)UNdO;OcvIEiC6?JESCO;_wzy<-rw=OJQH{?B|Q6ZEOYL0ST7X}nT zLqoy4A>xxCo{d3#&uIO?>=ERVW3~|NDz}@2cy16sAoRn62mX^2I?xjE;hmO^3}* z6ZFG|s$tGchvk2PexNv_#%!vtNP{O#EC-~w`T`SEewu;cHd`syaUN*);@TO|AnT1p zjoSfRwrnF}wXYJCkwJ!)uNe=>PukSro+=D)R7-O-+;vvfBbo_G z2nMOoet_L`K^BUZ5&OcSqwZIPd#Fa~-Y~r1w$E!@F%ey%-(o}0!!pS8&tgKR-`mqw zw`6$`C@jV!T=ad}J2T+tA*ucLvIy>zT)63|^mAnC)PAJfXbHOa3uO?}4@{E1hC|BtYD0IqD^x`sRHBpq8F+qP}1W81cE+qP}nwrzLP zNjmy>pL6b4-}~MB-?u7N$4aQLrL>2f^|Tfe#nc?!1l`F|d-=3;Y7yhW!Az%b$kPd35bB@;gwlA!Z+(Xql7{q< zg6@BqdJ4b|*s;eL!z(=>PMe-Tr(Az#>_mp(xSLi}Rh+8}Qbb>2u2h!uXqZ&ZEW7-# zM1?VserjoO10Au4rn7-}#E#9L>*j1WT-=YKl%2KqD zeu%l{>vUIWJTZ>SsiPAAVrCSuku^X8x*8DR%h^f_=nPJzG7m>M)xkBqDl@fMFz~P(gfd@D$o?jk>TacIOLT4FarGshcoyk zK(_)#U2|RP5>ZO#^hoJarpY1MZkZisNj829dMV(51}Tx2i31z$rj49>gW*E11i4<5 z%I4@Ce`We=-tsQNVm`c%f5oSVx9R6u4e5kpPN#J{LneE}56qwa^GY01qBtJVa6B6! zng=wEKMQ8fO3j^SN~2bQ-vlb^tNij13}+Uym(g(32vh$B3TcLe7*7J3f5k#a@2&Yb zuj${6{dn*Be0m-v@w_ zuC1fd&1im!E78t_|npn1h2AcP1M z{;hoOT9&Fss`+e0!E|WD&B(UaqCYtB<$Z;K!q^D_t(C*;wpq@UnW6Qzf(0K{*Nh_* zNo0DrjG!%}36wy@snDv8z{Bi{xYgEQ5B=>7KEO0!_R+cm9NM7j%XqCWZQ*&8watUi1QYTz&CYhnGG%s*`&8#5a`bo(381z8mHAhYV9d4|dO4meQ@ z;l=-E9qR7=$@1A4lK>*bgmT5VBmOedo{sV$sFs{L00yurco%8(!RcJVDfe2)$DZA# z$No20JzMA{3u{)C$?s0ol3)gFlng*{yyRqn9gMpWX6MD(zk>8+gaH!c9lw=|#3lj- ztt)!uIe!HTIFIa^@Lrmn5ukGJX?R_sv9b&M)jckT|FckZWTU1wax zq>NC?JuRF&X~a@8+d3JVxTw2)VugTmpnLt?uGzbY!Riw;{MNkf%FGGRx0dY7CTK4r z>qiF`OiG_bor%AaM*Diufb~<&?{$*-Ec#!LLKFCU=8e&@rl$wD=bp01f9LakXT;`h z*k<>_D1|1X*NDHj8{aGL9Zy(Y1HQOJKJ;3|L<%}MqJ_oYB3A<@D_XADc9ccd^)UIv7%MZVzb%v# zM|CwbXOlTwRVoVr-|dbXk~nkAYGj!QPD@N(fjc|qI$5zIW~>lO?8Sw}AYyvFnK$a- z`I!UuCL2IkBq2%ywkGz|G&&QkHo*2dZL(MkxE_E7vRVqIZU&Sgj~|t9loKQ2tOaDg zP@OCUwTtp*ZGo5{TO0Kk)IzMb#@r8uIpFT`NR?E;8_=Ey*(?M({ezOp0Or!Okm49Z zdxP-h_5&y4At;k2HT7Uwx<+CSp6>?O><__Z6m*%mvinAfwqhtU%R}N5-COYH+F{my z(fJ2`EmbI0DB>vbj`!9JrLw7FaeE+%&HOQ)WNCa3!o6MT?Ebc}a`_8uK}Go_Gt79! z49UcUS7|Kq`YA>J|91y7fX18V!SR55DBLA8`EWR-B0t( z=0?|qa7;Q}$RY9G=wDtZyxuBauvK-V`IjL*fvOBYP7 z>95`9+VDjytx&3)w-t+FXTuxqYU%OKK6U+zyibcfj_si!vsTJT3A#* zSM(hH1i&fdjWx%2L00E9hjxsu{gZg3{t?y*LR9odPz44?6*3tknINf7#Ya{1|6LWX zPHw0Irf!c_QYx)T|4 zKlIrtv7E1Gc+!i;KC4h}+l49Lk zySl~S4D1kDDS;H0Ax3&qYMlczuT~;Y zv3(eo$KrZs$o4!o;&Rf3Z%gh{?RjSwV=9yzof6kI{;|y5z4KxZzvgLo+~t<3<}>wO z3b@d%S0VWaKVF;|9!8YRXSPib+)D;bFYhlOpZT`u=NsSc7|GX_5L$_x85=`V+3Z2u z&wJVf-uIGECTgMZJKEtyWm+I4%^mv*>I#=H=YL5OX8QF$bw6>hCY!27L|?V!=Q(VA zx37+zC>uO~|LMs5FESJC$Z|Ed1%_;ejSBE-ydCjx9{a z7Or56Y$SZ_YdEd)izJn7tb((*Roo*+l?F$UY^+snnB-r=RhfVKo+ibJ1hr(qB;~bJ z{^2PSo`#QVx8-5c6q#(YGBWusPej^0w(zt#Y=HryuXg%u5&ET|)LWdhjmFeo<7Raw>`8LvqYWeEl`mnf|0$>-_iCyEj?E0EOKCuHv%>QpTH>0L9RT=5?C49~Et)=;*c8Z6qeczW_!mH65nfNPF$SfJ z;Z7@E*c;AW(Kiyd-ur|X6diiMi#3S@9gA(t8&25n)4rP!BeW)hADS{+{@o6zO6Ie% zq4hpX@itpWI4i(?FGXUbY1U5C@dhSo24G15+(t6Z*UQ6Wrzho}jG5)X&bs`$x`;rR z-Tw#Qzr|^4G3zy7T_L>%$;Zm#i@mQ9LIk1KJHe;P)Zi>r)NJX~I-F#YvbnRoz=;v4 zWoP>^?jN^TLMa95x1%6p$F7IlFi+a9%+HUhR(#Cp{CH_X zu~6dwG{G}*f!@X4y*B}H|8#^eQs|DSiu`rL+ah|`BuO_ zlV@f3PSAFRj^MbV$9(L5V{_F{#Z3oNSn?#r#j zDsMy@o5sQnfRS-P`_=L8{X2PnO`=Df?jva79lWWNM@HiN)Wany*ePQbq4k+HwZaRz zr2Ms4PuEbO06ipSCD>@Gb~QoAv&KDmf6=W1<2Y!biTd|X^N$X0J|H@<9J6Gagg zdJBbA&_zBRi6afK_rTI9izLWW9(NoXk15$|!o#lepJU?|A!M_E0LLj9m{kfl=4^8$>BrAAcW z0B-*Rz}XskBUsll1@`tW>&X%I2->qdeEr>)%K<6|ZCF)B&Z`xl7l(}Y33oy+3Iqg-r86|Ja;4R_BL|6+o^GEI=W(wIjAPHfE(AI)vMfn#%BRXE(9x9G;Tw z)Fow(EeSJl-5TUiHr{c#7VhMIZ9mGY-p*2ecb@Ao*J@w@;z3ebwqChb8Al0^lqf|u z6*SK$QcP1rlSD~m$V?5Hx+05|qmqhKfG@Jd0JWCoc@aDW`%RZvwrhF=KWxv>K-kP=SzPcHcRe_Gf~%b_rsdBUt-@kt z>Sq5I+3*F=jPRX8ux>vi;j*iL(NuHt2|}nf0jOF+dXQ1pa&ABQK2e*EbQf5^*ZEle z`ml7HcAlv@`SVTosOzSsfu3WdD`M9FkN>8he=<+o0+v|!dLySLk$*ppt_)$v@?B7OD)4F{HkogC;(H&Zh!VSlF;kgbwAhH~osW;G~H+47>Q!rju-dbVLi_vnudLI#^PMeB>Sp z;chfB^@&4B#7cvS<}889iYaERm8yPqLFHvD@2kh9#d{^d1g~w zwc9``b0jx;h#(G%U{j>eDhWl``tY05&g#UNNMrqs zV~|FHO{rL&n)is~h=bkXO}pphF~JLB!OwzXB}5)F_BcTRYee6>YO)08=ns|VucRW# z_dV?eiT4ia8SZnBclW%aX1E&n^`VHNal#m@Wz#+)<0(rz)VBNSjXh~R2l4V*>g|1P zb&_-@h{`59SAxKn9-QiMt7AW$^7aqla^v&)N-Lt0QaLp+5|Uh5eN=4nx=GXV)VNEOWbfork>qp0_-9)GK)ZY&DvdHT}*bG5;>tR_--0!H<9 zy@g#2`UrL?iaS=@{w!#EFG5 zvPfHk>*^GTOv90VF{h{5qfp3qbA+HWdB_B?*lSL4Jq6r)!sZ)MdhT$@9Fy4n0%{je z^p2Z1c!erz&yaXa-t%^2Yqjj>G0gdV@AkZJ@Zlt}W5{$o^z=99mstP_49O_IJUKp= z45xu~)bGpQ1IupGj^sG*ykfiduaCEz4l`|T`vN{Q4Q@xT+fO{CTv=0GNSX>HU#LiK*UZPROG{K(%3h4KS>LHj;W6sNC%7J7HomC)a!xxnlyDU_8-uC)J)mbtDJokAY^ zsD5*bM1!7_utH;cA)Coqw zgiNt9G?J-=C41w7!;q=8*3k7|7;HZN=Q$3@sG!_Pl?y|wP94J6k6FgtGNw!i{I$MD z_4eLslmlaSz30aE0)*|~Q5e}tEh&t+U(0Q&!WD?55EM|3xPH9Ffy8IoLB>iI4mMM| zAvbu9M&ahtnL!_IvPrDbFEj29ijW<{7v542+ZF4R4`Oh{?lM}QZu(ZO^uPcZAFVFK zZN_yl7AE8gcXf55`Q%bjiDY~dv__BRk|4_1equzx8-G>*x!HVx-q8Hn%jb79{%w~n zrxYZdw2Q!hA-7b_eu_JTB`cjy7s_wPHXkJ3$0pujDgL*m-hnZ1x4Y#?cxpK+3h8WZ za0y>u>#o~fDhsX4X#ac9wIYls+-r6LOCfN8sR;lFtFWjI|pq%Ek*xj)Eat zCU2(VG%kC2Nr5BavTq0lNyWhV!~I>Sa_@CYgi$-H5jhh@yJwsdVq7rt z3=~(5oNA&mw-G59#fby*_ozHN_Rz^)dc%jqO{Uo!xW;h^hawaKkc3DHxgel0L0)18B0=@toVNveb{J$SyDVd zUw3Z&yIrm~-L#!bWB>B6zTlG~y_&FM87x-zK44y_g17>y)tx`ZKV0rS@2dm3cDxO7 zy?*~rMGh#6^xwTB3@r>n5M#oN2WLEvs?1k^b7|_KKe~fR)ZUC)eTL81 z4DHgbOJDGd)MhHiO=w%KTNVzhC7ty~NN~oOXuSj8 z##)H%TzW5aBF4cYe{_V2o04E{Fv(du*%FwOJM59>B_+$V)SKj7Nx12fO4-Mv9p{){ zFU~;-a;>4JX|Ei1wvS?*Q2WFK;C%{T<-Vhoj}wd`?^{((ABCdHQ3u6gvisc;hS0m| z^MZ;3(yI$mV#a7Xevy88A`H&Cr3UOOm2JRa7U$e%7mRp#0xz#4V_k;9NIC@s9`ZcY089){|^dR5KxNm49esW>nZZxoIj@SZ6m_J)m93QM)s0IBymjO#15 z#~al@s-Ax${(t=XLZPS#5P=NehkBLsJSSJu_5@n`C@2Md21uIf8PKh~^s0QvTljI0 z5CluJJ%VlgIgKF@3WI~vOAmy&GK3R%CH>sJAocalm@C6pB8fP%eq_9$43&`{(5ijW z%4$F=thxV3UUv|;HrVA3;+enb5s1s=3grhr(gC6CZ5(OsjVn&a_Co=3Tw}gKRwRT- zX6#WV3e}u+GfLRd+;&4)G<%lm)pqz^UP3B5worBjWMTtSDQd}SKBHfl-#gpO>^s}9 zt{TGiMH!VsnUnCv*63Xgl?hPw7x4YL&AOMNSqy#0{sh zoR=k;6nC_IMa9_tEIvG;YVQIZ9T)Rli`uIX$K*4M&MOcRlEC#`XYRl|C)$o)YF5PFWAu{ zsw3!HvGt*~U+2W2t?onss~m*{e`0Xx&qbA&L4_T|7OJmj?UE&%=ebsnMNy;Ice@={ zer_K}Ik|I5!Z<5?En_^YL)>dn!5ZCVBPl56@(z0$y>2R@Pyj zvu55Px9v`}KeoPn+W#+NpS$%Wa@0w39Bzn11EO*)DTLRQBhmQ`v)|~95m6IV$5-gf z-?`a7dD=beQ?A9j0B{@wo-}YFhgijR?c&Ca$tPq0BOSFKx(lfFf1a%OKG=vzEb6mLd@Eo49=@x<_71Y#rybej}RidTqt! zV-VAm_O<5nL-s#os3#nu+vW`%d#BaQZOWn%$416~#A`Fgj&~FdmlwvduoNL062}&1 z?h9=LisR||uDL-XQw|YNBgPfg*SMRaJDSm$MiRWz*(}w15awb`cOpK!8A--vkL~m# z%_j`{gCs;D8kaY5{M!LSH2HKV{&vF&>R||6kV+>kdIk?<0zjG8FAkJ|Yh=HV(OTEyqxGWm5u*zi7GUo!9}oR# z9i2ZoIB31;ezl$9e%g%_#o_ny;T;|xMt@av`ebP_TOhIA?)=W_d}$l8-2Hp0M%yrg z;xBPrNm)Q+sK}%oLs&QckNv?T3=Ix~eB4>=@R7U0xI1qvIq%lRD^x zD}*j?qZeVyf(t^^q!pf$ZS~+PlI93=4KKy%yvkJe>>D>$ZB4uTqhE0Q#v#$_pU%S3 zciy-`0~ow2`o8iEL9QoYOqDzS$5Whh^+ys+RXhAHMB(umSL4t_ME_+aEi3COte ztA?NfakkQ~$oL&h#ij@u*IO}rXt*NIw`5>BztKP(62N~pkY$_x0qQV1nhVN2Fx6MC z`5abQm>R1bu0;^+f1yDa1Ef61b`7SOM#heTyA4oMVCmQW#Rk zDur>z@A0PjWxLemY(o(FJ;OL!j1Esu3b$o~Q6dWQ&XSF~KTVv7~S(7ivZ zId2yLYhYh^J#l^dsHIPKlM;uYwLVo`cn?7oDa&*kUiAU9&f1sAyE|T%tsh-%Z=*W% zOKzu)*Q?=PydMX=(cf@A;X7Pzc&@r>{&TGSR{+&)2gzIwj1~?;(-Arg@*=zO`JQwj z%2iUJpDiQWOyN-mwu^Na7r9jd*r#{j7to7&-RhX9wNF@q8a~SP4jlffEz+ni5_^|) z;(8xJvJcRbfloIVF73eVJ6uDP)o~0kDeVmu&G~#gxf`POMp(PtgnB%(XYYKNm$dEx z40zmy_&kRIw01FXBYK`AYJGYlhV)HJwNg?7_;hq|y{}fhVQ#!`Jnp7lx*gcll`siv z^#SNlqdsmFNAo&F>hq~5h}ghD!K#lwBK3-u2;-Lj|6;fbZCrpWq zAZ_Ypxg!vF!tet0DLvsXrP&;a_V#yGw=`XHtZqe3(E2e~@ZrN~s^@=_c|C2p91!BZ zfCqSXWKPMlKPKqPUi8R2$f$;G_0(;%~cLB3gqvPWow7)5`kbwpG{=7pM z3!)nOkhPIaE>MWJY%?(Nxd{~E^c*Cnobfg0?JnneV&)osbPrZlYm@cbfT-{x(RK4@ zl%(y%eH)vzBPc4Zb|sf9#FYjLx1n~oCwsHaPIO^m;p~Dv6-b~jJp4bW0M7rn7bomM zH3L9s9oX3Hz$bnIwz%BTHb&%~%cweEG-n|%-^2V0p4mgv&Z$B=s&Up42&WzN(TtzC zr5m4L_3Zh|DFcFm30`=kx3MY*ofa4#Z0Dj`I5B_E5t2vOU9=AMoqprQ;eOr?keD=d zc`PX|&MzwyS8L_gWJe{a!<=t-x~R3?>$epqvWW%XbUlc2J;`zbD|0SW2G7g^5%P8P z-ex^}bQ8*@)emoP=SWOUBBUTk1GDd!Kioo~Q?8N;Y7SOc!rJh=FW87>yd#LraKYYR zSlA=ci<=P7$BxL~J3FQBcyuI6@2zVkrQpfVq&kSxrjtQfj7^|mCv1vEFGHMKDw$QX z1D;AEozrxJEZ$!*Etcq%m!~T%#AmS}+IJYiBO%nV6A71)2*KxpZAT}BXv!be9pUpQ zLIpJwQ(c^^?~fhgoUA{nfVwJWI@B!$k2Mu2o75jGUOFNfA>nL8lkd<*fymNNWYJ7K zsoxOSHB=bnH;)P#zVOfJUSw0Z7(*!o`*n~c_6p0=rglINY z6h9#^0UH)QKSmxtsJJLVVni-qwzS z2MVhaDCWmxsPnhob%%opc|QE;tY9GdV}-u(r%-;b_Ua$oS1AWF_CmjN9yRV<5DD4O zUSDjBt8#LBp%zn?SgCQQtsTuXUI)D*0v`rmtNX?)PWWZ7XETdsvLLnHVz#2O9&*{4 zumSx;KsJHRVznMf_FE%{=JZpm=T{QfPS{el#6+=cezgMl6b;|NH#;I3jF?n}H9Cc!2jtGeM9n)e&JbLi?efg^@a;hn06?Vl$$S1Q3N{LdAJ}SUI7=-CyEL!-nK!INt{%I2I;U zc<#{66fGVf1O%E{>eq}oslKjxJjQm0+gFAN*sK5J<^FFk(~Ss%cu;V+o28Q9SdWv@ zg8Tg!{ri(7uI}b2G*vpY^Xh9q_G~PHVAohxjwpI*oau*n9CXwbE(1OXK}*fS}}Sxx-8P< z^s!;fn*r{Vwj>2B`7L*B3I#~PRRAHwg54c)IV(rd$lO0!Uvy&t(#v85PN0UJE9rnG z>!Gv1DkA?$3iV+vt)l5z1xe^`=J2W$()>?9zmA(o$0#$qFUy}kpmkN67u%S z#s_of_j1cEp!2!A?Qs({W_V6EK|tL7>vnG-lvMDG_@9sKw}*!ZT)3A@W2H?8vPfmG zXD3OUFtq8f+yFB-W;SbDAQrnY0rjmcRb5bq+YnyK;Wyp6L`=VKr0}mmH6osIqLl&% z%S4mdD*__dFogG-{ANcHYR6z`^!@nQM0Ut1gOj`uDt01frM`6qsFb$sOh=5p`gwD( zrm0fuPxPe?Uf*yK>flya^mxTFeDVyegnRguAAHf`Zgj=98i-+Gkrbw5UZGB+;k{(z zV*bTsLc~N1c954J}Ax7Ucwc^33eGO#;$imlF&W8tH-7#Mwi~GJ@Ic z85xF)`q482$q=dPQYB0xN#_tCVpJW64fe+vqLy0XvbT91ctkx zS1efuwg%2Yx$bT*W~SW+1UV@FL)6+rY_;^(69SLbYz!ZN@_vNW_I$IJ`YuYj4`aaL zSTAq}^+b+1KOaHjycU&2sghq`j|j*8Ah*hJv0OFq6|l^O_iYbOZ$`5Czs5$uJrd#p zikX5`abwqf?e;A>OtlHR?L)j76 z+t1O-N$5$~j+wiJw@IV^K#0~~>lO&7{faWY9)Hb+?nlrDcPTRj{du|qr1?O^0;E;X zdvqagK|~7X8as9#U<0=H0*9`Hv$333vrJk+#i-!#-8;#+ALu8kokr7K$@k+MkmaK` zguPk3f#h$3SK1PFQU`Q+fb~t4h&JaMaz|5xR|}N}W61avEuhxL@C>ai@DLOTGat-t zs{M=duzn?DuvJmtE~by>m4Y5K8kt6NgEY|x4~m)*35?^L6esMmON`+opteyH z8}s2JeVr$MF& zBiE)+iy?*p`nR~#8^pgm&yJLv7ec{Jtxb>2M5X*q`SaQ5wj`t{tW8lAPBnF5=qT=1{09*(+ZQB2IGk+y-|MEG1 zy?|c>QNltiEBVnY9$E-83G>5+o9L8H1I$Gpfvc*qw3V$F8s){ij2+2Au+!fDeOWetsHM*jE@S z^Y^~@;1RZrf_n#7=rU%K#YV-RqF^?FztzlKo2oA7ar|X!K!M(T*nWI5{&nt4XiWQe z1gIL#MHW)$PO0d*-dqNO3p+A>WECmM#qUUoUNIXGEeplqv6)p(wM|M1;AQAmMz6EZ zji{32kR)zf#=(}5fqAIz!s3y@;@2nq(@ zzKcz#g|;qY2@MtX!B;6_<+Yl;X$_OI5JbqJmcO=7Xu(PdR%hu|$)I^boUh7Z+v=Dq z&S8#AQ+{V+O*oA}QSTBX;5i2+A}9DaZ}A+CAQl-jymw1dz!s1yH6NX+1cy)2c9gp#P`=N^(Qm)}B(tijcKQ-)Ug!G95o z>ZNi)oVT{(Tk52rQv!(!Gp}#I!fUsi%r$<=S~|$9UF?IiRZ`q74%R2{I`l5g;(%Dk zN35{3JY10F#SRP;7Jch1tl1~@AwC$18IkqAM|yiG;e9kAuc2~;B;})^rv8yV_Y8%G zib_!}iKG7ssDt+bytW@83ewWjfFeYIpC9OWDkG$#y1iT{VyJ=cd^C=5wa14S7K_c- zU?du!npzq`y3RJd<>A56$EDqqnubP1TwHwQ#cZJ%pO_ewD;qGW4u$J^3zVOq-+S;f z%-Zcou2}4t2(wjIR@QfSFk-hq7#6M4u@$|#s(N^MNOquAtLt}PN%5f0!{cxqS%2rP zftmIlq_99Vh9aNNXL$%s2fC`+f?Y&Q3mYIB^|d>C&30>TZ7r3<$$TU^E^e=;dSb=z zaKVVsUI6?do^R#mSz8%z=ub{7<%_MM$~C6~1S(sxsh$2@TO{Lwon?WWjuoX0+A$Q_ zUQak1k4M4oz_h;*zgNG|Du&0T6n4xN2~0mHg8slE#N3jXEks4qpk|kt`4r z8EaWC+hGWVBD!buMOo95!T)PSqyci~n~xR?Ne2 zrzzD&eXi{#qPx?#baQj_Q}f#XjQM$4U&B~S*S8f-ePXd(MxU_nnDwN3-BtS;cXu`Jku+RXWL z6dCWs?k9jfR$>T1?x6vbc0{U|$f>E11~J^IsY`XA&j&F9tUmiZB&4LTaGcsN+i$;G zdO&H{P3lxR?gy?s0rbK_+>hIDL?k4^oK=S~AUQOYDM$jjF(9i4Lh*kBx==5zz`4~U z6@lJT)5ehk2_KaqMs?xxEXbsceoj4L7(rHaKU6;ab;h>!;+88`{?t*Oh;$gAnjFZE ze(sR(Fh6S3aUII^L4I6lKt@JHTZ7S_lxA@Cg_XeI(lRpJ`}^?BD+USe2beLfMwFWh zuWy^mJEt*K8%mHvO<(C)M4TEO6uDY~n5l5WbRf}b!9ng^+z~PPjoT(w=lSZX>#C}p zOQSo=g9u7kp^_~-79I0aL3KUIlF?9UMYVt0R#s`Ii0E$cjn$#YtHP@`@JW$)Zir=p ztInVQ?%y1wUo|*Yhbh6nL6lY&PO~Q}h?c|6!fI>RMF```I(v1-MySwTT<`~v{ksvP zJGYSb*v(bT4j6AOWJ;zC>7RK-EH1Xh3WMN_u*3fl_y6zuBalxAqV&|J7sLK8H))Ez z+uF1XzLVO?_GTSOMOav;gZd~W)OY0C_v+AWwTBH{)(OE;`&%WEnEq2iAFPSt6JfYQ z;E*JL?E?;TB&{zAi@TV}#~5jjqxs3k&WCeJXSeaG8UH&9r80=t@HE#=*ORuKc58rE zhckIJ?^amMGl%o3o=INL`=!ZVImCEHO^r(SU8QyxN98kFDINCPV~x*Hfok7XVjXXS*kGxmrg^_nP^{YPDX- z#?1Y8I{0*mmUXct{y~l2p3K)Z@8?2nxXS@d>(27<~!CsQ7N; ztNs4eidG2f6Hf#z92jQo2k z2wA8Tu;QR?6C7d(jyEz7e;tyn5IQ62M=25!IT!ESaa0;JDJAb)&Y_u7Y(xB5Kp<)# zkGm`j?6U`}9wt!5sL*9jLk5aBPxaaO$*nM`4_)^y*?TYRlNqs9@;?=Ux~Jf$W5 z$&cEn436Ai%`w&Q-gUaeGkRW0JzFnMeVM16?6NdjTM)v|=3kIvvk`Yns_!JM-fD>` zDJd_Vs;a750fT6A%F3v}It?NJ&FTKnx|8n^arV$qklUR~31e&4dH%|`r5!n1Fl4X1 z><$za)(Wn$2?yMj%)0Ke>Pc^>8{0hmst|rMyC2M>wC-d9D|vLkn5+p>Jqjnik?T}s zE_t=Z1e3dE(J8D-qXjHWN=&SGGL13d{T3YS2X;a2;00tXGSEI^^ot@n-=nF7X zOaj_2B{@07$ne~tWt0@{`J)Jxs|hYWuf!zs1cWm4E&BqH;I4tep;tV z05VMoOqF{Y5lS$gOS%^cB-0TD!d&=kZ*7*27k=!Ke|n8X5B5j-1ZbURazuFK~%gFW870&3pB8%9~uI zkSS=Xu|^v}8)le{*3Xj(OpJo7M^CON{nrg=Q zg)CN@bCoB12L}`c1y9fCZ=OGX{7?lTw(05Vzkl>-68&5D`v3UO0YScutgkQ--*aOy z?qOZAQCoXfpgxd)o}qIvG%*@*!JV=&Z!iKBi% ziOnYhbe;Q_4XdxOZ~JnTLP$y~O3vZ^<~o_ftFvbEMBoe$DMiKcdm-ne@F8Htu}tx6#juUf>qfN0WX|icENu9a5gNHQ zC0!H_H^xopPgo30Kt+>=6tRR#r3$YqwdQl%_btgjOU5x_4m-!1CP7gkcLyYR`Kfki zD-kNF_eIo~6vhihPH2P#Z@W~GILup9tw1j{n&4Zu9y%w4)~eO$kz=gu2>-iS?hQB( zX&z1^q2Rn)c7(ZD+9Uzdj*t*&!;-)_7Gi5EW-cM9$MSQ8Zm9TICxBYInPz`ZM6YI3 zu+ocr?*6HE=4u;G$2rtwlnvVIA&yGO_8&!%9=ub3 zBgE)kYe#*1jG`V-hBp~(?B|M{mKOAOra;`!N3eLPayPDDpPM)47dPS#pSZByRsD{w zLFjJjmzBXq^R0p8=$rAQna_A4x$8w$3vwO;uP1~wKsoIz@56ed8B%_J@CUz>sn4P6 ze*pXbhkJA<$tC_qv{e{pi(vrdU@(IQZ3{6o=T)nC+oShOs?>mkvl`mgK|zZaBGu(O z$n3pCZsmtS$$kIjnc3LAw(_Q6UGL*Z*F$z>IxnWYfykrnQg4 zKXX2@L<;1|U3PncKzJ9)E4v z1PE(q>Khm&MLjvS>xQs8)9q7h{+{`KlfB$%p*>xUV%-i!)A2;`^K6ZYK&9>{&GGcd zeLoc)_qx+j($T3oq%YVm%zl0-h9xHi`7Hqed%TEAj)M4b!D~bPgT%T}6l$?`%oTv8 zP>yWlQbnp{&IK*Lsw|SC>z&|{KI*_|DPb`gHk}rQ=@Jnw*VJOda{{Wh!9Hny@^9=H zsT$_HcIu}Ayf}8`YH}7!M7!aUJWnZ@F+VC)=DKck≪jUJid`Za(_ZF?+XB)MugE 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

yYIH8@OYFj-g_qcw^8d(M1b<3$oo%pkn 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%0DS1D(VgP_L|wmmo+nun=MRH0?EEMO%7K^svGWM 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

gWIntZQc0QI(X&WmuC=%YY$VZHAPUZaag8+5; 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%0AOwTGt@R%tF3 zmGH;=fd8gDKI$`FRMaVT{Y~!(+ab7a5E0WLUT@xJ3n%nV_VAN}jN^(;i_}kgOaAfS z_4s#kCkvs5nXm+FU9bzQ<};p_2Yc3Xrlfv|=~KwK*Z1`51TIAcsfOEhQ#SVes@m-* zIc3W4pkBto6PA;rWt|?#jnd7F^WUV!gYGTYcBwDB#rY0*#$n{fwN}|UOe!eK{P&T5 z+~MzP91R15+V%QnP%$c#If#HYny539B{(a4b#rhd_6Vv=AtO`!)g;q~Fx79!xtru? zrR^5luy6;^sA7YuY6h1u>AVC2Yh*OnpzbSK+{LajIgfhls@Qbnt4yIe*Gl)}gZZWf zIa`a!knfl|?I&H-w}M>^_wU%>He{qpXH#6VaH0$3x=SEJ%IY!nqK@*rQvWV>KW;o^ zlP(!m(OFAj_pbcoS?7c9ASoM-+f0$n4{S$LaELBBJd|3m8EbM~9J}ORTy#FFamY3&msy4#hw#ZNTg0gMHG4Icj5GnO)vpG zFjD+~5%Ra$LCguVpk*jzte0&0YGLA9%l4LK;CNMwWBnL~71q!QcXPHs7FFrHh5J8F z=z$MtM%U5EWi2*jJqdGZy>=?}S;Sj`l8w5>1`_^?)45bGdH@<)TjRSk`ajHivH-fk zL4B-R<_86WmD{MT6l`oF$Z3=qd_|?D@}=XEnLcr7c6R5rDp|o#dgMr+h!CEk!LuJ9 z2B5f*u9?3)T>?5iU0gTLp|ax7(W4C`A^UO4|Ftc9Y$yzGD9dIuCQ8tQM@>Md3)qb> z=Y!nDb#%Z(LnB6Co^cD48BrJ~<$crugT*X)av1WDcfPqCyy-caOLZj4k@|jY{BAsP zZ;#rpzg`)Bt`h3htt`4D$3s!`no{B)w*Uo|?EYo2pJxTr8VCokp{eF;Qn1SDP{Pm5 zJSWe-)u?Msi0+CpJ1Ss$kt-XLGwu?I=BhD==sE@%TugBgg-nl&KE<zDh|i`FPrtpMl%O;+$77O1MR8Kbj{3|3WgJAjcq{sgW@!`K5s=B^@Wz-B*g`6Wf6*jyv;P!%9^%`w z8}%<9i@$;aY(=pA-i^Q8GPl5nLm-4j_++iE3{e4zS(E6Xa!kuM`7sdmUqb-?v%|U< z?N)`Y>#hI#@RBTyipkk2JWd^NLIrY=2p!@H%e-R+30F7Vzy0=~Tj@{(*vHm5w|js0 zy(#TkJ)qA_#>)?D5>ux}?81MyqQ5-rDzI?t!nYa!ZN`8z%raIQ<1<0)syUU=<9)@m zEPFLso4=*|pR!*l0-RzHsY{f9H?CVv!(n%9YKmuL4)sQrxc$(u^(d#?>EkPZ{{HXg zaRpM0J(Sl2D?a#i_3s{w;UES9{GpbwM!6&I#s+@-w?LXU!o2_NFuw+w0Cz=>kuc9c zsqv$b{2h7!vU=qdkQGtzSm;l3`HNruImF6+fb_E7BfmIh{IA(T%n9*9IV~!j#(zta zKgaoBv`x4Vc!baUs(uk{`(Nvk4+1uNxWc^UCw=(8=KJ$=lEcu@LIp52dH+JvUr+ka zFXt#E*O6Yg>WZLw)k@*q#Oig_8Hut1WT)GH!K8<+PXMtIifwCcpvrC=C;}&>4yF*~ z=>fVXcpFgE+E2SKH;2iIjO~nevepa5#>Q&yTR9{&05_PQ%2b`o5UM|4N&mvc0E+Yp zu$ze$YZQFTCW)?em++90^!sbWQdhFYQ%!6vSE{!+Y`g^Pb|MN0sWb5V9N{`@uky$R zou?et(h9Vt9z8%wi+>9D=!xN^uR9(tXql|EpO3Z3UyXgV67jc6^iNX!7s-W{L3iF! zR(;Em0c^LVZ;0E$CI#=bivhXYN=k%~g8@PxGMuZ{D(7`PI0`_L(x87y{Q z1x-K=gr3%e9044G4UBLsDkK8VYF&4<BJ>&y#*>v;)_>=%VNmYc=k{mcTt zB5IB#aKO%q?9|6}uz>&&VZ1$j^MT&ad3bqSt;(lv+j#EAVFyqA|M0JX1n^}0c;w^P zAVJjhFA_f2@q#bAX*dCJ>`t3bvHw?s1AFlx3S?DDxn2ppRM&#ofDu|2$|9s99xjva zTeV*#ECN;p{_lb+PlrMj+JS~BqF`mSnXYl!>z63e15(I60`G9rP48v!8rA#Zkd^gN z^dtem%>dd+G?$rT&FM}jyWK*Y%Wm8ZdG$t_*51Yh?@7(&R@`RMj-HYQbMf*PsE8KS z?rRF2te0$earQnTMO-q!*Ts1eP}R`_fCmu8+0-3r3e#VF%1m@)Jl_uSGHew9x+;@! zn=4xuHQz1*`XIDAO;|;FnK=pS>;i~7FmfsZ2h$tme1%5!&>#RCmR&VpJEr!&%3Vpl zMRNv^J)n7c>FlKV_u{WJ@ zzz5vZooogOZdTBouxwS#2ivZs_&-%rQrfRNJ*bjP5*c%5NO%@pKINpfUz;G{XrAV5 z9Hryb?wP)vFQ+wg)E&#swA2+tFqkRFy5jWN8-4o=HY{AE*M*PF>v5i?|G(KJ#71b-DTxcz?`eF>h+R%U^S9^oo;Uf-6a@Q3v_kt z1{m&d?0o+^!P5HcPfwu(|-oYY^$oz);mv`Sj( zrK9lyU8pxwA>ypx|4G~yNb5G<>cl%==vnsKgbm7WU-srD!)h1RH9t8<6ohPf9#n6` z>(5JvR@aLFq#C{+0QARF{=Rd6GqGO0aO8yO@k;7EZ~c*sb@^~FVVh)1a6A&AZyfZ= z&>9Zet53>@reQKX?bjN|u_70oU7K!77>eCpRkyOTl6u8>5qrA9RS&>RWi0m5iypNf ze#Z0cE7mioL2v63K;-cO{3j(MiVhnfO+Rq3(vql!1KM1h$1?mF-0MC~K&<`h(R%re zC%fy;f_F;Vm42Xnlg!4oQ|s#+0@=4fcK~7c^Ve5#+pa|n91aQsIdkdbfQ~1CYun4D zHH?hIa1!*~c_7|=qiiONUIt)l0)>-87sA964jHS=#NT8m!n zCc1CF0}5LO$PUd|J;FDEM$4_mFFr8kSKPZ`N1tF)&3oGm-n9RK%46jlG9Z&}E|W7E zj!IX#573&eJm#!syM;^(Cu%{@1v#unOhO5;(^00NrJ%3QdnT&%4tWOCva-39$;21&dKy%SL$4 zj`n7K@LC>SrwGSMT?}dG`9E6+9YBYVs}+)kh^i?V16@s-OQeac75kR^#PGUR1tm`^ z%N$k*_%>jJ#YE5ST6aX1lId04T>(|FgC_wfgZ0Yg#IXWcg2m;YXfYxdf+LQlKL-;I z#Bdl%eqQb7nRrO1{cKs0FH5i96Mb1pf36;oGn$}k<&(WkQ3_%m2Zhhs%0@zuwJJwm%(-he{M2<;p#GQbX2`yz|wvZ%Q=U0b5^W|BbnYi`99U}ZjhF*~yAie_hbSm`?z1GK}e6jAE9IR$t9 zo=6}mH{=R5QHd_T|o zc|Y&Z^LZXq@`=*i>KD|hs4h9^XJMUMb21EW_ALB5LQ+U?YlMO&n~{b#mDK#neo0?h z@C1~7q4J-k<$vUbs@Tbp;h(i05uL~PxkItm>YTLmkm>JMz(|H@V0T^=uj zJ9vSGAUaKqTyo7<S1NbzigjJ8x z1bkxC30=%%d>$Q6yU)Mvwv!QGjHQo)(@>k#aEU$ei}SP;$}zaSJi&7)UG3Kty)2;t zj|O#NS|+({%bR(H^6d=Q12a*b@r`o13=?0`!>)jieeRYIgVwiFv?LZ8i|q2EvEt#} zu8VKxci|Z|6a)NFMrL-+DD%(L5dKJTl$#)n1kc{!UjMgb^p9MdcAmM}0gZtLMEN2G z3e<)5@6s>vIs`$R&ph!Ki4!F~O0Isozl-nUcdO6J-b%QU=^vRf4qbE7`a1*`XRGbbCG{&m zS8+N+PZD6CdCtvS;03D1+^7<7HJrqSd$#H zRH8{$&K+E166abfGV=+mE7n9T;RAnaV{zh@w>CYTDT#s@TwHg!Z!@v zndAQcb(ehq;5@iMvB4qvt~u=ya7w7^2JH<0>zx-_?)_1QuNiH>pSk~$HGk$W%6Me` z-%YsHS1N&1bONX@)RYJ~KxDoksboCU%SZ|SS@c|lnZf|n2MK{D0@?i&1`%gEOMVfb z@2v{CBI(`3B|cB%g)Z05$-#$4DG02gn!~SYi)4Kqpvp^bNINN7;HT-)5WdToYT#@_1!RvJAd`dLE% zd9udpGxZ8HS0#z#S5RpUKTL`_a^HF~lB}!cM7h(kPqbnhR(fAy99uKWFPLEclw8!6 zZi%0Q2w}bUg#$)`LY}snGh<#SsWEq&_$f@aClsA zfEPts5vP&_XmA^pH|>@)uGWoKc@1foB|b2*zhQRrfo}CyFT1^a_x71J{MrsR(A^H+ z-ign~amQV=PN9%}Mr|Yf&9f*GLaN#8yMF;sf|ii1_A-4|S?6~>D%<%TyScE8l6Vi$SBju6zBvEWqQ3!q1nPhV2`sz~Y`tJfNS&K$ zUGlz7;mS{_xIGoYYgWj892da>=Ieyf-!l^h+kmO^YGRAYLBziahhIPr8pJp zyncV2!8T!^sI#KFlfbMGqYr}-`b1>(_7$@39+g{wc%+XM3hQ&vyu7h)6TxmhLIczF z#{py%q+hwdIR7T)M(#i)tv5_*E3kaa%6EpQZurUtRmF)2e|BhxI^M#esOOU1sWi;k zV+y8^`NUdrqoIk@kulvP-eW)~M?;0OUZmVO(dKMQL}k0~TJ+JJ=N~_jHh?LdlDK25 z!B8b+QK{5!SEn-)@gs=M_kqn1c|i}(AitHI1>a5{yJNK8Y?0a0d&{Nnvcc#GXbe{` zu8|W#f-=hHZtT9()t@o+KSJ;Cf6>)K6qS5q1*lm1ZOYG*@BaRF;UGhU9;Jw46A z^M;N&vt^H!+LPFQncbZQ?x~tLHy}aG0U+q(z+tT~s=_s6iQ9vX&FnWFKy1+xHe{xL zC2hOA9(Ocm2l(JTE zE%!RP(~Xa#w@2kU8`TQhEkzAN);e(`>a2W@r0IGiF+T(G+d^&79*3}1%7-}>J=)gR zHVENdEs?+rF|5t7Yc17)GI&UUscQ#n)D0P`cV} zYPf}*NYdAq-9FJm?zR$Ue7|MynJiB}1y9#XH)^mx^&%jmOMTrU-+l*^g)w9MwE~LX zS=qM3ztzQ>rSHC;#|ZNov2=Q&wLfb-^mUj}z<0jWc_iAsF7}w(!ThOG@)y+SKkTwZ zc|`6^YZ}?%a=gIqc;J(t7G=|8j}kSwHJekP#_cEf=d!-hsjYmXlHt1dXE z3t?cGu%p^uT9bU}&_Kj~ue9{01A9=XC7?g6zvW{#o8jx*M?P7J;=P-foj~ik-CQhj zV*b}dftyU)j=I<|WNr1cZkwCmjBoB7r4P5YIXaryzl!s9@JYy1oavjn+3qkZ%PHV} zE;+oX)tbcLTOC$!dSXHfPw;|nu$#N)J7;hS9^rpjhcAduO(JmhAtbZ;X>|#069Mz& zEfU2P1V0;U%4~Tv2`ZyTtqZcrqemfDYce#mZ*{a6GQHt1M~!AmI!K*<5`>_@>G}lI zb66BHRB2(h=4bTMF!$)pKb1ryU4rdkCU5X11OJi@;mf036Ll5%TU#l>s>kV6^K&?(vgZnXZEY+hr}zR*(8fl$@KUA=U6=y@`i+z35B`<9vYR6N!s@jv(|@z-CsAztu^=K`Wa&UOqa@*u4~AWX^VZ-(Y^ z6uYz#dWEJ_jD`J5H7J;1e2d6@)4DL3$=ffd(R5=%?BFZ#%n=;&`#a7Z8oM?!psK`t z?$54kqmJa(=Hh>wnAcd54HA~@;+f;r9e1{k6&ed&8 z#U}FykXRz!@ob}R`g+7i52u|YsN{7BRv$=4knxMg8M*JVCpMvwx-YGh_%uc`Z`tP`U32+ zePEwg^GYu~N5l#L;r4d*ZCSuRD5bS@kclLVQqS{W>8ku-CsCQ&3`_L-RID|PyV$wI z&CM-mrqj!MWnkBA)qdx|JW@LIrpg!0?PC$!Z%hzQCHRl!#63O9njJ?;;VOTdCWb2o z97f^|TD(W+W+0dKy?65Jf?0`=IhAHBAFa(`0Wk;xnKC1h#EOTmZx0dW%J+8PH1b*h z-i1)4ugjkYqP0n;Kh&ey8XfKfoLpj10u>D8sYqna*?x(k7P6Ux)chPs zcj@LzzQTB^;@7dZ6Kk`Y+%rx$9fSC1Vbffb10uxV8_CtE6bJO@k{hJQJ3p0N^xCGC zGdsVXUrej0X^Lq$^*nKU|wIkVxbn@8Vy>;N1 zfq0&F`$E%$i|GxGfbFIbR7*K@6m^`QmOB14UcRu~sO@;JmAd=WE9{n{yAS;kJ4b|+ z4c0%NuDeB5IfD&3nG_<8Eh^(>rfJ(`(3{*E!Tl%*M1I zeF~bhOQ+lX^%16BS;oKQU?LNO2}-s}KW3~ zxC;I`{E-u&2ST}|jdW)uU`6P&hgb;oWSXu+nCP(iZHg zdk@I{vEUPAJdVeaXm|&RJ{%8cWE*sBglyX(VWSGV*@5E))wyacnNnl}j(k5(@Y}9d&QDMu)K{ zZj_rOZP4GNelVFHok8d?L=Fvj`P7Gz(}x(4E0WPFqAWKE&5n@UV_tQu$GkLl);uOHD)PQohl%AN5_xz;$ULke1vzTM#ICPKzyKl;i`}>ovt;4ydh2W}y||v|+Ht!`b(K zbL=Xk6;^>}d~LOAiaE|p9IyOXzz{vq$Enr87JZnHXcMftNv^Gh{n3P~#DfJZgz*#<7E6HsV-ueqf`FS$~ z{+iTD(TWHTBmSn~YF~(@tDuEyL35bWB5P6zUr^(iqynW%iY~3;kM)(|-C~=`G+3a$ zVL$e@)@w=w;cU<1HPBT%BYXnUYhI5gJ0m%NMMB!Xo$gKp~yWxvE%ole2& zXlZH9nP%t2W4&Jy=SRh>^;bD`SNI{yf#}qYMRq|0h})Vcu+({_X%}wEXWLUMLOZb5<(|)+KQJ zH@pM$|AqBN$G4_@-*?~tpnI3(uD1@0S5U8vWJOoqz*0KkmcDt`6LKBc^}va+Yo zG#4oGl=%C)q9&1Dh%!1msH$YV?t6^^{XuJxPac=&_qoRoKqPT(_0Fi0#D|sRz17vi zisP64rEK_U@DqY@j1z>Oq^WS{k`~m(VZi?b&Q;U>m+2V_!&27@5}amx z0;>@)MvN<|Xh@4_mi}`MnfNZ#ZcrG%^=zg+$fK>p@58?Iw1h2){#9V{1P=N5RQcTu zl56DGDzVNb4^I$mxh?d%e+meh2ApQqauvMDLvX-aY)1+eIXyuQFhIovps$0jr5h2U znGZy@=jFbO9XESwO8WDXGeMPR~a=@~js+`p|prOqCK15EKS^(YUJUP+XZ z8*K;k*GeRzq8=GX2R-sXXq-(ydmJ(ibn=IPf=l)Y(AO$X2C` zuqITsrdl`=MKea>?IUN=9jBIlik1ZlBE?P4v6{9VI!bI;Z_psFiWj{6kwE(ikHNLu zQ!vuFC_`s(C?s2_cnD;Rlr*Jhn^5;il+DupCy|h)l1LfrfD=P;$jJRXr#RBb1#N!FC-1eR zL5h3`*v|uJ7^?1}8qqs115*?Zl^eP(GuwU9vhnuO-AHZ%RC>#eia-bs#}zP*LhJ+8 zjl$Yjfm?}Hh4S+vKC+Rs)cAgMzBN{>*rq`Gl$~uIqeSjjyM(F zF8!Nt_ey~v+iYrTX)ShwbzM{+5>59@$QHbQ{Tk7xE#Opad%e8c5~Gp#z^cYU`C-)* z#_!~VOEiQIWO?UHyNp5pj0sQ(Jg*|og-_Pms*hr6%l~b zE11CSwk~i?HNIJVNA?XNEli~$xd#tn-|>kVW?!9~9H_p1G|6J*WsVb^P0*mFApc6v zHFrFJ12C5z1DHkKbKqQly-h%ISZ9;3>Ffij~h<^EI~niO(32 zAu@QE9Ut+fY~0UGPvjnqZ@uic+|~00$sxmI^y;mpMvMQz1?5&4U!#5J(g_gPdblqWm?#AI|m<{qH zl;6Rnb3CJMv+M^;vV@g@l-E^)QSnBcOBnOvH)R-t>3X)*Jz8q=%I~}FI+9&6@=$KM zreBJjW!!UD(O%yA{bl-pnf`yJ>91Np;rY!sn+DYnA2j&T-admx|9KclEb|O>01P&` zR{^;)7UOiVCIE>ABf=24O!bC;Ipy$xevyTMY@MZKda- zU)%1}Ph#B3F3WM-&&D|@{EKQjkiDWj&jH6NMwxGq&g(d%zGAIEc5}MgfZ)zUo=eUw z`^UTV!-D(Im_Y6IUiu2X2hn~w55cBoTQAf7-*$$dk2O<%uv`cBzdn7x*ruDu>ed{9 zlGz+7-@=g`zmCE?gLHjczIKR_f6K{n3h7<*FT(Kko~|F^h2=S0KV$PB@57Jzn?aVc zeN$*h#WFqfy1#hgU%c=yUbrk!{%;BiyB7-`XGAi;JqQWs0=w2vuGm;8G)AikDca1_ z!||=u%EH8mAkx|sBbv`>PcYSubnTY(*)Lpa`y}%8aG=$C9x8r}LSG4d<|Qz^w>197 zGQHR;9$jU$@bog=_xm5*%N-Lo^X7#1g^C!|39_N=*0BEZ^ZD6MGJG{>DQDxQmNTnH zo*3`4a%Rp30N}TTZdbXeR}M2?gNx-e^QCuMhPCr9Ed$v7iaA~sJ0Ycao@pu12S5Gz ziVLXMD~WMw>jlG&%yW#cr`pKb%fvmEd%F3bg-kv@?$h5k#HFd&WyUtT{KfD6^!Qa) z>taqD-CwiZ;SX1d2-1phzn4H;>WYT{th_>$wpsk(*S`9H|Cxd+FuV$nT^?xoVPG4J z)}8sNy5d(O#cmkBJ6ms=Mv%NtR~hG|qOp{h{lW4Et=Cl!c8dDa?fQRTum4|V!2ke| zU@7A-)O-KT=nKkMVffWdgJr^x=(m_~y<5*WeD3j|*{T0rDGL~GVUn^O7YE;{wk`3( zb^6ulWtsju!F5837cjlpCEv9D$6S@s06iG%{4W%F``|tQ+t2j-0fzrzn7+(~(*s*g zkxAPAxyOIOjQ*!heKN)fS@v1+bN61=xZe}6ADEo!p6QyLGl@;LSuVZMRnBn4MttM9 zhT}$UiV3-8O=L<*7em`+S-gVD@q!tFP?fI+un)JDYPXLr*8?h>Zw(hkmOYCj?rG}C%zQJ|cV%sV?u%R7mVwTRWfgss?541& zWgURRnk#?jXLD)$$g;K|GW;*c@}=$eX&d-YI~LXo3rB;zO)E{NzJY)0N3;)T|7`C6 Ef22c?Jpcdz literal 0 HcmV?d00001 diff --git a/imgs/usage.png b/imgs/usage.png new file mode 100644 index 0000000000000000000000000000000000000000..ab5bfcb03e2e49f3f559a04a54f15bee6bdb04f8 GIT binary patch literal 418890 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


f~wvH}U{jl{^F;rl_R^pXLUrC@6v66}hCl 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
*6~4rYIUrx?lJsm$j(>L1 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 Empty (If PVC not available) + if cluster.GetSupportedVersions(string(internaltypes.PVCKind)) == nil { + vEmpty := convertPVCVolumeToEmptyVolume(volume) + log.Warnf("PVC not supported in target cluster. Defaulting volume [%s] to emptyDir", volume.Name) + return *vEmpty + + } + return volume + } + if volume.VolumeSource.HostPath != nil || volume.VolumeSource.EmptyDir != nil { + return volume + } + log.Warnf("Unsupported storage type (volume) detected") + + return corev1.Volume{} +} + +func stringMapToByteMap(sm map[string]string) map[string][]byte { + bm := make(map[string][]byte) + + for k, v := range sm { + bm[k] = []byte(v) + } + + return bm +} + +func byteMapToStringMap(bm map[string][]byte) map[string]string { + sm := make(map[string]string) + + for k, v := range bm { + sm[k] = string(v) + } + + return sm +} diff --git a/internal/apiresourceset/apiresourceset.go b/internal/apiresourceset/apiresourceset.go new file mode 100644 index 000000000..e2b4985d9 --- /dev/null +++ b/internal/apiresourceset/apiresourceset.go @@ -0,0 +1,38 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package apiresourceset + +import ( + "k8s.io/apimachinery/pkg/runtime" +) + +func intersection(objs1 []runtime.Object, objs2 []runtime.Object) []runtime.Object { + objs := []runtime.Object{} + for _, obj1 := range objs1 { + found := false + for _, obj2 := range objs2 { + if obj1 == obj2 { + found = true + break + } + } + if found { + objs = append(objs, obj1) + } + } + return objs +} diff --git a/internal/apiresourceset/k8sapiresourceset.go b/internal/apiresourceset/k8sapiresourceset.go new file mode 100644 index 000000000..1e3d92177 --- /dev/null +++ b/internal/apiresourceset/k8sapiresourceset.go @@ -0,0 +1,143 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package apiresourceset + +import ( + "io/ioutil" + + log "github.com/sirupsen/logrus" + + okdapi "github.com/openshift/api" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/serializer" + k8sapischeme "k8s.io/client-go/kubernetes/scheme" + + "github.com/konveyor/move2kube/internal/apiresource" + "github.com/konveyor/move2kube/internal/common" + irtypes "github.com/konveyor/move2kube/internal/types" + plantypes "github.com/konveyor/move2kube/types/plan" + tektonscheme "github.com/tektoncd/pipeline/pkg/client/clientset/versioned/scheme" +) + +// K8sAPIResourceSet for handling K8s related resources +type K8sAPIResourceSet struct { +} + +// GetScheme returns K8s scheme +func (k *K8sAPIResourceSet) GetScheme() *runtime.Scheme { + scheme := runtime.NewScheme() + _ = okdapi.Install(scheme) + _ = okdapi.InstallKube(scheme) + _ = k8sapischeme.AddToScheme(scheme) + _ = tektonscheme.AddToScheme(scheme) + return scheme +} + +func (k *K8sAPIResourceSet) getAPIResources(ir irtypes.IR) []apiresource.APIResource { + apiresources := []apiresource.APIResource{{IAPIResource: &apiresource.Deployment{ClusterSpec: ir.TargetClusterSpec}}, {IAPIResource: &apiresource.Storage{Cluster: ir.TargetClusterSpec}}, {IAPIResource: &apiresource.Service{Cluster: ir.TargetClusterSpec}}, {IAPIResource: &apiresource.ImageStream{Cluster: ir.TargetClusterSpec}}, {IAPIResource: &apiresource.NetworkPolicy{Cluster: ir.TargetClusterSpec}}} + return apiresources +} + +// CreateAPIResources converts IR to runtime objects +func (k *K8sAPIResourceSet) CreateAPIResources(ir irtypes.IR) []runtime.Object { + targetobjs := []runtime.Object{} + ignoredobjs := ir.CachedObjects + for _, a := range k.getAPIResources(ir) { + a.SetClusterContext(ir.TargetClusterSpec) + resourceignoredobjs := a.LoadResources(ir.CachedObjects) + ignoredobjs = intersection(ignoredobjs, resourceignoredobjs) + objs := a.GetUpdatedResources(ir) + targetobjs = append(targetobjs, objs...) + } + targetobjs = append(targetobjs, ignoredobjs...) + return targetobjs +} + +// GetServiceOptions analyses a directory and returns possible plan services +func (k *K8sAPIResourceSet) GetServiceOptions(inputPath string, plan plantypes.Plan) ([]plantypes.Service, error) { + services := make([]plantypes.Service, 0) + //TODO: Should we add service analysis too, to get service name? + + codecs := serializer.NewCodecFactory(k.GetScheme()) + + files, err := common.GetFilesByExt(inputPath, []string{".yml", ".yaml"}) + if err != nil { + log.Warnf("Unable to fetch yaml files and recognize k8 yamls : %s", err) + } + for _, path := range files { + data, err := ioutil.ReadFile(path) + if err != nil { + log.Debugf("ignoring file %s", path) + continue + } + obj, _, err := codecs.UniversalDeserializer().Decode(data, nil, nil) + if err != nil { + log.Debugf("ignoring file %s since serialization failed", path) + continue + } else { + name, _, err := (&apiresource.Deployment{}).GetNameAndPodSpec(obj) + if err == nil { + service := newK8sService(name) + relpath, _ := plan.GetRelativePath(path) + service.SourceArtifacts[plantypes.K8sFileArtifactType] = []string{relpath} + services = append(services, service) + } + } + } + return services, nil +} + +// Translate tanslates plan services to IR +func (k *K8sAPIResourceSet) Translate(services []plantypes.Service, p plantypes.Plan) (irtypes.IR, error) { + ir := irtypes.NewIR(p) + ir.Services = make(map[string]irtypes.Service) + codecs := serializer.NewCodecFactory(k.GetScheme()) + + for _, service := range services { + irservice := irtypes.Service{Name: service.ServiceName} + if len(service.SourceArtifacts[plantypes.K8sFileArtifactType]) > 0 { + fullpath := p.GetFullPath(service.SourceArtifacts[plantypes.K8sFileArtifactType][0]) + data, err := ioutil.ReadFile(fullpath) + if err != nil { + log.Debugf("Unable to load file : %s", fullpath) + continue + } + obj, _, err := codecs.UniversalDeserializer().Decode(data, nil, nil) + if err != nil { + log.Debugf("ignoring file %s since serialization failed", fullpath) + continue + } + _, podSpec, err := (&apiresource.Deployment{}).GetNameAndPodSpec(obj) + if err == nil { + irservice.PodSpec = podSpec + } + } else { + log.Warnf("No k8s artifacts found in service %s", service.ServiceName) + } + ir.Services[service.ServiceName] = irservice + } + return ir, nil +} + +func newK8sService(serviceName string) plantypes.Service { + service := plantypes.NewService(serviceName, plantypes.Kube2KubeTranslation) + service.ContainerBuildType = plantypes.ReuseContainerBuildTypeValue + service.SourceTypes = []plantypes.SourceTypeValue{plantypes.K8sSourceTypeValue} + service.UpdateContainerBuildPipeline = false + service.UpdateDeployPipeline = true + return service +} diff --git a/internal/apiresourceset/knativeapiresourceset.go b/internal/apiresourceset/knativeapiresourceset.go new file mode 100644 index 000000000..c4d379b07 --- /dev/null +++ b/internal/apiresourceset/knativeapiresourceset.go @@ -0,0 +1,137 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package apiresourceset + +import ( + "io/ioutil" + + log "github.com/sirupsen/logrus" + + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/serializer" + knativev1 "knative.dev/serving/pkg/apis/serving/v1" + knative "knative.dev/serving/pkg/client/clientset/versioned/scheme" + + "github.com/konveyor/move2kube/internal/apiresource" + "github.com/konveyor/move2kube/internal/common" + irtypes "github.com/konveyor/move2kube/internal/types" + plantypes "github.com/konveyor/move2kube/types/plan" +) + +// KnativeAPIResourceSet manages knative related objects +type KnativeAPIResourceSet struct { +} + +// GetScheme returns knative scheme object +func (k *KnativeAPIResourceSet) GetScheme() *runtime.Scheme { + scheme := runtime.NewScheme() + _ = knative.AddToScheme(scheme) + return scheme +} + +func (k *KnativeAPIResourceSet) getAPIResources(ir irtypes.IR) []apiresource.APIResource { + apiresources := []apiresource.APIResource{{IAPIResource: &apiresource.KnativeService{Cluster: ir.TargetClusterSpec}}} + return apiresources +} + +// CreateAPIResources converts ir object to runtime objects +func (k *KnativeAPIResourceSet) CreateAPIResources(ir irtypes.IR) []runtime.Object { + targetobjs := []runtime.Object{} + ignoredobjs := ir.CachedObjects + for _, apiresource := range k.getAPIResources(ir) { + apiresource.SetClusterContext(ir.TargetClusterSpec) + resourceignoredobjs := apiresource.LoadResources(ir.CachedObjects) + ignoredobjs = intersection(ignoredobjs, resourceignoredobjs) + objs := apiresource.GetUpdatedResources(ir) + targetobjs = append(targetobjs, objs...) + } + targetobjs = append(targetobjs, ignoredobjs...) + return targetobjs +} + +// GetServiceOptions returns plan service options for an input folder +func (k *KnativeAPIResourceSet) GetServiceOptions(inputPath string, plan plantypes.Plan) ([]plantypes.Service, error) { + services := make([]plantypes.Service, 0) + + codecs := serializer.NewCodecFactory(k.GetScheme()) + + files, err := common.GetFilesByExt(inputPath, []string{".yml", ".yaml"}) + if err != nil { + log.Warnf("Unable to fetch yaml files and recognize knative yamls : %s", err) + } + for _, path := range files { + //relpath, _ := plan.GetRelativePath(path) + data, err := ioutil.ReadFile(path) + if err != nil { + log.Debugf("ignoring file %s", path) + continue + } + obj, _, err := codecs.UniversalDeserializer().Decode(data, nil, nil) + if err != nil { + log.Debugf("ignoring file %s since serialization failed", path) + continue + } else { + if d1, ok := obj.(*knativev1.Service); ok { + service := newKnativeService(d1.Name) + relpath, _ := plan.GetRelativePath(path) + service.SourceArtifacts[plantypes.KnativeFileArtifactType] = []string{relpath} + services = append(services, service) + } + } + } + return services, nil +} + +// Translate translates plan services to IR +func (k *KnativeAPIResourceSet) Translate(services []plantypes.Service, p plantypes.Plan) (irtypes.IR, error) { + ir := irtypes.NewIR(p) + ir.Services = make(map[string]irtypes.Service) + codecs := serializer.NewCodecFactory(k.GetScheme()) + + for _, service := range services { + irservice := irtypes.Service{Name: service.ServiceName} + if len(service.SourceArtifacts[plantypes.KnativeFileArtifactType]) > 0 { + fullpath := p.GetFullPath(service.SourceArtifacts[plantypes.KnativeFileArtifactType][0]) + data, err := ioutil.ReadFile(fullpath) + if err != nil { + log.Debugf("Unable to load file : %s", fullpath) + continue + } + obj, _, err := codecs.UniversalDeserializer().Decode(data, nil, nil) + if err != nil { + log.Debugf("ignoring file %s since serialization failed", fullpath) + continue + } + if d1, ok := obj.(*knativev1.Service); ok { + irservice.PodSpec = d1.Spec.ConfigurationSpec.Template.Spec.PodSpec + } + } else { + log.Warnf("No knative artifacts found in service %s", service.ServiceName) + } + ir.Services[service.ServiceName] = irservice + } + return ir, nil +} + +func newKnativeService(serviceName string) plantypes.Service { + service := plantypes.NewService(serviceName, plantypes.Knative2KubeTranslation) + service.ContainerBuildType = plantypes.ReuseContainerBuildTypeValue + service.SourceTypes = []plantypes.SourceTypeValue{plantypes.KNativeSourceTypeValue} + service.UpdateContainerBuildPipeline = false + service.UpdateDeployPipeline = true + return service +} diff --git a/internal/assets/assets.go b/internal/assets/assets.go new file mode 100644 index 000000000..c25273aee --- /dev/null +++ b/internal/assets/assets.go @@ -0,0 +1,19 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package assets + +//go:generate go run github.com/konveyor/move2kube/internal/common/generator . maketar diff --git a/internal/assets/constants.go b/internal/assets/constants.go new file mode 100644 index 000000000..71b6f83fe --- /dev/null +++ b/internal/assets/constants.go @@ -0,0 +1,23 @@ +// Code generated by go generate; DO NOT EDIT. +// This file was generated by robots at +// 2020-09-14 15:52:43.971455 +0530 IST m=+0.005163665 + +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package assets + +const Tar = `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LgojICAgWW91IG1heSBvYnRhaW4gYSBjb3B5IG9mIHRoZSBMaWNlbnNlIGF0CiMKIyAgICAgICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wCiMKIyAgIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvciBhZ3JlZWQgdG8gaW4gd3JpdGluZywgc29mdHdhcmUKIyAgIGRpc3RyaWJ1dGVkIHVuZGVyIHRoZSBMaWNlbnNlIGlzIGRpc3RyaWJ1dGVkIG9uIGFuICJBUyBJUyIgQkFTSVMsCiMgICBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC4KIyAgIFNlZSB0aGUgTGljZW5zZSBmb3IgdGhlIHNwZWNpZmljIGxhbmd1YWdlIGdvdmVybmluZyBwZXJtaXNzaW9ucyBhbmQKIyAgIGxpbWl0YXRpb25zIHVuZGVyIHRoZSBMaWNlbnNlLgoKRlJPTSByZWdpc3RyeS5hY2Nlc3MucmVkaGF0LmNvbS91Ymk4L3ViaTpsYXRlc3QgQVMgYnVpbGRfYmFzZQpSVU4geXVtIGluc3RhbGwgLXkgamF2YS0xLjguMC1vcGVuamRrLWRldmVsClJVTiB5dW0gaW5zdGFsbCAteSB3Z2V0ClJVTiB5dW0gaW5zdGFsbCAteSB1bnppcApSVU4gd2dldCBodHRwczovL21pcnJvcnMuZXN0b2ludGVybmV0LmluL2FwYWNoZS8vYW50L2JpbmFyaWVzL2FwYWNoZS1hbnQtMS4xMC44LWJpbi56aXAgLVAgL3RtcApSVU4gdW56aXAgLWQgL29wdC9hcGFjaGUtYW50IC90bXAvYXBhY2hlLWFudC0xLjEwLjgtYmluLnppcApFTlYgUEFUSD0iJHtQQVRIfTovb3B0L2FwYWNoZS1hbnQvYXBhY2hlLWFudC0xLjEwLjgvYmluLyIKQ09QWSAuIC97ey5BUFBOQU1FfX0KV09SS0RJUiAve3suQVBQTkFNRX19ClJVTiB7ey5BTlRDTUR9fQoKRlJPTSByZWdpc3RyeS5hY2Nlc3MucmVkaGF0LmNvbS9qYm9zcy1lYXAt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aW9uIDIuMCAodGhlICJMaWNlbnNlIik7CiMgICB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuCiMgICBZb3UgbWF5IG9idGFpbiBhIGNvcHkgb2YgdGhlIExpY2Vuc2UgYXQKIwojICAgICAgICBodHRwOi8vd3d3LmFwYWNoZS5vcmcvbGljZW5zZXMvTElDRU5TRS0yLjAKIwojICAgVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZQojICAgZGlzdHJpYnV0ZWQgdW5kZXIgdGhlIExpY2Vuc2UgaXMgZGlzdHJpYnV0ZWQgb24gYW4gIkFTIElTIiBCQVNJUywKIyAgIFdJVEhPVVQgV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIEFOWSBLSU5ELCBlaXRoZXIgZXhwcmVzcyBvciBpbXBsaWVkLgojICAgU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZAojICAgbGltaXRhdGlvbnMgdW5kZXIgdGhlIExpY2Vuc2UuCgojIEJ1aWxkIEFwcApGUk9NIHJlZ2lzdHJ5LmFjY2Vzcy5yZWRoYXQuY29tL3ViaTgvdWJpOmxhdGVzdCBBUyBidWlsZF9iYXNlClJVTiB5dW0gaW5zdGFsbCAteSBqYXZhLTEuOC4wLW9wZW5qZGstZGV2ZWwKUlVOIHl1bSBpbnN0YWxsIC15IG1hdmVuCkNPUFkgLiAve3suQVBQTkFNRX19CldPUktESVIgL3t7LkFQUE5BTUV9fQpSVU4gbXZuIHBhY2thZ2UKCiMgUnVuIEFwcApGUk9NIHJlZ2lzdHJ5LmFjY2Vzcy5yZWRoYXQuY29tL2pib3NzLWVhcC02L2VhcDY0LW9wZW5zaGlmdDpsYXRlc3QKRVhQT1NFIHt7LlBvcnR9fQpDT1BZIC0tZnJvbT1idWlsZF9iYXNlIC97ey5BUFBOQU1FfX0vdGFyZ2V0LyogL29wdC9lYXAvc3RhbmRhbG9uZS9kZXBsb3ltZW50cy8AAAAA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bGljYWJsZSBsYXcgb3IgYWdyZWVkIHRvIGluIHdyaXRpbmcsIHNvZnR3YXJlCiMgICBkaXN0cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiAiQVMgSVMiIEJBU0lTLAojICAgV0lUSE9VVCBXQVJSQU5USUVTIE9SIENPTkRJVElPTlMgT0YgQU5ZIEtJTkQsIGVpdGhlciBleHByZXNzIG9yIGltcGxpZWQuCiMgICBTZWUgdGhlIExpY2Vuc2UgZm9yIHRoZSBzcGVjaWZpYyBsYW5ndWFnZSBnb3Zlcm5pbmcgcGVybWlzc2lvbnMgYW5kCiMgICBsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS4KCiMgVGFrZXMgYXMgaW5wdXQgdGhlIHNvdXJjZSBmb2xkZXIgYW5kIHJldHVybnMgZXJyb3IgaWYgaXQgaXMgbm90IGZpdApCQVNFX0RJUj0kMQpOQVRJVkVfSU1BR0U9InJlZ2lzdHJ5LmFjY2Vzcy5yZWRoYXQuY29tL3JlZGhhdC1vcGVuamRrLTE4L29wZW5qZGsxOC1vcGVuc2hpZnQ6bGF0ZXN0IgpXRUJfSU1BR0U9InJlZ2lzdHJ5LmFjY2Vzcy5yZWRoYXQuY29tL2pib3NzLWVhcC02L2VhcDY0LW9wZW5zaGlmdDpsYXRlc3QiCgojIEdyYWRsZSBub3Qgc3VwcG9ydGVkIHlldAppZiBbIC1mICIkMS9idWlsZC5ncmFkbGUiIF07IHRoZW4KICAgZXhpdCAxCmZpCgojIEFudCBub3Qgc3VwcG9ydGVkIHlldAppZiBbIC1mICIkMS9idWlsZC54bWwiIF07IHRoZW4KICAgZXhpdCAxCmZpCgppZiBbIC1mICIkMS9wb20ueG1sIiBdOyB0aGVuCiAgIGVjaG8gJ3siQnVpbGRlciI6ICInJFdFQl9JTUFHRSciLCAiUG9ydCI6IDgwODB9JwogICBleGl0IDAKZmkKCmZvdW5kPWBmaW5kICRCQVNFX0RJUi8uIC1uYW1lICIqLmphdmEiIC1wcmludCAtcXVpdCB8IHdjIC1sYAoKaWYgWyAkZm91bmQgLWVxIDEgXTsgdGhlbgogICAgZWNobyAneyJCdWlsZGVyIjogIickTkFUSVZFX0lNQUdFJyIsICJQb3J0IjogODA4MH0nCmVsc2UgCiAgICBleGl0IDEKZmkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAczJpL25vZGVqcwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAwMDA3NTUAMDAwMDc2NQAwMDAwMDI0ADAwMDAwMDAwMDAwADEzNzI3NjMyNDQ0ADAxNjUwMQAgNQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB1c3RhcgAwMGhhcmlrcmlzaG5hbmJhbGFnb3BhbAAAAAAAAAAAAAAAc3RhZmYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwMDAwMDAwADAwMDAwMDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABzMmkvbm9kZWpzLy5zMmkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMDAwMDc1NQAwMDAwNzY1ADAwMDAwMjQAMDAwMDAwMDAwMDAAMTM3Mjc2MzI0NDQAMDE3MjU0ACA1AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHVzdGFyADAwaGFyaWtyaXNobmFuYmFsYWdvcGFsAAAAAAAAAAAAAABzdGFmZgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAwMDAwMDAAMDAwMDAwMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHMyaS9ub2RlanMvLnMyaS9lbnZpcm9ubWVudAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwMDAwNjQ0ADAwMDA3NjUAMDAwMDAyNAAwMDAwMDAwMDIyNQAxMzcyNzYzMjQ0NAAwMjE2MjEAIDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAdXN0YXIAMDBoYXJpa3Jpc2huYW5iYWxhZ29wYWwAAAAAAAAAAAAAAHN0YWZmAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMDAwMDAwMAAwMDAwMDAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAe3stIHJhbmdlICRrZXksICR2YWx1ZSA6PSAuIH19Cnt7LSBpZiBhbmQgKG5lICRrZXkgIkJ1aWxkZXIiKSAobmUgJGtleSAiSW1hZ2VOYW1lIikgKG5lICRrZXkgIlBvcnQiKSB9fQp7eyAka2V5IH19PXt7ICR2YWx1ZSB9fQp7ey0gZW5kIH19Cnt7LSBlbmQgfX0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABzMmkvbm9kZWpzL20ya3MyaWRldGVjdC5zaAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMDAwMDc1NQAwMDAwNzY1ADAwMDAwMjQAMDAwMDAwMDE0NjIAMTM3Mjc2MzI0NDQAMDIxNDIyACAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHVzdGFyADAwaGFyaWtyaXNobmFuYmFsYWdvcGFsAAAAAAAAAAAAAABzdGFmZgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAwMDAwMDAAMDAwMDAwMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACMgICBDb3B5cmlnaHQgSUJNIENvcnBvcmF0aW9uIDIwMjAKIwojICAgTGljZW5zZWQgdW5kZXIgdGhlIEFwYWNoZSBMaWNlbnNlLCBWZXJzaW9uIDIuMCAodGhlICJMaWNlbnNlIik7CiMgICB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuCiMgICBZb3UgbWF5IG9idGFpbiBhIGNvcHkgb2YgdGhlIExpY2Vuc2UgYXQKIwojICAgICAgICBodHRwOi8vd3d3LmFwYWNoZS5vcmcvbGljZW5zZXMvTElDRU5TRS0yLjAKIwojICAgVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZQojICAgZGlzdHJpYnV0ZWQgdW5kZXIgdGhlIExpY2Vuc2UgaXMgZGlzdHJpYnV0ZWQgb24gYW4gIkFTIElTIiBCQVNJUywKIyAgIFdJVEhPVVQgV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIEFOWSBLSU5ELCBlaXRoZXIgZXhwcmVzcyBvciBpbXBsaWVkLgojICAgU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZAojICAgbGltaXRhdGlvbnMgdW5kZXIgdGhlIExpY2Vuc2UuCgojIFRha2VzIGFzIGlucHV0IHRoZSBzb3VyY2UgZGlyZWN0b3J5IGFuZCByZXR1cm5zIGVycm9yIGlmIGl0IGlzIG5vdCBmaXQKaWYgWyAhIC1mICIkMS9wYWNrYWdlLmpzb24iIF07IHRoZW4KICAgZXhpdCAxCmZpCgpJTUFHRT0icmVnaXN0cnkuYWNjZXNzLnJlZGhhdC5jb20vdWJpOC9ub2RlanMtMTAiCmVjaG8gJ3siQnVpbGRlciI6ICInJElNQUdFJyIsICJQb3J0IjogODA4MH0nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABzMmkvcGhwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMDAwMDc1NQAwMDAwNzY1ADAwMDAwMjQAMDAwMDAwMDAwMDAAMTM3Mjc2MzI0NDQAMDE2MDA2ACA1AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHVzdGFyADAwaGFyaWtyaXNobmFuYmFsYWdvcGFsAAAAAAAAAAAAAABzdGFmZgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAwMDAwMDAAMDAwMDAwMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHMyaS9waHAvLnMyaQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwMDAwNzU1ADAwMDA3NjUAMDAwMDAyNAAwMDAwMDAwMDAwMAAxMzcyNzYzMjQ0NAAwMTY1NjEAIDUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAdXN0YXIAMDBoYXJpa3Jpc2huYW5iYWxhZ29wYWwAAAAAAAAAAAAAAHN0YWZmAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMDAwMDAwMAAwMDAwMDAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAczJpL3BocC8uczJpL2Vudmlyb25tZW50AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAwMDA2NDQAMDAwMDc2NQAwMDAwMDI0ADAwMDAwMDAwMjI1ADEzNzI3NjMyNDQ0ADAyMTEyNgAgMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB1c3RhcgAwMGhhcmlrcmlzaG5hbmJhbGFnb3BhbAAAAAAAAAAAAAAAc3RhZmYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwMDAwMDAwADAwMDAwMDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB7ey0gcmFuZ2UgJGtleSwgJHZhbHVlIDo9IC4gfX0Ke3stIGlmIGFuZCAobmUgJGtleSAiQnVpbGRlciIpIChuZSAka2V5ICJJbWFnZU5hbWUiKSAobmUgJGtleSAiUG9ydCIpIH19Cnt7ICRrZXkgfX09e3sgJHZhbHVlIH19Cnt7LSBlbmQgfX0Ke3stIGVuZCB9fQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHMyaS9waHAvbTJrczJpZGV0ZWN0LnNoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwMDAwNjQ0ADAwMDA3NjUAMDAwMDAyNAAwMDAwMDAwMTYwNAAxMzcyNzYzMjQ0NAAwMjA3MjIAIDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAdXN0YXIAMDBoYXJpa3Jpc2huYW5iYWxhZ29wYWwAAAAAAAAAAAAAAHN0YWZmAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMDAwMDAwMAAwMDAwMDAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIyAgIENvcHlyaWdodCBJQk0gQ29ycG9yYXRpb24gMjAyMAojCiMgICBMaWNlbnNlZCB1bmRlciB0aGUgQXBhY2hlIExpY2Vuc2UsIFZlcnNpb24gMi4wICh0aGUgIkxpY2Vuc2UiKTsKIyAgIHlvdSBtYXkgbm90IHVzZSB0aGlzIGZpbGUgZXhjZXB0IGluIGNvbXBsaWFuY2Ugd2l0aCB0aGUgTGljZW5zZS4KIyAgIFlvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdAojCiMgICAgICAgIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMAojCiMgICBVbmxlc3MgcmVxdWlyZWQgYnkgYXBwbGljYWJsZSBsYXcgb3IgYWdyZWVkIHRvIGluIHdyaXRpbmcsIHNvZnR3YXJlCiMgICBkaXN0cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiAiQVMgSVMiIEJBU0lTLAojICAgV0lUSE9VVCBXQVJSQU5USUVTIE9SIENPTkRJVElPTlMgT0YgQU5ZIEtJTkQsIGVpdGhlciBleHByZXNzIG9yIGltcGxpZWQuCiMgICBTZWUgdGhlIExpY2Vuc2UgZm9yIHRoZSBzcGVjaWZpYyBsYW5ndWFnZSBnb3Zlcm5pbmcgcGVybWlzc2lvbnMgYW5kCiMgICBsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS4KCiMgVGFrZXMgYXMgaW5wdXQgdGhlIHNvdXJjZSBmb2xkZXIgYW5kIHJldHVybnMgZXJyb3IgaWYgaXQgaXMgbm90IGZpdApCQVNFX0RJUj0kMQpJTUFHRT0icmVnaXN0cnkuYWNjZXNzLnJlZGhhdC5jb20vcmhzY2wvcGhwLTcyLXJoZWw3OmxhdGVzdCIKCmZvdW5kPWBmaW5kICRCQVNFX0RJUi8uIC1uYW1lICIqLnBocCIgLXByaW50IC1xdWl0IHwgd2MgLWxgCgppZiBbICRmb3VuZCAtZXEgMSBdOyB0aGVuCiAgICBlY2hvICd7IkJ1aWxkZXIiOiAiJyRJTUFHRSciLCAiUG9ydCI6IDgwODB9JwplbHNlIAogICAgZXhpdCAxCmZpAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHMyaS9weXRob24AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwMDAwNzU1ADAwMDA3NjUAMDAwMDAyNAAwMDAwMDAwMDAwMAAxMzcyNzYzMjQ0NAAwMTY1NDAAIDUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAdXN0YXIAMDBoYXJpa3Jpc2huYW5iYWxhZ29wYWwAAAAAAAAAAAAAAHN0YWZmAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMDAwMDAwMAAwMDAwMDAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAczJpL3B5dGhvbi8uczJpAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAwMDA3NTUAMDAwMDc2NQAwMDAwMDI0ADAwMDAwMDAwMDAwADEzNzI3NjMyNDQ0ADAxNzMxMwAgNQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB1c3RhcgAwMGhhcmlrcmlzaG5hbmJhbGFnb3BhbAAAAAAAAAAAAAAAc3RhZmYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwMDAwMDAwADAwMDAwMDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABzMmkvcHl0aG9uLy5zMmkvZW52aXJvbm1lbnQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMDAwMDY0NAAwMDAwNzY1ADAwMDAwMjQAMDAwMDAwMDAyMjUAMTM3Mjc2MzI0NDQAMDIxNjYwACAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHVzdGFyADAwaGFyaWtyaXNobmFuYmFsYWdvcGFsAAAAAAAAAAAAAABzdGFmZgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAwMDAwMDAAMDAwMDAwMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHt7LSByYW5nZSAka2V5LCAkdmFsdWUgOj0gLiB9fQp7ey0gaWYgYW5kIChuZSAka2V5ICJCdWlsZGVyIikgKG5lICRrZXkgIkltYWdlTmFtZSIpIChuZSAka2V5ICJQb3J0IikgfX0Ke3sgJGtleSB9fT17eyAkdmFsdWUgfX0Ke3stIGVuZCB9fQp7ey0gZW5kIH19AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAczJpL3B5dGhvbi9tMmtzMmlkZXRlY3Quc2gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAwMDA3NTUAMDAwMDc2NQAwMDAwMDI0ADAwMDAwMDAyMTUxADEzNzI3NjMyNDQ0ADAyMTQ1NQAgMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB1c3RhcgAwMGhhcmlrcmlzaG5hbmJhbGFnb3BhbAAAAAAAAAAAAAAAc3RhZmYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwMDAwMDAwADAwMDAwMDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAjICAgQ29weXJpZ2h0IElCTSBDb3Jwb3JhdGlvbiAyMDIwCiMKIyAgIExpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSAiTGljZW5zZSIpOwojICAgeW91IG1heSBub3QgdXNlIHRoaXMgZmlsZSBleGNlcHQgaW4gY29tcGxpYW5jZSB3aXRoIHRoZSBMaWNlbnNlLgojICAgWW91IG1heSBvYnRhaW4gYSBjb3B5IG9mIHRoZSBMaWNlbnNlIGF0CiMKIyAgICAgICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wCiMKIyAgIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvciBhZ3JlZWQgdG8gaW4gd3JpdGluZywgc29mdHdhcmUKIyAgIGRpc3RyaWJ1dGVkIHVuZGVyIHRoZSBMaWNlbnNlIGlzIGRpc3RyaWJ1dGVkIG9uIGFuICJBUyBJUyIgQkFTSVMsCiMgICBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC4KIyAgIFNlZSB0aGUgTGljZW5zZSBmb3IgdGhlIHNwZWNpZmljIGxhbmd1YWdlIGdvdmVybmluZyBwZXJtaXNzaW9ucyBhbmQKIyAgIGxpbWl0YXRpb25zIHVuZGVyIHRoZSBMaWNlbnNlLgoKIyBUYWtlcyBhcyBpbnB1dCB0aGUgc291cmNlIGZvbGRlciBhbmQgcmV0dXJucyBlcnJvciBpZiBpdCBpcyBub3QgZml0CkJBU0VfRElSPSQxClNQRUNJQUxfRklMRVM9KCRCQVNFX0RJUi9yZXF1aXJlbWVudHMudHh0ICRCQVNFX0RJUi9zZXR1cC5weSAkQkFTRV9ESVIvZW52aXJvbm1lbnQueW1sICRCQVNFX0RJUi9QaXBmaWxlKQpJTUFHRT0icmVnaXN0cnkuYWNjZXNzLnJlZGhhdC5jb20vcmhzY2wvcHl0aG9uLTM2LXJoZWw3OmxhdGVzdCIKCmZvciBmaWxlTmFtZSBpbiAiJHtTUEVDSUFMX0ZJTEVTW0BdfSIKZG8KICAgaWYgWyAtZiAiJGZpbGVOYW1lIiBdOyB0aGVuCiAgICAgIHN0YXJ0U2NyaXB0PWBncmVwIC1sUmUgIl9fbWFpbl9fIiAkQkFTRV9ESVIgfCBhd2sgJ3twcmludCAkMX0nIHwgeGFyZ3MgLW4xIGJhc2VuYW1lYAogICAgICBlY2hvICd7IkJ1aWxkZXIiOiAiJyRJTUFHRSciLCAiQVBQX0ZJTEUiOiAiJyRzdGFydFNjcmlwdCciLCAiUG9ydCI6IDgwODB9JwogICAgICBleGl0IDAKICAgZmkKZG9uZQoKZXhpdCAxAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABzMmkvcnVieQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMDAwMDc1NQAwMDAwNzY1ADAwMDAwMjQAMDAwMDAwMDAwMDAAMTM3Mjc2MzI0NDQAMDE2MjAwACA1AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHVzdGFyADAwaGFyaWtyaXNobmFuYmFsYWdvcGFsAAAAAAAAAAAAAABzdGFmZgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAwMDAwMDAAMDAwMDAwMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHMyaS9ydWJ5Ly5zMmkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwMDAwNzU1ADAwMDA3NjUAMDAwMDAyNAAwMDAwMDAwMDAwMAAxMzcyNzYzMjQ0NAAwMTY3NTMAIDUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAdXN0YXIAMDBoYXJpa3Jpc2huYW5iYWxhZ29wYWwAAAAAAAAAAAAAAHN0YWZmAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMDAwMDAwMAAwMDAwMDAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAczJpL3J1YnkvLnMyaS9lbnZpcm9ubWVudAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAwMDA2NDQAMDAwMDc2NQAwMDAwMDI0ADAwMDAwMDAwMjI1ADEzNzI3NjMyNDQ0ADAyMTMyMAAgMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB1c3RhcgAwMGhhcmlrcmlzaG5hbmJhbGFnb3BhbAAAAAAAAAAAAAAAc3RhZmYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwMDAwMDAwADAwMDAwMDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB7ey0gcmFuZ2UgJGtleSwgJHZhbHVlIDo9IC4gfX0Ke3stIGlmIGFuZCAobmUgJGtleSAiQnVpbGRlciIpIChuZSAka2V5ICJJbWFnZU5hbWUiKSAobmUgJGtleSAiUG9ydCIpIH19Cnt7ICRrZXkgfX09e3sgJHZhbHVlIH19Cnt7LSBlbmQgfX0Ke3stIGVuZCB9fQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHMyaS9ydWJ5L20ya3MyaWRldGVjdC5zaAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwMDAwNjQ0ADAwMDA3NjUAMDAwMDAyNAAwMDAwMDAwMTUyMAAxMzcyNzYzMjQ0NAAwMjExMTEAIDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAdXN0YXIAMDBoYXJpa3Jpc2huYW5iYWxhZ29wYWwAAAAAAAAAAAAAAHN0YWZmAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMDAwMDAwMAAwMDAwMDAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIyAgIENvcHlyaWdodCBJQk0gQ29ycG9yYXRpb24gMjAyMAojCiMgICBMaWNlbnNlZCB1bmRlciB0aGUgQXBhY2hlIExpY2Vuc2UsIFZlcnNpb24gMi4wICh0aGUgIkxpY2Vuc2UiKTsKIyAgIHlvdSBtYXkgbm90IHVzZSB0aGlzIGZpbGUgZXhjZXB0IGluIGNvbXBsaWFuY2Ugd2l0aCB0aGUgTGljZW5zZS4KIyAgIFlvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdAojCiMgICAgICAgIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMAojCiMgICBVbmxlc3MgcmVxdWlyZWQgYnkgYXBwbGljYWJsZSBsYXcgb3IgYWdyZWVkIHRvIGluIHdyaXRpbmcsIHNvZnR3YXJlCiMgICBkaXN0cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiAiQVMgSVMiIEJBU0lTLAojICAgV0lUSE9VVCBXQVJSQU5USUVTIE9SIENPTkRJVElPTlMgT0YgQU5ZIEtJTkQsIGVpdGhlciBleHByZXNzIG9yIGltcGxpZWQuCiMgICBTZWUgdGhlIExpY2Vuc2UgZm9yIHRoZSBzcGVjaWZpYyBsYW5ndWFnZSBnb3Zlcm5pbmcgcGVybWlzc2lvbnMgYW5kCiMgICBsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS4KCiMgVGFrZXMgYXMgaW5wdXQgdGhlIHNvdXJjZSBmb2xkZXIgYW5kIHJldHVybnMgZXJyb3IgaWYgaXQgaXMgbm90IGZpdApCQVNFX0RJUj0kMQpJTUFHRT0icmVnaXN0cnkuYWNjZXNzLnJlZGhhdC5jb20vcmhzY2wvcnVieS0yNS1yaGVsNzpsYXRlc3QiCgppZiBbIC1mICRCQVNFX0RJUi9HZW1maWxlIF07IHRoZW4KICAgIGVjaG8gJ3siQnVpbGRlciI6ICInJElNQUdFJyIsICJQb3J0IjogODA4MH0nCmVsc2UgCiAgICBleGl0IDEKZmk=` diff --git a/internal/assets/dockerfiles/django/Dockerfile b/internal/assets/dockerfiles/django/Dockerfile new file mode 100644 index 000000000..eed65657d --- /dev/null +++ b/internal/assets/dockerfiles/django/Dockerfile @@ -0,0 +1,21 @@ +# Copyright IBM Corporation 2020 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +FROM registry.access.redhat.com/ubi8/python-36 + +WORKDIR /app +COPY . . +RUN pip install -r requirements.txt +EXPOSE {{.Port}} +CMD ["python", "manage.py", "runserver", "{{.BINDING}}"] \ No newline at end of file diff --git a/internal/assets/dockerfiles/django/m2kdfdetect.sh b/internal/assets/dockerfiles/django/m2kdfdetect.sh new file mode 100755 index 000000000..931005536 --- /dev/null +++ b/internal/assets/dockerfiles/django/m2kdfdetect.sh @@ -0,0 +1,22 @@ +# Copyright IBM Corporation 2020 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Takes as input the source folder and returns error if it is not fit +BASE_DIR=$1 + +if [ ! -f "$1/Pipfile" ]; then + exit 1 +else + echo '{"Port": 8080, "BINDING": "0.0.0.0:8080"}' +fi \ No newline at end of file diff --git a/internal/assets/dockerfiles/golang/Dockerfile b/internal/assets/dockerfiles/golang/Dockerfile new file mode 100644 index 000000000..e7e5262cb --- /dev/null +++ b/internal/assets/dockerfiles/golang/Dockerfile @@ -0,0 +1,36 @@ +# Copyright IBM Corporation 2020 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Build App +FROM registry.access.redhat.com/ubi8/ubi:latest AS build_base + +WORKDIR /temp +ENV GOPATH=/go +ENV PATH=$GOPATH/bin:/usr/local/go/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin +RUN curl -o go.tar.gz https://dl.google.com/go/go1.15.linux-amd64.tar.gz +RUN tar -xzf go.tar.gz && mv go /usr/local/ +RUN yum install git make -y +RUN mkdir -p $GOPATH/src $GOPATH/bin && chmod -R 777 $GOPATH +WORKDIR /{{.APPNAME}} +COPY . . +RUN go build -o {{.APPNAME}} +RUN cp ./{{.APPNAME}} /bin/{{.APPNAME}} + +# Run App +FROM registry.access.redhat.com/ubi8/ubi:latest +COPY --from=build_base /bin/{{.APPNAME}} /bin/{{.APPNAME}} + +EXPOSE {{.Port}} + +CMD ["{{.APPNAME}}"] \ No newline at end of file diff --git a/internal/assets/dockerfiles/golang/m2kdfdetect.sh b/internal/assets/dockerfiles/golang/m2kdfdetect.sh new file mode 100755 index 000000000..6652330ab --- /dev/null +++ b/internal/assets/dockerfiles/golang/m2kdfdetect.sh @@ -0,0 +1,22 @@ +# Copyright IBM Corporation 2020 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Takes as input the source directory and returns error if it is not fit +found=`find $1/. -name "*.go" -print -quit | wc -l` + +if [ ! $found -eq 1 ]; then + exit 1 +else + echo '{"Port": 8080, "APPNAME": "app-bin"}' +fi diff --git a/internal/assets/dockerfiles/javaant/Dockerfile b/internal/assets/dockerfiles/javaant/Dockerfile new file mode 100644 index 000000000..ecd081a8b --- /dev/null +++ b/internal/assets/dockerfiles/javaant/Dockerfile @@ -0,0 +1,28 @@ +# Copyright IBM Corporation 2020 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +FROM registry.access.redhat.com/ubi8/ubi:latest AS build_base +RUN yum install -y java-1.8.0-openjdk-devel +RUN yum install -y wget +RUN yum install -y unzip +RUN wget https://mirrors.estointernet.in/apache//ant/binaries/apache-ant-1.10.8-bin.zip -P /tmp +RUN unzip -d /opt/apache-ant /tmp/apache-ant-1.10.8-bin.zip +ENV PATH="${PATH}:/opt/apache-ant/apache-ant-1.10.8/bin/" +COPY . /{{.APPNAME}} +WORKDIR /{{.APPNAME}} +RUN {{.ANTCMD}} + +FROM registry.access.redhat.com/jboss-eap-6/eap64-openshift:latest +EXPOSE {{.Port}} +COPY --from=build_base /{{.APPNAME}}/output/{{.APPNAME}}.ear /opt/eap/standalone/deployments/ \ No newline at end of file diff --git a/internal/assets/dockerfiles/javaant/m2kdfdetect.sh b/internal/assets/dockerfiles/javaant/m2kdfdetect.sh new file mode 100755 index 000000000..d5e6be6a9 --- /dev/null +++ b/internal/assets/dockerfiles/javaant/m2kdfdetect.sh @@ -0,0 +1,20 @@ +# Copyright IBM Corporation 2020 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Takes as input the source directory and returns error if it is not fit +if [ ! -f "$1/build.xml" ]; then + exit 1 +else + echo '{"Port": 8080, "ANTCMD": "ant all", "APPNAME": "simplewebapp"}' +fi \ No newline at end of file diff --git a/internal/assets/dockerfiles/javagradle/Dockerfile b/internal/assets/dockerfiles/javagradle/Dockerfile new file mode 100644 index 000000000..abeb59125 --- /dev/null +++ b/internal/assets/dockerfiles/javagradle/Dockerfile @@ -0,0 +1,30 @@ +# Copyright IBM Corporation 2020 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Build App +FROM registry.access.redhat.com/ubi8/ubi:latest AS build_base +RUN yum install -y java-1.8.0-openjdk-devel +RUN yum install -y wget +RUN yum install -y unzip +RUN wget https://services.gradle.org/distributions/gradle-6.6-bin.zip -P /tmp +RUN unzip -d /opt/gradle /tmp/gradle-6.6-bin.zip +ENV PATH="${PATH}:/opt/gradle/gradle-6.6/bin/" +COPY . /{{.APPNAME}} +WORKDIR /{{.APPNAME}} +RUN gradle build + +# Run App +FROM registry.access.redhat.com/jboss-eap-6/eap64-openshift:latest +EXPOSE {{.Port}} +COPY --from=build_base /{{.APPNAME}}/build/libs/* /opt/eap/standalone/deployments/ \ No newline at end of file diff --git a/internal/assets/dockerfiles/javagradle/m2kdfdetect.sh b/internal/assets/dockerfiles/javagradle/m2kdfdetect.sh new file mode 100755 index 000000000..2059eb207 --- /dev/null +++ b/internal/assets/dockerfiles/javagradle/m2kdfdetect.sh @@ -0,0 +1,20 @@ +# Copyright IBM Corporation 2020 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Takes as input the source directory and returns error if it is not fit +if [ ! -f "$1/build.gradle" ]; then + exit 1 +else + echo '{"Port": 8080, "APPNAME": "simplewebapp"}' +fi \ No newline at end of file diff --git a/internal/assets/dockerfiles/javamaven/Dockerfile b/internal/assets/dockerfiles/javamaven/Dockerfile new file mode 100644 index 000000000..57a0930b3 --- /dev/null +++ b/internal/assets/dockerfiles/javamaven/Dockerfile @@ -0,0 +1,26 @@ +# Copyright IBM Corporation 2020 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Build App +FROM registry.access.redhat.com/ubi8/ubi:latest AS build_base +RUN yum install -y java-1.8.0-openjdk-devel +RUN yum install -y maven +COPY . /{{.APPNAME}} +WORKDIR /{{.APPNAME}} +RUN mvn package + +# Run App +FROM registry.access.redhat.com/jboss-eap-6/eap64-openshift:latest +EXPOSE {{.Port}} +COPY --from=build_base /{{.APPNAME}}/target/* /opt/eap/standalone/deployments/ \ No newline at end of file diff --git a/internal/assets/dockerfiles/javamaven/m2kdfdetect.sh b/internal/assets/dockerfiles/javamaven/m2kdfdetect.sh new file mode 100755 index 000000000..06a8f39c8 --- /dev/null +++ b/internal/assets/dockerfiles/javamaven/m2kdfdetect.sh @@ -0,0 +1,20 @@ +# Copyright IBM Corporation 2020 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Takes as input the source directory and returns error if it is not fit +if [ ! -f "$1/pom.xml" ]; then + exit 1 +else + echo '{"Port": 8080, "APPNAME": "app"}' +fi \ No newline at end of file diff --git a/internal/assets/dockerfiles/nodejs/Dockerfile b/internal/assets/dockerfiles/nodejs/Dockerfile new file mode 100644 index 000000000..496027e20 --- /dev/null +++ b/internal/assets/dockerfiles/nodejs/Dockerfile @@ -0,0 +1,20 @@ +# Copyright IBM Corporation 2020 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +FROM registry.access.redhat.com/ubi8/nodejs-12 +ADD . . +RUN npm install +EXPOSE {{.Port}} +CMD npm run -d start \ No newline at end of file diff --git a/internal/assets/dockerfiles/nodejs/m2kdfdetect.sh b/internal/assets/dockerfiles/nodejs/m2kdfdetect.sh new file mode 100755 index 000000000..302bc045b --- /dev/null +++ b/internal/assets/dockerfiles/nodejs/m2kdfdetect.sh @@ -0,0 +1,20 @@ +# Copyright IBM Corporation 2020 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Takes as input the source directory and returns error if it is not fit +if [ ! -f "$1/package.json" ]; then + exit 1 +else + echo '{"Port": 8080, "APPNAME": "app"}' +fi \ No newline at end of file diff --git a/internal/assets/dockerfiles/php/Dockerfile b/internal/assets/dockerfiles/php/Dockerfile new file mode 100644 index 000000000..4a40b70f5 --- /dev/null +++ b/internal/assets/dockerfiles/php/Dockerfile @@ -0,0 +1,25 @@ +# Copyright IBM Corporation 2020 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +FROM registry.access.redhat.com/ubi8/ubi:latest + +RUN yum update -y +RUN yum install -y php + +RUN mkdir -p /{{.APPNAME}} +COPY . /{{.APPNAME}} +WORKDIR /{{.APPNAME}} +RUN cd /{{.APPNAME}} +EXPOSE {{.Port}} +CMD ["php", "-S", "{{.BINDING}}"] \ No newline at end of file diff --git a/internal/assets/dockerfiles/php/m2kdfdetect.sh b/internal/assets/dockerfiles/php/m2kdfdetect.sh new file mode 100755 index 000000000..033ec3b50 --- /dev/null +++ b/internal/assets/dockerfiles/php/m2kdfdetect.sh @@ -0,0 +1,24 @@ +# Copyright IBM Corporation 2020 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Takes as input the source folder and returns error if it is not fit +BASE_DIR=$1 + +found=`find $BASE_DIR/. -name "*.php" -print -quit | wc -l` + +if [ $found -eq 1 ]; then + echo '{"Port": 8080, "BINDING": "0.0.0.0:8080", "APPNAME": "app"}' +else + exit 1 +fi diff --git a/internal/assets/dockerfiles/python/Dockerfile b/internal/assets/dockerfiles/python/Dockerfile new file mode 100644 index 000000000..9913e2ec7 --- /dev/null +++ b/internal/assets/dockerfiles/python/Dockerfile @@ -0,0 +1,22 @@ +# Copyright IBM Corporation 2020 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +FROM registry.access.redhat.com/ubi8/python-36 +COPY . /{{.APPNAME}} +RUN mkdir -p /{{.APPNAME}} +WORKDIR /{{.APPNAME}} +RUN cd /{{.APPNAME}} +RUN pip install -r requirements.txt +EXPOSE {{.Port}} +CMD ["python", "/{{.APPNAME}}/{{.MAINSCRIPT}}"] \ No newline at end of file diff --git a/internal/assets/dockerfiles/python/m2kdfdetect.sh b/internal/assets/dockerfiles/python/m2kdfdetect.sh new file mode 100755 index 000000000..b54dc6e42 --- /dev/null +++ b/internal/assets/dockerfiles/python/m2kdfdetect.sh @@ -0,0 +1,28 @@ +# Copyright IBM Corporation 2020 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Takes as input the source folder and returns error if it is not fit +BASE_DIR=$1 +SPECIAL_FILES=($BASE_DIR/requirements.txt $BASE_DIR/setup.py $BASE_DIR/environment.yml $BASE_DIR/Pipfile) + +for fileName in "${SPECIAL_FILES[@]}" +do + if [ -f "$fileName" ]; then + startScript=`grep -lRe "__main__" $1 | awk '{print $1}' | xargs -n1 basename` + echo '{"MAINSCRIPT": "'$startScript'", "APPNAME": "app", "Port": 8080}' + exit 0 + fi +done + +exit 1 \ No newline at end of file diff --git a/internal/assets/s2i/golang/.s2i/environment b/internal/assets/s2i/golang/.s2i/environment new file mode 100644 index 000000000..89d4f223f --- /dev/null +++ b/internal/assets/s2i/golang/.s2i/environment @@ -0,0 +1,5 @@ +{{- range $key, $value := . }} +{{- if and (ne $key "Builder") (ne $key "ImageName") (ne $key "Port") }} +{{ $key }}={{ $value }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/internal/assets/s2i/golang/m2ks2idetect.sh b/internal/assets/s2i/golang/m2ks2idetect.sh new file mode 100644 index 000000000..67f042a9e --- /dev/null +++ b/internal/assets/s2i/golang/m2ks2idetect.sh @@ -0,0 +1,29 @@ +# Copyright IBM Corporation 2020 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Takes as input the source folder and returns error if it is not fit +BASE_DIR=$1 +IMAGE="registry.access.redhat.com/ubi8/go-toolset:latest" + +if [ ! -f "$1/go.mod" ]; then + found=`find $BASE_DIR/. -name "*.go" -print -quit | wc -l` + + if [ $found -eq 1 ]; then + echo '{"Builder": "'$IMAGE'", "Port": 8080}' + else + exit 1 + fi +else + echo '{"Builder": "'$IMAGE'", "Port": 8080}' +fi \ No newline at end of file diff --git a/internal/assets/s2i/java/.s2i/environment b/internal/assets/s2i/java/.s2i/environment new file mode 100644 index 000000000..89d4f223f --- /dev/null +++ b/internal/assets/s2i/java/.s2i/environment @@ -0,0 +1,5 @@ +{{- range $key, $value := . }} +{{- if and (ne $key "Builder") (ne $key "ImageName") (ne $key "Port") }} +{{ $key }}={{ $value }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/internal/assets/s2i/java/m2ks2idetect.sh b/internal/assets/s2i/java/m2ks2idetect.sh new file mode 100644 index 000000000..9ae11f7df --- /dev/null +++ b/internal/assets/s2i/java/m2ks2idetect.sh @@ -0,0 +1,41 @@ +# Copyright IBM Corporation 2020 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Takes as input the source folder and returns error if it is not fit +BASE_DIR=$1 +NATIVE_IMAGE="registry.access.redhat.com/redhat-openjdk-18/openjdk18-openshift:latest" +WEB_IMAGE="registry.access.redhat.com/jboss-eap-6/eap64-openshift:latest" + +# Gradle not supported yet +if [ -f "$1/build.gradle" ]; then + exit 1 +fi + +# Ant not supported yet +if [ -f "$1/build.xml" ]; then + exit 1 +fi + +if [ -f "$1/pom.xml" ]; then + echo '{"Builder": "'$WEB_IMAGE'", "Port": 8080}' + exit 0 +fi + +found=`find $BASE_DIR/. -name "*.java" -print -quit | wc -l` + +if [ $found -eq 1 ]; then + echo '{"Builder": "'$NATIVE_IMAGE'", "Port": 8080}' +else + exit 1 +fi \ No newline at end of file diff --git a/internal/assets/s2i/nodejs/.s2i/environment b/internal/assets/s2i/nodejs/.s2i/environment new file mode 100644 index 000000000..89d4f223f --- /dev/null +++ b/internal/assets/s2i/nodejs/.s2i/environment @@ -0,0 +1,5 @@ +{{- range $key, $value := . }} +{{- if and (ne $key "Builder") (ne $key "ImageName") (ne $key "Port") }} +{{ $key }}={{ $value }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/internal/assets/s2i/nodejs/m2ks2idetect.sh b/internal/assets/s2i/nodejs/m2ks2idetect.sh new file mode 100755 index 000000000..34567a7b7 --- /dev/null +++ b/internal/assets/s2i/nodejs/m2ks2idetect.sh @@ -0,0 +1,21 @@ +# Copyright IBM Corporation 2020 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Takes as input the source directory and returns error if it is not fit +if [ ! -f "$1/package.json" ]; then + exit 1 +fi + +IMAGE="registry.access.redhat.com/ubi8/nodejs-10" +echo '{"Builder": "'$IMAGE'", "Port": 8080}' \ No newline at end of file diff --git a/internal/assets/s2i/php/.s2i/environment b/internal/assets/s2i/php/.s2i/environment new file mode 100644 index 000000000..89d4f223f --- /dev/null +++ b/internal/assets/s2i/php/.s2i/environment @@ -0,0 +1,5 @@ +{{- range $key, $value := . }} +{{- if and (ne $key "Builder") (ne $key "ImageName") (ne $key "Port") }} +{{ $key }}={{ $value }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/internal/assets/s2i/php/m2ks2idetect.sh b/internal/assets/s2i/php/m2ks2idetect.sh new file mode 100644 index 000000000..198b739dc --- /dev/null +++ b/internal/assets/s2i/php/m2ks2idetect.sh @@ -0,0 +1,25 @@ +# Copyright IBM Corporation 2020 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Takes as input the source folder and returns error if it is not fit +BASE_DIR=$1 +IMAGE="registry.access.redhat.com/rhscl/php-72-rhel7:latest" + +found=`find $BASE_DIR/. -name "*.php" -print -quit | wc -l` + +if [ $found -eq 1 ]; then + echo '{"Builder": "'$IMAGE'", "Port": 8080}' +else + exit 1 +fi \ No newline at end of file diff --git a/internal/assets/s2i/python/.s2i/environment b/internal/assets/s2i/python/.s2i/environment new file mode 100644 index 000000000..89d4f223f --- /dev/null +++ b/internal/assets/s2i/python/.s2i/environment @@ -0,0 +1,5 @@ +{{- range $key, $value := . }} +{{- if and (ne $key "Builder") (ne $key "ImageName") (ne $key "Port") }} +{{ $key }}={{ $value }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/internal/assets/s2i/python/m2ks2idetect.sh b/internal/assets/s2i/python/m2ks2idetect.sh new file mode 100755 index 000000000..6b082bfeb --- /dev/null +++ b/internal/assets/s2i/python/m2ks2idetect.sh @@ -0,0 +1,29 @@ +# Copyright IBM Corporation 2020 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Takes as input the source folder and returns error if it is not fit +BASE_DIR=$1 +SPECIAL_FILES=($BASE_DIR/requirements.txt $BASE_DIR/setup.py $BASE_DIR/environment.yml $BASE_DIR/Pipfile) +IMAGE="registry.access.redhat.com/rhscl/python-36-rhel7:latest" + +for fileName in "${SPECIAL_FILES[@]}" +do + if [ -f "$fileName" ]; then + startScript=`grep -lRe "__main__" $BASE_DIR | awk '{print $1}' | xargs -n1 basename` + echo '{"Builder": "'$IMAGE'", "APP_FILE": "'$startScript'", "Port": 8080}' + exit 0 + fi +done + +exit 1 \ No newline at end of file diff --git a/internal/assets/s2i/ruby/.s2i/environment b/internal/assets/s2i/ruby/.s2i/environment new file mode 100644 index 000000000..89d4f223f --- /dev/null +++ b/internal/assets/s2i/ruby/.s2i/environment @@ -0,0 +1,5 @@ +{{- range $key, $value := . }} +{{- if and (ne $key "Builder") (ne $key "ImageName") (ne $key "Port") }} +{{ $key }}={{ $value }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/internal/assets/s2i/ruby/m2ks2idetect.sh b/internal/assets/s2i/ruby/m2ks2idetect.sh new file mode 100644 index 000000000..b951318a4 --- /dev/null +++ b/internal/assets/s2i/ruby/m2ks2idetect.sh @@ -0,0 +1,23 @@ +# Copyright IBM Corporation 2020 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Takes as input the source folder and returns error if it is not fit +BASE_DIR=$1 +IMAGE="registry.access.redhat.com/rhscl/ruby-25-rhel7:latest" + +if [ -f $BASE_DIR/Gemfile ]; then + echo '{"Builder": "'$IMAGE'", "Port": 8080}' +else + exit 1 +fi \ No newline at end of file diff --git a/internal/collector/cfappscollector.go b/internal/collector/cfappscollector.go new file mode 100644 index 000000000..38bf9310e --- /dev/null +++ b/internal/collector/cfappscollector.go @@ -0,0 +1,102 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package collector + +import ( + "encoding/json" + "os" + "os/exec" + "path/filepath" + + log "github.com/sirupsen/logrus" + + sourcetypes "github.com/konveyor/move2kube/internal/collector/sourcetypes" + common "github.com/konveyor/move2kube/internal/common" + collecttypes "github.com/konveyor/move2kube/types/collection" +) + +// CfAppsCollector collects cf runtime applications +type CfAppsCollector struct { +} + +// GetAnnotations returns annotations on which this collector should be invoked +func (c *CfAppsCollector) GetAnnotations() []string { + annotations := []string{"cf", "cloudfoundry"} + return annotations +} + +//Collect gets the cf app metadata by querying the cf app. Assumes that the authentication with cluster is already done. +func (c *CfAppsCollector) Collect(inputPath string, outputPath string) error { + + //To run: cf curl /v2/apps/ + cmd := exec.Command("cf", "curl", "/v2/apps") + output, err := cmd.Output() + if err != nil { + log.Errorf("%s", err.Error()) + return err + } + log.Debugf("Cf Curl output %s", output) + sourcecfinstanceapps := sourcetypes.CfInstanceApps{} + err = json.Unmarshal([]byte(output), &sourcecfinstanceapps) + if err != nil { + log.Errorf("Error in unmarshalling yaml: %s. Skipping.", err) + return err + } + outputPath = filepath.Join(outputPath, "cf") + err = os.MkdirAll(outputPath, common.DefaultDirectoryPermission) + if err != nil { + log.Errorf("Unable to create outputPath %s : %s", outputPath, err) + } + cfinstanceapps := collecttypes.NewCfInstanceApps() + cfinstanceapps.Spec.CfApplications = []collecttypes.CfApplication{} + fileName := "instanceapps_" + + log.Debugf("Detected %d apps", len(sourcecfinstanceapps.CfResources)) + for _, sourcecfapp := range sourcecfinstanceapps.CfResources { + app := collecttypes.CfApplication{} + app.Name = sourcecfapp.CfAppEntity.Name + log.Debugf("Reading info about %s", app.Name) + + if sourcecfapp.CfAppEntity.Buildpack != "null" { + app.Buildpack = sourcecfapp.CfAppEntity.Buildpack + } + if sourcecfapp.CfAppEntity.DetectedBuildpack != "null" { + app.DetectedBuildpack = sourcecfapp.CfAppEntity.DetectedBuildpack + } + if sourcecfapp.CfAppEntity.DockerImage != "null" { + app.DockerImage = sourcecfapp.CfAppEntity.DockerImage + } + app.Instances = sourcecfapp.CfAppEntity.Instances + app.Memory = sourcecfapp.CfAppEntity.Memory + app.Env = sourcecfapp.CfAppEntity.Env + app.Ports = sourcecfapp.CfAppEntity.Ports + cfinstanceapps.Spec.CfApplications = append(cfinstanceapps.Spec.CfApplications, app) + + fileName = fileName + app.Name + } + + if fileName != "" { + outputPath = filepath.Join(outputPath, common.NormalizeForFilename(fileName)+".yaml") + err = common.WriteYaml(outputPath, cfinstanceapps) + if err != nil { + log.Errorf("Unable to write collect output : %s", err) + } + return err + } + + return nil +} diff --git a/internal/collector/cfcontainertypescollector.go b/internal/collector/cfcontainertypescollector.go new file mode 100644 index 000000000..c477f9611 --- /dev/null +++ b/internal/collector/cfcontainertypescollector.go @@ -0,0 +1,211 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package collector + +import ( + "encoding/json" + "fmt" + "os" + "os/exec" + "path/filepath" + "strings" + + log "github.com/sirupsen/logrus" + + sourcetypes "github.com/konveyor/move2kube/internal/collector/sourcetypes" + common "github.com/konveyor/move2kube/internal/common" + containerize "github.com/konveyor/move2kube/internal/containerizer" + source "github.com/konveyor/move2kube/internal/source" + collecttypes "github.com/konveyor/move2kube/types/collection" + "github.com/konveyor/move2kube/types/plan" + plantypes "github.com/konveyor/move2kube/types/plan" +) + +// CFContainerTypesCollector collects buildpacks supported by the instance +type CFContainerTypesCollector struct { +} + +// GetAnnotations returns annotations on which this collector should be invoked +func (c *CFContainerTypesCollector) GetAnnotations() []string { + annotations := []string{"cloudfoundry", "cf"} + return annotations +} + +//Collect gets the cf containerization types +func (c *CFContainerTypesCollector) Collect(inputDirectory string, outputPath string) error { + //Creating the output sub-directory if it does not exist + outputPath = filepath.Join(outputPath, "cf") + err := os.MkdirAll(outputPath, common.DefaultDirectoryPermission) + if err != nil { + log.Errorf("Unable to create output path %s : %s", outputPath, err) + return err + } + var cfcontainerizers = collecttypes.NewCfContainerizers() + cfcontainerizers.Spec.BuildpackContainerizers = []collecttypes.BuildpackContainerizer{} + buildpackNames := getCfbuildpackNames(inputDirectory) + log.Debugf("buildpackNames : %s", buildpackNames) + cnbcontainerizer := new(containerize.CNBContainerizer) + //TODO: How do you also load existing builders that are currently being collected by cnbbuildercollector? + cnbcontainerizer.Init("") + buildpacks := cnbcontainerizer.GetAllBuildpacks() + log.Debugf("buildpacks : %s", buildpacks) + fileName := "cfcontainertypes_" + for _, buildpackName := range buildpackNames { + buildpackcontainerizer := getBuildpackContainerizer(buildpackName, buildpacks) + cfcontainerizers.Spec.BuildpackContainerizers = append(cfcontainerizers.Spec.BuildpackContainerizers, buildpackcontainerizer) + fileName = fileName + buildpackName + } + if fileName != "" { + outputPath = filepath.Join(outputPath, common.NormalizeForFilename(fileName)+".yaml") + err := common.WriteYaml(outputPath, cfcontainerizers) + if err != nil { + log.Errorf("Unable to write cf container type output %s : %s", fileName, err) + } + return err + } + return fmt.Errorf("No buildpacks found") +} + +func getBuildpackContainerizer(buildpackName string, options map[string][]string) collecttypes.BuildpackContainerizer { //[containerization taregt option][builder] + buildpackcontainerizer := collecttypes.BuildpackContainerizer{} + buildpackcontainerizer.ContainerBuildType = plan.CNBContainerBuildTypeValue + buildpackcontainerizer.BuildpackName = buildpackName + bpoptions := make(map[string]string) + bps := []string{} + for targetoption, buildpacks := range options { + option := common.GetClosestMatchingString(buildpacks, buildpackName) + if _, ok := bpoptions[option]; !ok { + bpoptions[option] = targetoption + bps = append(bps, option) + } + } + bp := common.GetClosestMatchingString(bps, buildpackName) + buildpackcontainerizer.ContainerizationTargetOptions = []string{bpoptions[bp]} + return buildpackcontainerizer +} + +func getCfbuildpackNames(inputPath string) []string { + buildpacks := []string{} + if inputPath != "" { + bps, err := getAllUsedBuildpacks(inputPath) + if err != nil { + log.Warnf("Unable to find used buildpacks : %s", err) + } else { + for _, buildpack := range bps { + if !common.IsStringPresent(buildpacks, buildpack) { + buildpacks = append(buildpacks, buildpack) + } + } + } + } else { + bps, err := getAllCfInstanceBuildpacks() + if err != nil { + log.Warnf("Unable to collect buildpacks from cf instance : %s", err) + } else { + for _, buildpack := range bps { + if !common.IsStringPresent(buildpacks, buildpack) { + buildpacks = append(buildpacks, buildpack) + } + } + } + + bps, err = getAllCfAppBuildpacks() + if err != nil { + log.Warnf("Unable to find used buildpacks : %s", err) + } else { + for _, buildpack := range bps { + if !common.IsStringPresent(buildpacks, buildpack) { + buildpacks = append(buildpacks, buildpack) + } + } + } + } + return buildpacks +} + +func getAllCfInstanceBuildpacks() ([]string, error) { + var buildpacks []string + cmd := exec.Command("cf", "buildpacks") + outputStr, err := cmd.Output() + if err != nil { + log.Warnf("Error while getting buildpacks : %s", err) + return nil, err + } + lines := strings.Split(string(outputStr), "\n") + for _, line := range lines { + if line == "Getting buildpacks..." { + continue + } + buildpackmatches := strings.Fields(string(line)) + if len(buildpackmatches) == 0 || buildpackmatches[0] == "buildpack" { + continue + } + buildpacks = append(buildpacks, buildpackmatches[0]) + + } + return buildpacks, nil +} + +func getAllCfAppBuildpacks() ([]string, error) { + var buildpacks []string + cmd := exec.Command("cf", "curl", "/v2/apps") + output, err := cmd.Output() + if err != nil { + log.Errorf("%s", err.Error()) + return nil, err + } + log.Debugf("Cf Curl output %s", output) + sourcecfinstanceapps := sourcetypes.CfInstanceApps{} + err = json.Unmarshal([]byte(output), &sourcecfinstanceapps) + if err != nil { + log.Errorf("Error in unmarshalling yaml: %s. Skipping", err) + return nil, err + } + + log.Debugf("Detected %d apps", len(sourcecfinstanceapps.CfResources)) + for _, sourcecfapp := range sourcecfinstanceapps.CfResources { + if sourcecfapp.CfAppEntity.Buildpack != "" { + buildpacks = append(buildpacks, sourcecfapp.CfAppEntity.Buildpack) + } + if sourcecfapp.CfAppEntity.DetectedBuildpack != "" { + buildpacks = append(buildpacks, sourcecfapp.CfAppEntity.DetectedBuildpack) + } + } + return buildpacks, nil +} + +func getAllUsedBuildpacks(directorypath string) ([]string, error) { + var buildpacks []string + files, err := common.GetFilesByExt(directorypath, []string{".yml", ".yaml"}) + if err != nil { + log.Warnf("Unable to fetch yaml files and recognize application manifest yamls : %s", err) + } + for _, fullpath := range files { + applications, _, err := source.ReadApplicationManifest(fullpath, "", plantypes.Yamls) + if err != nil { + log.Debugf("Error while trying to parse manifest : %s", err) + continue + } + for _, application := range applications { + if application.Buildpack.IsSet { + buildpacks = append(buildpacks, application.Buildpack.Value) + } + buildpacks = append(buildpacks, application.Buildpacks...) + } + } + return buildpacks, nil +} diff --git a/internal/collector/clustercollector.go b/internal/collector/clustercollector.go new file mode 100644 index 000000000..0d45621aa --- /dev/null +++ b/internal/collector/clustercollector.go @@ -0,0 +1,648 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package collector + +import ( + "fmt" + "os" + "os/exec" + "path/filepath" + "regexp" + "runtime/debug" + "sort" + "strings" + + semver "github.com/Masterminds/semver/v3" + log "github.com/sirupsen/logrus" + "gopkg.in/yaml.v3" + "k8s.io/apimachinery/pkg/runtime/schema" + + "github.com/konveyor/move2kube/internal/apiresourceset" + common "github.com/konveyor/move2kube/internal/common" + collecttypes "github.com/konveyor/move2kube/types/collection" + cgdiscovery "k8s.io/client-go/discovery" + "k8s.io/client-go/kubernetes/scheme" + cgclientcmd "k8s.io/client-go/tools/clientcmd" +) + +//ClusterCollector Implements Collector interface +type ClusterCollector struct { + clusterCmd string +} + +// GetAnnotations returns annotations on which this collector should be invoked +func (c ClusterCollector) GetAnnotations() []string { + annotations := []string{"k8s"} + return annotations +} + +//Collect gets the cluster metadata by querying the cluster. Assumes that the authentication with cluster is already done. +func (c *ClusterCollector) Collect(inputPath string, outputPath string) error { + + //Creating the output sub-directory if it does not exist + outputPath = filepath.Join(outputPath, "clusters") + err := os.MkdirAll(outputPath, common.DefaultDirectoryPermission) + if err != nil { + log.Errorf("Unable to create outputpath %s : %s", outputPath, err) + return err + } + cmd := c.getClusterCommand() + if cmd == "" { + errStr := "No Kubectl or oc in path. Add Kubectl to path and rerun to collect data about the cluster in context." + log.Warnf(errStr) + return fmt.Errorf(errStr) + } + name, err := c.getClusterContextName() + if err != nil { + log.Warnf("Unable to access cluster in context : %s", err) + return err + } + clusterMd := collecttypes.NewClusterMetadata(name) + clusterMd.Spec.StorageClasses, err = c.getStorageClasses() + if err != nil { + //If no storage classes, this will be an empty array + clusterMd.Spec.StorageClasses = []string{} + } + + APIKindVersionMap, err := c.collectUsingAPI() + if err != nil { + log.Warnf("Falling back to using CLI based collect") + clusterMd.Spec.APIKindVersionMap, err = c.collectUsingCLI() + if err != nil { + return err + } + } else { + clusterMd.Spec.APIKindVersionMap = APIKindVersionMap + } + + c.groupOrderPolicy(&clusterMd.Spec.APIKindVersionMap) + //c.VersionOrderPolicy(&clusterMd.APIKindVersionMap) + + outputPath = filepath.Join(outputPath, common.NormalizeForFilename(clusterMd.Name)+".yaml") + err = common.WriteYaml(outputPath, clusterMd) + return err +} + +func (c *ClusterCollector) getClusterCommand() string { + if c.clusterCmd == "" { + cmd := "kubectl" + _, err := exec.LookPath(cmd) + if err != nil { + log.Warnf("Unable to find "+cmd+" : %v", err) + cmd = "oc" + _, err := exec.LookPath(cmd) + if err != nil { + log.Warnf("Unable to find "+cmd+" : %v", err) + } else { + c.clusterCmd = cmd + } + } else { + c.clusterCmd = cmd + } + } + return c.clusterCmd +} + +func (c *ClusterCollector) getClusterContextName() (string, error) { + cmd := exec.Command(c.getClusterCommand(), "config", "current-context") + name, err := cmd.Output() + return string(name), err +} + +func (c *ClusterCollector) getStorageClasses() ([]string, error) { + ccmd := c.getClusterCommand() + cmd := exec.Command(ccmd, "get", "sc", "-o", "yaml") + yamlOutput, err := cmd.CombinedOutput() + if err != nil { + errDesc := c.interpretError(string(yamlOutput)) + if errDesc != "" { + log.Warnf("Error while running %s. %s", ccmd, errDesc) + } else { + log.Warnf("Error while fetching storage classes using command [%s]", cmd) + } + return nil, err + } + + var fileContents map[string]interface{} + err = yaml.Unmarshal(yamlOutput, &fileContents) + if err != nil { + log.Errorf("Error in unmarshalling yaml: %s. Skipping.", err) + return nil, err + } + + scArray := fileContents["items"].([]interface{}) + var storageClasses []string + + for _, sc := range scArray { + if mapSC, ok := sc.(map[string]interface{}); ok { + storageClasses = append(storageClasses, mapSC["metadata"].(map[string]interface{})["name"].(string)) + } else { + log.Warnf("Unknown type detected in cluster metadata [%T]", mapSC) + } + } + + return storageClasses, nil +} + +func (c *ClusterCollector) interpretError(cmdOutput string) string { + errorTerms := []string{"Unauthorized", "Username"} + + for _, e := range errorTerms { + if c.getClusterCommand() == "oc" && strings.Contains(cmdOutput, e) { + return "Please login to cluster before running collect. (e.g. oc login --token=)" + } else if c.getClusterCommand() == "kubectl" && strings.Contains(cmdOutput, e) { + return "Please configure the cluster authentication with following instructions: [https://kubernetes.io/docs/reference/kubectl/cheatsheet/#kubectl-context-and-configuration]" + } + } + + return "" +} + +func (c ClusterCollector) getGlobalGroupOrder() []string { + return []string{`^.+\.openshift\.io$`, `^.+\.k8s\.io$`, `^apps$`, `^extensions$`} +} + +func (c *ClusterCollector) getAPI() (*cgdiscovery.DiscoveryClient, error) { + rules := cgclientcmd.NewDefaultClientConfigLoadingRules() + cfg, err := cgclientcmd.NewNonInteractiveDeferredLoadingClientConfig(rules, &cgclientcmd.ConfigOverrides{}).ClientConfig() + if err != nil { + return nil, err + } + + return cgdiscovery.NewDiscoveryClientForConfig(cfg) +} + +func (c *ClusterCollector) getPreferredResourceUsingAPI(api *cgdiscovery.DiscoveryClient) ([]schema.GroupVersion, error) { + defer func() []schema.GroupVersion { + if rErr := recover(); rErr != nil { + log.Errorf("Recovered from error in getPreferredResourceUsingAPI [%s]", rErr) + return nil + } + return []schema.GroupVersion{} + }() + debug.SetPanicOnFault(true) + var gvList []schema.GroupVersion + if api == nil { + log.Errorf("API object is null") + return nil, fmt.Errorf("API object is null") + } + apiGroupList, err := api.ServerGroups() + if err != nil { + log.Errorf("API request for server-group list failed") + return nil, err + } + for _, group := range apiGroupList.Groups { + preferredGV, err := schema.ParseGroupVersion(group.PreferredVersion.GroupVersion) + if err != nil { + continue + } + gvList = append(gvList, preferredGV) + prioritizedGVList := scheme.Scheme.PrioritizedVersionsForGroup(group.Name) + for _, prioritizedGV := range prioritizedGVList { + if strings.Compare(group.PreferredVersion.GroupVersion, prioritizedGV.String()) == 0 { + continue + } + for _, gvObj := range group.Versions { + if strings.Compare(prioritizedGV.String(), gvObj.GroupVersion) == 0 { + gv, _ := schema.ParseGroupVersion(gvObj.GroupVersion) + gvList = append(gvList, gv) + break + } + } + } + for _, version := range group.Versions { + gv, _ := schema.ParseGroupVersion(version.GroupVersion) + if gvExists(gvList, gv) { + continue + } + gvList = append(gvList, gv) + } + } + return gvList, nil +} + +func (c *ClusterCollector) getKindsForGroups(api *cgdiscovery.DiscoveryClient) (map[string][]schema.GroupVersion, error) { + defer func() map[string][]schema.GroupVersion { + if rErr := recover(); rErr != nil { + log.Errorf("Recovered from error in getKindsForGroups [%s]", rErr) + return nil + } + var emptyMap map[string][]schema.GroupVersion + return emptyMap + }() + + mapKind := make(map[string][]schema.GroupVersion) + + _, apiResourceList, err := api.ServerGroupsAndResources() + if err != nil { + return nil, err + } + + for _, rscListObj := range apiResourceList { + gvObj, err := schema.ParseGroupVersion(rscListObj.GroupVersion) + for err != nil { + log.Warnf("Ignoring group-version [%s]. Could not parse it", rscListObj.GroupVersion) + continue + } + + for _, rscObj := range rscListObj.APIResources { + if gvList, ok := mapKind[rscObj.Kind]; ok { + if !gvExists(gvList, gvObj) { + gvList = append(gvList, gvObj) + } + mapKind[rscObj.Kind] = gvList + } else { + mapKind[rscObj.Kind] = []schema.GroupVersion{gvObj} + + } + } + } + + return mapKind, nil +} + +func (c *ClusterCollector) sortGroupVersionByPreferrence(prefGVList []schema.GroupVersion, mapKind *map[string][]schema.GroupVersion) { + for kind, gvList := range *mapKind { + var gvOrderedList []schema.GroupVersion + unorderedList := []string{} + for _, pGV := range prefGVList { + if gvExists(gvList, pGV) { + gvOrderedList = append(gvOrderedList, pGV) + } else { + unorderedList = append(unorderedList, pGV.String()) + } + } + + unorderedList = c.clusterByGroupsAndSortVersions(unorderedList) + for _, gvStr := range unorderedList { + gvObj, err := schema.ParseGroupVersion(gvStr) + if err == nil { + continue + } + gvOrderedList = append(gvOrderedList, gvObj) + } + (*mapKind)[kind] = gvOrderedList + } +} + +func (c *ClusterCollector) collectUsingAPI() (map[string][]string, error) { + api, err := c.getAPI() + if err != nil { + log.Warnf("Failed to api handle for cluster") + return nil, err + } + + gvList, err := c.getPreferredResourceUsingAPI(api) + errStr := "Failed to retrieve preferred group information from cluster" + if err != nil { + log.Warnf(errStr) + return nil, err + } else if len(gvList) == 0 { + log.Warnf(errStr) + return nil, fmt.Errorf(errStr) + } + + mapKind, err := c.getKindsForGroups(api) + errStr = "Failed to retrieve information from cluster" + if err != nil { + log.Warnf(errStr) + return nil, err + } else if len(mapKind) == 0 { + log.Warnf(errStr) + return nil, fmt.Errorf(errStr) + } + + c.sortGroupVersionByPreferrence(gvList, &mapKind) + + APIKindVersionMap := make(map[string][]string) + + for kind, gvList := range mapKind { + gvStrList := make([]string, len(gvList)) + for i, gv := range gvList { + gvStrList[i] = gv.String() + } + APIKindVersionMap[kind] = gvStrList + } + + return APIKindVersionMap, nil +} + +func (c *ClusterCollector) getAllGVMatchingGroup(groupRegex string, gvList []string) []string { + var filtered []string + + for _, gv := range gvList { + gvObj, err := schema.ParseGroupVersion(gv) + if err != nil { + continue + } + + if gvObj.Group == "" { + continue + } + + re := regexp.MustCompile(groupRegex) + if re.MatchString(gvObj.Group) { + filtered = append(filtered, gv) + } + } + + return filtered +} + +func (c *ClusterCollector) groupOrderPolicy(mapKindGV *map[string][]string) { + globalOrder := c.getGlobalGroupOrder() + for kind, gvList := range *mapKindGV { + sortedGV := []string{} + + //First priority is for known groups + for _, groupKey := range globalOrder { + subsetOfGV := c.getAllGVMatchingGroup(groupKey, gvList) + sortedGV = append(sortedGV, subsetOfGV...) + } + + //Second priority is for unknown groups (which are not empty string) + for _, gv := range gvList { + gvObj, err := schema.ParseGroupVersion(gv) + if err != nil { + continue + } + + if common.IsStringPresent(sortedGV, gv) { + continue + } + + if strings.Compare(gvObj.Group, "") != 0 { + sortedGV = append(sortedGV, gv) + } + } + + //Third priority is for empty groups + for _, gv := range gvList { + gvObj, err := schema.ParseGroupVersion(gv) + if err != nil { + continue + } + + if strings.Compare(gvObj.Group, "") == 0 { + sortedGV = append(sortedGV, gv) + } + } + + if len(sortedGV) > 0 { + (*mapKindGV)[kind] = sortedGV + } else { + (*mapKindGV)[kind] = gvList + } + } +} + +func (c *ClusterCollector) sortVersionList(vList *[]string) { + srcVersionKeys := []string{"alpha", "beta"} + trVersionKeys := []string{"-alpha.", "-beta."} + regex := []string{`\-alpha\.`, `\-beta\.`} + + for index, version := range *vList { + for i, vKey := range srcVersionKeys { + re := regexp.MustCompile(vKey) + if re.MatchString(version) { + //Tranforming the string to the format suitable for semver pkg + (*vList)[index] = re.ReplaceAllString(version, trVersionKeys[i]) + break + } + } + } + + svObjList := make([]*semver.Version, len(*vList)) + for index, versionStr := range *vList { + svObj, err := semver.NewVersion(versionStr) + if err != nil { + log.Warnf("Skipping Version: %s", versionStr) + continue + } + + svObjList[index] = svObj + } + + sort.Sort(sort.Reverse(semver.Collection(svObjList))) + + for index, svObj := range svObjList { + transfVersionStr := svObj.Original() + noMatches := true + for i, vKey := range regex { + re := regexp.MustCompile(vKey) + if re.MatchString(transfVersionStr) { + (*vList)[index] = re.ReplaceAllString(transfVersionStr, srcVersionKeys[i]) + noMatches = false + break + } + } + if noMatches { + (*vList)[index] = transfVersionStr + } + } +} + +func (c *ClusterCollector) clusterByGroupsAndSortVersions(gvList []string) []string { + gvMap := make(map[string][]string) + for _, gvStr := range gvList { + gvObj, err := schema.ParseGroupVersion(gvStr) + if err != nil { + log.Debugf("Error parting group version [%s]", gvStr) + continue + } + + if vList, ok := gvMap[gvObj.Group]; ok { + vList = append(vList, gvObj.Version) + gvMap[gvObj.Group] = vList + } else { + vList = []string{gvObj.Version} + gvMap[gvObj.Group] = vList + } + } + + for _, vList := range gvMap { + c.sortVersionList(&vList) + } + + sortedGVList := []string{} + for group, vList := range gvMap { + for _, v := range vList { + gvObj := schema.GroupVersion{Group: group, Version: v} + sortedGVList = append(sortedGVList, gvObj.String()) + } + } + + return sortedGVList +} + +func (c *ClusterCollector) collectUsingCLI() (map[string][]string, error) { + cmd := exec.Command("bash", "-c", c.getClusterCommand()+" api-resources -o name") + outputStr, err := cmd.Output() + if err != nil { + log.Errorf("Error while running kubectl api-resources: %s", err) + return nil, err + } + log.Debugf("Got kind information for cluster") + nameList := strings.Split(string(outputStr), "\n") + mapKind := make(map[string][]schema.GroupVersion) + for _, name := range nameList { + tmpArray := strings.Split(name, ".") + if len(tmpArray) > 0 { + name := tmpArray[0] + kind, gvStr, err := c.getGVKUsingNameCLI(name) + if err != nil { + log.Debugf("Erroring parsing kind from CLI output") + continue + } + group := "" + for i, tmp := range tmpArray { + if i == 1 { + group = tmp + } else if i > 1 { + tmp = strings.TrimSpace(tmp) + group = group + "." + tmp + } + } + + if group != "" { + if groupArray, ok := mapKind[kind]; ok { + groupArray = append(groupArray, schema.GroupVersion{Group: group, Version: ""}) + mapKind[kind] = groupArray + } else { + mapKind[kind] = []schema.GroupVersion{{Group: group, Version: ""}} + } + } else { + mapKind[kind] = []schema.GroupVersion{{Group: "", Version: gvStr}} + } + } + } + + apiMd := make(map[string][]string) + + for kind, availableGroupList := range mapKind { + if len(availableGroupList) == 1 { + singletonObj := availableGroupList[0] + if strings.Compare(singletonObj.Group, "") == 0 { + apiMd[kind] = []string{singletonObj.Version} + continue + } + } + if len(availableGroupList) > 0 { + gvList := c.getPreferredGVUsingCLI(kind, availableGroupList) + apiMd[kind] = gvList + } else { + log.Warnf("Empty group for kind [%s]", kind) + } + } + + return apiMd, nil +} + +func (c *ClusterCollector) getPreferredGVUsingCLI(kind string, availableGroupList []schema.GroupVersion) []string { + scheme := (&apiresourceset.K8sAPIResourceSet{}).GetScheme() + var gvList []string + for _, gvObj := range availableGroupList { + prioritizedGVList := scheme.PrioritizedVersionsForGroup(gvObj.Group) + if len(prioritizedGVList) > 0 { + for _, gv := range prioritizedGVList { + isSupported, err := c.isSupportedGV(kind, gv.String()) + if isSupported { + gvList = append(gvList, gv.String()) + } else { + log.Debugf("Group version not found by CLI for kind [%s] : %s", kind, err) + } + } + } else { + _, gvStr, err := c.getGVKUsingNameCLI(kind) + if err == nil { + gvList = append(gvList, gvStr) + } + } + } + + return gvList +} + +func (c *ClusterCollector) isSupportedGV(kind string, gvStr string) (bool, error) { + cmd := exec.Command("bash", "-c", c.getClusterCommand()+" explain "+kind+" --api-version="+gvStr+" --recursive") + outputStr, err := cmd.Output() + if err != nil { + log.Debugf("Error while running %s for verifying [%s]\n", c.getClusterCommand(), gvStr) + return false, err + } + + lines := strings.Split(string(outputStr), "\n") + + if len(lines) < 2 { + return false, fmt.Errorf("Description incomplete") + } + + if strings.Contains(lines[1], "VERSION") { + return true, nil + } + + return false, fmt.Errorf("GV [%s] not found", gvStr) +} + +func (c *ClusterCollector) getGVKUsingNameCLI(name string) (string, string, error) { + cmd := exec.Command("bash", "-c", c.getClusterCommand()+" explain "+name) + outputStr, err := cmd.Output() + if err != nil { + //log.Errorf("Error while running kubectl: %s\n", err) + return "", "", err + } + + var gvk schema.GroupVersionKind + + lines := strings.Split(string(outputStr), "\n") + + if len(lines) < 2 { + return "", "", fmt.Errorf("Description incomplete") + } + + if strings.Contains(lines[0], "KIND") { + tmpArray := strings.Split(lines[0], ":") + gvk.Kind = strings.TrimSpace(tmpArray[1]) + } else { + return "", "", err + } + + if strings.Contains(lines[1], "VERSION") { + tmpArray := strings.Split(lines[1], ":") + tmpGV := strings.TrimSpace(tmpArray[1]) + tmpGVLines := strings.Split(tmpGV, "/") + if len(tmpGVLines) == 2 { + gvk.Group = tmpGVLines[0] + gvk.Version = tmpGVLines[1] + } else { + gvk.Group = "" + gvk.Version = tmpGVLines[0] + } + } + + return gvk.Kind, gvk.GroupVersion().String(), nil +} + +//GVExists looks up group version from list +func gvExists(gvList []schema.GroupVersion, gvKey schema.GroupVersion) bool { + for _, gv := range gvList { + if gv.String() == gvKey.String() { + return true + } + } + return false +} diff --git a/internal/collector/collector.go b/internal/collector/collector.go new file mode 100644 index 000000000..b5b6fc211 --- /dev/null +++ b/internal/collector/collector.go @@ -0,0 +1,29 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package collector + +//Collector defines interface for collecting data from data sources +type Collector interface { + Collect(inputDirectory string, outputPath string) error + GetAnnotations() []string +} + +// GetCollectors returns different collectors +func GetCollectors() ([]Collector, error) { + var collectors = []Collector{new(ClusterCollector), new(ImagesCollector), new(CFContainerTypesCollector), new(CfAppsCollector)} + return collectors, nil +} diff --git a/internal/collector/imagescollector.go b/internal/collector/imagescollector.go new file mode 100644 index 000000000..2f7446500 --- /dev/null +++ b/internal/collector/imagescollector.go @@ -0,0 +1,171 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package collector + +import ( + "encoding/json" + "os" + "os/exec" + "path/filepath" + "regexp" + "strconv" + "strings" + + log "github.com/sirupsen/logrus" + + sourcetypes "github.com/konveyor/move2kube/internal/collector/sourcetypes" + common "github.com/konveyor/move2kube/internal/common" + collecttypes "github.com/konveyor/move2kube/types/collection" +) + +//ImagesCollector collects the docker images +type ImagesCollector struct { +} + +// GetAnnotations returns annotations on which this collector should be invoked +func (c ImagesCollector) GetAnnotations() []string { + annotations := []string{"k8s", "dockerswarm", "dockercompose"} + return annotations +} + +//Collect gets the image metadata using docker inspect +func (c *ImagesCollector) Collect(inputDirectory string, outputPath string) error { + //Creating the output sub-directory if it does not exist + outputPath = filepath.Join(outputPath, "images") + err := os.MkdirAll(outputPath, common.DefaultDirectoryPermission) + if err != nil { + log.Errorf("Unable to create output directory %s : %s", outputPath, err) + return err + } + imageNames, err := getImageNames(inputDirectory) + if err != nil { + return err + } + log.Debugf("Images : %s", imageNames) + for _, imageName := range imageNames { + imagedata, err := getDockerInspectResult(imageName) + if err != nil { + continue + } + if imagedata != nil { + imageInfo := getImageInfo(imagedata) + shortesttag := "" + for _, tag := range imageInfo.Spec.Tags { + if shortesttag == "" { + shortesttag = tag + } else { + if len(shortesttag) > len(tag) { + shortesttag = tag + } + } + } + imagefile := filepath.Join(outputPath, common.NormalizeForFilename(shortesttag)+".yaml") + err := common.WriteYaml(imagefile, imageInfo) + log.Errorf("Unable to write file %s : %s", imagefile, err) + } + } + + return nil +} + +func getDockerInspectResult(imageName string) ([]byte, error) { + cmd := exec.Command("docker", "inspect", imageName) + jsonOutput, err := cmd.CombinedOutput() + if err != nil { + if strings.Contains(string(jsonOutput), "permission denied") { + log.Warnf("Error while running docker-inspect due to lack of permissions") + log.Warnf("Please refer to [https://docs.docker.com/engine/install/linux-postinstall/] to fix this issue") + } else if strings.Contains(string(jsonOutput), "No such object") { + log.Warnf("Image [%s] not available in local image repo. Run \"docker pull %s\"", imageName, imageName) + return nil, nil + } else { + log.Warnf("Error while running docker-inspect: %s", err) + } + return nil, err + } + return jsonOutput, nil +} + +func getImageInfo(data []byte) collecttypes.ImageInfo { + imageInfo := collecttypes.NewImageInfo() + imgLayerInfo := make([]sourcetypes.DockerImage, 0) + err := json.Unmarshal(data, &imgLayerInfo) + if err != nil { + log.Errorf("Unable to unmarshal image info : %s", err) + } + for _, image := range imgLayerInfo { + imageInfo.Spec.Tags = image.RepoTags + imageInfo.Spec.UserID, err = strconv.Atoi(image.CConfig.User) + if err != nil { + log.Debugf("UserID not available in image metadata for [%s]", image.RepoTags[0]) + imageInfo.Spec.UserID = -1 + } + imageInfo.Spec.AccessedDirs = append(imageInfo.Spec.AccessedDirs, image.CConfig.WorkingDir) + for key := range image.CConfig.EPorts { + regex := regexp.MustCompile("[0-9]+") + portNumber, err := strconv.Atoi(string(regex.FindAll([]byte(key), -1)[0])) + if err != nil { + log.Debugf("PortNumber not available in image metadata for [%s]", image.RepoTags[0]) + } else { + imageInfo.Spec.PortsToExpose = append(imageInfo.Spec.PortsToExpose, portNumber) + } + } + } + return imageInfo +} + +func getImageNames(inputPath string) ([]string, error) { + if inputPath == "" { + return getAllImageNames() + } + return getDCImageNames(inputPath) +} + +func getAllImageNames() ([]string, error) { + cmd := exec.Command("bash", "-c", "docker image list --format '{{.Repository}}:{{.Tag}}'") + outputStr, err := cmd.Output() + if err != nil { + log.Warnf("Error while running docker image list : %s", err) + return nil, err + } + images := strings.Split(string(outputStr), "\n") + cleanimages := []string{} + for _, image := range images { + if strings.HasPrefix(image, "") || strings.HasSuffix(image, "") { + log.Debugf("Ignore image with : %s", image) + continue + } + } + return cleanimages, err +} + +func getDCImageNames(directorypath string) ([]string, error) { + var imageNames []string + files, err := common.GetFilesByExt(directorypath, []string{".yml", ".yaml"}) + if err != nil { + log.Warnf("Unable to fetch yaml files and recognize Docker image yamls : %s", err) + } + for _, path := range files { + dc := new(sourcetypes.DockerCompose) + if common.ReadYaml(path, &dc) == nil { + for _, dcservice := range dc.DCServices { + imageNames = append(imageNames, dcservice.Image) + } + } + } + return imageNames, nil +} diff --git a/internal/collector/sourcetypes/cfinstanceapps.go b/internal/collector/sourcetypes/cfinstanceapps.go new file mode 100644 index 000000000..31115e1db --- /dev/null +++ b/internal/collector/sourcetypes/cfinstanceapps.go @@ -0,0 +1,39 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package sourcetypes + +// CfInstanceApps for reading cf running instance metadata +type CfInstanceApps struct { + CfResources []CfResource `json:"resources"` +} + +// CfResource reads entity +type CfResource struct { + CfAppEntity CfSourceApplication `json:"entity"` +} + +// CfSourceApplication reads source application +type CfSourceApplication struct { + Name string `json:"name"` + Buildpack string `json:"buildpack"` + DetectedBuildpack string `json:"detected_buildpack"` + Memory int64 `json:"memory"` + Instances int `json:"instances"` + DockerImage string `json:"dockerimage"` + Ports []int32 `json:"ports"` + Env map[string]string `json:"environment_json,omitempty"` +} diff --git a/internal/collector/sourcetypes/dockercompose.go b/internal/collector/sourcetypes/dockercompose.go new file mode 100644 index 000000000..5752ccff0 --- /dev/null +++ b/internal/collector/sourcetypes/dockercompose.go @@ -0,0 +1,28 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package sourcetypes + +// DockerCompose reads docker compose files +type DockerCompose struct { + Version string `yaml:"version"` + DCServices map[string]DCService `yaml:"services"` +} + +// DCService reads service +type DCService struct { + Image string `yaml:"image,omitempty"` +} diff --git a/internal/collector/sourcetypes/dockerinspect.go b/internal/collector/sourcetypes/dockerinspect.go new file mode 100644 index 000000000..f12189cc9 --- /dev/null +++ b/internal/collector/sourcetypes/dockerinspect.go @@ -0,0 +1,31 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package sourcetypes + +// DockerImage loads docker image +type DockerImage struct { + RepoTags []string `json:"RepoTags"` + CConfig ContainerConfig `json:"ContainerConfig"` +} + +// ContainerConfig loads container config +type ContainerConfig struct { + EPorts map[string]interface{} `json:"ExposedPorts"` + User string `json:"User"` + Env []string `json:"Env"` + WorkingDir string `json:"WorkingDir"` +} diff --git a/internal/common/constants.go b/internal/common/constants.go new file mode 100644 index 000000000..270aa650f --- /dev/null +++ b/internal/common/constants.go @@ -0,0 +1,67 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package common + +import ( + "os" + "path/filepath" + + "github.com/konveyor/move2kube/types" + "k8s.io/apimachinery/pkg/api/resource" +) + +const ( + // DefaultProjectName represents the short app name + DefaultProjectName string = "myproject" + // DefaultPlanFile defines default name for plan file + DefaultPlanFile string = types.AppNameShort + ".plan" + // TempDirPrefix defines the prefix of the temp directory + TempDirPrefix string = types.AppNameShort + "-" + // AssetsDir defines the dir of the assets temp directory + AssetsDir string = types.AppNameShort + "assets" + // VolumePrefix defines the prefix to be used for volumes + VolumePrefix string = "vol" + // DefaultStorageClassName defines the default storage class to be used + DefaultStorageClassName string = "default" + // DefaultDirectoryPermission defines the default permission used when a directory is created + DefaultDirectoryPermission os.FileMode = 0755 + // DefaultExecutablePermission defines the default permission used when an executable file is created + DefaultExecutablePermission os.FileMode = 0744 + // DefaultFilePermission defines the default permission used when a non-executable file is created + DefaultFilePermission os.FileMode = 0644 + // DefaultRegistryURL points to the default registry url that will be used + DefaultRegistryURL string = "docker.io" + // ImagePullSecretPrefix is the prefix that will be prepended to pull secret name + ImagePullSecretPrefix string = "imagepullsecret" + // QACacheFile defines the location of the QA cache file + QACacheFile string = types.AppNameShort + "qacache.yaml" + // DefaultClusterType defines the default cluster type chosen by plan + DefaultClusterType string = "Kubernetes" + // IgnoreFilename is the name of the file containing the ignore rules and exceptions + IgnoreFilename string = "." + types.AppNameShort + "ignore" +) + +var ( + // DefaultPVCSize stores the default PVC size + DefaultPVCSize, _ = resource.ParseQuantity("100Mi") + // IgnoreEnvironment indicates whether to ignore the current environment or not + IgnoreEnvironment = false + // TempPath defines where all app data get stored during execution + TempPath = TempDirPrefix + "temp" + // AssetsPath defines where all assets get stored during execution + AssetsPath = filepath.Join(TempPath, AssetsDir) +) diff --git a/internal/common/generator/generator.go b/internal/common/generator/generator.go new file mode 100644 index 000000000..d318258a0 --- /dev/null +++ b/internal/common/generator/generator.go @@ -0,0 +1,211 @@ +// +build !excludecodegen + +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// This program generates dockerfiles.go. It can be invoked by running +// go generate +package main + +import ( + "io/ioutil" + "os" + "path/filepath" + "strings" + "text/template" + "time" + + "github.com/konveyor/move2kube/internal/common" + log "github.com/sirupsen/logrus" +) + +// Reads all non .go files in the current directory +// and encodes them as strings literals in .go + +const ( + license = `/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/` + + conststemp = `// Code generated by go generate; DO NOT EDIT. +// This file was generated by robots at +// {{ .Timestamp }} + +` + license + ` + +package {{ .Directory }} + +const ( +{{ range $file, $contents := .Files }} + {{ $file }} = ` + "`{{ $contents }}`" + ` +{{ end }} +)` + + maptemp = `// Code generated by go generate; DO NOT EDIT. +// This file was generated by robots at +// {{ .Timestamp }} + +` + license + ` + +package {{ .Directory }} + +var Constants= map[string]string{ +{{ range $file, $contents := .Files }} + ` + "`{{ $file }}`" + ` : ` + "`{{ $contents }}`," + ` +{{ end }} +}` + + tartemp = `// Code generated by go generate; DO NOT EDIT. +// This file was generated by robots at +// {{ .Timestamp }} + +` + license + ` + +package {{ .Directory }} + +const Tar = ` + "`{{ .TarString }}`" +) + +//TODO: Fix cases where the file has ` in contents +func main() { + directory := os.Args[1] + if len(os.Args) == 3 { + if os.Args[2] == "makemaps" { + if err := makeConstants(directory, maptemp); err != nil { + log.Fatalf("Error during code gen on directory %q with makemaps Error: %q", directory, err) + } + } else if os.Args[2] == "maketar" { + if err := makeTar(directory); err != nil { + log.Fatalf("Error during code gen on directory %q with maketar Error: %q", directory, err) + } + } + } else { + if err := makeConstants(directory, conststemp); err != nil { + log.Fatalf("Error during code gen on directory %q with consts template Error: %q", directory, err) + } + } +} + +func makeConstants(directory string, tplstr string) error { + files := make(map[string]string) + + log.Infof("Generating constants from %q", directory) + fs, err := ioutil.ReadDir(directory) + if err != nil { + log.Errorf("Failed to read the directory %q Error: %q", directory, err) + return err + } + for _, f := range fs { + file := f.Name() + if f.IsDir() { + continue + } + if !strings.HasSuffix(file, ".go") && !strings.HasPrefix(file, ".") { + currpath := filepath.Join(directory, file) + content, err := ioutil.ReadFile(currpath) + if err != nil { + log.Errorf("Failed to read the file at path %q Error: %q", currpath, err) + return err + } + // Convert []byte to string + files[strings.ReplaceAll(file, ".", "_")] = string(content) + } + } + + outputpath := filepath.Join(directory, "constants.go") + f, err := os.Create(outputpath) + if err != nil { + log.Errorf("Failed to create the file at path %q Error: %q", outputpath, err) + return err + } + defer f.Close() + + var tpl = template.Must(template.New("").Parse(tplstr)) + + absdirectory, err := filepath.Abs(directory) + if err != nil { + log.Errorf("Unable to resolve full path of directory %q : %q", absdirectory, err) + return err + } + + err = tpl.Execute(f, struct { + Timestamp time.Time + Directory string + Files map[string]string + }{ + Timestamp: time.Now(), + Directory: filepath.Base(absdirectory), + Files: files, + }) + if err != nil { + log.Errorf("Failed to execute the template. Error: %q", err) + return err + } + return nil +} + +func makeTar(directory string) error { + outputpath := filepath.Join(directory, "constants.go") + f, err := os.Create(outputpath) + if err != nil { + log.Errorf("Failed to create the file at path %q Error: %q", outputpath, err) + return err + } + defer f.Close() + + log.Infof("Generating tar from %q", directory) + + tarString, err := common.TarAsString(directory, []string{"constants.go", "assets.go"}) + if err != nil { + log.Errorf("Error while creating tar : %q", err) + return err + } + + var tpl = template.Must(template.New("").Parse(tartemp)) + + absdirectory, err := filepath.Abs(directory) + if err != nil { + log.Errorf("Unable to resolve full path of directory %q : %q", absdirectory, err) + return err + } + + err = tpl.Execute(f, struct { + Timestamp time.Time + Directory string + TarString string + }{ + Timestamp: time.Now(), + Directory: filepath.Base(absdirectory), + TarString: tarString, + }) + if err != nil { + log.Errorf("Failed to execute the template. Error: %q", err) + return err + } + return nil +} diff --git a/internal/common/generator/generator_test.go b/internal/common/generator/generator_test.go new file mode 100644 index 000000000..2c59d01bd --- /dev/null +++ b/internal/common/generator/generator_test.go @@ -0,0 +1,274 @@ +// +build !excludecodegen + +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +import ( + "io/ioutil" + "os" + "path/filepath" + "strings" + "testing" +) + +func TestMakeConstants(t *testing.T) { + t.Run("try to generate code for non existent directory", func(t *testing.T) { + path := "testdata/nonexistent" + if err := makeConstants(path, maptemp); err == nil { + t.Fatalf("Should have failed since the directory %q does not exist.", path) + } + }) + + t.Run("read empty directory and generate code with maptemp", func(t *testing.T) { + // Setup + testparentdir := t.TempDir() + testdir := filepath.Join(testparentdir, "foobar") + if err := os.Mkdir(testdir, os.ModePerm); err != nil { + t.Fatalf("Failed to create the test directory at path %q. Error: %q", testdir, err) + } + fpath := filepath.Join(testdir, "constants.go") + testdatapath := "testdata/maptempemptyskiptimestamp.txt" + testdatabytes, err := ioutil.ReadFile(testdatapath) + if err != nil { + t.Fatalf("Failed to read the testdata at path %q. Error: %q", testdatapath, err) + } + want := string(testdatabytes) + wantNumLines := 8 + 17 // 17 lines for license and spaces + + // Test + if err := makeConstants(testdir, maptemp); err != nil { + t.Fatalf("Failed to generate the code for directory %q with maps template Error: %q", testdir, err) + } + databytes, err := ioutil.ReadFile(fpath) + if err != nil { + t.Fatal("Failed to create the constants.go file (or failed to read it after creation). Error:", err) + } + data := string(databytes) + lines := strings.Split(data, "\n") + if len(lines) != wantNumLines { + t.Fatal("Failed to generate the code properly. Expected number of lines:", wantNumLines, "Actual:", len(lines)) + } + lines = append(lines[:2], lines[3:]...) // Skip the timestamp + data = strings.Join(lines, "\n") + if data != want { + t.Fatal("Failed to generate the code properly. Expected:", want, "Actual:", data) + } + }) + + t.Run("read empty directory and generate code with conststemp", func(t *testing.T) { + // Setup + testparentdir := t.TempDir() + testdir := filepath.Join(testparentdir, "foobar") + if err := os.Mkdir(testdir, os.ModePerm); err != nil { + t.Fatalf("Failed to create the test directory at path %q. Error: %q", testdir, err) + } + fpath := filepath.Join(testdir, "constants.go") + testdatapath := "testdata/conststempemptyskiptimestamp.txt" + testdatabytes, err := ioutil.ReadFile(testdatapath) + if err != nil { + t.Fatalf("Failed to read the testdata at path %q. Error: %q", testdatapath, err) + } + want := string(testdatabytes) + wantNumLines := 8 + 17 // 17 lines for license and spaces + + // Test + if err := makeConstants(testdir, conststemp); err != nil { + t.Fatalf("Failed to generate the code for directory %q with consts template Error: %q", testdir, err) + } + databytes, err := ioutil.ReadFile(fpath) + if err != nil { + t.Fatal("Failed to create the constants.go file (or failed to read it after creation). Error:", err) + } + data := string(databytes) + lines := strings.Split(data, "\n") + if len(lines) != wantNumLines { + t.Fatal("Failed to generate the code properly. Expected number of lines:", wantNumLines, "Actual:", len(lines)) + } + lines = append(lines[:2], lines[3:]...) // Skip the timestamp + data = strings.Join(lines, "\n") + if data != want { + t.Fatal("Failed to generate the code properly. Expected:", want, "Actual:", data) + } + }) + + t.Run("read filled directory and generate code with maptemp", func(t *testing.T) { + // Setup + testdir := "testdata/datafortempfilled" + fpath := filepath.Join(testdir, "constants.go") + // Remove the constants.go file if it exists from previous runs. + if err := os.Remove(fpath); err != nil && !os.IsNotExist(err) { + t.Fatalf("Failed to remove the file at path %q. Error: %q", fpath, err) + } + testdatapath := "testdata/maptempfilledskiptimestamp.txt" + testdatabytes, err := ioutil.ReadFile(testdatapath) + if err != nil { + t.Fatalf("Failed to read the testdata at path %q. Error: %q", testdatapath, err) + } + want := string(testdatabytes) + wantNumLines := 22 + 17 // 17 lines for license and spaces + + // Test + if err := makeConstants(testdir, maptemp); err != nil { + t.Fatalf("Failed to generate the code for directory %q with maps template Error: %q", testdir, err) + } + defer os.Remove(fpath) + databytes, err := ioutil.ReadFile(fpath) + if err != nil { + t.Fatal("Failed to create the constants.go file (or failed to read it after creation). Error:", err) + } + data := string(databytes) + lines := strings.Split(data, "\n") + if len(lines) != wantNumLines { + t.Fatal("Failed to generate the code properly. Expected number of lines:", wantNumLines, "Actual:", len(lines)) + } + lines = append(lines[:2], lines[3:]...) // Skip the timestamp + data = strings.Join(lines, "\n") + if data != want { + t.Fatal("Failed to generate the code properly. Expected:", want, "Actual:", data) + } + }) + + t.Run("read filled directory and generate code with conststemp", func(t *testing.T) { + // Setup + testdir := "testdata/datafortempfilled" + fpath := filepath.Join(testdir, "constants.go") + // Remove the constants.go file if it exists from previous runs. + if err := os.Remove(fpath); err != nil && !os.IsNotExist(err) { + t.Fatalf("Failed to remove the file at path %q. Error: %q", fpath, err) + } + testdatapath := "testdata/conststempfilledskiptimestamp.txt" + testdatabytes, err := ioutil.ReadFile(testdatapath) + if err != nil { + t.Fatalf("Failed to read the testdata at path %q. Error: %q", testdatapath, err) + } + want := string(testdatabytes) + wantNumLines := 22 + 17 // 17 lines for license and spaces + + // Test + if err := makeConstants(testdir, conststemp); err != nil { + t.Fatalf("Failed to generate the code for directory %q with consts template Error: %q", testdir, err) + } + defer os.Remove(fpath) + databytes, err := ioutil.ReadFile(fpath) + if err != nil { + t.Fatal("Failed to create the constants.go file (or failed to read it after creation). Error:", err) + } + data := string(databytes) + lines := strings.Split(data, "\n") + if len(lines) != wantNumLines { + t.Fatal("Failed to generate the code properly. Expected number of lines:", wantNumLines, "Actual:", len(lines)) + } + lines = append(lines[:2], lines[3:]...) // Skip the timestamp + data = strings.Join(lines, "\n") + if data != want { + t.Fatal("Failed to generate the code properly. Expected:", want, "Actual:", data) + } + }) + + t.Run("generate code from directory containing files that we have no permissions to read", func(t *testing.T) { + // Setup + testdir := t.TempDir() + fpath := filepath.Join(testdir, "foobar") + if err := ioutil.WriteFile(fpath, []byte("no permission to read this file"), 0); err != nil { + t.Fatalf("Failed to create the temporary file %q for testing.", fpath) + } + + // Test + if err := makeConstants(testdir, conststemp); err == nil { + t.Fatalf("Should not have succeeded since the directory contains a file %q we don't have permissions to read.", fpath) + } + }) + + t.Run("generate code from directory that we have no permissions to write to", func(t *testing.T) { + // Setup + tempdir := t.TempDir() + testdir := filepath.Join(tempdir, "foobar") + if err := os.Mkdir(testdir, 0400); err != nil { + t.Fatalf("Failed to create the temporary directory %q for testing. Error: %q", testdir, err) + } + + // Test + if err := makeConstants(testdir, conststemp); err == nil { + t.Fatalf("Should not have succeeded since we don't have permissions to write into the directory %q", testdir) + } + }) +} + +func TestMakeTar(t *testing.T) { + t.Run("make a tar using a filled directory", func(t *testing.T) { + // Setup + testdir := "testdata/datafortempfilled" + fpath := filepath.Join(testdir, "constants.go") + // Remove the constants.go file if it exists from previous runs. + if err := os.Remove(fpath); err != nil && !os.IsNotExist(err) { + t.Fatalf("Failed to remove the file at path %q. Error: %q", fpath, err) + } + testdatapath := "testdata/tartempfilledskiptimestampandtar.txt" + testdatabytes, err := ioutil.ReadFile(testdatapath) + if err != nil { + t.Fatalf("Failed to read the testdata at path %q. Error: %q", testdatapath, err) + } + want := string(testdatabytes) + wantNumLines := 6 + 17 // 17 lines for license and spaces + + // Test + if err := makeTar(testdir); err != nil { + t.Fatalf("Failed to generate the code for directory %q with tar template Error: %q", testdir, err) + } + defer os.Remove(fpath) + databytes, err := ioutil.ReadFile(fpath) + if err != nil { + t.Fatal("Failed to create the constants.go file (or failed to read it after creation). Error:", err) + } + data := string(databytes) + lines := strings.Split(data, "\n") + if len(lines) != wantNumLines { + t.Fatal("Failed to generate the code properly. Expected number of lines:", wantNumLines, "Actual:", len(lines)) + } + lines = append(lines[:2], lines[3:len(lines)-1]...) // Skip the timestamp and the last line since the tar string also has a timestamp + data = strings.Join(lines, "\n") + if data != want { + t.Fatal("Failed to generate the code properly. Expected:", want, "Actual:", data) + } + }) + + t.Run("make a tar when the directory has files which we have no permissions to read", func(t *testing.T) { + tempdir := t.TempDir() + fpath := filepath.Join(tempdir, "nopermstoread") + if err := ioutil.WriteFile(fpath, []byte("no permission to read this file"), 0); err != nil { + t.Fatalf("Failed to create the temporary file %q for testing.", fpath) + } + if err := makeTar(tempdir); err == nil { + t.Fatalf("Should not have succeeded since the directory contains a file %q we don't have permissions to read.", fpath) + } + }) + + t.Run("make a tar in a directory that we have no permissions to write to", func(t *testing.T) { + // Setup + tempdir := t.TempDir() + testdir := filepath.Join(tempdir, "foobar") + if err := os.Mkdir(testdir, 0400); err != nil { + t.Fatalf("Failed to create the temporary directory %q for testing. Error: %q", testdir, err) + } + + // Test + if err := makeTar(testdir); err == nil { + t.Fatalf("Should not have succeeded since we don't have permissions to write into the directory %q", testdir) + } + }) +} diff --git a/internal/common/generator/testdata/conststempemptyskiptimestamp.txt b/internal/common/generator/testdata/conststempemptyskiptimestamp.txt new file mode 100644 index 000000000..a0c4e43a8 --- /dev/null +++ b/internal/common/generator/testdata/conststempemptyskiptimestamp.txt @@ -0,0 +1,24 @@ +// Code generated by go generate; DO NOT EDIT. +// This file was generated by robots at + +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package foobar + +const ( + +) \ No newline at end of file diff --git a/internal/common/generator/testdata/conststempfilledskiptimestamp.txt b/internal/common/generator/testdata/conststempfilledskiptimestamp.txt new file mode 100644 index 000000000..24e03f9d2 --- /dev/null +++ b/internal/common/generator/testdata/conststempfilledskiptimestamp.txt @@ -0,0 +1,38 @@ +// Code generated by go generate; DO NOT EDIT. +// This file was generated by robots at + +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package datafortempfilled + +const ( + + test1_json = `{ + "foo": "bar", + "id": 42, + "key1": ["val1", "val2", "val3"] +}` + + test2_yml = `--- +key1: + subkey1: subval1 + subkey2: + - subval2arr1 + - subval2arr2 +...` + +) \ No newline at end of file diff --git a/internal/common/generator/testdata/datafortempfilled/test1.json b/internal/common/generator/testdata/datafortempfilled/test1.json new file mode 100644 index 000000000..44e2ea174 --- /dev/null +++ b/internal/common/generator/testdata/datafortempfilled/test1.json @@ -0,0 +1,5 @@ +{ + "foo": "bar", + "id": 42, + "key1": ["val1", "val2", "val3"] +} \ No newline at end of file diff --git a/internal/common/generator/testdata/datafortempfilled/test2.yml b/internal/common/generator/testdata/datafortempfilled/test2.yml new file mode 100644 index 000000000..4fe77ac27 --- /dev/null +++ b/internal/common/generator/testdata/datafortempfilled/test2.yml @@ -0,0 +1,7 @@ +--- +key1: + subkey1: subval1 + subkey2: + - subval2arr1 + - subval2arr2 +... \ No newline at end of file diff --git a/internal/common/generator/testdata/datafortempfilled/testconfigs/test3.yml b/internal/common/generator/testdata/datafortempfilled/testconfigs/test3.yml new file mode 100644 index 000000000..c5d0fb977 --- /dev/null +++ b/internal/common/generator/testdata/datafortempfilled/testconfigs/test3.yml @@ -0,0 +1,7 @@ +--- +key1: + subkey1: foo + subkey2: + - bar + - baz +... \ No newline at end of file diff --git a/internal/common/generator/testdata/maptempemptyskiptimestamp.txt b/internal/common/generator/testdata/maptempemptyskiptimestamp.txt new file mode 100644 index 000000000..5eede2739 --- /dev/null +++ b/internal/common/generator/testdata/maptempemptyskiptimestamp.txt @@ -0,0 +1,24 @@ +// Code generated by go generate; DO NOT EDIT. +// This file was generated by robots at + +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package foobar + +var Constants= map[string]string{ + +} \ No newline at end of file diff --git a/internal/common/generator/testdata/maptempfilledskiptimestamp.txt b/internal/common/generator/testdata/maptempfilledskiptimestamp.txt new file mode 100644 index 000000000..150ca6aa6 --- /dev/null +++ b/internal/common/generator/testdata/maptempfilledskiptimestamp.txt @@ -0,0 +1,38 @@ +// Code generated by go generate; DO NOT EDIT. +// This file was generated by robots at + +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package datafortempfilled + +var Constants= map[string]string{ + + `test1_json` : `{ + "foo": "bar", + "id": 42, + "key1": ["val1", "val2", "val3"] +}`, + + `test2_yml` : `--- +key1: + subkey1: subval1 + subkey2: + - subval2arr1 + - subval2arr2 +...`, + +} \ No newline at end of file diff --git a/internal/common/generator/testdata/tartempfilledskiptimestampandtar.txt b/internal/common/generator/testdata/tartempfilledskiptimestampandtar.txt new file mode 100644 index 000000000..448492a9e --- /dev/null +++ b/internal/common/generator/testdata/tartempfilledskiptimestampandtar.txt @@ -0,0 +1,20 @@ +// Code generated by go generate; DO NOT EDIT. +// This file was generated by robots at + +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package datafortempfilled diff --git a/internal/common/tar.go b/internal/common/tar.go new file mode 100644 index 000000000..fef4b1239 --- /dev/null +++ b/internal/common/tar.go @@ -0,0 +1,116 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package common + +import ( + "archive/tar" + "bytes" + "encoding/base64" + "fmt" + "io" + "os" + "path/filepath" + + log "github.com/sirupsen/logrus" +) + +// TarAsString converts a directory into a string +func TarAsString(path string, ignorefiles []string) (string, error) { + + buf := bytes.NewBuffer([]byte{}) + tw := tar.NewWriter(buf) + defer tw.Close() + + err := filepath.Walk(path, func(currpath string, finfo os.FileInfo, err error) error { + if err != nil { + return err + } + hdr, err := tar.FileInfoHeader(finfo, finfo.Name()) + if err != nil { + return err + } + if hdr.Name, err = filepath.Rel(path, currpath); err != nil { + return err + } + for _, ignorefile := range ignorefiles { + if hdr.Name == ignorefile { + return nil + } + } + if err := tw.WriteHeader(hdr); err != nil { + return err + } + if finfo.Mode().IsDir() { + return nil + } + currfile, err := os.Open(currpath) + if err != nil { + return err + } + defer currfile.Close() + _, err = io.Copy(tw, currfile) + if err != nil { + return err + } + return nil + }) + if err != nil { + log.Warnf("Failed to create tar string: %s : %s", path, err) + } + return base64.StdEncoding.EncodeToString(buf.Bytes()), err +} + +// UnTarString converts a string into a directory +func UnTarString(tarstring string, path string) (err error) { + val, err := base64.StdEncoding.DecodeString(tarstring) + if err != nil { + log.Errorf("Unable to decode tarstring : %s", err) + return err + } + tr := tar.NewReader(bytes.NewReader(val)) + for { + hdr, err := tr.Next() + if err == io.EOF { + break + } + if err != nil { + return err + } + finfo := hdr.FileInfo() + fileName := hdr.Name + filepath := filepath.Join(path, fileName) + if finfo.Mode().IsDir() { + if err := os.MkdirAll(filepath, DefaultDirectoryPermission); err != nil { + return err + } + continue + } + file, err := os.OpenFile(filepath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, finfo.Mode().Perm()) + if err != nil { + return err + } + defer file.Close() + size, err := io.Copy(file, tr) + if err != nil { + return err + } + if size != finfo.Size() { + return fmt.Errorf("Size mismatch: Wrote %d, Expected %d", size, finfo.Size()) + } + } + return nil +} diff --git a/internal/common/tar_test.go b/internal/common/tar_test.go new file mode 100644 index 000000000..df5549cbe --- /dev/null +++ b/internal/common/tar_test.go @@ -0,0 +1,277 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package common_test + +import ( + "archive/tar" + "bytes" + "encoding/base64" + "encoding/json" + "fmt" + "io" + "io/ioutil" + "os" + "path/filepath" + "testing" + + "github.com/konveyor/move2kube/internal/common" + log "github.com/sirupsen/logrus" +) + +// myFileInfo is used to hold the part of the expected outputs for each testcase +// This is only for testing purposes. +type myFileInfo struct { + Name string + Size int64 + Mode os.FileMode + IsDir bool +} + +func newMyFileInfo(f os.FileInfo) myFileInfo { + return myFileInfo{f.Name(), f.Size(), f.Mode(), f.IsDir()} +} + +// myUnTarForTesting extracts information from a tar string. +// This function is for testing purposes only. +func myUnTarForTesting(tarstring string, myfinfos []myFileInfo, contents []string) error { + val, err := base64.StdEncoding.DecodeString(tarstring) + if err != nil { + log.Errorf("Unable to decode tarstring : %s", err) + } + tr := tar.NewReader(bytes.NewReader(val)) + expectedTotal := len(myfinfos) + + for i := range myfinfos { + hdr, err := tr.Next() + if err == io.EOF { + return fmt.Errorf("The tar string %q contains less files than expected. Expected: %d Actual: %d", tarstring, expectedTotal, i) + } + if err != nil { + return err + } + finfo := hdr.FileInfo() + actualmyfinfo := newMyFileInfo(finfo) + if actualmyfinfo != myfinfos[i] { + return fmt.Errorf("The info for file number %d is incorrect. Expected: %v Actual %v", i, myfinfos[i], actualmyfinfo) + } + if finfo.Mode().IsDir() { + continue + } + buf := bytes.NewBuffer([]byte{}) + size, err := io.Copy(buf, tr) + if err != nil { + return err + } + if size != finfo.Size() { + return fmt.Errorf("Size mismatch: Wrote %d, Expected %d", size, finfo.Size()) + } + actualContents := buf.String() + if actualContents != contents[i] { + return fmt.Errorf("The contents of the file at path %q is incorrect. Expected: %q Actual: %q", actualmyfinfo.Name, contents[i], actualContents) + } + } + if _, err := tr.Next(); err != io.EOF { + return fmt.Errorf("The tar string %q contains more files than expected. Expected: %d Actual: at least %d", tarstring, expectedTotal, expectedTotal+1) + } + return nil +} + +func TestTarAsString(t *testing.T) { + log.SetLevel(log.DebugLevel) + + t.Run("tar as string when the path doesn't exist", func(t *testing.T) { + if _, err := common.TarAsString("foobar", []string{}); err == nil { + t.Fatal("Should not have succeeded since the path doesn't exist.") + } + }) + + t.Run("tar as string when the path is a file", func(t *testing.T) { + path1 := "testdata/datafortestingtar/tobetarred/test1.yaml" + // want := "" + expectedInfos := []myFileInfo{ + {".", 217, 0644, false}, + } + data, err := ioutil.ReadFile(path1) + if err != nil { + t.Fatalf("Failed to read the test data at %q. Error %q", path1, err) + } + expectedContents := []string{ + string(data), + } + if tarstring, err := common.TarAsString(path1, []string{}); err != nil { + t.Fatalf("Failed to tar the file %q. Error: %q", path1, err) + } else if err := myUnTarForTesting(tarstring, expectedInfos, expectedContents); err != nil { + t.Fatal("Failed to tar the file", path1, "properly. Error:", err) + } + }) + + t.Run("tar as string when the path is an empty directory", func(t *testing.T) { + parent := t.TempDir() + path1 := filepath.Join(parent, "foobar") + if err := os.Mkdir(path1, os.ModePerm); err != nil { + t.Fatal("Failed to make the directory", path1, "Error:", err) + } + // want := "" + expectedInfos := []myFileInfo{ + {".", 0, 0o20000000755, true}, + } + expectedContents := []string{} + if tarstring, err := common.TarAsString(path1, []string{}); err != nil { + t.Fatalf("Failed to tar the file %q. Error: %q", path1, err) + } else if err := myUnTarForTesting(tarstring, expectedInfos, expectedContents); err != nil { + t.Fatal("Failed to tar the file", path1, "properly. Error:", err) + } + }) + + t.Run("tar as string when the path is a filled directory", func(t *testing.T) { + testdirpath := "testdata/datafortestingtar/tobetarred" + // want := "" + expectedInfos := []myFileInfo{ + {".", 0, 0o20000000755, true}, + } + expectedContents := []string{ + "", + } + finfos, err := ioutil.ReadDir(testdirpath) + if err != nil { + t.Fatalf("Failed to read the testdata at path: %q", testdirpath) + } + for _, finfo := range finfos { + expectedInfos = append(expectedInfos, newMyFileInfo(finfo)) + testfilepath := filepath.Join(testdirpath, finfo.Name()) + testfilecontents, err := ioutil.ReadFile(testfilepath) + if err != nil { + t.Fatalf("Failed to read the testdata at path: %q", testfilepath) + } + expectedContents = append(expectedContents, string(testfilecontents)) + } + if tarstring, err := common.TarAsString(testdirpath, []string{}); err != nil { + t.Fatalf("Failed to tar the file %q. Error: %q", testdirpath, err) + } else if err := myUnTarForTesting(tarstring, expectedInfos, expectedContents); err != nil { + t.Fatal("Failed to tar the file", testdirpath, "properly. Error:", err) + } + }) + + t.Run("tar as string while ignoring some files", func(t *testing.T) { + testdirpath := "testdata/datafortestingtar/tobetarred" + ignoredFiles := []string{"test2.yml", "versioninfo.json", "foobar.json"} + // want := "" + expectedInfos := []myFileInfo{ + {".", 0, 0o20000000755, true}, + } + expectedContents := []string{ + "", + } + finfos, err := ioutil.ReadDir(testdirpath) + if err != nil { + t.Fatalf("Failed to read the testdata at path: %q", testdirpath) + } + for _, finfo := range finfos { + if common.IsStringPresent(ignoredFiles, finfo.Name()) { + continue + } + expectedInfos = append(expectedInfos, newMyFileInfo(finfo)) + testfilepath := filepath.Join(testdirpath, finfo.Name()) + testfilecontents, err := ioutil.ReadFile(testfilepath) + if err != nil { + t.Fatalf("Failed to read the testdata at path: %q", testfilepath) + } + expectedContents = append(expectedContents, string(testfilecontents)) + } + if tarstring, err := common.TarAsString(testdirpath, ignoredFiles); err != nil { + t.Fatalf("Failed to tar the file %q. Error: %q", testdirpath, err) + } else if err := myUnTarForTesting(tarstring, expectedInfos, expectedContents); err != nil { + t.Fatal("Failed to tar the file", testdirpath, "properly. Error:", err) + } + }) + + t.Run("tar as string when the directory has files which you don't have permission to read", func(t *testing.T) { + path1 := t.TempDir() + path2 := filepath.Join(path1, "nopermstoread") + if err := ioutil.WriteFile(path2, []byte("no permission to read this file"), 0); err != nil { + t.Fatalf("Failed to create the temporary file %q for testing.", path2) + } + if _, err := common.TarAsString(path2, []string{}); err == nil { + t.Fatalf("Should not have succeeded since the directory contains a file %q we don't have permissions to read.", path2) + } + }) +} + +func TestUnTarString(t *testing.T) { + log.SetLevel(log.DebugLevel) + + testdatadir := "testdata/datafortestingtar/untarstring.json" + testdata := map[string]string{} + if testdatabytes, err := ioutil.ReadFile(testdatadir); err != nil { + t.Fatal("Failed to read the testdata at path:", testdatadir, "Error:", err) + } else if err := json.Unmarshal(testdatabytes, &testdata); err != nil { + t.Fatal("Failed to unmarshal the json testdata at path:", testdatadir, "Error:", err) + } + + t.Run("untar a valid tarstring", func(t *testing.T) { + path := t.TempDir() + tarstring := testdata["untar_a_valid_tarstring"] + if err := common.UnTarString(tarstring, path); err != nil { + t.Fatalf("Failed to untar the tarstring %q to the path %q. Error: %q", tarstring, path, err) + } + if _, err := common.TarAsString(path, []string{}); err != nil { + t.Fatalf("Failed to tar as string the directory %q we just untarred. Error: %q", path, err) + } + }) + + t.Run("untar an invalid base 64 string", func(t *testing.T) { + path := t.TempDir() + tarstring := testdata["untar_an_invalid_base_64_string"] + if err := common.UnTarString(tarstring, path); err == nil { + t.Fatalf("Should have given an error since the tarstring %q is not a valid base 64 string.", tarstring) + } + }) + + t.Run("untar an invalid tarstring", func(t *testing.T) { + path := t.TempDir() + tarstring := testdata["untar_an_invalid_tarstring"] + if err := common.UnTarString(tarstring, path); err == nil { + t.Fatalf("Should have given an error since the tarstring %q is not valid.", tarstring) + } + }) + + t.Run("untar into a directory we don't have permission to write to", func(t *testing.T) { + parent := t.TempDir() + noPermDir := filepath.Join(parent, "nopermstowrite") + if err := os.Mkdir(noPermDir, 0); err != nil { + t.Fatalf("Failed to create the temporary directory %q for testing. Error: %q", noPermDir, err) + } + path := filepath.Join(noPermDir, "foobar") + tarstring := testdata["untar_into_a_directory_we_dont_have_permission_to_write_to"] + if err := common.UnTarString(tarstring, path); err == nil { + t.Fatalf("Should have given an error since we don't have permission to write to the directory %q", path) + } + }) + + t.Run("untar a single file into a directory we don't have permission to write to", func(t *testing.T) { + parent := t.TempDir() + noPermDir := filepath.Join(parent, "nopermstowrite") + if err := os.Mkdir(noPermDir, 0); err != nil { + t.Fatalf("Failed to create the temporary directory %q for testing. Error: %q", noPermDir, err) + } + path := filepath.Join(noPermDir, "foobar") + tarstring := testdata["untar_a_single_file_into_a_directory_we_dont_have_permission_to_write_to"] + if err := common.UnTarString(tarstring, path); err == nil { + t.Fatalf("Should have given an error since we don't have permission to write to the directory %q", path) + } + }) +} diff --git a/internal/common/testdata/datafortestingtar/tobetarred/test1.json b/internal/common/testdata/datafortestingtar/tobetarred/test1.json new file mode 100644 index 000000000..27271cfdf --- /dev/null +++ b/internal/common/testdata/datafortestingtar/tobetarred/test1.json @@ -0,0 +1,5 @@ +{ + "name": "name1", + "foo": 42, + "bar": ["bar"] +} \ No newline at end of file diff --git a/internal/common/testdata/datafortestingtar/tobetarred/test1.yaml b/internal/common/testdata/datafortestingtar/tobetarred/test1.yaml new file mode 100644 index 000000000..7da038c28 --- /dev/null +++ b/internal/common/testdata/datafortestingtar/tobetarred/test1.yaml @@ -0,0 +1,17 @@ +--- +kind: clustermetadata +contextname: name1 +rootuserallowed: false +storageclasses: + - class1 + - class2 +apikindversionmap: + key1: + - 1.0.0 + - 1.1.0 + - 1.1.1 + key2: + - 2.0.0 + - 2.2.0 + - 2.2.2 +... diff --git a/internal/common/testdata/datafortestingtar/tobetarred/test2.yml b/internal/common/testdata/datafortestingtar/tobetarred/test2.yml new file mode 100644 index 000000000..7da038c28 --- /dev/null +++ b/internal/common/testdata/datafortestingtar/tobetarred/test2.yml @@ -0,0 +1,17 @@ +--- +kind: clustermetadata +contextname: name1 +rootuserallowed: false +storageclasses: + - class1 + - class2 +apikindversionmap: + key1: + - 1.0.0 + - 1.1.0 + - 1.1.1 + key2: + - 2.0.0 + - 2.2.0 + - 2.2.2 +... diff --git a/internal/common/testdata/datafortestingtar/untarstring.json b/internal/common/testdata/datafortestingtar/untarstring.json new file mode 100644 index 000000000..a67d96a91 --- /dev/null +++ b/internal/common/testdata/datafortestingtar/untarstring.json @@ -0,0 +1,7 @@ +{ + "untar_a_valid_tarstring": "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", + "untar_an_invalid_base_64_string": "==", + "untar_an_invalid_tarstring": "LgAAAAAAAADAwMDA3NTUAMDAwMDc2NQAwMDAwMDIhcmlrcmlzaG5hbmJhbGFAAc3AAAAAAAtLS0KdmVyc2lvbjogMC4wLjAKZ2l0X2NvbW1pdDogMS4wLjAKZ2l0X3RyZWVfc3RhdGU6IDEuMS4wCmdvX3ZlcnNpb246IDEuMS4xCi4uLg==", + "untar_into_a_directory_we_dont_have_permission_to_write_to": "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", + "untar_a_single_file_into_a_directory_we_dont_have_permission_to_write_to": "LgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAwMDA2NDQAMDAwMDc2NQAwMDAwMDI0ADAwMDAwMDAwMzMxADEzNzIyMjcxNTAyADAxNDY0MwAgMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB1c3RhcgAwMGhhcmlrcmlzaG5hbmJhbGFnb3BhbAAAAAAAAAAAAAAAc3RhZmYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwMDAwMDAwADAwMDAwMDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAtLS0Ka2luZDogY2x1c3Rlcm1ldGFkYXRhCmNvbnRleHRuYW1lOiBuYW1lMQpyb290dXNlcmFsbG93ZWQ6IGZhbHNlCnN0b3JhZ2VjbGFzc2VzOgogIC0gY2xhc3MxCiAgLSBjbGFzczIKYXBpa2luZHZlcnNpb25tYXA6CiAga2V5MToKICAgIC0gMS4wLjAKICAgIC0gMS4xLjAKICAgIC0gMS4xLjEKICBrZXkyOgogICAgLSAyLjAuMAogICAgLSAyLjIuMAogICAgLSAyLjIuMgouLi4K" +} diff --git a/internal/common/testdata/invalidfiles/test1.json b/internal/common/testdata/invalidfiles/test1.json new file mode 100644 index 000000000..7c08ffd5e --- /dev/null +++ b/internal/common/testdata/invalidfiles/test1.json @@ -0,0 +1,5 @@ +{ + some invalid json "name": "name1", + "foo": 42, + "bar": ["bar"] +} \ No newline at end of file diff --git a/internal/common/testdata/invalidfiles/test1.yaml b/internal/common/testdata/invalidfiles/test1.yaml new file mode 100644 index 000000000..09a253d9d --- /dev/null +++ b/internal/common/testdata/invalidfiles/test1.yaml @@ -0,0 +1,2 @@ +this: is[: not a!{{ real yaml file. +this is invalid yaml used only for testing. \ No newline at end of file diff --git a/internal/common/testdata/validfiles/test1.json b/internal/common/testdata/validfiles/test1.json new file mode 100644 index 000000000..27271cfdf --- /dev/null +++ b/internal/common/testdata/validfiles/test1.json @@ -0,0 +1,5 @@ +{ + "name": "name1", + "foo": 42, + "bar": ["bar"] +} \ No newline at end of file diff --git a/internal/common/testdata/validfiles/test1.yaml b/internal/common/testdata/validfiles/test1.yaml new file mode 100644 index 000000000..63de724aa --- /dev/null +++ b/internal/common/testdata/validfiles/test1.yaml @@ -0,0 +1,16 @@ +--- +kind: ClusterMetadata +contextName: name1 +storageClasses: + - class1 + - class2 +apiKindVersionMap: + key1: + - 1.0.0 + - 1.1.0 + - 1.1.1 + key2: + - 2.0.0 + - 2.2.0 + - 2.2.2 +... diff --git a/internal/common/testdata/validfiles/test2.yml b/internal/common/testdata/validfiles/test2.yml new file mode 100644 index 000000000..63de724aa --- /dev/null +++ b/internal/common/testdata/validfiles/test2.yml @@ -0,0 +1,16 @@ +--- +kind: ClusterMetadata +contextName: name1 +storageClasses: + - class1 + - class2 +apiKindVersionMap: + key1: + - 1.0.0 + - 1.1.0 + - 1.1.1 + key2: + - 2.0.0 + - 2.2.0 + - 2.2.2 +... diff --git a/internal/common/testdata/validfiles/versioninfo.json b/internal/common/testdata/validfiles/versioninfo.json new file mode 100644 index 000000000..7217b5367 --- /dev/null +++ b/internal/common/testdata/validfiles/versioninfo.json @@ -0,0 +1,6 @@ +{ + "Version": "0.0.0", + "GitCommit": "1.0.0", + "GitTreeState": "1.1.0", + "GoVersion": "1.1.1" +} \ No newline at end of file diff --git a/internal/common/testdata/validfiles/versioninfo.yaml b/internal/common/testdata/validfiles/versioninfo.yaml new file mode 100644 index 000000000..36c7f4a56 --- /dev/null +++ b/internal/common/testdata/validfiles/versioninfo.yaml @@ -0,0 +1,6 @@ +--- +version: 0.0.0 +gitCommit: 1.0.0 +gitTreeState: 1.1.0 +goVersion: 1.1.1 +... \ No newline at end of file diff --git a/internal/common/utils.go b/internal/common/utils.go new file mode 100644 index 000000000..6da60b69d --- /dev/null +++ b/internal/common/utils.go @@ -0,0 +1,436 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package common + +import ( + "bytes" + "encoding/json" + "hash/crc64" + "io/ioutil" + "math" + "os" + "path/filepath" + "reflect" + "regexp" + "strconv" + "strings" + "text/template" + + "github.com/konveyor/move2kube/internal/assets" + "github.com/konveyor/move2kube/types" + log "github.com/sirupsen/logrus" + "github.com/xrash/smetrics" + yaml "gopkg.in/yaml.v3" +) + +//GetFilesByExt returns files by extension +func GetFilesByExt(inputPath string, exts []string) ([]string, error) { + var files []string + if info, err := os.Stat(inputPath); os.IsNotExist(err) { + log.Warnf("Error in walking through files due to : %q", err) + return nil, err + } else if !info.IsDir() { + log.Warnf("The path %q is not a directory.", inputPath) + } + err := filepath.Walk(inputPath, func(path string, info os.FileInfo, err error) error { + if err != nil { + log.Warnf("Skipping path %q due to error: %q", path, err) + return nil + } + // Skip directories + if info.IsDir() { + return nil + } + fext := filepath.Ext(path) + for _, ext := range exts { + if fext == ext { + files = append(files, path) + } + } + return nil + }) + if err != nil { + log.Warnf("Error in walking through files due to : %q", err) + return files, err + } + log.Debugf("No of files with %s ext identified : %d", exts, len(files)) + return files, nil +} + +//GetFilesByName returns files by name +func GetFilesByName(inputPath string, names []string) ([]string, error) { + var files []string + if info, err := os.Stat(inputPath); os.IsNotExist(err) { + log.Warnf("Error in walking through files due to : %q", err) + return files, err + } else if !info.IsDir() { + log.Warnf("The path %q is not a directory.", inputPath) + } + err := filepath.Walk(inputPath, func(path string, info os.FileInfo, err error) error { + if err != nil { + log.Warnf("Skipping path %q due to error: %q", path, err) + return nil + } + // Skip directories + if info.IsDir() { + return nil + } + fname := filepath.Base(path) + for _, name := range names { + if fname == name { + files = append(files, path) + } + } + return nil + }) + if err != nil { + log.Warnf("Error in walking through files due to : %s", err) + return files, nil + } + log.Debugf("No of files with %s names identified : %d", names, len(files)) + return files, nil +} + +//YamlAttrPresent returns YAML attributes +func YamlAttrPresent(path string, attr string) (bool, interface{}) { + yamlFile, err := ioutil.ReadFile(path) + if err != nil { + log.Warnf("Error in reading yaml file %s: %s. Skipping", path, err) + return false, nil + } + var fileContents map[string]interface{} + err = yaml.Unmarshal(yamlFile, &fileContents) + if err != nil { + log.Warnf("Error in unmarshalling yaml file %s: %s. Skipping", path, err) + return false, nil + } + if value, ok := fileContents[attr]; ok { + log.Debugf("%s file has %s attribute", path, attr) + return true, value + } + return false, nil +} + +// GetImageNameAndTag splits an image full name and returns the image name and tag +func GetImageNameAndTag(image string) (string, string) { + parts := strings.Split(image, "/") + imageAndTag := strings.Split(parts[len(parts)-1], ":") + imageName := imageAndTag[0] + var tag string + if len(imageAndTag) == 1 { + // no tag, assume latest + tag = "latest" + } else { + tag = imageAndTag[1] + } + + return imageName, tag +} + +// WriteYaml writes an yaml to disk +func WriteYaml(outputPath string, data interface{}) error { + var b bytes.Buffer + encoder := yaml.NewEncoder(&b) + encoder.SetIndent(2) + if err := encoder.Encode(data); err != nil { + log.Error("Error while Encoding object") + return err + } + if err := encoder.Close(); err != nil { + log.Error("Error while closing the encoder. Data not written to file", outputPath, "Error:", err) + return err + } + err := ioutil.WriteFile(outputPath, b.Bytes(), DefaultFilePermission) + if err != nil { + log.Errorf("Error writing yaml to file: %s", err) + return err + } + return nil +} + +// ReadYaml reads an yaml into an object +func ReadYaml(file string, data interface{}) error { + yamlFile, err := ioutil.ReadFile(file) + if err != nil { + log.Debugf("Error in reading yaml file %s: %s.", file, err) + return err + } + err = yaml.Unmarshal(yamlFile, data) + if err != nil { + log.Debugf("Error in unmarshalling yaml file %s: %s.", file, err) + return err + } + rv := reflect.ValueOf(data) + if rv.Kind() == reflect.Ptr && rv.Elem().Kind() == reflect.Struct { + rv = rv.Elem() + fv := rv.FieldByName("APIVersion") + if fv.IsValid() { + if fv.Kind() == reflect.String { + val := strings.TrimSpace(fv.String()) + if strings.HasPrefix(val, types.SchemeGroupVersion.Group) && !strings.HasSuffix(val, types.SchemeGroupVersion.Version) { + log.Warnf("The application file (%s) was generated using a different version than (%s)", val, types.SchemeGroupVersion.String()) + } + } + } + } + return nil +} + +// WriteJSON writes an json to disk +func WriteJSON(outputPath string, data interface{}) error { + var b bytes.Buffer + encoder := json.NewEncoder(&b) + if err := encoder.Encode(data); err != nil { + log.Error("Error while Encoding object") + return err + } + err := ioutil.WriteFile(outputPath, b.Bytes(), DefaultFilePermission) + if err != nil { + log.Errorf("Error writing json to file: %s", err) + return err + } + return nil +} + +// ReadJSON reads an json into an object +func ReadJSON(file string, data interface{}) error { + jsonFile, err := ioutil.ReadFile(file) + if err != nil { + log.Debugf("Error in reading json file %s: %s.", file, err) + return err + } + err = json.Unmarshal(jsonFile, &data) + if err != nil { + log.Debugf("Error in unmarshalling json file %s: %s.", file, err) + return err + } + return nil +} + +// NormalizeForFilename normalizes a string to only filename valid characters +func NormalizeForFilename(name string) string { + processedString := MakeFileNameCompliant(name) + //TODO: Make it more robust by taking some characters from start and also from end + const maxPrefixLength = 15 + if len(processedString) > maxPrefixLength { + processedString = processedString[0:maxPrefixLength] + } + crc64Table := crc64.MakeTable(0xC96C5795D7870F42) + crc64Int := crc64.Checksum([]byte(name), crc64Table) + return processedString + "_" + strconv.FormatUint(crc64Int, 16) +} + +// NormalizeForServiceName converts the string to be compatible for service name +func NormalizeForServiceName(svcName string) string { + re := regexp.MustCompile("[._]") + newName := strings.ToLower(re.ReplaceAllString(svcName, "-")) + if newName != svcName { + log.Infof("Changing service name to %s from %s", svcName, newName) + } + return newName +} + +// IsStringPresent checks if a value is present in a slice +func IsStringPresent(list []string, value string) bool { + for _, val := range list { + if strings.EqualFold(val, value) { + return true + } + } + return false +} + +// IsIntPresent checks if a value is present in a slice +func IsIntPresent(list []int, value int) bool { + for _, val := range list { + if val == value { + return true + } + } + return false +} + +// MergeStringSlices merges two string slices +func MergeStringSlices(slice1 []string, slice2 []string) []string { + for _, item := range slice2 { + if !IsStringPresent(slice1, item) { + slice1 = append(slice1, item) + } + } + return slice1 +} + +// MergeIntSlices merges two int slices +func MergeIntSlices(slice1 []int, slice2 []int) []int { + for _, item := range slice2 { + if !IsIntPresent(slice1, item) { + slice1 = append(slice1, item) + } + } + return slice1 +} + +// GetStringFromTemplate returns string for a template +func GetStringFromTemplate(tpl string, config interface{}) (string, error) { + var tplbuffer bytes.Buffer + var packageTemplate = template.Must(template.New("").Parse(tpl)) + err := packageTemplate.Execute(&tplbuffer, config) + if err != nil { + log.Warnf("Unable to translate template %q to string using the data %v", tpl, config) + return "", err + } + return tplbuffer.String(), nil +} + +// WriteTemplateToFile writes a templated string to a file +func WriteTemplateToFile(tpl string, config interface{}, writepath string, filemode os.FileMode) error { + var tplbuffer bytes.Buffer + var packageTemplate = template.Must(template.New("").Parse(tpl)) + err := packageTemplate.Execute(&tplbuffer, config) + if err != nil { + log.Warnf("Unable to translate template %q to string using the data %v", tpl, config) + return err + } + err = ioutil.WriteFile(writepath, tplbuffer.Bytes(), filemode) + if err != nil { + log.Warnf("Error writing file at %s : %s", writepath, err) + return err + } + return nil +} + +// GetClosestMatchingString returns the closest matching string for a given search string +func GetClosestMatchingString(options []string, searchstring string) string { + // tokenize all strings + reg := regexp.MustCompile("[^a-zA-Z0-9]+") + searchstring = reg.ReplaceAllString(searchstring, "") + searchstring = strings.ToLower(searchstring) + + leastDistance := math.MaxInt32 + matchString := "" + + // Simply find the option with least distance + for _, option := range options { + // do tokensize the search space string too + tokenizedOption := reg.ReplaceAllString(option, "") + tokenizedOption = strings.ToLower(tokenizedOption) + + currDistance := smetrics.WagnerFischer(tokenizedOption, searchstring, 1, 1, 2) + + if currDistance < leastDistance { + matchString = option + leastDistance = currDistance + } + } + + return matchString +} + +// MergeStringMaps merges two string maps +func MergeStringMaps(map1 map[string]string, map2 map[string]string) map[string]string { + mergedmap := make(map[string]string) + for k, v := range map1 { + mergedmap[k] = v + } + for k, v := range map2 { + mergedmap[k] = v + } + return mergedmap +} + +// MakeFileNameCompliant returns a DNS-1123 standard string +// Motivated by https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#syntax-and-character-set +// Also see page 1 "ASSUMPTIONS" heading of https://tools.ietf.org/html/rfc952 +// Also see page 13 of https://tools.ietf.org/html/rfc1123#page-13 +func MakeFileNameCompliant(name string) string { + if len(name) == 0 { + log.Error("The input name is empty.") + return "" + } + baseName := filepath.Base(name) + invalidChars := regexp.MustCompile("[^a-zA-Z0-9-.]+") + processedName := invalidChars.ReplaceAllString(baseName, "-") + if len(processedName) > 63 { + log.Warnf("The processed name %q is longer than 63 characters long.", processedName) + } + first := processedName[0] + last := processedName[len(processedName)-1] + if first == '-' || first == '.' || last == '-' || last == '.' { + log.Warnf("The first and/or last characters of the name %q are not alphanumeric.", processedName) + } + return processedName +} + +// CleanAndFindCommonDirectory finds the common ancestor directory among a list of absolute paths. +// Cleans the paths you give it before finding the directory. +// Also see FindCommonDirectory +func CleanAndFindCommonDirectory(paths []string) string { + cleanedpaths := make([]string, len(paths)) + for i, path := range paths { + cleanedpaths[i] = filepath.Clean(path) + } + return FindCommonDirectory(cleanedpaths) +} + +// FindCommonDirectory finds the common ancestor directory among a list of cleaned absolute paths. +// Will not clean the paths you give it before trying to find the directory. +// Also see CleanAndFindCommonDirectory +func FindCommonDirectory(paths []string) string { + if len(paths) == 0 { + return "" + } + slash := string(filepath.Separator) + commonDir := paths[0] + for commonDir != slash { + found := true + for _, path := range paths { + if !strings.HasPrefix(path+slash, commonDir+slash) { + found = false + break + } + } + if found { + break + } + commonDir = filepath.Dir(commonDir) + } + return commonDir +} + +// CreateAssetsData creates an assets directory and dumps the assets data into it +func CreateAssetsData() (assetsPath string, tempPath string, finalerr error) { + assetsPath = AssetsPath + tempPath = TempPath + + if newTempPath, err := ioutil.TempDir("", TempDirPrefix); err != nil { + log.Errorf("Unable to create temp dir. Defaulting to local path.") + } else { + tempPath = newTempPath + assetsPath = filepath.Join(newTempPath, AssetsDir) + } + + if err := os.MkdirAll(assetsPath, DefaultDirectoryPermission); err != nil { + log.Errorf("Unable to create the assets directory at path %q Error: %q", assetsPath, err) + return "", "", err + } + if err := UnTarString(assets.Tar, assetsPath); err != nil { + log.Errorf("Unable to untar the assets into the assets directory at path %q Error: %q", assetsPath, err) + return "", "", err + } + + return assetsPath, tempPath, nil +} diff --git a/internal/common/utils_test.go b/internal/common/utils_test.go new file mode 100644 index 000000000..2bd9e4fdb --- /dev/null +++ b/internal/common/utils_test.go @@ -0,0 +1,827 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package common_test + +import ( + "fmt" + "io/ioutil" + "os" + "reflect" + "testing" + + "github.com/konveyor/move2kube/internal/common" + "github.com/konveyor/move2kube/types/info" + log "github.com/sirupsen/logrus" +) + +func TestGetFilesByExt(t *testing.T) { + log.SetLevel(log.DebugLevel) + + t.Run("get files by extension when the path doesn't exist", func(t *testing.T) { + path1 := "foobar" + if _, err := common.GetFilesByExt(path1, []string{".yaml", ".yml"}); err == nil { + t.Fatal("Should have given an error since the path is non existent.") + } + }) + + t.Run("get files by extension when the path is a file", func(t *testing.T) { + path1 := "testdata/validfiles/test1.yaml" + filepaths, err := common.GetFilesByExt(path1, []string{".yaml", ".yml"}) + if err != nil { + t.Fatal("Should not have given any error. Error:", err) + } + if len(filepaths) != 1 || filepaths[0] != path1 { + t.Fatal("Failed to get the correct paths. Expected:", path1, "Actual:", filepaths) + } + }) + + t.Run("get files by extension in the normal use case", func(t *testing.T) { + path1 := "testdata/validfiles" + filepaths, err := common.GetFilesByExt(path1, []string{".yaml", ".yml"}) + if err != nil { + t.Fatal("Should not have given any error. Error:", err) + } + want := []string{"testdata/validfiles/test1.yaml", "testdata/validfiles/test2.yml", "testdata/validfiles/versioninfo.yaml"} + if !reflect.DeepEqual(filepaths, want) { + t.Fatal("Failed to get the correct paths. Expected:", want, "Actual:", filepaths) + } + }) + + t.Run("get files by extension when the directory is empty", func(t *testing.T) { + path1 := t.TempDir() + filepaths, err := common.GetFilesByExt(path1, []string{".yaml", ".yml"}) + if err != nil { + t.Fatal("Should not have given any error. Error:", err) + } + if len(filepaths) != 0 { + t.Fatal("Should not have returned any paths. Paths returned:", filepaths) + } + }) + + // TODO: do we need to handle this edge case? + // t.Run("get files by extension when you don't have permissions for the directory", func(t *testing.T) { + // parentDir := t.TempDir() + // path1 := filepath.Join(parentDir, "app1") + // if err := os.Mkdir(path1, 0); err != nil { + // t.Fatal("Failed to create the temporary directory", path1, "for testing. Error:", err) + // } + // if _, err := common.GetFilesByExt(path1, []string{".yaml", ".yml"}); err == nil { + // t.Fatal("Should have given an error since we don't have permissions to read the directory.") + // } + // }) +} + +func TestGetFilesByName(t *testing.T) { + t.Run("get files by name when the path doesn't exist", func(t *testing.T) { + path1 := "foobar" + if _, err := common.GetFilesByName(path1, []string{"test1.yaml", "test2.yml"}); err == nil { + t.Fatal("Should have given an error since the path is non existent. Error:", err) + } + }) + + t.Run("get files by name when the path is a file", func(t *testing.T) { + path1 := "testdata/validfiles/test1.yaml" + filepaths, err := common.GetFilesByName(path1, []string{"test1.yaml", "test2.yml"}) + if err != nil { + t.Fatal("Should not have given any error. Error:", err) + } + if len(filepaths) != 1 || filepaths[0] != path1 { + t.Fatal("Failed to get the correct paths. Expected:", path1, "Actual:", filepaths) + } + }) + + t.Run("get files by name in the normal use case", func(t *testing.T) { + path1 := "testdata/validfiles" + filepaths, err := common.GetFilesByName(path1, []string{"test1.yaml", "test2.yml"}) + if err != nil { + t.Fatal("Should not have given any error. Error:", err) + } + want := []string{"testdata/validfiles/test1.yaml", "testdata/validfiles/test2.yml"} + if !reflect.DeepEqual(filepaths, want) { + t.Fatal("Failed to get the correct paths. Expected:", want, "Actual:", filepaths) + } + }) + + t.Run("get files by name when the directory is empty", func(t *testing.T) { + path1 := t.TempDir() + filepaths, err := common.GetFilesByName(path1, []string{"test1.yaml", "test2.yml"}) + if err != nil { + t.Fatal("Should not have given any error. Error:", err) + } + if len(filepaths) != 0 { + t.Fatal("Should not have returned any paths. Paths returned:", filepaths) + } + }) + + // TODO: do we need to handle this edge case? + // t.Run("get files by name when you don't have permissions for the directory", func(t *testing.T) { + // parentDir := t.TempDir() + // path1 := filepath.Join(parentDir, "app1") + // if err := os.Mkdir(path1, 0); err != nil { + // t.Fatal("Failed to create the temporary directory", path1, "for testing. Error:", err) + // } + // if _, err := common.GetFilesByName(path1, []string{"test1.yaml", "test2.yml"}); err == nil { + // t.Fatal("Should have given an error since we don't have permissions to read the directory.") + // } + // }) +} + +func TestYamlAttrPresent(t *testing.T) { + log.SetLevel(log.DebugLevel) + + t.Run("get attribute from non existent path", func(t *testing.T) { + path1 := "foobar" + attr1 := "attr1" + if ok, _ := common.YamlAttrPresent(path1, attr1); ok { + t.Fatal("Should not have succeeded. The file", path1, "does not exist.") + } + }) + + t.Run("get attribute from invalid yaml file", func(t *testing.T) { + path1 := "testdata/invalidfiles/test1.yaml" + attr1 := "attr1" + if ok, _ := common.YamlAttrPresent(path1, attr1); ok { + t.Fatal("Should not have succeeded. The file", path1, "is not a valid yaml file.") + } + }) + + t.Run("get non existent attribute from yaml file", func(t *testing.T) { + path1 := "testdata/validfiles/test1.yaml" + attr1 := "attr1" + if ok, _ := common.YamlAttrPresent(path1, attr1); ok { + t.Fatal("Should not have succeeded. The file", path1, "does not contain the attribute", attr1) + } + }) + + t.Run("get attribute from yaml file", func(t *testing.T) { + path1 := "testdata/validfiles/test1.yaml" + attr1 := "kind" + want := "ClusterMetadata" + if ok, val := common.YamlAttrPresent(path1, attr1); !ok || val != want { + t.Fatal("Failed to get the attribute", attr1, "from the file", path1, "properly. Expected:", want, "Actual:", val) + } + }) +} + +func TestGetImageNameAndTag(t *testing.T) { + log.SetLevel(log.DebugLevel) + + t.Run("get imagename and tag", func(t *testing.T) { + wantImageName := "getting-started" + wantTag := "1.2.3-alpha.beta.gamma+hello.123.world" + imageNameAndTag := "konveyor/" + wantImageName + ":" + wantTag + imageName, tag := common.GetImageNameAndTag(imageNameAndTag) + if imageName != wantImageName { + t.Fatal("Tag is incorrect. Expected:", wantImageName, "Actual:", imageName) + } else if tag != wantTag { + t.Fatal("Tag is incorrect. Expected:", wantTag, "Actual:", tag) + } + }) + + t.Run("get imagename and tag when there is no tag", func(t *testing.T) { + wantImageName := "getting-started" + wantTag := "latest" + imageNameAndTag := "konveyor/" + wantImageName + imageName, tag := common.GetImageNameAndTag(imageNameAndTag) + if imageName != wantImageName { + t.Fatal("Tag is incorrect. Expected:", wantImageName, "Actual:", imageName) + } else if tag != wantTag { + t.Fatal("Tag is incorrect. Expected:", wantTag, "Actual:", tag) + } + }) + +} + +type givesYamlError struct{} + +func (_ *givesYamlError) MarshalYAML() (interface{}, error) { + return nil, fmt.Errorf("Can't marshal this type to yaml.") +} + +func TestWriteYaml(t *testing.T) { + log.SetLevel(log.DebugLevel) + + t.Run("write some data to an invalid path", func(t *testing.T) { + path1 := "/this/does/not/exist/foobar.yaml" + data1 := "contents1" + if err := common.WriteYaml(path1, data1); err == nil { + t.Fatal("Should not have succeeded since the path", path1, "is invalid.") + } + }) + + t.Run("write some data to a yaml file", func(t *testing.T) { + path1 := t.TempDir() + "foobar.yaml" + data1 := struct { + Foo string + Bar int + }{"contents1", 42} + if err := common.WriteYaml(path1, data1); err != nil { + t.Fatal("Failed to write the data", data1, "to the file path", path1, ". Error:", err) + } + want := "foo: contents1\nbar: 42\n" + if yamldata, err := ioutil.ReadFile(path1); err != nil { + t.Fatal("Failed to read the file we just wrote. Error:", err) + } else if yamldatastr := string(yamldata); yamldatastr != want { + t.Fatal("Failed to encode the data to yaml properly. Expected:", want, "Actual:", yamldatastr) + } + }) + + t.Run("write some data that cannot be encoded to yaml to file", func(t *testing.T) { + path1 := t.TempDir() + "foobar.yaml" + data1 := &givesYamlError{} + if err := common.WriteYaml(path1, data1); err == nil { + t.Fatal("Should not have succeeded since the data", data1, "cannot be marshalled to yaml.") + } + }) +} + +func TestReadYaml(t *testing.T) { + log.SetLevel(log.DebugLevel) + + t.Run("read some data from non existent path", func(t *testing.T) { + path1 := "foobar" + data1 := struct { + Name string + Tag string + }{"foo", "bar"} + if err := common.ReadYaml(path1, &data1); err == nil { + t.Fatal("Should not have succeeded. The file", path1, "does not exist.") + } + }) + + t.Run("read some data from invalid yaml file", func(t *testing.T) { + path1 := "testdata/invalidfiles/test1.yaml" + data1 := struct { + Name string + Tag string + }{"foo", "bar"} + if err := common.ReadYaml(path1, &data1); err == nil { + t.Fatal("Should not have succeeded. The file", path1, "is not a valid yaml file.") + } + }) + + t.Run("read some non existent keys from yaml file", func(t *testing.T) { + path1 := "testdata/validfiles/test1.yaml" + data1 := struct { + Name string + Tag string + }{"foo", "bar"} + want := struct { + Name string + Tag string + }{"foo", "bar"} + if err := common.ReadYaml(path1, &data1); err != nil { + t.Fatal("Failed to read yaml from the file", path1, "Error:", err) + } + if data1 != want { + t.Fatal("Failed to read the data properly. Expected:", want, "Actual:", data1) + } + }) + + t.Run("read some data from yaml file", func(t *testing.T) { + path1 := "testdata/validfiles/test1.yaml" + data1 := struct { + Kind string `yaml:"kind"` + ContextName string `yaml:"contextName"` + }{"foo", "bar"} + want := struct { + Kind string `yaml:"kind"` + ContextName string `yaml:"contextName"` + }{"ClusterMetadata", "name1"} + if err := common.ReadYaml(path1, &data1); err != nil { + t.Fatal("Failed to read yaml from the file", path1, "Error:", err) + } + if data1 != want { + t.Fatal("Failed to read the data properly. Expected:", want, "Actual:", data1) + } + }) + + t.Run("read version info from yaml file", func(t *testing.T) { + path1 := "testdata/validfiles/versioninfo.yaml" + data1 := info.VersionInfo{Version: "0.0.0", GitCommit: "0.0.0", GitTreeState: "0.0.0", GoVersion: "0.0.0"} + want := info.VersionInfo{Version: "0.0.0", GitCommit: "1.0.0", GitTreeState: "1.1.0", GoVersion: "1.1.1"} + if err := common.ReadYaml(path1, &data1); err != nil { + t.Fatal("Failed to read yaml from the file", path1, "Error:", err) + } + if data1 != want { + t.Fatal("Failed to read the data properly. Expected:", want, "Actual:", data1) + } + }) +} + +type givesJSONError struct{} + +func (_ *givesJSONError) MarshalJSON() ([]byte, error) { + return nil, fmt.Errorf("Can't marshal this type to json.") +} + +func TestWriteJSON(t *testing.T) { + log.SetLevel(log.DebugLevel) + + t.Run("write some data to an invalid path", func(t *testing.T) { + path1 := "/this/does/not/exist/foobar.json" + data1 := "contents1" + if err := common.WriteJSON(path1, data1); err == nil { + t.Fatal("Should not have succeeded since the path", path1, "is invalid.") + } + }) + + t.Run("write some data to a json file", func(t *testing.T) { + path1 := t.TempDir() + "foobar.json" + data1 := struct { + Foo string + Bar int + }{"contents1", 42} + if err := common.WriteJSON(path1, data1); err != nil { + t.Fatal("Failed to write the data", data1, "to the file path", path1, ". Error:", err) + } + want := "{\"Foo\":\"contents1\",\"Bar\":42}\n" + if yamldata, err := ioutil.ReadFile(path1); err != nil { + t.Fatal("Failed to read the file we just wrote. Error:", err) + } else if yamldatastr := string(yamldata); yamldatastr != want { + //log.Errorf("%q", yamldatastr) + t.Fatal("Failed to encode the data to json properly. Expected:", want, "Actual:", yamldatastr) + } + }) + + t.Run("write some data that cannot be encoded to json to file", func(t *testing.T) { + path1 := t.TempDir() + "foobar.json" + data1 := &givesJSONError{} + if err := common.WriteJSON(path1, data1); err == nil { + t.Fatal("Should not have succeeded since the data", data1, "cannot be marshalled to json.") + } + }) +} + +func TestReadJSON(t *testing.T) { + log.SetLevel(log.DebugLevel) + + t.Run("read some data from non existent path", func(t *testing.T) { + path1 := "foobar" + data1 := struct { + Name string + Foo int + Bar []string + }{} + if err := common.ReadJSON(path1, &data1); err == nil { + t.Fatal("Should not have succeeded. The file", path1, "does not exist.") + } + }) + + t.Run("read some data from invalid json file", func(t *testing.T) { + path1 := "testdata/invalidfiles/test1.json" + data1 := struct { + Name string + Foo int + Bar []string + }{} + if err := common.ReadJSON(path1, &data1); err == nil { + t.Fatal("Should not have succeeded. The file", path1, "is not a valid json file.") + } + }) + + t.Run("read some non existent keys from json file", func(t *testing.T) { + path1 := "testdata/validfiles/test1.json" + data1 := struct { + Key1 string + Key2 string + }{"foo", "bar"} + want := struct { + Key1 string + Key2 string + }{"foo", "bar"} + if err := common.ReadJSON(path1, &data1); err != nil { + t.Fatal("Failed to read json from the file", path1, "Error:", err) + } + if data1 != want { + t.Fatal("Failed to read the data properly. Expected:", want, "Actual:", data1) + } + }) + + t.Run("read some data from json file", func(t *testing.T) { + path1 := "testdata/validfiles/test1.json" + data1 := struct { + Name string + Foo int + Bar []string + }{} + want := struct { + Name string + Foo int + Bar []string + }{"name1", 42, []string{"bar"}} + if err := common.ReadJSON(path1, &data1); err != nil { + t.Fatal("Failed to read json from the file", path1, "Error:", err) + } + if !reflect.DeepEqual(data1, want) { + t.Fatal("Failed to read the data properly. Expected:", want, "Actual:", data1) + } + }) + + t.Run("read version info from json file", func(t *testing.T) { + path1 := "testdata/validfiles/versioninfo.json" + data1 := info.VersionInfo{Version: "0.0.0", GitCommit: "0.0.0", GitTreeState: "0.0.0", GoVersion: "0.0.0"} + want := info.VersionInfo{Version: "0.0.0", GitCommit: "1.0.0", GitTreeState: "1.1.0", GoVersion: "1.1.1"} + if err := common.ReadJSON(path1, &data1); err != nil { + t.Fatal("Failed to read json from the file", path1, "Error:", err) + } + if data1 != want { + t.Fatal("Failed to read the data properly. Expected:", want, "Actual:", data1) + } + }) +} + +func TestNormalizeForFilename(t *testing.T) { + log.SetLevel(log.DebugLevel) + + tcs := []struct{ name, in, out string }{ + {"normalize an invalid filename", "foobar%${/2\n\tinv.json.yaml.", "2-inv.json.yaml_d65d80a1c389718f"}, + {"normalize a valid filename", "foobar", "foobar_534a426c0464b01e"}, + {"normalize a long valid filename", "thisisalongfilenamefoobar", "thisisalongfile_730bb88a395ce114"}, + {"normalize a valid filename with an extension", "foobar.json", "foobar.json_f161da8efa921f1f"}, + {"normalize a valid filepath", "path/to/a/file/foobar.json", "foobar.json_b1760918996ebb3"}, + } + for _, tc := range tcs { + t.Run(tc.name, func(t *testing.T) { + output := common.NormalizeForFilename(tc.in) + if output != tc.out { + t.Fatalf("Failed to normalize the string %q properly. Expected: %q Actual: %q", tc.in, tc.out, output) + } + }) + } +} + +func TestNormalizeForServiceName(t *testing.T) { + log.SetLevel(log.DebugLevel) + + tcs := []struct{ name, in, out string }{ + // {"normalize an invalid service name", "foobar%${/2\n\tinv.website.registration.", "foobar%${/2\n\tinv-website-registration-"}, // TODO: does this edge case have to be handled? + {"normalize an invalid service name", "foobar.website.registration.", "foobar-website-registration-"}, + {"normalize a valid service name", "foobar", "foobar"}, + {"normalize a long valid service name", "thisisalongservicenamefoobar", "thisisalongservicenamefoobar"}, + } + for _, tc := range tcs { + t.Run(tc.name, func(t *testing.T) { + output := common.NormalizeForServiceName(tc.in) + if output != tc.out { + t.Fatalf("Failed to normalize the string %q properly. Expected: %q Actual: %q", tc.in, tc.out, output) + } + }) + } +} + +func TestIsStringPresent(t *testing.T) { + log.SetLevel(log.DebugLevel) + + tcs := []struct { + name string + inArr []string + inQuery string + out bool + }{ + {"find a string in the array", []string{"foo", "bar"}, "foo", true}, + {"find a non existent string in the array", []string{"foo", "bar"}, "str1", false}, + } + for _, tc := range tcs { + t.Run(tc.name, func(t *testing.T) { + found := common.IsStringPresent(tc.inArr, tc.inQuery) + if found != tc.out { + if tc.out { + t.Fatalf("Failed to find the string %q in the array %v", tc.inQuery, tc.inArr) + } else { + t.Fatalf("Should not have found the string %q in the array %v", tc.inQuery, tc.inArr) + } + } + }) + } +} + +func TestIsIntPresent(t *testing.T) { + log.SetLevel(log.DebugLevel) + + tcs := []struct { + name string + inArr []int + inQuery int + out bool + }{ + {"find a int in an empty array", []int{}, 0, false}, + {"find a int in an array", []int{100, 0, 1, -1, -42}, 0, true}, + {"find a non existent int in an array", []int{100, 0, 1, -1, -42}, 200, false}, + {"find a int in an array when there are duplicates", []int{100, 0, -42, -42, 1}, -42, true}, + } + for _, tc := range tcs { + t.Run(tc.name, func(t *testing.T) { + found := common.IsIntPresent(tc.inArr, tc.inQuery) + if found != tc.out { + if tc.out { + t.Fatalf("Failed to find the int %d in the array %v", tc.inQuery, tc.inArr) + } else { + t.Fatalf("Should not have found the int %d in the array %v", tc.inQuery, tc.inArr) + } + } + }) + } +} + +func TestMergeStringSlices(t *testing.T) { + log.SetLevel(log.DebugLevel) + + tcs := []struct { + name string + inArr1 []string + inArr2 []string + out []string + }{ + {"merge 2 empty arrays", []string{}, []string{}, []string{}}, + {"merge a filled array into an empty array", []string{}, []string{"foo", "bar"}, []string{"foo", "bar"}}, + {"merge an empty array into a filled array", []string{"foo", "bar"}, []string{}, []string{"foo", "bar"}}, + {"merge 2 filled arrays", []string{"foo", "bar"}, []string{"foo", "bar", "item1", "item2"}, []string{"foo", "bar", "item1", "item2"}}, + } + for _, tc := range tcs { + t.Run(tc.name, func(t *testing.T) { + merged := common.MergeStringSlices(tc.inArr1, tc.inArr2) + if !reflect.DeepEqual(merged, tc.out) { + t.Fatalf("Failed to merge the arrays properly. Array1: %v Array2: %v Expected: %v Actual: %v", tc.inArr1, tc.inArr2, tc.out, merged) + } + }) + } +} + +func TestMergeIntSlices(t *testing.T) { + log.SetLevel(log.DebugLevel) + + tcs := []struct { + name string + inArr1 []int + inArr2 []int + out []int + }{ + {"merge 2 empty arrays", []int{}, []int{}, []int{}}, + {"merge a filled array into an empty array", []int{}, []int{100, 0}, []int{100, 0}}, + {"merge an empty array into a filled array", []int{100, -42, -1, 0}, []int{}, []int{100, -42, -1, 0}}, + {"merge 2 filled arrays", []int{100, -42, -1, 0}, []int{10, -1, -1, 0, 2}, []int{100, -42, -1, 0, 10, 2}}, + } + for _, tc := range tcs { + t.Run(tc.name, func(t *testing.T) { + merged := common.MergeIntSlices(tc.inArr1, tc.inArr2) + if !reflect.DeepEqual(merged, tc.out) { + t.Fatalf("Failed to merge the arrays properly. Array1: %v Array2: %v Expected: %v Actual: %v", tc.inArr1, tc.inArr2, tc.out, merged) + } + }) + } +} + +func TestGetStringFromTemplate(t *testing.T) { + log.SetLevel(log.DebugLevel) + + tcs := []struct { + name string + inTmpl string + inData interface{} + outStr string + outErr bool + }{ + {"fill an empty template with an empty string", "", "", "", false}, + {"fill an empty template with an empty struct with no fields", "", struct{}{}, "", false}, + {"fill an empty template with an empty struct", "", struct { + Name string + ID int + }{}, "", false}, + {"fill an empty template with a filled struct", "", struct { + Name string + ID int + }{"foobar", 42}, "", false}, + {"fill a template with an empty struct with no fields", "Hello! My name is {{.Name}} and my ID is {{.ID}}", struct{}{}, "", true}, + {"fill a template with an empty struct", "Hello! My name is {{.Name}} and my ID is {{.ID}}", struct { + Name string + ID int + }{}, "Hello! My name is and my ID is 0", false}, + {"fill a template with a filled struct", "Hello! My name is {{.Name}} and my ID is {{.ID}}", struct { + Name string + ID int + }{"foobar", 42}, "Hello! My name is foobar and my ID is 42", false}, + } + for _, tc := range tcs { + t.Run(tc.name, func(t *testing.T) { + filled, err := common.GetStringFromTemplate(tc.inTmpl, tc.inData) + if !tc.outErr { + if err != nil { + t.Fatalf("Got an error while trying to fill the tempate %q with the data %v properly. Expected: %q Actual: Error: %v", tc.inTmpl, tc.inData, tc.outStr, err) + } + if filled != tc.outStr { + t.Fatalf("Failed to fill the tempate %q with the data %v properly. Expected: %q Actual: %v", tc.inTmpl, tc.inData, tc.outStr, filled) + } + } else { + if err == nil { + t.Fatalf("Should not have succeeded in filling the tempate %q with the data %v. Expected an error. Actual: %v", tc.inTmpl, tc.inData, filled) + } + } + }) + } +} + +func TestWriteTemplateToFile(t *testing.T) { + log.SetLevel(log.DebugLevel) + + tcs := []struct { + name string + inTmpl string + inData interface{} + outStr string + outErr bool + }{ + {"fill an empty template with an empty string", "", "", "", false}, + {"fill an empty template with an empty struct with no fields", "", struct{}{}, "", false}, + {"fill an empty template with an empty struct", "", struct { + Name string + ID int + }{}, "", false}, + {"fill an empty template with a filled struct", "", struct { + Name string + ID int + }{"foobar", 42}, "", false}, + {"fill a template with an empty struct with no fields", "Hello! My name is {{.Name}} and my ID is {{.ID}}", struct{}{}, "", true}, + {"fill a template with an empty struct", "Hello! My name is {{.Name}} and my ID is {{.ID}}", struct { + Name string + ID int + }{}, "Hello! My name is and my ID is 0", false}, + {"fill a template with a filled struct", "Hello! My name is {{.Name}} and my ID is {{.ID}}", struct { + Name string + ID int + }{"foobar", 42}, "Hello! My name is foobar and my ID is 42", false}, + } + for _, tc := range tcs { + t.Run(tc.name, func(t *testing.T) { + path := t.TempDir() + "test1.go" + err := common.WriteTemplateToFile(tc.inTmpl, tc.inData, path, os.ModePerm) + if !tc.outErr { + if err != nil { + t.Fatalf("Got an error while trying to fill the tempate %q with the data %v and write it to the path %q. Expected: %q Actual: Error: %v", tc.inTmpl, tc.inData, path, tc.outStr, err) + } + filledBytes, err := ioutil.ReadFile(path) + if err != nil { + t.Fatalf("Failed to read the file %q that we just wrote.", path) + } + if filled := string(filledBytes); filled != tc.outStr { + t.Fatalf("Failed to fill the tempate %q with the data %v properly. Expected: %q Actual: %v", tc.inTmpl, tc.inData, tc.outStr, filled) + } + } else { + if err == nil { + t.Fatalf("Should not have succeeded in filling the tempate %q with the data %v. Expected an error.", tc.inTmpl, tc.inData) + } + } + }) + } + t.Run("try to write filled template when the path doesn't exist", func(t *testing.T) { + inTmpl := "Hello! My name is {{.Name}} and my ID is {{.ID}}" + inData := struct { + Name string + ID int + }{"foobar", 42} + path := "/this/path/does/not/exist/foobar" + err := common.WriteTemplateToFile(inTmpl, inData, path, os.ModePerm) + if err == nil { + t.Fatalf("Should not have succeeded in writing to the path %q since it doesn't exit. Expected an error.", path) + } + }) +} + +func TestGetClosestMatchingString(t *testing.T) { + log.SetLevel(log.DebugLevel) + + tcs := []struct { + name string + inArr []string + inQuery string + out string + }{ + {"find the closest in an empty array", []string{}, "foo", ""}, + {"find the closest in the array when the string exists", []string{"foo", "bar"}, "foo", "foo"}, + {"find the closest in the array when the string doesn't exist", []string{"foo", "bar"}, "bar2", "bar"}, + } + + for _, tc := range tcs { + t.Run(tc.name, func(t *testing.T) { + foundStr := common.GetClosestMatchingString(tc.inArr, tc.inQuery) + if foundStr != tc.out { + t.Fatalf("Failed to find the closest string to %q in the array %v. Expected: %q Actual: %q", tc.inQuery, tc.inArr, tc.out, foundStr) + } + }) + } +} + +func TestMergeStringMaps(t *testing.T) { + log.SetLevel(log.DebugLevel) + + type mss = map[string]string + tcs := []struct { + name string + inMap1 mss + inMap2 mss + out mss + }{ + {"merge 2 empty maps", mss{}, mss{}, mss{}}, + {"merge a filled map into an empty map", mss{}, mss{"key1": "val1"}, mss{"key1": "val1"}}, + {"merge an empty map into a filled map", mss{"key1": "val1"}, mss{}, mss{"key1": "val1"}}, + {"merge 2 filled maps", mss{"key1": "val1", "key2": "val2"}, mss{"key2": "newval2", "key3": "val3"}, mss{"key1": "val1", "key2": "newval2", "key3": "val3"}}, + } + for _, tc := range tcs { + t.Run(tc.name, func(t *testing.T) { + merged := common.MergeStringMaps(tc.inMap1, tc.inMap2) + if !reflect.DeepEqual(merged, tc.out) { + t.Fatalf("Failed to merge the maps properly. Map1: %v Map2: %v Expected: %v Actual: %v", tc.inMap1, tc.inMap2, tc.out, merged) + } + }) + } +} + +func TestMakeFileNameCompliant(t *testing.T) { + log.SetLevel(log.DebugLevel) + + tcs := []struct { + name string + in string + out string + }{ + {"normalize an empty name", "", ""}, + {"normalize an invalid name", "foo\n123.bar%4.inv#22.-", "foo-123.bar-4.inv-22.-"}, + {"normalize an invalid name", "foo/bar/", "bar"}, + {"normalize an invalid name", "path/prefix/foo_bar_baz", "foo-bar-baz"}, + {"normalize a valid name", "foo.bar.baz", "foo.bar.baz"}, + {"normalize a valid long name", "01234567890123456789012345678901234567890123456789012345678901234567890123456789", "01234567890123456789012345678901234567890123456789012345678901234567890123456789"}, + } + for _, tc := range tcs { + t.Run(tc.name, func(t *testing.T) { + output := common.MakeFileNameCompliant(tc.in) + if output != tc.out { + t.Fatalf("Failed to normalize the string %q to DNS-1123 standard properly. Expected: %q Actual: %q", tc.in, tc.out, output) + } + }) + } +} + +func TestCleanAndFindCommonDirectory(t *testing.T) { + log.SetLevel(log.DebugLevel) + + tcs := []struct { + name string + in []string + out string + }{ + {"find common directory when list is empty", []string{}, ""}, + {"normal use case", []string{"/foo/bar/baz", "/foo/bar", "/foo"}, "/foo"}, + {"normal use case and common directory is root", []string{"/foo/bar/baz", "/foo/bar", "/app1/service1/module1"}, "/"}, + {"find common directory when list has unclean paths", []string{"/app1/./service1/", "/app1/service1/module2/", "/app1/./service1/../service1/module1"}, "/app1/service1"}, + {"find common directory when list has unclean paths and common directory is root", []string{"/foo/bar///baz", "/foo/bar///.", "/app1/./service1/../service1/module1"}, "/"}, + {"list has identical paths", []string{"/foo/bar/baz", "/foo/bar/baz", "/foo/bar/baz"}, "/foo/bar/baz"}, + {"list contains root", []string{"/", "/.", "/..", "/.app/.bar", "/.app/.bar"}, "/"}, + {"list contains root", []string{"/foo/bar", "/", "/foo/bar/baz"}, "/"}, + {"list has identical but unclean paths", []string{"/foo/bar/baz////", "/foo/bar/baz", "/foo/bar/baz/././../baz/"}, "/foo/bar/baz"}, + } + for _, tc := range tcs { + t.Run(tc.name, func(t *testing.T) { + output := common.CleanAndFindCommonDirectory(tc.in) + if output != tc.out { + t.Fatal("Expected:", tc.out, "Actual:", output) + } + }) + } +} + +func TestFindCommonDirectory(t *testing.T) { + log.SetLevel(log.DebugLevel) + + tcs := []struct { + name string + in []string + out string + }{ + {"find common directory when list is empty", []string{}, ""}, + {"normal use case", []string{"/foo/bar/baz", "/foo/bar", "/foo"}, "/foo"}, + {"normal use case and common directory is root", []string{"/foo/bar/baz", "/foo/bar", "/app1/service1/module1"}, "/"}, + {"list has identical paths", []string{"/foo/bar/baz", "/foo/bar/baz", "/foo/bar/baz"}, "/foo/bar/baz"}, + } + for _, tc := range tcs { + t.Run(tc.name, func(t *testing.T) { + output := common.FindCommonDirectory(tc.in) + if output != tc.out { + t.Fatal("Expected:", tc.out, "Actual:", output) + } + }) + } +} diff --git a/internal/containerizer/cnb/containerruntimeprovider.go b/internal/containerizer/cnb/containerruntimeprovider.go new file mode 100644 index 000000000..12c1c999b --- /dev/null +++ b/internal/containerizer/cnb/containerruntimeprovider.go @@ -0,0 +1,133 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package cnb + +import ( + "errors" + "fmt" + "os/exec" + "path/filepath" + + log "github.com/sirupsen/logrus" + + "github.com/konveyor/move2kube/internal/common" +) + +type containerRuntimeProvider struct { +} + +var ( + containerRuntime = "" + availableBuilders = []string{} +) + +func (r *containerRuntimeProvider) getAllBuildpacks(builders []string) (map[string][]string, error) { //[Containerization target option value] buildpacks + buildpacks := make(map[string][]string) + containerRuntime, available := r.getContainerRuntime() + if !available { + return buildpacks, errors.New("Container runtime not supported in this instance") + } + log.Debugf("Getting data of all builders %s", builders) + for _, builder := range builders { + inspectcmd := exec.Command(containerRuntime, "inspect", "--format", `{{ index .Config.Labels "`+orderLabel+`"}}`, builder) + log.Debugf("Inspecting image %s", builder) + output, err := inspectcmd.CombinedOutput() + if err != nil { + log.Debugf("Unable to inspect image %s : %s, %s", builder, err, output) + continue + } + buildpacks[builder] = getBuildersFromLabel(string(output)) + } + + return buildpacks, nil +} + +func (r *containerRuntimeProvider) getContainerRuntime() (runtime string, available bool) { + if containerRuntime == "" { + detectcmd := exec.Command("docker", "run", "--rm", "hello-world") + output, err := detectcmd.CombinedOutput() + if err != nil { + log.Debugf("Docker not supported : %s : %s", err, output) + detectcmd := exec.Command("podman", "run", "--rm", "hello-world") + output, err = detectcmd.CombinedOutput() + if err != nil { + log.Debugf("Podman not supported : %s : %s", err, output) + containerRuntime = "none" + return containerRuntime, false + } + containerRuntime = "podman" + return containerRuntime, true + } + containerRuntime = "docker" + return containerRuntime, true + } else if containerRuntime == "none" { + return containerRuntime, false + } + return containerRuntime, true +} + +func (r *containerRuntimeProvider) isBuilderAvailable(builder string) bool { + containerRuntime, available := r.getContainerRuntime() + if !available { + return false + } + if common.IsStringPresent(availableBuilders, builder) { + return true + } + // Check if the image exists locally + existcmd := exec.Command(containerRuntime, "images", "-q", builder) + log.Debugf("Checking if the image %s exists locally", builder) + output, err := existcmd.Output() + if err != nil { + log.Warnf("Error while checking if the builder %s exists locally. Error: %q Output: %q", builder, err, output) + return false + } + if len(output) > 0 { + // Found the image in the local machine, no need to pull. + availableBuilders = append(availableBuilders, builder) + return true + } + + pullcmd := exec.Command(containerRuntime, "pull", builder) + log.Debugf("Pulling image %s", builder) + output, err = pullcmd.CombinedOutput() + if err != nil { + log.Warnf("Error while pulling builder %s : %s : %s", builder, err, output) + return false + } + availableBuilders = append(availableBuilders, builder) + return true +} + +func (r *containerRuntimeProvider) isBuilderSupported(path string, builder string) (bool, error) { + if !r.isBuilderAvailable(builder) { + return false, fmt.Errorf("Builder image not available : %s", builder) + } + containerRuntime, _ := r.getContainerRuntime() + p, err := filepath.Abs(path) + if err != nil { + log.Warnf("Unable to resolve to absolute path : %s", err) + } + detectcmd := exec.Command(containerRuntime, "run", "--rm", "-v", p+":/workspace", builder, "/cnb/lifecycle/detector") + log.Debugf("Running detect on image %s", builder) + output, err := detectcmd.CombinedOutput() + if err != nil { + log.Debugf("Detect failed %s : %s : %s", builder, err, output) + return false, nil + } + return true, nil +} diff --git a/internal/containerizer/cnb/containerruntimeprovider_test.go b/internal/containerizer/cnb/containerruntimeprovider_test.go new file mode 100644 index 000000000..597b5c0ed --- /dev/null +++ b/internal/containerizer/cnb/containerruntimeprovider_test.go @@ -0,0 +1,63 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package cnb + +import ( + "reflect" + "testing" + + log "github.com/sirupsen/logrus" +) + +func TestIsBuilderAvailable(t *testing.T) { + log.SetLevel(log.DebugLevel) + + t.Run("normal use case", func(t *testing.T) { + provider := containerRuntimeProvider{} + builder := "cloudfoundry/cnb:cflinuxfs3" + + // Test + if !provider.isBuilderAvailable(builder) { + t.Fatalf("Failed to find the builder %q locally and/or pull it.", builder) + } + }) + + t.Run("normal use case where we get result from cache", func(t *testing.T) { + provider := containerRuntimeProvider{} + builder := "cloudfoundry/cnb:cflinuxfs3" + want := []string{builder} + + // Test + if !provider.isBuilderAvailable(builder) { + t.Fatalf("Failed to find the builder %q locally and/or pull it.", builder) + } + if !reflect.DeepEqual(availableBuilders, want) { + t.Fatalf("Failed to add the builder %q to the list of available builders. Expected: %v Actual %v", builder, want, availableBuilders) + } + if !provider.isBuilderAvailable(builder) { + t.Fatalf("Failed to find the builder %q locally and/or pull it.", builder) + } + }) + + t.Run("check for a non existent image", func(t *testing.T) { + provider := containerRuntimeProvider{} + builder := "this/doesnotexist:foobar" + if provider.isBuilderAvailable(builder) { + t.Fatalf("Should not have succeeded. The builder image %q does not exist", builder) + } + }) +} diff --git a/internal/containerizer/cnb/packprovider.go b/internal/containerizer/cnb/packprovider.go new file mode 100644 index 000000000..81edc4572 --- /dev/null +++ b/internal/containerizer/cnb/packprovider.go @@ -0,0 +1,145 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package cnb + +import ( + "bufio" + "errors" + "os" + "os/exec" + "regexp" + "strings" + "sync" + + "github.com/konveyor/move2kube/types" + log "github.com/sirupsen/logrus" +) + +const ( + dockersock = "/var/run/docker.sock" +) + +type packProvider struct { +} + +func (p *packProvider) isAvailable() bool { + _, err := exec.LookPath("pack") + if err != nil { + log.Debugf("Unable to find pack : %s", err) + return false + } + _, err = os.Stat(dockersock) + if os.IsNotExist(err) { + log.Debugf("Unable to find pack docker socket, ignoring CNB based containerization approach : %s", err) + return false + } + return true +} + +func (p *packProvider) isBuilderSupported(path string, builder string) (bool, error) { + if !p.isAvailable() { + return false, errors.New("Pack not supported in this instance") + } + cmd := exec.Command("pack", "build", types.AppNameShort+"testcflinuxf2selector:1", "-B", builder, "-p", path) + + var wg sync.WaitGroup + + stdout, err := cmd.StdoutPipe() + if err != nil { + log.Errorf("RunCommand: cmd.StdoutPipe(): %v", err) + return false, err + } + stderr, err := cmd.StderrPipe() + if err != nil { + log.Errorf("RunCommand: cmd.StderrPipe(): %v", err) + return false, err + } + + if err := cmd.Start(); err != nil { + log.Errorf("RunCommand: cmd.Start(): %v", err) + return false, err + } + + outch := make(chan string, 10) + + scannerStdout := bufio.NewScanner(stdout) + scannerStdout.Split(bufio.ScanLines) + wg.Add(1) + go func() { + for scannerStdout.Scan() { + text := scannerStdout.Text() + if strings.TrimSpace(text) != "" { + outch <- text + } + } + wg.Done() + }() + scannerStderr := bufio.NewScanner(stderr) + scannerStderr.Split(bufio.ScanLines) + wg.Add(1) + go func() { + for scannerStderr.Scan() { + text := scannerStderr.Text() + if strings.TrimSpace(text) != "" { + outch <- text + } + } + wg.Done() + }() + + go func() { + wg.Wait() + close(outch) + }() + + for t := range outch { + log.Debug(t) + if strings.Contains(t, "===> ANALYZING") { + log.Debugf("Found compatible cnb for %s", path) + _ = cmd.Process.Kill() + return true, nil + } + if strings.Contains(t, "No buildpack groups passed detection.") { + log.Debugf("No compatible cnb for %s", path) + _ = cmd.Process.Kill() + return false, nil + } + } + return false, errors.New("Error while using pack") +} + +func (p *packProvider) getAllBuildpacks(builders []string) (map[string][]string, error) { //[Containerization target option value] buildpacks + buildpacks := make(map[string][]string) + log.Debugf("Getting data of all builders %s", builders) + for _, builder := range builders { + cmd := exec.Command("pack", "inspect-builder", string(builder)) + var buildpackregex = regexp.MustCompile(`(?s)Group\s#\d+:[\r\n\s]+[^\s]+`) + outputStr, err := cmd.Output() + log.Debugf("Builder %s data :%s", builder, outputStr) + if err != nil { + log.Warnf("Error while getting supported buildpacks for builder %s : %s", builder, err) + continue + } + buildpackmatches := buildpackregex.FindAllString(string(outputStr), -1) + log.Debugf("Builder %s data :%s", builder, buildpackmatches) + for _, buildpackmatch := range buildpackmatches { + buildpackfields := strings.Fields(buildpackmatch) + buildpacks[builder] = append(buildpacks[builder], buildpackfields[len(buildpackfields)-1]) + } + } + return buildpacks, nil +} diff --git a/internal/containerizer/cnb/provider.go b/internal/containerizer/cnb/provider.go new file mode 100644 index 000000000..60ddb4296 --- /dev/null +++ b/internal/containerizer/cnb/provider.go @@ -0,0 +1,109 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package cnb + +import ( + "encoding/json" + + log "github.com/sirupsen/logrus" +) + +const ( + orderLabel string = "io.buildpacks.buildpack.order" +) + +var cnbwarnnotsupported = false +var cnbwarnlongwait = true +var cnbproviders = []provider{&containerRuntimeProvider{}, &packProvider{}, &runcProvider{}} + +type order []orderEntry + +type orderEntry struct { + Group []buildpackRef `toml:"group" json:"group"` +} + +type buildpackRef struct { + buildpackInfo + Optional bool `toml:"optional,omitempty" json:"optional,omitempty"` +} + +type buildpackInfo struct { + ID string `toml:"id" json:"id,omitempty"` + Version string `toml:"version" json:"version,omitempty"` + Homepage string `toml:"homepage,omitempty" json:"homepage,omitempty"` +} + +type provider interface { + isBuilderSupported(path string, builder string) (bool, error) + getAllBuildpacks(builders []string) (map[string][]string, error) +} + +// GetAllBuildpacks returns all buildpacks supported +func GetAllBuildpacks(builders []string) (buildpacks map[string][]string) { + for _, cp := range cnbproviders { + buildpacks, err := cp.getAllBuildpacks(builders) + if err == nil && len(buildpacks) > 0 { + return buildpacks + } + } + logCNBNotSupported() + return buildpacks +} + +// IsBuilderSupported returns if a builder supports a path +func IsBuilderSupported(path string, builder string) (valid bool) { + logCNBLongWait() + for _, cp := range cnbproviders { + valid, err := cp.isBuilderSupported(path, builder) + if err == nil { + return valid // if one of the builders reports no support the other builders will as well. + } + } + logCNBNotSupported() + return valid +} + +func logCNBLongWait() { + if !cnbwarnlongwait { + log.Warn("This could take a few minutes to complete.") + cnbwarnlongwait = true + } +} + +func logCNBNotSupported() { + if !cnbwarnnotsupported { + log.Warn("No CNB containerizer method accessible") + cnbwarnnotsupported = true + } +} + +func getBuildersFromLabel(label string) (buildpacks []string) { + buildpacks = []string{} + ogs := order{} + err := json.Unmarshal([]byte(label), &ogs) + if err != nil { + log.Warnf("Unable to read order : %s", err) + return + } + log.Debugf("Builder data :%s", label) + for _, og := range ogs { + for _, buildpackref := range og.Group { + buildpacks = append(buildpacks, buildpackref.ID) + } + } + return +} diff --git a/internal/containerizer/cnb/runcprovider.go b/internal/containerizer/cnb/runcprovider.go new file mode 100644 index 000000000..fd01b7a94 --- /dev/null +++ b/internal/containerizer/cnb/runcprovider.go @@ -0,0 +1,208 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package cnb + +import ( + "encoding/json" + "errors" + "fmt" + "os" + "os/exec" + "path/filepath" + "strings" + + "github.com/containers/skopeo/cmd/skopeo/inspect" + ocispec "github.com/opencontainers/runtime-spec/specs-go" + log "github.com/sirupsen/logrus" + + "github.com/konveyor/move2kube/internal/common" +) + +var ( + // CNBContainersPath defines the location of the cnb container cache used by runc + cnbContainersPath string = filepath.Join(common.AssetsPath, "cnb") + runcImagesPath = filepath.Join(cnbContainersPath, "images") + runcBundlesPath = filepath.Join(cnbContainersPath, "bundles") +) + +type runcProvider struct { +} + +func (r *runcProvider) getAllBuildpacks(builders []string) (map[string][]string, error) { //[Containerization target option value] buildpacks + buildpacks := make(map[string][]string) + if !r.isAvailable() { + return buildpacks, errors.New("Runc not supported in this instance") + } + log.Debugf("Getting data of all builders %s", builders) + for _, builder := range builders { + cmd := exec.Command("skopeo", "inspect", "docker://"+string(builder)) + output, err := cmd.CombinedOutput() + log.Debugf("Builder %s data :%s", builder, output) + if err != nil { + log.Warnf("Error while getting supported buildpacks for builder %s : %s", builder, err) + continue + } + sio := inspect.Output{} + err = json.Unmarshal(output, &sio) + if err != nil { + log.Warnf("Unable to seriablize inspect output for builder %s : %s", builder, err) + continue + } + o, found := sio.Labels[orderLabel] + if !found { + log.Warnf("%s missing in builder %s : %s", orderLabel, builder, err) + continue + } + buildpacks[builder] = getBuildersFromLabel(o) + } + return buildpacks, nil +} + +func (r *runcProvider) isAvailable() bool { + _, err := exec.LookPath("runc") + if err != nil { + log.Debugf("Unable to find runc, ignoring runc based cnb check : %s", err) + return false + } + _, err = exec.LookPath("skopeo") + if err != nil { + log.Debugf("Unable to find skopeo, ignoring runc based cnb check : %s", err) + return false + } + _, err = exec.LookPath("umoci") + if err != nil { + log.Debugf("Unable to find umoci, ignoring runc based cnb check : %s", err) + return false + } + return true +} + +func (r *runcProvider) isBuilderAvailable(builder string) bool { + if !r.isAvailable() { + return false + } + r.init([]string{builder}) + image, _ := common.GetImageNameAndTag(builder) + _, err := os.Stat(filepath.Join(runcBundlesPath, image)) + if os.IsNotExist(err) { + log.Debugf("Unable to find pack builder oci bundle, ignoring builder : %s", err) + return false + } + return true +} + +func (r *runcProvider) isBuilderSupported(path string, builder string) (bool, error) { + if !r.isBuilderAvailable(builder) { + return false, fmt.Errorf("Runc Builder image not available : %s", builder) + } + image, _ := common.GetImageNameAndTag(builder) + ociimagespec := ocispec.Spec{} + configfilepath := filepath.Join(runcBundlesPath, image, "config.json") + err := common.ReadJSON(configfilepath, &ociimagespec) + if err != nil { + log.Errorf("Unable to read config for image %s : %s", builder, err) + return false, err + } + + mount := ocispec.Mount{} + mount.Source, _ = filepath.Abs(path) + mount.Destination = "/workspace" + mount.Type = "bind" + mount.Options = []string{"rbind", "ro"} + found := false + for i, m := range ociimagespec.Mounts { + if m.Destination == mount.Destination { + mounts := ociimagespec.Mounts + mounts[i] = mount + ociimagespec.Mounts = mounts + found = true + } + } + if !found { + ociimagespec.Mounts = append(ociimagespec.Mounts, mount) + } + ociimagespec.Process.Args = []string{"/cnb/lifecycle/detector"} + ociimagespec.Process.Terminal = false + err = common.WriteJSON(configfilepath, ociimagespec) + if err != nil { + log.Errorf("Unable to write config json %s : %s", configfilepath, err) + } + + //TODO: Check if two instances of runc can be spawned by two processes with same container name without errors + cmd := exec.Command("runc", "run", "cnbbuilder") + cmd.Dir = filepath.Join(runcBundlesPath, image) + output, err := cmd.CombinedOutput() + if err != nil { + log.Debugf("Error while executing runc %+v at %s : %s, %s, %s", cmd, cmd.Dir, path, output, err) + return false, err + } + + if strings.Contains(string(output), "ERROR: No buildpack groups passed detection.") { + log.Debugf("No compatible cnb for %s", path) + return false, nil + } + return true, nil +} + +func (r *runcProvider) init(builders []string) { + if !r.isAvailable() { + return + } + + err := os.MkdirAll(runcImagesPath, common.DefaultDirectoryPermission) + if err != nil { + log.Debugf("Unable to create cnb directory ignoring runc based cnb check : %s", err) + return + } + + err = os.MkdirAll(runcBundlesPath, common.DefaultDirectoryPermission) + if err != nil { + log.Debugf("Unable to create cnb directory ignoring runc based cnb check : %s", err) + return + } + + for _, builder := range builders { + image, tag := common.GetImageNameAndTag(builder) + if _, err := os.Stat(filepath.Join(runcImagesPath, image)); !os.IsNotExist(err) { + continue + } + skopeocmd := exec.Command("skopeo", "copy", "docker://"+builder, "oci:"+image+":"+tag) + skopeocmd.Dir = runcImagesPath + log.Debugf("Pulling %s", builder) + output, err := skopeocmd.CombinedOutput() + if err != nil { + log.Debugf("Unable to copy image %s : %s, %s", image, err, output) + continue + } else { + log.Debugf("Image pull done : %s", output) + } + fullbundlepath, err := filepath.Abs(filepath.Join(runcBundlesPath, image)) + if err != nil { + log.Errorf("Unable to resolve full path of directory %s : %s", fullbundlepath, err) + } + umocicmd := exec.Command("umoci", "unpack", "--image", image+":"+tag, fullbundlepath) + umocicmd.Dir = runcImagesPath + log.Debugf("Creating OCI image %s", builder) + output, err = umocicmd.CombinedOutput() + if err != nil { + log.Debugf("Unable to copy image %s : %s, %s", image, err, output) + continue + } else { + log.Debugf("Image extract done : %s", output) + } + } +} diff --git a/internal/containerizer/cnbcontainerizer.go b/internal/containerizer/cnbcontainerizer.go new file mode 100644 index 000000000..c4dd876f7 --- /dev/null +++ b/internal/containerizer/cnbcontainerizer.go @@ -0,0 +1,97 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package containerizer + +import ( + "errors" + "path/filepath" + + log "github.com/sirupsen/logrus" + + common "github.com/konveyor/move2kube/internal/common" + "github.com/konveyor/move2kube/internal/containerizer/cnb" + "github.com/konveyor/move2kube/internal/containerizer/scripts" + irtypes "github.com/konveyor/move2kube/internal/types" + plantypes "github.com/konveyor/move2kube/types/plan" +) + +// CNBContainerizer implements Containerizer interface +type CNBContainerizer struct { + builders []string +} + +// Cache +var cnbcache = make(map[string][]string) + +// Init initializes the containerizer +func (d *CNBContainerizer) Init(path string) { + d.builders = []string{"cloudfoundry/cnb:cflinuxfs3"} + //initRunc(d.builders) + //TODO: Load from CNB Builder name collector +} + +// GetTargetOptions gets all possible target options for a path +func (d *CNBContainerizer) GetTargetOptions(plan plantypes.Plan, path string) []string { + if options, ok := cnbcache[path]; ok { + return options + } + + builders := d.builders + supportedbuilders := []string{} + + for _, builder := range builders { + if cnb.IsBuilderSupported(path, string(builder)) { + supportedbuilders = append(supportedbuilders, builder) + } + } + cnbcache[path] = supportedbuilders + return supportedbuilders +} + +// GetContainerBuildStrategy returns the containerization build strategy for the containerizer +func (d *CNBContainerizer) GetContainerBuildStrategy() plantypes.ContainerBuildTypeValue { + return plantypes.CNBContainerBuildTypeValue +} + +// GetContainer returns the container for the service +func (d *CNBContainerizer) GetContainer(plan plantypes.Plan, service plantypes.Service) (irtypes.Container, error) { + // TODO: Fix exposed ports too + container := irtypes.NewContainer(service.Image, true) + if service.ContainerBuildType == d.GetContainerBuildStrategy() && len(service.ContainerizationTargetOptions) > 0 { + builder := service.ContainerizationTargetOptions[0] + cnbbuilderstring, err := common.GetStringFromTemplate(scripts.CNBBuilder_sh, struct { + ImageName string + Builder string + }{ + ImageName: service.Image, + Builder: builder, + }) + if err != nil { + log.Warnf("Unable to translate template to string : %s", scripts.CNBBuilder_sh) + } else { + container.AddFile(filepath.Join(service.SourceArtifacts[plantypes.SourceDirectoryArtifactType][0], service.ServiceName+"cnbbuilder.sh"), cnbbuilderstring) + } + container.ExposedPorts = []int{8080} + return container, nil + } + return container, errors.New("Unsupported service type for Containerization or insufficient information in service") +} + +// GetAllBuildpacks returns all supported buildpacks +func (d *CNBContainerizer) GetAllBuildpacks() map[string][]string { + return cnb.GetAllBuildpacks(d.builders) +} diff --git a/internal/containerizer/containerizer.go b/internal/containerizer/containerizer.go new file mode 100644 index 000000000..49b75df5f --- /dev/null +++ b/internal/containerizer/containerizer.go @@ -0,0 +1,86 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package containerizer + +import ( + "fmt" + + common "github.com/konveyor/move2kube/internal/common" + irtypes "github.com/konveyor/move2kube/internal/types" + plantypes "github.com/konveyor/move2kube/types/plan" + log "github.com/sirupsen/logrus" +) + +//go:generate go run github.com/konveyor/move2kube/internal/common/generator scripts + +// Containerizer interface defines interface for containerizing applications +type Containerizer interface { + Init(path string) + GetTargetOptions(plan plantypes.Plan, path string) []string + GetContainer(plan plantypes.Plan, service plantypes.Service) (irtypes.Container, error) + GetContainerBuildStrategy() plantypes.ContainerBuildTypeValue +} + +// Containerizers keep track of all initialized containerizers +type Containerizers struct { + containerizers []Containerizer +} + +// ContainerizationOption defines the containerization option for a path +type ContainerizationOption struct { + ContainerizationType plantypes.ContainerBuildTypeValue + TargetOptions []string +} + +// InitContainerizers initializes the containerizers +func (c *Containerizers) InitContainerizers(path string) { + c.containerizers = []Containerizer{new(DockerfileContainerizer), new(S2IContainerizer), new(CNBContainerizer), new(ReuseContainerizer)} + for _, containerizer := range c.containerizers { + containerizer.Init(path) + containerizer.Init(common.AssetsPath) + } +} + +// GetContainerizationOptions returns ContainerizerOptions for given sourcepath +func (c *Containerizers) GetContainerizationOptions(plan plantypes.Plan, sourcepath string) []ContainerizationOption { + cops := make([]ContainerizationOption, 0) + for _, containerizer := range c.containerizers { + if targetoptions := containerizer.GetTargetOptions(plan, sourcepath); len(targetoptions) != 0 { + cops = append(cops, ContainerizationOption{ + ContainerizationType: containerizer.GetContainerBuildStrategy(), + TargetOptions: targetoptions, + }) + } + } + return cops +} + +// GetContainer get the container for a service +func (c *Containerizers) GetContainer(plan plantypes.Plan, service plantypes.Service) (irtypes.Container, error) { + for _, containerizer := range c.containerizers { + if containerizer.GetContainerBuildStrategy() == service.ContainerBuildType { + log.Debugf("Containerizing %s using %s", service.ServiceName, service.ContainerBuildType) + container, err := containerizer.GetContainer(plan, service) + if err != nil { + log.Errorf("Error during containerization : %s", err) + return irtypes.Container{}, err + } + return container, nil + } + } + return irtypes.Container{}, fmt.Errorf("Containerization strategy invalid for service : %s", service.ServiceName) +} diff --git a/internal/containerizer/dockerfilecontainerizer.go b/internal/containerizer/dockerfilecontainerizer.go new file mode 100644 index 000000000..3b53065b3 --- /dev/null +++ b/internal/containerizer/dockerfilecontainerizer.go @@ -0,0 +1,179 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package containerizer + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "os" + "os/exec" + "path/filepath" + + log "github.com/sirupsen/logrus" + + common "github.com/konveyor/move2kube/internal/common" + "github.com/konveyor/move2kube/internal/containerizer/scripts" + irtypes "github.com/konveyor/move2kube/internal/types" + "github.com/konveyor/move2kube/types" + plantypes "github.com/konveyor/move2kube/types/plan" +) + +const ( + dockerfileDetectscript string = types.AppNameShort + "dfdetect.sh" +) + +// DockerfileContainerizer implements Containerizer interface +type DockerfileContainerizer struct { + dfcontainerizers []string //Paths to directories containing containerizers +} + +// Init initializes docker file containerizer +func (d *DockerfileContainerizer) Init(path string) { + var files, err = common.GetFilesByName(path, []string{dockerfileDetectscript}) + if err != nil { + log.Warnf("Unable to fetch files to recognize docker detect scripts : %s", err) + } + for _, file := range files { + fpath := filepath.Dir(file) + d.dfcontainerizers = append(d.dfcontainerizers, fpath) + } + log.Debugf("Detected dockerfile containerization options : %s ", d.dfcontainerizers) +} + +// GetTargetOptions returns the target options for a path +func (d *DockerfileContainerizer) GetTargetOptions(plan plantypes.Plan, path string) []string { + targetOptions := []string{} + for _, dfcontainerizer := range d.dfcontainerizers { + abspath, err := filepath.Abs(path) + if err != nil { + log.Errorf("Unable to resolve full path of directory %s : %s", abspath, err) + } + outputStr, err := d.detect(dfcontainerizer, abspath) + log.Debugf("Detect output of %s : %s", dfcontainerizer, outputStr) + if err != nil { + log.Debugf("%s detector cannot containerize %s : %s", dfcontainerizer, path, err) + continue + } else { + if path != common.AssetsPath { + dfcontainerizer, _ = plan.GetRelativePath(dfcontainerizer) + } + targetOptions = append(targetOptions, dfcontainerizer) + } + } + return targetOptions +} + +func (d *DockerfileContainerizer) detect(scriptpath string, directory string) (string, error) { + cmd := exec.Command("/bin/sh", dockerfileDetectscript, directory) + cmd.Dir = scriptpath + log.Debugf("Executing detect script %s on %s : %s", scriptpath, directory, cmd) + outputbytes, err := cmd.Output() + return string(outputbytes), err +} + +// GetContainerBuildStrategy returns the ContaierBuildStrategy +func (d *DockerfileContainerizer) GetContainerBuildStrategy() plantypes.ContainerBuildTypeValue { + return plantypes.DockerFileContainerBuildTypeValue +} + +// GetContainer returns the container for a service +func (d *DockerfileContainerizer) GetContainer(plan plantypes.Plan, service plantypes.Service) (irtypes.Container, error) { + // TODO: Fix exposed ports too + if service.ContainerBuildType != d.GetContainerBuildStrategy() || len(service.ContainerizationTargetOptions) == 0 { + return irtypes.Container{}, fmt.Errorf("Unsupported service type for Containerization or insufficient information in service") + } + container := irtypes.NewContainer(service.Image, true) + dfdirectory := plan.GetFullPath(service.ContainerizationTargetOptions[0]) + content, err := ioutil.ReadFile(filepath.Join(dfdirectory, "Dockerfile")) + dockerfilename := "Dockerfile." + service.ServiceName + if err != nil { + log.Errorf("Unable to read docker file at %s : %s", dfdirectory, err) + return container, err + } + dockerfilestring := string(content) + abspath, err := filepath.Abs(plan.GetFullPath(service.SourceArtifacts[plantypes.SourceDirectoryArtifactType][0])) + if err != nil { + log.Errorf("Unable to resolve full path of directory %q Error: %q", abspath, err) + return container, err + } + + outputStr, err := d.detect(dfdirectory, abspath) + if err != nil { + log.Errorf("Detect failed : %s", err) + return container, err + } + if outputStr != "" { + m := map[string]interface{}{} + if err := json.Unmarshal([]byte(outputStr), &m); err != nil { + log.Errorf("Unable to unmarshal the output of the detect script at path %q. Output: %q Error: %q", dfdirectory, outputStr, err) + return container, err + } + + if value, present := m["Port"]; present { + portToExpose := int(value.(float64)) + container.ExposedPorts = append(container.ExposedPorts, portToExpose) + } + + dockerfilestring, err = common.GetStringFromTemplate(string(content), m) + if err != nil { + log.Warnf("Template conversion failed : %s", err) + } + } + //log.Debugf("Creating Dockerfile at %s with %s", filepath.Join(service.SourceArtifacts[plantypes.SourceDirectoryArtifactType][0], service.ServiceName+"Dockerfile"), dockerfilestring) + container.AddFile(filepath.Join(service.SourceArtifacts[plantypes.SourceDirectoryArtifactType][0], dockerfilename), dockerfilestring) + dockerbuildscript, err := common.GetStringFromTemplate(scripts.Dockerbuild_sh, struct { + Dockerfilename string + ImageName string + Context string + }{ + Dockerfilename: dockerfilename, + ImageName: service.Image, + Context: ".", + }) + if err != nil { + log.Warnf("Unable to translate template to string : %s", scripts.Dockerbuild_sh) + } else { + container.AddFile(filepath.Join(service.SourceArtifacts[plantypes.SourceDirectoryArtifactType][0], service.ServiceName+"dockerbuild.sh"), dockerbuildscript) + } + err = filepath.Walk(dfdirectory, func(path string, info os.FileInfo, err error) error { + if err != nil { + log.Warnf("Skipping path %s due to error: %s", path, err) + return nil + } + // Skip directories + if info.IsDir() { + return nil + } + filename := filepath.Base(path) + if filename == "Dockerfile" || filename == dockerfileDetectscript { + return nil + } + content, err := ioutil.ReadFile(path) + if err != nil { + log.Fatal(err) + } + //TODO: Should we allow subdirectories? + container.AddFile(filepath.Join(service.SourceArtifacts[plantypes.SourceDirectoryArtifactType][0], filename), string(content)) + return nil + }) + if err != nil { + log.Warnf("Error in walking through files due to : %s", err) + } + + return container, nil +} diff --git a/internal/containerizer/dockerfilecontainerizer_test.go b/internal/containerizer/dockerfilecontainerizer_test.go new file mode 100644 index 000000000..77d2f0559 --- /dev/null +++ b/internal/containerizer/dockerfilecontainerizer_test.go @@ -0,0 +1,100 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package containerizer_test + +import ( + "os" + "reflect" + "testing" + + log "github.com/sirupsen/logrus" + + "github.com/konveyor/move2kube/internal/common" + "github.com/konveyor/move2kube/internal/containerizer" + irtypes "github.com/konveyor/move2kube/internal/types" + plantypes "github.com/konveyor/move2kube/types/plan" +) + +func TestDockerFileGetContainer(t *testing.T) { + log.SetLevel(log.DebugLevel) + + t.Run("get container for the sample nodejs app using dockerfile", func(t *testing.T) { + // Setup + setupAssets(t) + defer os.RemoveAll(common.TempPath) + + // Test data + testdatapath := "testdata/dockerfilecontainerizer/getcontainer/normal/" + want := irtypes.Container{} + mustreadyaml(t, join(testdatapath, "container.yaml"), &want) + plan := plantypes.Plan{} + mustreadyaml(t, join(testdatapath, "plan.yaml"), &plan) + service := plantypes.Service{} + mustreadyaml(t, join(testdatapath, "service.yaml"), &service) + + dockerfilecontainerizer := new(containerizer.DockerfileContainerizer) + + // Test + cont, err := dockerfilecontainerizer.GetContainer(plan, service) + if err != nil { + t.Fatal("Failed to get the container. Error:", err) + } + if !reflect.DeepEqual(cont, want) { + t.Fatal("Failed to create the container properly. Expected:", want, "Actual:", cont) + } + }) + + t.Run("get container for the dockerfile sample when the service is wrong", func(t *testing.T) { + // Setup + setupAssets(t) + defer os.RemoveAll(common.TempPath) + + // Test data + testdatapath := "testdata/dockerfilecontainerizer/getcontainer/incorrectservice/" + plan := plantypes.Plan{} + mustreadyaml(t, join(testdatapath, "plan.yaml"), &plan) + service := plantypes.Service{} + mustreadyaml(t, join(testdatapath, "service.yaml"), &service) + + dockerfilecontainerizer := new(containerizer.DockerfileContainerizer) + + // Test + if _, err := dockerfilecontainerizer.GetContainer(plan, service); err == nil { + t.Fatal("Should not have succeeded since the service has the incorrect target options.") + } + }) + + t.Run("get container for the dockerfile sample when the container build type is wrong", func(t *testing.T) { + // Setup + setupAssets(t) + defer os.RemoveAll(common.TempPath) + + // Test data + testdatapath := "testdata/dockerfilecontainerizer/getcontainer/incorrectbuilder/" + plan := plantypes.Plan{} + mustreadyaml(t, join(testdatapath, "plan.yaml"), &plan) + service := plantypes.Service{} + mustreadyaml(t, join(testdatapath, "service.yaml"), &service) + + dockerfilecontainerizer := new(containerizer.DockerfileContainerizer) + + // Test + if _, err := dockerfilecontainerizer.GetContainer(plan, service); err == nil { + t.Fatal("Should not have succeeded since the service has the wrong builder type.") + } + }) +} diff --git a/internal/containerizer/manualcontainerizer.go b/internal/containerizer/manualcontainerizer.go new file mode 100644 index 000000000..cbb86f3ad --- /dev/null +++ b/internal/containerizer/manualcontainerizer.go @@ -0,0 +1,52 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package containerizer + +import ( + "fmt" + + irtypes "github.com/konveyor/move2kube/internal/types" + plantypes "github.com/konveyor/move2kube/types/plan" +) + +// ManualContainerizer implements Containerizer interface +type ManualContainerizer struct { +} + +// Init initializes the containerizer +func (d *ManualContainerizer) Init(path string) { +} + +// GetTargetOptions returns empty for Manual +func (d ManualContainerizer) GetTargetOptions(plan plantypes.Plan, path string) []string { + return []string{} +} + +// GetContainerBuildStrategy returns the containerbuildstrategy +func (d ManualContainerizer) GetContainerBuildStrategy() plantypes.ContainerBuildTypeValue { + return plantypes.ManualContainerBuildTypeValue +} + +// GetContainer returns the container for a service +func (d ManualContainerizer) GetContainer(plan plantypes.Plan, service plantypes.Service) (irtypes.Container, error) { + // TODO: Fix exposed ports too + if service.ContainerBuildType == d.GetContainerBuildStrategy() { + container := irtypes.NewContainer(service.Image, true) + return container, nil + } + return irtypes.Container{}, fmt.Errorf("Unsupported service type for Containerization or insufficient information in service") +} diff --git a/internal/containerizer/manualcontainerizer_test.go b/internal/containerizer/manualcontainerizer_test.go new file mode 100644 index 000000000..baaac834c --- /dev/null +++ b/internal/containerizer/manualcontainerizer_test.go @@ -0,0 +1,73 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package containerizer_test + +import ( + "reflect" + "testing" + + log "github.com/sirupsen/logrus" + + "github.com/konveyor/move2kube/internal/containerizer" + irtypes "github.com/konveyor/move2kube/internal/types" + plantypes "github.com/konveyor/move2kube/types/plan" +) + +func TestManualGetContainer(t *testing.T) { + log.SetLevel(log.DebugLevel) + + t.Run("get container for the sample nodejs app", func(t *testing.T) { + // Setup + + // Test data + testdatapath := "testdata/manualcontainerizer/getcontainer/normal/" + plan := plantypes.Plan{} + mustreadyaml(t, join(testdatapath, "plan.yaml"), &plan) + service := plantypes.Service{} + mustreadyaml(t, join(testdatapath, "service.yaml"), &service) + want := irtypes.NewContainer(service.Image, true) + + manualcontainerizer := new(containerizer.ManualContainerizer) + + // Test + cont, err := manualcontainerizer.GetContainer(plan, service) + if err != nil { + t.Fatal("Failed to get the container. Error:", err) + } + if !reflect.DeepEqual(cont, want) { + t.Fatal("Failed to create the container properly. Expected:", want, "Actual:", cont) + } + }) + + t.Run("get container for the nodejs app when the service is wrong", func(t *testing.T) { + // Setup + + // Test data + testdatapath := "testdata/manualcontainerizer/getcontainer/incorrectservice/" + plan := plantypes.Plan{} + mustreadyaml(t, join(testdatapath, "plan.yaml"), &plan) + service := plantypes.Service{} + mustreadyaml(t, join(testdatapath, "service.yaml"), &service) + + manualcontainerizer := new(containerizer.ManualContainerizer) + + // Test + if _, err := manualcontainerizer.GetContainer(plan, service); err == nil { + t.Fatal("Should not have succeeded since the service has the incorrect target options.") + } + }) +} diff --git a/internal/containerizer/reusecontainerizer.go b/internal/containerizer/reusecontainerizer.go new file mode 100644 index 000000000..023df470b --- /dev/null +++ b/internal/containerizer/reusecontainerizer.go @@ -0,0 +1,52 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package containerizer + +import ( + "fmt" + + irtypes "github.com/konveyor/move2kube/internal/types" + plantypes "github.com/konveyor/move2kube/types/plan" +) + +// ReuseContainerizer implements Containerizer interface +type ReuseContainerizer struct { +} + +// Init initializes the containerizer +func (d *ReuseContainerizer) Init(path string) { +} + +// GetTargetOptions does nothing for reuse containerizer +func (d ReuseContainerizer) GetTargetOptions(plan plantypes.Plan, path string) []string { + return []string{} +} + +// GetContainerBuildStrategy returns the containerbuildstrategy that is supported +func (d ReuseContainerizer) GetContainerBuildStrategy() plantypes.ContainerBuildTypeValue { + return plantypes.ReuseContainerBuildTypeValue +} + +// GetContainer returns the container for a service +func (d ReuseContainerizer) GetContainer(plan plantypes.Plan, service plantypes.Service) (irtypes.Container, error) { + // TODO: Fix exposed ports too + if service.ContainerBuildType == d.GetContainerBuildStrategy() { + container := irtypes.NewContainer(service.Image, false) + return container, nil + } + return irtypes.Container{}, fmt.Errorf("Unsupported service type for Containerization or insufficient information in service") +} diff --git a/internal/containerizer/reusecontainerizer_test.go b/internal/containerizer/reusecontainerizer_test.go new file mode 100644 index 000000000..8c31a1bb8 --- /dev/null +++ b/internal/containerizer/reusecontainerizer_test.go @@ -0,0 +1,72 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package containerizer_test + +import ( + "reflect" + "testing" + + "github.com/konveyor/move2kube/internal/containerizer" + irtypes "github.com/konveyor/move2kube/internal/types" + plantypes "github.com/konveyor/move2kube/types/plan" + log "github.com/sirupsen/logrus" +) + +func TestReuseGetContainer(t *testing.T) { + log.SetLevel(log.DebugLevel) + + t.Run("get container for the sample nodejs app", func(t *testing.T) { + // Setup + + // Test data + testdatapath := "testdata/reusecontainerizer/getcontainer/normal/" + plan := plantypes.Plan{} + mustreadyaml(t, join(testdatapath, "plan.yaml"), &plan) + service := plantypes.Service{} + mustreadyaml(t, join(testdatapath, "service.yaml"), &service) + want := irtypes.NewContainer(service.Image, false) + + reusecontainerizer := new(containerizer.ReuseContainerizer) + + // Test + cont, err := reusecontainerizer.GetContainer(plan, service) + if err != nil { + t.Fatal("Failed to get the container. Error:", err) + } + if !reflect.DeepEqual(cont, want) { + t.Fatal("Failed to create the container properly. Expected:", want, "Actual:", cont) + } + }) + + t.Run("get container for the nodejs app when the service is wrong", func(t *testing.T) { + // Setup + + // Test data + testdatapath := "testdata/reusecontainerizer/getcontainer/incorrectservice/" + plan := plantypes.Plan{} + mustreadyaml(t, join(testdatapath, "plan.yaml"), &plan) + service := plantypes.Service{} + mustreadyaml(t, join(testdatapath, "service.yaml"), &service) + + reusecontainerizer := new(containerizer.ReuseContainerizer) + + // Test + if _, err := reusecontainerizer.GetContainer(plan, service); err == nil { + t.Fatal("Should not have succeeded since the service has the incorrect target options.") + } + }) +} diff --git a/internal/containerizer/reusedockerfilecontainerizer.go b/internal/containerizer/reusedockerfilecontainerizer.go new file mode 100644 index 000000000..b3507bbd8 --- /dev/null +++ b/internal/containerizer/reusedockerfilecontainerizer.go @@ -0,0 +1,70 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package containerizer + +import ( + "os" + "path/filepath" + + log "github.com/sirupsen/logrus" + + common "github.com/konveyor/move2kube/internal/common" + "github.com/konveyor/move2kube/internal/containerizer/scripts" + irtypes "github.com/konveyor/move2kube/internal/types" + plantypes "github.com/konveyor/move2kube/types/plan" +) + +// ReuseDockerfileContainerizer uses its own containerization interface +type ReuseDockerfileContainerizer struct { +} + +// GetContainerBuildStrategy returns the containerization build strategy +func (d *ReuseDockerfileContainerizer) GetContainerBuildStrategy() plantypes.ContainerBuildTypeValue { + return plantypes.ReuseDockerFileContainerBuildTypeValue +} + +// GetContainer returns the container for the service +func (d *ReuseDockerfileContainerizer) GetContainer(path string, serviceName string, imageName string, dockerfile string, context string) (irtypes.Container, error) { + container := irtypes.NewContainer(imageName, true) + _, err := os.Stat(filepath.Join(path, dockerfile)) + if os.IsNotExist(err) { + log.Errorf("Unable to find docker file %s : %s", dockerfile, err) + log.Errorf("Will assume the dockerfile will be copied and will proceed.") + } + if context == "" { + context = "." + } + if dockerfile == "" { + dockerfile = "Dockerfile" + } + dockerbuildscript, err := common.GetStringFromTemplate(scripts.Dockerbuild_sh, struct { + Dockerfilename string + ImageName string + Context string + }{ + Dockerfilename: dockerfile, + ImageName: imageName, + Context: context, + }) + if err != nil { + log.Warnf("Unable to translate template to string : %s", scripts.Dockerbuild_sh) + } else { + container.AddFile(filepath.Join(path, serviceName+"dockerbuild.sh"), dockerbuildscript) + } + + return container, nil +} diff --git a/internal/containerizer/s2icontainerizer.go b/internal/containerizer/s2icontainerizer.go new file mode 100644 index 000000000..893736150 --- /dev/null +++ b/internal/containerizer/s2icontainerizer.go @@ -0,0 +1,176 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package containerizer + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "os" + "os/exec" + "path/filepath" + "strings" + + log "github.com/sirupsen/logrus" + + common "github.com/konveyor/move2kube/internal/common" + "github.com/konveyor/move2kube/internal/containerizer/scripts" + irtypes "github.com/konveyor/move2kube/internal/types" + "github.com/konveyor/move2kube/types" + plantypes "github.com/konveyor/move2kube/types/plan" +) + +const ( + s2iDetectscript string = types.AppNameShort + "s2idetect.sh" +) + +// S2IContainerizer implements Containerizer interface +type S2IContainerizer struct { + s2icontainerizers []string //Paths to directories containing containerizers +} + +// Init initializes the containerizer +func (d *S2IContainerizer) Init(path string) { + var files, err = common.GetFilesByName(path, []string{s2iDetectscript}) + if err != nil { + log.Warnf("Unable to fetch files to recognize s2i detect files : %s", err) + } + for _, file := range files { + fpath := filepath.Dir(file) + d.s2icontainerizers = append(d.s2icontainerizers, fpath) + } + log.Debugf("Detected S2I containerization options : %s ", d.s2icontainerizers) +} + +// GetTargetOptions returns the target options for a path +func (d *S2IContainerizer) GetTargetOptions(plan plantypes.Plan, path string) []string { + abspath, err := filepath.Abs(path) + if err != nil { + log.Errorf("Unable to resolve path %q Error: %q", abspath, err) + return nil + } + targetOptions := []string{} + for _, s2icontainerizer := range d.s2icontainerizers { + outputStr, err := d.detect(s2icontainerizer, abspath) + log.Debugf("Detect output of %q : %q", s2icontainerizer, outputStr) + if err != nil { + log.Debugf("%q detector cannot containerize %q Error: %q", s2icontainerizer, path, err) + continue + } + if path != common.AssetsPath { + s2icontainerizer, _ = plan.GetRelativePath(s2icontainerizer) + } + targetOptions = append(targetOptions, s2icontainerizer) + } + return targetOptions +} + +func (d *S2IContainerizer) detect(scriptpath string, directory string) (string, error) { + cmd := exec.Command("/bin/sh", s2iDetectscript, directory) + cmd.Dir = scriptpath + log.Debugf("Executing detect script %q on %q : %q", scriptpath, directory, cmd) + outputbytes, err := cmd.Output() + return string(outputbytes), err +} + +// GetContainerBuildStrategy returns the containerization build strategy +func (d *S2IContainerizer) GetContainerBuildStrategy() plantypes.ContainerBuildTypeValue { + return plantypes.S2IContainerBuildTypeValue +} + +// GetContainer returns the container for a service +func (d *S2IContainerizer) GetContainer(plan plantypes.Plan, service plantypes.Service) (irtypes.Container, error) { + if service.ContainerBuildType != d.GetContainerBuildStrategy() || len(service.ContainerizationTargetOptions) == 0 { + return irtypes.Container{}, fmt.Errorf("Unsupported service type for Containerization or insufficient information in service") + } + + container := irtypes.NewContainer(service.Image, true) + dfdirectory := plan.GetFullPath(service.ContainerizationTargetOptions[0]) + abspath, err := filepath.Abs(plan.GetFullPath(service.SourceArtifacts[plantypes.SourceDirectoryArtifactType][0])) + if err != nil { + log.Errorf("Unable to resolve full path of directory %s : %s", abspath, err) + return container, err + } + outputStr, err := d.detect(dfdirectory, abspath) + if err != nil { + log.Errorf("Detect failed for S2I (%s) : %s (%s)", dfdirectory, err, outputStr) + return container, err + } + outputStr = strings.TrimSpace(outputStr) + + m := map[string]interface{}{} + if err := json.Unmarshal([]byte(outputStr), &m); err != nil { + log.Errorf("Unable to unmarshal the output of the detect script at path %q. Output: %q Error: %q", dfdirectory, outputStr, err) + return container, err + } + + if value, ok := m["Port"]; ok { + portToExpose := int(value.(float64)) // json numbers are float64 + container.ExposedPorts = append(container.ExposedPorts, portToExpose) + } + + m["ImageName"] = service.Image + s2ibuildscript, err := common.GetStringFromTemplate(scripts.S2IBuilder_sh, m) + if err != nil { + log.Errorf("Unable to translate the template %q to string. Error: %q", scripts.S2IBuilder_sh, err) + return container, err + } + + container.AddFile(filepath.Join(service.SourceArtifacts[plantypes.SourceDirectoryArtifactType][0], service.ServiceName+"s2ibuild.sh"), s2ibuildscript) + + var relFilePath string + err = filepath.Walk(dfdirectory, func(path string, info os.FileInfo, err error) error { + if err != nil { + log.Warnf("Skipping path %s due to error: %s", path, err) + return nil + } + if info.IsDir() { + return nil + } + filename := filepath.Base(path) + if filename == s2iDetectscript { + return nil + } + + relFilePath, err = filepath.Rel(dfdirectory, path) + if err != nil { + log.Errorf("Skipping path %q . Failed to get the relative path. Error: %q", path, err) + return nil + } + + tmpl, err := ioutil.ReadFile(path) + if err != nil { + log.Errorf("Skipping path %q . Failed to read the template. Error: %q", path, err) + return nil + } + + contentStr, err := common.GetStringFromTemplate(string(tmpl), m) + if err != nil { + log.Errorf("Skipping path %q . Unable to translate the template to string. Error %q", path, err) + return nil + } + + //Allowing sub-directories + container.AddFile(filepath.Join(service.SourceArtifacts[plantypes.SourceDirectoryArtifactType][0], relFilePath), contentStr) + return nil + }) + if err != nil { + log.Warnf("Error in walking through files due to : %s", err) + } + + return container, nil +} diff --git a/internal/containerizer/s2icontainerizer_test.go b/internal/containerizer/s2icontainerizer_test.go new file mode 100644 index 000000000..42aaa4ce7 --- /dev/null +++ b/internal/containerizer/s2icontainerizer_test.go @@ -0,0 +1,120 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package containerizer_test + +import ( + "os" + "path/filepath" + "reflect" + "testing" + + "github.com/konveyor/move2kube/internal/common" + "github.com/konveyor/move2kube/internal/containerizer" + irtypes "github.com/konveyor/move2kube/internal/types" + plantypes "github.com/konveyor/move2kube/types/plan" + log "github.com/sirupsen/logrus" +) + +// Helper functions +var join = filepath.Join + +func mustreadyaml(t *testing.T, path string, x interface{}) { + if err := common.ReadYaml(path, x); err != nil { + t.Fatalf("Failed to read the testdata at path %q Error: %q", path, err) + } +} + +func setupAssets(t *testing.T) { + assetsPath, tempPath, err := common.CreateAssetsData() + if err != nil { + t.Fatalf("Unable to create the assets directory. Error: %q", err) + } + + common.TempPath = tempPath + common.AssetsPath = assetsPath +} + +// Tests +func TestS2IGetContainer(t *testing.T) { + log.SetLevel(log.DebugLevel) + + t.Run("get container for the sample nodejs app", func(t *testing.T) { + // Setup + setupAssets(t) + defer os.RemoveAll(common.TempPath) + + // Test data + testdatapath := "testdata/s2icontainerizer/getcontainer/normal/" + want := irtypes.Container{} + mustreadyaml(t, join(testdatapath, "container.yaml"), &want) + plan := plantypes.Plan{} + mustreadyaml(t, join(testdatapath, "plan.yaml"), &plan) + service := plantypes.Service{} + mustreadyaml(t, join(testdatapath, "service.yaml"), &service) + + s2icontainerizer := new(containerizer.S2IContainerizer) + + // Test + cont, err := s2icontainerizer.GetContainer(plan, service) + if err != nil { + t.Fatal("Failed to get the container. Error:", err) + } + if !reflect.DeepEqual(cont, want) { + t.Fatal("Failed to create the container properly. Expected:", want, "Actual:", cont) + } + }) + + t.Run("get container for the nodejs app when the service is wrong", func(t *testing.T) { + // Setup + setupAssets(t) + defer os.RemoveAll(common.TempPath) + + // Test data + testdatapath := "testdata/s2icontainerizer/getcontainer/incorrectservice/" + plan := plantypes.Plan{} + mustreadyaml(t, join(testdatapath, "plan.yaml"), &plan) + service := plantypes.Service{} + mustreadyaml(t, join(testdatapath, "service.yaml"), &service) + + s2icontainerizer := new(containerizer.S2IContainerizer) + + // Test + if _, err := s2icontainerizer.GetContainer(plan, service); err == nil { + t.Fatal("Should not have succeeded since the service has the incorrect target options.") + } + }) + + t.Run("get container for the nodejs app when the container build type is wrong", func(t *testing.T) { + // Setup + setupAssets(t) + defer os.RemoveAll(common.TempPath) + + // Test data + testdatapath := "testdata/s2icontainerizer/getcontainer/incorrectbuilder/" + plan := plantypes.Plan{} + mustreadyaml(t, join(testdatapath, "plan.yaml"), &plan) + service := plantypes.Service{} + mustreadyaml(t, join(testdatapath, "service.yaml"), &service) + + s2icontainerizer := new(containerizer.S2IContainerizer) + + // Test + if _, err := s2icontainerizer.GetContainer(plan, service); err == nil { + t.Fatal("Should not have succeeded since the service has the wrong builder type.") + } + }) +} diff --git a/internal/containerizer/scripts/CNBBuilder.sh b/internal/containerizer/scripts/CNBBuilder.sh new file mode 100644 index 000000000..3bf24ca34 --- /dev/null +++ b/internal/containerizer/scripts/CNBBuilder.sh @@ -0,0 +1,15 @@ +# Copyright IBM Corporation 2020 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +pack build {{ .ImageName }} -B {{ .Builder }} \ No newline at end of file diff --git a/internal/containerizer/scripts/Dockerbuild.sh b/internal/containerizer/scripts/Dockerbuild.sh new file mode 100644 index 000000000..11adaf9fa --- /dev/null +++ b/internal/containerizer/scripts/Dockerbuild.sh @@ -0,0 +1,15 @@ +# Copyright IBM Corporation 2020 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +docker build -f {{ .Dockerfilename }} -t {{ .ImageName }} {{ .Context }} \ No newline at end of file diff --git a/internal/containerizer/scripts/S2IBuilder.sh b/internal/containerizer/scripts/S2IBuilder.sh new file mode 100644 index 000000000..05d4c01cc --- /dev/null +++ b/internal/containerizer/scripts/S2IBuilder.sh @@ -0,0 +1,15 @@ +# Copyright IBM Corporation 2020 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +s2i build . {{ .Builder }} {{ .ImageName }} \ No newline at end of file diff --git a/internal/containerizer/scripts/constants.go b/internal/containerizer/scripts/constants.go new file mode 100644 index 000000000..08c4211f4 --- /dev/null +++ b/internal/containerizer/scripts/constants.go @@ -0,0 +1,73 @@ +// Code generated by go generate; DO NOT EDIT. +// This file was generated by robots at +// 2020-09-14 15:52:45.608874 +0530 IST m=+0.001107857 + +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package scripts + +const ( + + CNBBuilder_sh = `# Copyright IBM Corporation 2020 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +pack build {{ .ImageName }} -B {{ .Builder }}` + + Dockerbuild_sh = `# Copyright IBM Corporation 2020 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +docker build -f {{ .Dockerfilename }} -t {{ .ImageName }} {{ .Context }}` + + S2IBuilder_sh = `# Copyright IBM Corporation 2020 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +s2i build . {{ .Builder }} {{ .ImageName }}` + +) \ No newline at end of file diff --git a/internal/containerizer/testdata/dockerfilecontainerizer/getcontainer/incorrectbuilder/plan.yaml b/internal/containerizer/testdata/dockerfilecontainerizer/getcontainer/incorrectbuilder/plan.yaml new file mode 100644 index 000000000..9c071d4ed --- /dev/null +++ b/internal/containerizer/testdata/dockerfilecontainerizer/getcontainer/incorrectbuilder/plan.yaml @@ -0,0 +1,29 @@ +apiVersion: move2kube.io/v1alpha1 +kind: Plan +metadata: + name: myproject +spec: + inputs: + rootDir: ../../samples/dockerfile/ + services: + dockerfile: + - serviceName: dockerfile + image: dockerfile:latest + translationType: Any2Kube + containerBuildType: NewDockerfile + sourceType: + - Directory + targetOptions: + - m2kassets/dockerfiles/nodejs + sourceArtifacts: + SourceCode: + - . + buildArtifacts: + SourceCode: + - . + updateContainerBuildPipeline: true + updateDeployPipeline: true + outputs: + kubernetes: + artifactType: Yamls + clusterType: Kubernetes diff --git a/internal/containerizer/testdata/dockerfilecontainerizer/getcontainer/incorrectbuilder/service.yaml b/internal/containerizer/testdata/dockerfilecontainerizer/getcontainer/incorrectbuilder/service.yaml new file mode 100644 index 000000000..1589e3e8e --- /dev/null +++ b/internal/containerizer/testdata/dockerfilecontainerizer/getcontainer/incorrectbuilder/service.yaml @@ -0,0 +1,16 @@ +serviceName: dockerfile +image: dockerfile:latest +translationType: Any2Kube +containerBuildType: S2I +sourceType: + - Directory +targetOptions: + - m2kassets/dockerfiles/nodejs +sourceArtifacts: + SourceCode: + - . +buildArtifacts: + SourceCode: + - . +updateContainerBuildPipeline: true +updateDeployPipeline: true diff --git a/internal/containerizer/testdata/dockerfilecontainerizer/getcontainer/incorrectservice/plan.yaml b/internal/containerizer/testdata/dockerfilecontainerizer/getcontainer/incorrectservice/plan.yaml new file mode 100644 index 000000000..9c071d4ed --- /dev/null +++ b/internal/containerizer/testdata/dockerfilecontainerizer/getcontainer/incorrectservice/plan.yaml @@ -0,0 +1,29 @@ +apiVersion: move2kube.io/v1alpha1 +kind: Plan +metadata: + name: myproject +spec: + inputs: + rootDir: ../../samples/dockerfile/ + services: + dockerfile: + - serviceName: dockerfile + image: dockerfile:latest + translationType: Any2Kube + containerBuildType: NewDockerfile + sourceType: + - Directory + targetOptions: + - m2kassets/dockerfiles/nodejs + sourceArtifacts: + SourceCode: + - . + buildArtifacts: + SourceCode: + - . + updateContainerBuildPipeline: true + updateDeployPipeline: true + outputs: + kubernetes: + artifactType: Yamls + clusterType: Kubernetes diff --git a/internal/containerizer/testdata/dockerfilecontainerizer/getcontainer/incorrectservice/service.yaml b/internal/containerizer/testdata/dockerfilecontainerizer/getcontainer/incorrectservice/service.yaml new file mode 100644 index 000000000..7dd6c1080 --- /dev/null +++ b/internal/containerizer/testdata/dockerfilecontainerizer/getcontainer/incorrectservice/service.yaml @@ -0,0 +1,16 @@ +serviceName: dockerfile +image: dockerfile:latest +translationType: Any2Kube +containerBuildType: NewDockerfile +sourceType: + - Directory +targetOptions: + - m2kassets/dockerfiles/java +sourceArtifacts: + SourceCode: + - . +buildArtifacts: + SourceCode: + - . +updateContainerBuildPipeline: true +updateDeployPipeline: true diff --git a/internal/containerizer/testdata/dockerfilecontainerizer/getcontainer/normal/container.yaml b/internal/containerizer/testdata/dockerfilecontainerizer/getcontainer/normal/container.yaml new file mode 100644 index 000000000..dc26b4394 --- /dev/null +++ b/internal/containerizer/testdata/dockerfilecontainerizer/getcontainer/normal/container.yaml @@ -0,0 +1,45 @@ +imagenames: + - dockerfile:latest +new: true +newfiles: + Dockerfile.dockerfile: |- + # Copyright IBM Corporation 2020 + # + # Licensed under the Apache License, Version 2.0 (the "License"); + # you may not use this file except in compliance with the License. + # You may obtain a copy of the License at + # + # http://www.apache.org/licenses/LICENSE-2.0 + # + # Unless required by applicable law or agreed to in writing, software + # distributed under the License is distributed on an "AS IS" BASIS, + # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + # See the License for the specific language governing permissions and + # limitations under the License. + + + FROM registry.access.redhat.com/ubi8/nodejs-12 + ADD . . + RUN npm install + EXPOSE 8080 + CMD npm run -d start + dockerfiledockerbuild.sh: |- + # Copyright IBM Corporation 2020 + # + # Licensed under the Apache License, Version 2.0 (the "License"); + # you may not use this file except in compliance with the License. + # You may obtain a copy of the License at + # + # http://www.apache.org/licenses/LICENSE-2.0 + # + # Unless required by applicable law or agreed to in writing, software + # distributed under the License is distributed on an "AS IS" BASIS, + # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + # See the License for the specific language governing permissions and + # limitations under the License. + + docker build -f Dockerfile.dockerfile -t dockerfile:latest . +exposedports: + - 8080 +userid: -1 +accesseddirs: [] diff --git a/internal/containerizer/testdata/dockerfilecontainerizer/getcontainer/normal/plan.yaml b/internal/containerizer/testdata/dockerfilecontainerizer/getcontainer/normal/plan.yaml new file mode 100644 index 000000000..9c071d4ed --- /dev/null +++ b/internal/containerizer/testdata/dockerfilecontainerizer/getcontainer/normal/plan.yaml @@ -0,0 +1,29 @@ +apiVersion: move2kube.io/v1alpha1 +kind: Plan +metadata: + name: myproject +spec: + inputs: + rootDir: ../../samples/dockerfile/ + services: + dockerfile: + - serviceName: dockerfile + image: dockerfile:latest + translationType: Any2Kube + containerBuildType: NewDockerfile + sourceType: + - Directory + targetOptions: + - m2kassets/dockerfiles/nodejs + sourceArtifacts: + SourceCode: + - . + buildArtifacts: + SourceCode: + - . + updateContainerBuildPipeline: true + updateDeployPipeline: true + outputs: + kubernetes: + artifactType: Yamls + clusterType: Kubernetes diff --git a/internal/containerizer/testdata/dockerfilecontainerizer/getcontainer/normal/service.yaml b/internal/containerizer/testdata/dockerfilecontainerizer/getcontainer/normal/service.yaml new file mode 100644 index 000000000..66c0b9247 --- /dev/null +++ b/internal/containerizer/testdata/dockerfilecontainerizer/getcontainer/normal/service.yaml @@ -0,0 +1,16 @@ +serviceName: dockerfile +image: dockerfile:latest +translationType: Any2Kube +containerBuildType: NewDockerfile +sourceType: + - Directory +targetOptions: + - m2kassets/dockerfiles/nodejs +sourceArtifacts: + SourceCode: + - . +buildArtifacts: + SourceCode: + - . +updateContainerBuildPipeline: true +updateDeployPipeline: true diff --git a/internal/containerizer/testdata/manualcontainerizer/getcontainer/incorrectservice/plan.yaml b/internal/containerizer/testdata/manualcontainerizer/getcontainer/incorrectservice/plan.yaml new file mode 100644 index 000000000..3bc0a67a7 --- /dev/null +++ b/internal/containerizer/testdata/manualcontainerizer/getcontainer/incorrectservice/plan.yaml @@ -0,0 +1,29 @@ +apiVersion: move2kube.io/v1alpha1 +kind: Plan +metadata: + name: myproject +spec: + inputs: + rootDir: ../../samples/dockerfile/ + services: + dockerfile: + - serviceName: dockerfile + image: dockerfile:latest + translationType: Any2Kube + containerBuildType: Manual + sourceType: + - Directory + targetOptions: + - m2kassets/dockerfiles/nodejs + sourceArtifacts: + SourceCode: + - . + buildArtifacts: + SourceCode: + - . + updateContainerBuildPipeline: true + updateDeployPipeline: true + outputs: + kubernetes: + artifactType: Yamls + clusterType: Kubernetes diff --git a/internal/containerizer/testdata/manualcontainerizer/getcontainer/incorrectservice/service.yaml b/internal/containerizer/testdata/manualcontainerizer/getcontainer/incorrectservice/service.yaml new file mode 100644 index 000000000..7dd6c1080 --- /dev/null +++ b/internal/containerizer/testdata/manualcontainerizer/getcontainer/incorrectservice/service.yaml @@ -0,0 +1,16 @@ +serviceName: dockerfile +image: dockerfile:latest +translationType: Any2Kube +containerBuildType: NewDockerfile +sourceType: + - Directory +targetOptions: + - m2kassets/dockerfiles/java +sourceArtifacts: + SourceCode: + - . +buildArtifacts: + SourceCode: + - . +updateContainerBuildPipeline: true +updateDeployPipeline: true diff --git a/internal/containerizer/testdata/manualcontainerizer/getcontainer/normal/plan.yaml b/internal/containerizer/testdata/manualcontainerizer/getcontainer/normal/plan.yaml new file mode 100644 index 000000000..3bc0a67a7 --- /dev/null +++ b/internal/containerizer/testdata/manualcontainerizer/getcontainer/normal/plan.yaml @@ -0,0 +1,29 @@ +apiVersion: move2kube.io/v1alpha1 +kind: Plan +metadata: + name: myproject +spec: + inputs: + rootDir: ../../samples/dockerfile/ + services: + dockerfile: + - serviceName: dockerfile + image: dockerfile:latest + translationType: Any2Kube + containerBuildType: Manual + sourceType: + - Directory + targetOptions: + - m2kassets/dockerfiles/nodejs + sourceArtifacts: + SourceCode: + - . + buildArtifacts: + SourceCode: + - . + updateContainerBuildPipeline: true + updateDeployPipeline: true + outputs: + kubernetes: + artifactType: Yamls + clusterType: Kubernetes diff --git a/internal/containerizer/testdata/manualcontainerizer/getcontainer/normal/service.yaml b/internal/containerizer/testdata/manualcontainerizer/getcontainer/normal/service.yaml new file mode 100644 index 000000000..8a95d26a0 --- /dev/null +++ b/internal/containerizer/testdata/manualcontainerizer/getcontainer/normal/service.yaml @@ -0,0 +1,16 @@ +serviceName: dockerfile +image: dockerfile:latest +translationType: Any2Kube +containerBuildType: Manual +sourceType: + - Directory +targetOptions: + - m2kassets/dockerfiles/java +sourceArtifacts: + SourceCode: + - . +buildArtifacts: + SourceCode: + - . +updateContainerBuildPipeline: true +updateDeployPipeline: true diff --git a/internal/containerizer/testdata/reusecontainerizer/getcontainer/incorrectservice/plan.yaml b/internal/containerizer/testdata/reusecontainerizer/getcontainer/incorrectservice/plan.yaml new file mode 100644 index 000000000..fb865701e --- /dev/null +++ b/internal/containerizer/testdata/reusecontainerizer/getcontainer/incorrectservice/plan.yaml @@ -0,0 +1,29 @@ +apiVersion: move2kube.io/v1alpha1 +kind: Plan +metadata: + name: myproject +spec: + inputs: + rootDir: ../../samples/dockerfile/ + services: + dockerfile: + - serviceName: dockerfile + image: dockerfile:latest + translationType: Any2Kube + containerBuildType: Reuse + sourceType: + - Directory + targetOptions: + - m2kassets/dockerfiles/nodejs + sourceArtifacts: + SourceCode: + - . + buildArtifacts: + SourceCode: + - . + updateContainerBuildPipeline: true + updateDeployPipeline: true + outputs: + kubernetes: + artifactType: Yamls + clusterType: Kubernetes diff --git a/internal/containerizer/testdata/reusecontainerizer/getcontainer/incorrectservice/service.yaml b/internal/containerizer/testdata/reusecontainerizer/getcontainer/incorrectservice/service.yaml new file mode 100644 index 000000000..7dd6c1080 --- /dev/null +++ b/internal/containerizer/testdata/reusecontainerizer/getcontainer/incorrectservice/service.yaml @@ -0,0 +1,16 @@ +serviceName: dockerfile +image: dockerfile:latest +translationType: Any2Kube +containerBuildType: NewDockerfile +sourceType: + - Directory +targetOptions: + - m2kassets/dockerfiles/java +sourceArtifacts: + SourceCode: + - . +buildArtifacts: + SourceCode: + - . +updateContainerBuildPipeline: true +updateDeployPipeline: true diff --git a/internal/containerizer/testdata/reusecontainerizer/getcontainer/normal/plan.yaml b/internal/containerizer/testdata/reusecontainerizer/getcontainer/normal/plan.yaml new file mode 100644 index 000000000..fb865701e --- /dev/null +++ b/internal/containerizer/testdata/reusecontainerizer/getcontainer/normal/plan.yaml @@ -0,0 +1,29 @@ +apiVersion: move2kube.io/v1alpha1 +kind: Plan +metadata: + name: myproject +spec: + inputs: + rootDir: ../../samples/dockerfile/ + services: + dockerfile: + - serviceName: dockerfile + image: dockerfile:latest + translationType: Any2Kube + containerBuildType: Reuse + sourceType: + - Directory + targetOptions: + - m2kassets/dockerfiles/nodejs + sourceArtifacts: + SourceCode: + - . + buildArtifacts: + SourceCode: + - . + updateContainerBuildPipeline: true + updateDeployPipeline: true + outputs: + kubernetes: + artifactType: Yamls + clusterType: Kubernetes diff --git a/internal/containerizer/testdata/reusecontainerizer/getcontainer/normal/service.yaml b/internal/containerizer/testdata/reusecontainerizer/getcontainer/normal/service.yaml new file mode 100644 index 000000000..720287321 --- /dev/null +++ b/internal/containerizer/testdata/reusecontainerizer/getcontainer/normal/service.yaml @@ -0,0 +1,16 @@ +serviceName: dockerfile +image: dockerfile:latest +translationType: Any2Kube +containerBuildType: Reuse +sourceType: + - Directory +targetOptions: + - m2kassets/dockerfiles/java +sourceArtifacts: + SourceCode: + - . +buildArtifacts: + SourceCode: + - . +updateContainerBuildPipeline: true +updateDeployPipeline: true diff --git a/internal/containerizer/testdata/s2icontainerizer/getcontainer/incorrectbuilder/plan.yaml b/internal/containerizer/testdata/s2icontainerizer/getcontainer/incorrectbuilder/plan.yaml new file mode 100644 index 000000000..387f55458 --- /dev/null +++ b/internal/containerizer/testdata/s2icontainerizer/getcontainer/incorrectbuilder/plan.yaml @@ -0,0 +1,29 @@ +apiVersion: move2kube.io/v1alpha1 +kind: Plan +metadata: + name: myproject +spec: + inputs: + rootDir: ../../samples/nodejs + services: + nodejs: + - serviceName: nodejs + image: nodejs:latest + translationType: Any2Kube + containerBuildType: S2I + sourceType: + - Directory + targetOptions: + - m2kassets/s2i/nodejs + sourceArtifacts: + SourceCode: + - . + buildArtifacts: + SourceCode: + - . + updateContainerBuildPipeline: true + updateDeployPipeline: true + outputs: + kubernetes: + artifactType: Yamls + clusterType: Kubernetes diff --git a/internal/containerizer/testdata/s2icontainerizer/getcontainer/incorrectbuilder/service.yaml b/internal/containerizer/testdata/s2icontainerizer/getcontainer/incorrectbuilder/service.yaml new file mode 100644 index 000000000..c2aaff5c1 --- /dev/null +++ b/internal/containerizer/testdata/s2icontainerizer/getcontainer/incorrectbuilder/service.yaml @@ -0,0 +1,16 @@ +serviceName: nodejs +image: nodejs:latest +translationType: Any2Kube +containerBuildType: NewDockerfile +sourceType: + - Directory +targetOptions: + - m2kassets/s2i/nodejs +sourceArtifacts: + SourceCode: + - . +buildArtifacts: + SourceCode: + - . +updateContainerBuildPipeline: true +updateDeployPipeline: true diff --git a/internal/containerizer/testdata/s2icontainerizer/getcontainer/incorrectservice/plan.yaml b/internal/containerizer/testdata/s2icontainerizer/getcontainer/incorrectservice/plan.yaml new file mode 100644 index 000000000..387f55458 --- /dev/null +++ b/internal/containerizer/testdata/s2icontainerizer/getcontainer/incorrectservice/plan.yaml @@ -0,0 +1,29 @@ +apiVersion: move2kube.io/v1alpha1 +kind: Plan +metadata: + name: myproject +spec: + inputs: + rootDir: ../../samples/nodejs + services: + nodejs: + - serviceName: nodejs + image: nodejs:latest + translationType: Any2Kube + containerBuildType: S2I + sourceType: + - Directory + targetOptions: + - m2kassets/s2i/nodejs + sourceArtifacts: + SourceCode: + - . + buildArtifacts: + SourceCode: + - . + updateContainerBuildPipeline: true + updateDeployPipeline: true + outputs: + kubernetes: + artifactType: Yamls + clusterType: Kubernetes diff --git a/internal/containerizer/testdata/s2icontainerizer/getcontainer/incorrectservice/service.yaml b/internal/containerizer/testdata/s2icontainerizer/getcontainer/incorrectservice/service.yaml new file mode 100644 index 000000000..3d090ad31 --- /dev/null +++ b/internal/containerizer/testdata/s2icontainerizer/getcontainer/incorrectservice/service.yaml @@ -0,0 +1,16 @@ +serviceName: nodejs +image: nodejs:latest +translationType: Any2Kube +containerBuildType: S2I +sourceType: + - Directory +targetOptions: + - m2kassets/s2i/php +sourceArtifacts: + SourceCode: + - . +buildArtifacts: + SourceCode: + - . +updateContainerBuildPipeline: true +updateDeployPipeline: true diff --git a/internal/containerizer/testdata/s2icontainerizer/getcontainer/normal/container.yaml b/internal/containerizer/testdata/s2icontainerizer/getcontainer/normal/container.yaml new file mode 100644 index 000000000..7a95b8910 --- /dev/null +++ b/internal/containerizer/testdata/s2icontainerizer/getcontainer/normal/container.yaml @@ -0,0 +1,25 @@ +imagenames: + - nodejs:latest +new: true +newfiles: + .s2i/environment: "" + nodejss2ibuild.sh: |- + # Copyright IBM Corporation 2020 + # + # Licensed under the Apache License, Version 2.0 (the "License"); + # you may not use this file except in compliance with the License. + # You may obtain a copy of the License at + # + # http://www.apache.org/licenses/LICENSE-2.0 + # + # Unless required by applicable law or agreed to in writing, software + # distributed under the License is distributed on an "AS IS" BASIS, + # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + # See the License for the specific language governing permissions and + # limitations under the License. + + s2i build . registry.access.redhat.com/ubi8/nodejs-10 nodejs:latest +exposedports: + - 8080 +userid: -1 +accesseddirs: [] diff --git a/internal/containerizer/testdata/s2icontainerizer/getcontainer/normal/plan.yaml b/internal/containerizer/testdata/s2icontainerizer/getcontainer/normal/plan.yaml new file mode 100644 index 000000000..387f55458 --- /dev/null +++ b/internal/containerizer/testdata/s2icontainerizer/getcontainer/normal/plan.yaml @@ -0,0 +1,29 @@ +apiVersion: move2kube.io/v1alpha1 +kind: Plan +metadata: + name: myproject +spec: + inputs: + rootDir: ../../samples/nodejs + services: + nodejs: + - serviceName: nodejs + image: nodejs:latest + translationType: Any2Kube + containerBuildType: S2I + sourceType: + - Directory + targetOptions: + - m2kassets/s2i/nodejs + sourceArtifacts: + SourceCode: + - . + buildArtifacts: + SourceCode: + - . + updateContainerBuildPipeline: true + updateDeployPipeline: true + outputs: + kubernetes: + artifactType: Yamls + clusterType: Kubernetes diff --git a/internal/containerizer/testdata/s2icontainerizer/getcontainer/normal/service.yaml b/internal/containerizer/testdata/s2icontainerizer/getcontainer/normal/service.yaml new file mode 100644 index 000000000..49338b771 --- /dev/null +++ b/internal/containerizer/testdata/s2icontainerizer/getcontainer/normal/service.yaml @@ -0,0 +1,16 @@ +serviceName: nodejs +image: nodejs:latest +translationType: Any2Kube +containerBuildType: S2I +sourceType: + - Directory +targetOptions: + - m2kassets/s2i/nodejs +sourceArtifacts: + SourceCode: + - . +buildArtifacts: + SourceCode: + - . +updateContainerBuildPipeline: true +updateDeployPipeline: true diff --git a/internal/customizer/customizer.go b/internal/customizer/customizer.go new file mode 100644 index 000000000..3a69b013c --- /dev/null +++ b/internal/customizer/customizer.go @@ -0,0 +1,49 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package customizer + +import ( + irtypes "github.com/konveyor/move2kube/internal/types" + log "github.com/sirupsen/logrus" +) + +//Customizer paramertizers the configuration +type customizer interface { + customize(ir *irtypes.IR) error +} + +//GetCustomizers gets the customizers registered with it +func getCustomizers() []customizer { + return []customizer{new(registryCustomizer), new(storageCustomizer)} +} + +//Customize invokes the customizes based on the customizer options +func Customize(ir irtypes.IR) (irtypes.IR, error) { + var customizers = getCustomizers() + log.Infoln("Begin Customization") + for _, c := range customizers { + log.Debugf("[%T] Begin Customization", c) + err := c.customize(&ir) + if err != nil { + log.Warnf("[%T] Failed : %s", c, err.Error()) + } else { + log.Debugf("[%T] Done", c) + } + } + log.Infoln("Customization done") + return ir, nil +} diff --git a/internal/customizer/registrycustomizer.go b/internal/customizer/registrycustomizer.go new file mode 100644 index 000000000..fa5f4e69a --- /dev/null +++ b/internal/customizer/registrycustomizer.go @@ -0,0 +1,289 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package customizer + +import ( + "bytes" + "fmt" + "net/url" + "strings" + + dockercliconfig "github.com/docker/cli/cli/config" + dockercliconfigfile "github.com/docker/cli/cli/config/configfile" + "github.com/docker/cli/cli/config/types" + dockerclitypes "github.com/docker/cli/cli/config/types" + log "github.com/sirupsen/logrus" + corev1 "k8s.io/api/core/v1" + + common "github.com/konveyor/move2kube/internal/common" + "github.com/konveyor/move2kube/internal/qaengine" + irtypes "github.com/konveyor/move2kube/internal/types" + qatypes "github.com/konveyor/move2kube/types/qaengine" +) + +const otherRegistry = "Other" + +// registryCustomizer customizes image registry related configurations +type registryCustomizer struct { +} + +// customize modifies image paths and secret +func (rc *registryCustomizer) customize(ir *irtypes.IR) error { + + usedRegistries := []string{} + registryList := []string{otherRegistry} + newimages := []string{} + + for _, container := range ir.Containers { + if container.New { + newimages = append(newimages, container.ImageNames...) + } + } + + for _, service := range ir.Services { + for _, container := range service.Containers { + if !common.IsStringPresent(newimages, container.Image) { + parts := strings.Split(container.Image, "/") + if len(parts) == 3 { + registryList = append(registryList, parts[0]) + usedRegistries = append(usedRegistries, parts[0]) + } + } + } + } + + registryAuthList := make(map[string]string) //Registry url and auth + defreg := "" + if !common.IgnoreEnvironment { + configFile, err := dockercliconfig.Load(dockercliconfig.Dir()) + if err == nil { + for regurl, regauth := range configFile.AuthConfigs { + u, err := url.Parse(regurl) + if err == nil { + if u.Host != "" { + regurl = u.Host + } + } + if regurl == "" { + continue + } + if !common.IsStringPresent(registryList, regurl) { + registryList = append(registryList, regurl) + } + if regauth.Auth != "" { + defreg = regurl + registryAuthList[regurl] = regauth.Auth + } + } + } + } + + if ir.Kubernetes.RegistryURL == "" && len(newimages) != 0 { + if !common.IsStringPresent(registryList, common.DefaultRegistryURL) { + registryList = append(registryList, common.DefaultRegistryURL) + } + if defreg == "" { + defreg = common.DefaultRegistryURL + } + problem, err := qatypes.NewSelectProblem("Select the registry where your images are hosted:", []string{"You can always change it later by changing the yamls."}, defreg, registryList) + if err != nil { + log.Fatalf("Unable to create problem : %s", err) + } + problem, err = qaengine.FetchAnswer(problem) + if err != nil { + log.Fatalf("Unable to fetch answer : %s", err) + } + reg, err := problem.GetStringAnswer() + if err != nil { + log.Fatalf("Unable to get answer : %s", err) + } + if reg != otherRegistry { + ir.Kubernetes.RegistryURL = reg + } + } + + if ir.Kubernetes.RegistryURL == "" && len(newimages) != 0 { + problem, err := qatypes.NewInputProblem("Enter the name of the registry : ", []string{"Ex : " + common.DefaultRegistryURL}, common.DefaultRegistryURL) + if err != nil { + log.Fatalf("Unable to create problem : %s", err) + } + problem, err = qaengine.FetchAnswer(problem) + if err != nil { + log.Fatalf("Unable to fetch answer : %s", err) + } + reg, err := problem.GetStringAnswer() + if err != nil { + log.Fatalf("Unable to get answer : %s", err) + } + if reg != "" { + ir.Kubernetes.RegistryURL = reg + } else { + ir.Kubernetes.RegistryURL = common.DefaultRegistryURL + } + } + + if ir.Kubernetes.RegistryNamespace == "" && len(newimages) != 0 { + problem, err := qatypes.NewInputProblem("Enter the namespace where the new images are pushed : ", []string{"Ex : " + ir.Name}, ir.Name) + if err != nil { + log.Fatalf("Unable to create problem : %s", err) + } + problem, err = qaengine.FetchAnswer(problem) + if err != nil { + log.Fatalf("Unable to fetch answer : %s", err) + } + ns, err := problem.GetStringAnswer() + if err != nil { + log.Fatalf("Unable to get answer : %s", err) + } + if ns != "" { + ir.Kubernetes.RegistryNamespace = ns + } else { + ir.Kubernetes.RegistryNamespace = ir.Name + } + } + + if !common.IsStringPresent(usedRegistries, ir.Kubernetes.RegistryURL) { + usedRegistries = append(usedRegistries, ir.Kubernetes.RegistryURL) + } + + imagePullSecrets := make(map[string]string) // registryurl, pull secret + + for _, registry := range usedRegistries { + dauth := dockerclitypes.AuthConfig{} + const dockerConfigLogin = "Docker login from config" + const noAuthLogin = "No authentication" + const userLogin = "UserName/Password" + const useExistingPullSecret = "Use existing pull secret" + authOptions := []string{useExistingPullSecret, noAuthLogin, userLogin} + if auth, ok := registryAuthList[ir.Kubernetes.RegistryURL]; ok { + imagePullSecrets[registry] = common.ImagePullSecretPrefix + common.MakeFileNameCompliant(imagePullSecrets[registry]) + dauth.Auth = auth + authOptions = append(authOptions, dockerConfigLogin) + } + + problem, err := qatypes.NewSelectProblem(fmt.Sprintf("[%s] What type of container registry login do you want to use?", registry), []string{"Docker login from config mode, will use the default config from your local machine."}, noAuthLogin, authOptions) + if err != nil { + log.Fatalf("Unable to create problem : %s", err) + } + problem, err = qaengine.FetchAnswer(problem) + if err != nil { + log.Fatalf("Unable to fetch answer : %s", err) + } + auth, err := problem.GetStringAnswer() + if err != nil { + log.Fatalf("Unable to get answer : %s", err) + } + if auth == noAuthLogin { + dauth.Auth = "" + } else if auth == useExistingPullSecret { + problem, err := qatypes.NewInputProblem(fmt.Sprintf("[%s] Enter the name of the pull secret : ", registry), []string{"The pull secret should exist in the namespace where you will be deploying the application."}, "") + if err != nil { + log.Fatalf("Unable to create problem : %s", err) + } + problem, err = qaengine.FetchAnswer(problem) + if err != nil { + log.Fatalf("Unable to fetch answer : %s", err) + } + ps, err := problem.GetStringAnswer() + if err != nil { + log.Fatalf("Unable to get answer : %s", err) + } + imagePullSecrets[registry] = ps + } else if auth != dockerConfigLogin { + problem, err := qatypes.NewInputProblem(fmt.Sprintf("[%s] Enter the container registry username : ", registry), []string{"Enter username for container registry login"}, "iamapikey") + if err != nil { + log.Fatalf("Unable to create problem : %s", err) + } + problem, err = qaengine.FetchAnswer(problem) + if err != nil { + log.Fatalf("Unable to fetch answer : %s", err) + } + un, err := problem.GetStringAnswer() + if err != nil { + log.Fatalf("Unable to get answer : %s", err) + } + dauth.Username = un + problem, err = qatypes.NewPasswordProblem(fmt.Sprintf("[%s] Enter the container registry password : ", registry), []string{"Enter password for container registry login."}) + if err != nil { + log.Fatalf("Unable to create problem : %s", err) + } + problem, err = qaengine.FetchAnswer(problem) + if err != nil { + log.Fatalf("Unable to fetch answer : %s", err) + } + pwd, err := problem.GetStringAnswer() + if err != nil { + log.Fatalf("Unable to get answer : %s", err) + } + dauth.Password = pwd + } + if dauth != (types.AuthConfig{}) { + dconfigfile := dockercliconfigfile.ConfigFile{ + AuthConfigs: map[string]dockerclitypes.AuthConfig{ir.Kubernetes.RegistryURL: dauth}, + } + dconfigbuffer := new(bytes.Buffer) + err := dconfigfile.SaveToWriter(dconfigbuffer) + if err == nil { + data := make(map[string][]byte) + data[".dockerconfigjson"] = dconfigbuffer.Bytes() + ir.AddStorage(irtypes.Storage{ + Name: imagePullSecrets[registry], + StorageType: irtypes.PullSecretKind, + Content: data, + }) + } else { + log.Warnf("Unable to create auth string : %s", err) + } + } + } + + ir.Values.RegistryNamespace = ir.Kubernetes.RegistryNamespace + ir.Values.RegistryURL = ir.Kubernetes.RegistryURL + for _, service := range ir.Services { + for i, serviceContainer := range service.Containers { + if common.IsStringPresent(newimages, serviceContainer.Image) { + parts := strings.Split(serviceContainer.Image, "/") + image, tag := common.GetImageNameAndTag(parts[len(parts)-1]) + if ir.Kubernetes.RegistryURL != "" && ir.Kubernetes.RegistryNamespace != "" { + serviceContainer.Image = ir.Kubernetes.RegistryURL + "/" + ir.Kubernetes.RegistryNamespace + "/" + image + ":" + tag + } else if ir.Kubernetes.RegistryNamespace != "" { + serviceContainer.Image = ir.Kubernetes.RegistryNamespace + "/" + image + ":" + tag + } else { + serviceContainer.Image = image + ":" + tag + } + service.Containers[i] = serviceContainer + } + parts := strings.Split(serviceContainer.Image, "/") + if len(parts) == 3 { + reg := parts[0] + if ps, ok := imagePullSecrets[reg]; ok { + found := false + for _, eps := range service.ImagePullSecrets { + if eps.Name == ps { + found = true + } + } + if !found { + service.ImagePullSecrets = append(service.ImagePullSecrets, corev1.LocalObjectReference{Name: ps}) + } + } + } + } + ir.Services[service.Name] = service + } + return nil +} diff --git a/internal/customizer/storagecustomizer.go b/internal/customizer/storagecustomizer.go new file mode 100644 index 000000000..81ec173fb --- /dev/null +++ b/internal/customizer/storagecustomizer.go @@ -0,0 +1,213 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package customizer + +import ( + "fmt" + "path/filepath" + + log "github.com/sirupsen/logrus" + + corev1 "k8s.io/api/core/v1" + + common "github.com/konveyor/move2kube/internal/common" + "github.com/konveyor/move2kube/internal/qaengine" + irtypes "github.com/konveyor/move2kube/internal/types" + qatypes "github.com/konveyor/move2kube/types/qaengine" +) + +//storageCustomizer customizes storage +type storageCustomizer struct { + ir *irtypes.IR +} + +const ( + alloption string = "Apply for all" +) + +//customize customizes the storage +func (ic *storageCustomizer) customize(ir *irtypes.IR) error { + ic.ir = ir + ic.convertHostPathToPVC() + + if len(ir.Storages) == 0 { + log.Debugf("Empty storage list. Nothing to customize.") + return nil + } + if ir.TargetClusterSpec.StorageClasses == nil || len(ir.TargetClusterSpec.StorageClasses) == 0 { + s := "No storage classes available in the cluster" + log.Warnf(s) + return fmt.Errorf(s) + } + claimSvcMap := ic.getPVCs() + + if len(claimSvcMap) == 0 { + log.Debugf("No service with volumes detected. Storage class configuration not required.") + return nil + } + + selectedKeys := []string{} + for k := range claimSvcMap { + selectedKeys = append(selectedKeys, k) + } + + if len(selectedKeys) > 1 { + if !ic.shouldConfigureSeparately(selectedKeys) { + storageClass := ic.selectStorageClass(ir.TargetClusterSpec.StorageClasses, alloption, []string{}) + for _, storage := range ir.Storages { + if storage.StorageType == irtypes.PVCKind { + storage.PersistentVolumeClaimSpec.StorageClassName = &storageClass + } + } + return nil + } + } + + for i, s := range ir.Storages { + if svs, ok := claimSvcMap[s.Name]; ok { + storageClassName := ic.selectStorageClass(ir.TargetClusterSpec.StorageClasses, s.Name, svs) + s.StorageClassName = &storageClassName + ir.Storages[i] = s + } + } + + return nil +} + +func (ic *storageCustomizer) convertHostPathToPVC() { + hostPathsVisited := make(map[string]string) + for _, service := range ic.ir.Services { + log.Debugf("Service %s has %d volumes", service.Name, len(service.Volumes)) + for vi, v := range service.Volumes { + if v.HostPath != nil { + if name, ok := hostPathsVisited[v.HostPath.Path]; ok { + hostPathsVisited[v.HostPath.Path] = "" + log.Debugf("Detected host path [%s]", v.HostPath.Path) + if !ic.shouldHostPathBeRetained(v.HostPath.Path) { + hostPathsVisited[v.HostPath.Path] = v.Name + v.VolumeSource = corev1.VolumeSource{ + PersistentVolumeClaim: &corev1.PersistentVolumeClaimVolumeSource{ + ClaimName: v.Name, + }} + service.Volumes[vi] = v + ic.ir.Services[service.Name] = service + storageObj := irtypes.Storage{ + StorageType: irtypes.PVCKind, + Name: v.Name, + PersistentVolumeClaimSpec: corev1.PersistentVolumeClaimSpec{ + VolumeName: v.Name, + Resources: corev1.ResourceRequirements{ + Requests: corev1.ResourceList{ + corev1.ResourceStorage: common.DefaultPVCSize, + }, + }, + }} + ic.ir.AddStorage(storageObj) + } + } else { + v.VolumeSource = corev1.VolumeSource{ + PersistentVolumeClaim: &corev1.PersistentVolumeClaimVolumeSource{ + ClaimName: name, + }} + service.Volumes[vi] = v + ic.ir.Services[service.Name] = service + } + } + } + } +} + +func (ic storageCustomizer) shouldHostPathBeRetained(hostPath string) bool { + if filepath.IsAbs(hostPath) { + return true + } + + problem, err := qatypes.NewConfirmProblem(fmt.Sprintf("Do you want to create PVC for host path [%s]?:", hostPath), []string{"Use PVC for persistent storage wherever applicable"}, false) + if err != nil { + log.Fatalf("Unable to create problem : %s", err) + } + problem, err = qaengine.FetchAnswer(problem) + if err != nil { + log.Fatalf("Unable to fetch answer : %s", err) + } + ans, err := problem.GetBoolAnswer() + if err != nil { + log.Fatalf("Unable to get answer : %s", err) + } + return !ans +} + +func (ic storageCustomizer) shouldConfigureSeparately(claims []string) bool { + context := make([]string, 2) + context[0] = "Storage classes have to be configured for below claims:" + context[1] = fmt.Sprintf("%+v", claims) + + problem, err := qatypes.NewConfirmProblem("Do you want to configure different storage classes for each claim?", context, false) + if err != nil { + log.Fatalf("Unable to create problem : %s", err) + } + problem, err = qaengine.FetchAnswer(problem) + if err != nil { + log.Fatalf("Unable to fetch answer : %s", err) + } + ans, err := problem.GetBoolAnswer() + if err != nil { + log.Fatalf("Unable to get answer : %s", err) + } + return ans +} + +func (ic storageCustomizer) selectStorageClass(storageClasses []string, claimName string, services []string) string { + var desc string + if claimName == alloption { + desc = "Which storage class to use for all persistent volume claims?" + } else { + desc = fmt.Sprintf("Which storage class to use for persistent volume claim [%s] used by %+v", claimName, services) + } + problem, err := qatypes.NewSelectProblem(desc, []string{"If you have a custom cluster, you can use collect to get storage classes from it."}, storageClasses[0], storageClasses) + if err != nil { + log.Fatalf("Unable to create problem : %s", err) + } + problem, err = qaengine.FetchAnswer(problem) + if err != nil { + log.Fatalf("Unable to fetch answer : %s", err) + } + sc, err := problem.GetStringAnswer() + if err != nil { + log.Fatalf("Unable to get answer : %s", err) + } + return sc +} + +func (ic *storageCustomizer) getPVCs() map[string][]string { + pvcmap := make(map[string][]string) + for _, s := range ic.ir.Storages { + if s.StorageType == irtypes.PVCKind { + svcList := []string{} + for svcName, svc := range ic.ir.Services { + for _, v := range svc.Volumes { + if v.Name == s.Name { + svcList = append(svcList, svcName) + break + } + } + } + pvcmap[s.Name] = svcList + } + } + return pvcmap +} diff --git a/internal/metadata/clustermdloader.go b/internal/metadata/clustermdloader.go new file mode 100644 index 000000000..1bda2823a --- /dev/null +++ b/internal/metadata/clustermdloader.go @@ -0,0 +1,93 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package metadata + +import ( + log "github.com/sirupsen/logrus" + "gopkg.in/yaml.v3" + + common "github.com/konveyor/move2kube/internal/common" + clustersmetadata "github.com/konveyor/move2kube/internal/metadata/clusters" + irtypes "github.com/konveyor/move2kube/internal/types" + collecttypes "github.com/konveyor/move2kube/types/collection" + plantypes "github.com/konveyor/move2kube/types/plan" +) + +//go:generate go run github.com/konveyor/move2kube/internal/common/generator clusters makemaps + +// ClusterMDLoader Implements Loader interface +type ClusterMDLoader struct { +} + +// UpdatePlan - output a plan based on the input directory contents +func (i ClusterMDLoader) UpdatePlan(inputPath string, plan *plantypes.Plan) error { + files, err := common.GetFilesByExt(inputPath, []string{".yml", ".yaml"}) + if err != nil { + log.Warnf("Unable to fetch yaml files and recognize cluster metadata yamls : %s", err) + } + for _, path := range files { + cm := new(collecttypes.ClusterMetadata) + if common.ReadYaml(path, &cm) == nil && cm.Kind == string(collecttypes.ClusterMetadataKind) { + relpath, _ := plan.GetRelativePath(path) + plan.Spec.Inputs.TargetInfoArtifacts[plantypes.K8sClusterArtifactType] = append(plan.Spec.Inputs.TargetInfoArtifacts[plantypes.K8sClusterArtifactType], relpath) + if plan.Spec.Outputs.Kubernetes.ClusterType == common.DefaultClusterType { + plan.Spec.Outputs.Kubernetes.ClusterType = cm.Name + } + + //If there is a cluster-metadata available from collect, then set below flag to true + plan.Spec.Outputs.Kubernetes.IgnoreUnsupportedKinds = true + } + } + return nil +} + +// LoadToIR loads target cluster in IR +func (i ClusterMDLoader) LoadToIR(p plantypes.Plan, ir *irtypes.IR) error { + clusters := i.GetClusters(p) + ir.TargetClusterSpec = clusters[p.Spec.Outputs.Kubernetes.ClusterType].Spec + return nil +} + +// GetClusters loads list of clusters +func (i ClusterMDLoader) GetClusters(p plantypes.Plan) map[string]collecttypes.ClusterMetadata { + clusters := make(map[string]collecttypes.ClusterMetadata) + for fname, clustermd := range clustersmetadata.Constants { + cm := collecttypes.ClusterMetadata{} + err := yaml.Unmarshal([]byte(clustermd), &cm) + if err != nil { + log.Warnf("Unable to marshal inbuilt cluster info : %s", fname) + continue + } + if len(cm.Spec.StorageClasses) == 0 { + cm.Spec.StorageClasses = []string{common.DefaultStorageClassName} + log.Debugf("No storage class in the cluster, adding [default]") + } + clusters[cm.Name] = cm + } + for _, clusterfilepath := range p.Spec.Inputs.TargetInfoArtifacts[plantypes.K8sClusterArtifactType] { + cm := new(collecttypes.ClusterMetadata) + if common.ReadYaml(p.GetFullPath(clusterfilepath), &cm) == nil && cm.Kind == string(collecttypes.ClusterMetadataKind) { + if len(cm.Spec.StorageClasses) == 0 { + cm.Spec.StorageClasses = []string{common.DefaultStorageClassName} + log.Debugf("No storage class in the cluster, adding [default]") + } + clusters[cm.Name] = *cm + clusters[clusterfilepath] = *cm + } + } + return clusters +} diff --git a/internal/metadata/clustermdloader_test.go b/internal/metadata/clustermdloader_test.go new file mode 100644 index 000000000..080676395 --- /dev/null +++ b/internal/metadata/clustermdloader_test.go @@ -0,0 +1,182 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package metadata_test + +import ( + "reflect" + "testing" + + log "github.com/sirupsen/logrus" + + "github.com/konveyor/move2kube/internal/metadata" + irtypes "github.com/konveyor/move2kube/internal/types" + collecttypes "github.com/konveyor/move2kube/types/collection" + plantypes "github.com/konveyor/move2kube/types/plan" +) + +func TestUpdatePlan(t *testing.T) { + log.SetLevel(log.DebugLevel) + + t.Run("update plan when there are no files", func(t *testing.T) { + // Setup + p := plantypes.NewPlan() + want := plantypes.NewPlan() + loader := metadata.ClusterMDLoader{} + inputPath := t.TempDir() + + // Test + if err := loader.UpdatePlan(inputPath, &p); err != nil { + t.Fatal("Failed to update the plan. Error:", err) + } + if !reflect.DeepEqual(p, want) { + t.Fatal("The updated plan is incorrect. Expected", want, "Actual:", p) + } + }) + + t.Run("update plan with some empty files", func(t *testing.T) { + // Setup + p := plantypes.NewPlan() + want := plantypes.NewPlan() + loader := metadata.ClusterMDLoader{} + inputPath := "testdata/emptyfiles" + + // Test + if err := loader.UpdatePlan(inputPath, &p); err != nil { + t.Fatal("Failed to update the plan. Error:", err) + } + if !reflect.DeepEqual(p, want) { + t.Fatal("The updated plan is incorrect. Expected", want, "Actual:", p) + } + }) + + t.Run("update plan with some invalid files", func(t *testing.T) { + // Setup + p := plantypes.NewPlan() + want := plantypes.NewPlan() + loader := metadata.ClusterMDLoader{} + inputPath := "testdata/invalidfiles" + + // Test + if err := loader.UpdatePlan(inputPath, &p); err != nil { + t.Fatal("Failed to update the plan. Error:", err) + } + if !reflect.DeepEqual(p, want) { + t.Fatal("The updated plan is incorrect. Expected", want, "Actual:", p) + } + }) + + t.Run("update plan with some valid files", func(t *testing.T) { + // Setup + p := plantypes.NewPlan() + want := plantypes.NewPlan() + want.Spec.Inputs.TargetInfoArtifacts[plantypes.K8sClusterArtifactType] = []string{"testdata/validfiles/test1.yaml", "testdata/validfiles/test2.yml"} + want.Spec.Outputs.Kubernetes.ClusterType = "name1" + want.Spec.Outputs.Kubernetes.IgnoreUnsupportedKinds = true + loader := metadata.ClusterMDLoader{} + inputPath := "testdata/validfiles" + + // Test + if err := loader.UpdatePlan(inputPath, &p); err != nil { + t.Fatal("Failed to update the plan. Error:", err) + } + if !reflect.DeepEqual(p, want) { + t.Fatal("The updated plan is incorrect. Expected", want, "Actual:", p) + } + }) +} + +func TestLoadToIR(t *testing.T) { + log.SetLevel(log.DebugLevel) + + t.Run("load IR with an empty plan", func(t *testing.T) { + p := plantypes.NewPlan() + ir := irtypes.NewIR(p) + loader := metadata.ClusterMDLoader{} + if err := loader.LoadToIR(p, &ir); err != nil { + t.Fatal("Failed to load IR. Error:", err) + } + }) +} + +func TestGetClusters(t *testing.T) { + log.SetLevel(log.DebugLevel) + + t.Run("get clusters from an empty plan", func(t *testing.T) { + p := plantypes.NewPlan() + loader := metadata.ClusterMDLoader{} + cmMap := loader.GetClusters(p) + if _, ok := cmMap["Kubernetes"]; !ok { + t.Fatal("Missing builtin kubernetes cluster metadata. The returned cluster info:", cmMap) + } + if _, ok := cmMap["Openshift"]; !ok { + t.Fatal("Missing builtin openshift cluster metadata. The returned cluster info:", cmMap) + } + for k, v := range cmMap { + if v.Kind != string(collecttypes.ClusterMetadataKind) { + t.Fatal("The kind is incorrect for key", k, "Expected:", collecttypes.ClusterMetadataKind, " Actual:", v.Kind) + } else if k != v.Name { + t.Fatal("The cluster metadata was inserted under incorrect key. Expected:", v.Name, "Actual:", k) + } else if len(v.Spec.StorageClasses) == 0 { + t.Fatal("There are no storage classes in the cluster metadata. Excpected there to be at least 'default' storage class. Actual:", v.Spec.StorageClasses) + } + } + }) + + t.Run("get clusters from a filled plan", func(t *testing.T) { + p := plantypes.NewPlan() + p.Spec.Inputs.TargetInfoArtifacts[plantypes.K8sClusterArtifactType] = []string{"testdata/validfiles/test1.yaml", "testdata/validfiles/test2.yml"} + loader := metadata.ClusterMDLoader{} + cmMap := loader.GetClusters(p) + if _, ok := cmMap["Kubernetes"]; !ok { + t.Fatal("Missing builtin kubernetes cluster metadata. The returned cluster info:", cmMap) + } + if _, ok := cmMap["Openshift"]; !ok { + t.Fatal("Missing builtin openshift cluster metadata. The returned cluster info:", cmMap) + } + for k, v := range cmMap { + if v.Kind != string(collecttypes.ClusterMetadataKind) { + t.Fatal("The kind is incorrect for key", k, "Expected:", collecttypes.ClusterMetadataKind, " Actual:", v.Kind) + } else if k != v.Name && !((k == "testdata/validfiles/test1.yaml" || k == "testdata/validfiles/test2.yml") && v.Name == "name1") { + t.Fatal("The cluster metadata was inserted under incorrect key. Expected the key to be either the context name", v.Name, "or the file path. Actual:", k) + } else if len(v.Spec.StorageClasses) == 0 { + t.Fatal("There are no storage classes in the cluster metadata. Excpected there to be at least 'default' storage class. Actual:", v.Spec.StorageClasses) + } + } + }) + + t.Run("get clusters from a filled plan", func(t *testing.T) { + p := plantypes.NewPlan() + p.Spec.Inputs.TargetInfoArtifacts[plantypes.K8sClusterArtifactType] = []string{"testdata/validfilesnostorageclasses/test1.yaml", "testdata/validfilesnostorageclasses/test2.yml"} + loader := metadata.ClusterMDLoader{} + cmMap := loader.GetClusters(p) + if _, ok := cmMap["Kubernetes"]; !ok { + t.Fatal("Missing builtin kubernetes cluster metadata. The returned cluster info:", cmMap) + } + if _, ok := cmMap["Openshift"]; !ok { + t.Fatal("Missing builtin openshift cluster metadata. The returned cluster info:", cmMap) + } + for k, v := range cmMap { + if v.Kind != string(collecttypes.ClusterMetadataKind) { + t.Fatal("The kind is incorrect for key", k, "Expected:", collecttypes.ClusterMetadataKind, " Actual:", v.Kind) + } else if k != v.Name && !((k == "testdata/validfilesnostorageclasses/test1.yaml" || k == "testdata/validfilesnostorageclasses/test2.yml") && v.Name == "name1") { + t.Fatal("The cluster metadata was inserted under incorrect key. Expected the key to be either the context name", v.Name, "or the file path. Actual:", k) + } else if len(v.Spec.StorageClasses) == 0 { + t.Fatal("There are no storage classes in the cluster metadata. Excpected there to be at least 'default' storage class. Actual:", v.Spec.StorageClasses) + } + } + }) +} diff --git a/internal/metadata/clusters/constants.go b/internal/metadata/clusters/constants.go new file mode 100644 index 000000000..dff698d68 --- /dev/null +++ b/internal/metadata/clusters/constants.go @@ -0,0 +1,482 @@ +// Code generated by go generate; DO NOT EDIT. +// This file was generated by robots at +// 2020-09-14 15:52:47.281083 +0530 IST m=+0.001006524 + +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package clusters + +var Constants= map[string]string{ + + `kubernetes_yaml` : `apiVersion: move2kube.io/v1alpha1 +kind: ClusterMetadata +metadata: + name: Kubernetes +spec: + storageClasses: + - default + - ibmc-block-bronze + - ibmc-block-custom + - ibmc-block-gold + - ibmc-block-retain-bronze + - ibmc-block-retain-custom + - ibmc-block-retain-gold + - ibmc-block-retain-silver + - ibmc-block-silver + - ibmc-file-bronze + - ibmc-file-bronze-gid + - ibmc-file-custom + - ibmc-file-gold + - ibmc-file-gold-gid + - ibmc-file-retain-bronze + - ibmc-file-retain-custom + - ibmc-file-retain-gold + - ibmc-file-retain-silver + - ibmc-file-silver + - ibmc-file-silver-gid + apiKindVersionMap: + APIService: + - apiregistration.k8s.io/v1 + Binding: + - v1 + CSIDriver: + - storage.k8s.io/v1beta1 + CSINode: + - storage.k8s.io/v1 + - storage.k8s.io/v1beta1 + CatalogSource: + - operators.coreos.com/v1alpha1 + CertificateSigningRequest: + - certificates.k8s.io/v1beta1 + ClusterImagePolicy: + - securityenforcement.admission.cloud.ibm.com/v1beta1 + ClusterRole: + - rbac.authorization.k8s.io/v1 + - rbac.authorization.k8s.io/v1beta1 + ClusterRoleBinding: + - rbac.authorization.k8s.io/v1 + - rbac.authorization.k8s.io/v1beta1 + ClusterServiceVersion: + - operators.coreos.com/v1alpha1 + ComponentStatus: + - v1 + ConfigMap: + - v1 + ControllerRevision: + - apps/v1 + CronJob: + - batch/v1beta1 + - batch/v2alpha1 + CustomResourceDefinition: + - apiextensions.k8s.io/v1 + DaemonSet: + - apps/v1 + Deployment: + - apps/v1 + EndpointSlice: + - discovery.k8s.io/v1beta1 + Endpoints: + - v1 + Event: + - events.k8s.io/v1beta1 + - v1 + HorizontalPodAutoscaler: + - autoscaling/v1 + - autoscaling/v2beta1 + - autoscaling/v2beta2 + ImagePolicy: + - securityenforcement.admission.cloud.ibm.com/v1beta1 + Ingress: + - networking.k8s.io/v1beta1 + - extensions/v1beta1 + InstallPlan: + - operators.coreos.com/v1alpha1 + Job: + - batch/v1 + Lease: + - coordination.k8s.io/v1beta1 + - coordination.k8s.io/v1 + LimitRange: + - v1 + LocalSubjectAccessReview: + - authorization.k8s.io/v1 + - authorization.k8s.io/v1beta1 + MutatingWebhookConfiguration: + - admissionregistration.k8s.io/v1beta1 + - admissionregistration.k8s.io/v1 + Namespace: + - v1 + NetworkPolicy: + - networking.k8s.io/v1 + Node: + - v1 + OperatorGroup: + - operators.coreos.com/v1 + PersistentVolume: + - v1 + PersistentVolumeClaim: + - v1 + Pod: + - v1 + PodDisruptionBudget: + - policy/v1beta1 + PodSecurityPolicy: + - policy/v1beta1 + PodTemplate: + - v1 + PriorityClass: + - scheduling.k8s.io/v1beta1 + - scheduling.k8s.io/v1 + ReplicaSet: + - apps/v1 + ReplicationController: + - v1 + ResourceQuota: + - v1 + Role: + - rbac.authorization.k8s.io/v1 + - rbac.authorization.k8s.io/v1beta1 + RoleBinding: + - rbac.authorization.k8s.io/v1 + - rbac.authorization.k8s.io/v1beta1 + Secret: + - v1 + SelfSubjectAccessReview: + - authorization.k8s.io/v1 + - authorization.k8s.io/v1beta1 + SelfSubjectRulesReview: + - authorization.k8s.io/v1 + - authorization.k8s.io/v1beta1 + Service: + - v1 + ServiceAccount: + - v1 + StatefulSet: + - apps/v1 + StorageClass: + - storage.k8s.io/v1 + - storage.k8s.io/v1beta1 + SubjectAccessReview: + - authorization.k8s.io/v1 + - authorization.k8s.io/v1beta1 + Subscription: + - operators.coreos.com/v1alpha1 + TokenReview: + - authentication.k8s.io/v1 + - authentication.k8s.io/v1beta1 + ValidatingWebhookConfiguration: + - admissionregistration.k8s.io/v1beta1 + - admissionregistration.k8s.io/v1 + VolumeAttachment: + - storage.k8s.io/v1 + - storage.k8s.io/v1beta1 +`, + + `openshift_yaml` : `apiVersion: move2kube.io/v1alpha1 +kind: ClusterMetadata +metadata: + name: Openshift +spec: + storageClasses: + - default + - ibmc-block-bronze + - ibmc-block-custom + - ibmc-block-gold + - ibmc-block-retain-bronze + - ibmc-block-retain-custom + - ibmc-block-retain-gold + - ibmc-block-retain-silver + - ibmc-block-silver + - ibmc-file-bronze + - ibmc-file-bronze-gid + - ibmc-file-custom + - ibmc-file-gold + - ibmc-file-gold-gid + - ibmc-file-retain-bronze + - ibmc-file-retain-custom + - ibmc-file-retain-gold + - ibmc-file-retain-silver + - ibmc-file-silver + - ibmc-file-silver-gid + apiKindVersionMap: + APIService: + - apiregistration.k8s.io/v1 + - apiregistration.k8s.io/v1beta1 + Alertmanager: + - monitoring.coreos.com/v1 + AppliedClusterResourceQuota: + - quota.openshift.io/v1 + BinaryBuildRequestOptions: + - build.openshift.io/v1 + Binding: + - v1 + BrokerTemplateInstance: + - template.openshift.io/v1 + Build: + - build.openshift.io/v1 + BuildConfig: + - build.openshift.io/v1 + BuildLog: + - build.openshift.io/v1 + BuildRequest: + - build.openshift.io/v1 + Bundle: + - automationbroker.io/v1alpha1 + BundleBinding: + - automationbroker.io/v1alpha1 + BundleInstance: + - automationbroker.io/v1alpha1 + CertificateSigningRequest: + - certificates.k8s.io/v1beta1 + ClusterNetwork: + - network.openshift.io/v1 + ClusterResourceQuota: + - quota.openshift.io/v1 + ClusterRole: + - authorization.openshift.io/v1 + - rbac.authorization.k8s.io/v1 + - rbac.authorization.k8s.io/v1beta1 + ClusterRoleBinding: + - authorization.openshift.io/v1 + - rbac.authorization.k8s.io/v1 + - rbac.authorization.k8s.io/v1beta1 + ClusterServiceBroker: + - servicecatalog.k8s.io/v1beta1 + ClusterServiceClass: + - servicecatalog.k8s.io/v1beta1 + ClusterServicePlan: + - servicecatalog.k8s.io/v1beta1 + ComponentStatus: + - v1 + ConfigMap: + - v1 + ControllerRevision: + - apps/v1 + - apps/v1beta1 + - apps/v1beta2 + CronJob: + - batch/v1beta1 + CustomResourceDefinition: + - apiextensions.k8s.io/v1beta1 + DaemonSet: + - apps/v1 + - apps/v1beta2 + - extensions/v1beta1 + Deployment: + - apps/v1 + - apps/v1beta1 + - apps/v1beta2 + - extensions/v1beta1 + DeploymentConfig: + - apps.openshift.io/v1 + DeploymentConfigRollback: + - apps.openshift.io/v1 + DeploymentLog: + - apps.openshift.io/v1 + DeploymentRequest: + - apps.openshift.io/v1 + DeploymentRollback: + - apps/v1beta1 + - extensions/v1beta1 + EgressNetworkPolicy: + - network.openshift.io/v1 + Endpoints: + - v1 + Event: + - events.k8s.io/v1beta1 + - v1 + Eviction: + - v1 + Group: + - user.openshift.io/v1 + HorizontalPodAutoscaler: + - autoscaling/v1 + - autoscaling/v2beta1 + HostSubnet: + - network.openshift.io/v1 + Identity: + - user.openshift.io/v1 + Image: + - image.openshift.io/v1 + ImageSignature: + - image.openshift.io/v1 + ImageStream: + - image.openshift.io/v1 + ImageStreamImage: + - image.openshift.io/v1 + ImageStreamImport: + - image.openshift.io/v1 + ImageStreamLayers: + - image.openshift.io/v1 + ImageStreamMapping: + - image.openshift.io/v1 + ImageStreamTag: + - image.openshift.io/v1 + Ingress: + - extensions/v1beta1 + Job: + - batch/v1 + LimitRange: + - v1 + LocalResourceAccessReview: + - authorization.openshift.io/v1 + LocalSubjectAccessReview: + - authorization.openshift.io/v1 + - authorization.k8s.io/v1 + - authorization.k8s.io/v1beta1 + MutatingWebhookConfiguration: + - admissionregistration.k8s.io/v1beta1 + Namespace: + - v1 + NetNamespace: + - network.openshift.io/v1 + NetworkPolicy: + - networking.k8s.io/v1 + - extensions/v1beta1 + Node: + - v1 + OAuthAccessToken: + - oauth.openshift.io/v1 + OAuthAuthorizeToken: + - oauth.openshift.io/v1 + OAuthClient: + - oauth.openshift.io/v1 + OAuthClientAuthorization: + - oauth.openshift.io/v1 + PersistentVolume: + - v1 + PersistentVolumeClaim: + - v1 + Pod: + - v1 + PodDisruptionBudget: + - policy/v1beta1 + PodSecurityPolicy: + - extensions/v1beta1 + - policy/v1beta1 + PodSecurityPolicyReview: + - security.openshift.io/v1 + PodSecurityPolicySelfSubjectReview: + - security.openshift.io/v1 + PodSecurityPolicySubjectReview: + - security.openshift.io/v1 + PodTemplate: + - v1 + PriorityClass: + - scheduling.k8s.io/v1beta1 + Project: + - project.openshift.io/v1 + ProjectRequest: + - project.openshift.io/v1 + Prometheus: + - monitoring.coreos.com/v1 + PrometheusRule: + - monitoring.coreos.com/v1 + RangeAllocation: + - security.openshift.io/v1 + ReplicaSet: + - apps/v1 + - apps/v1beta2 + - extensions/v1beta1 + ReplicationController: + - v1 + ReplicationControllerDummy: + - extensions/v1beta1 + ResourceAccessReview: + - authorization.openshift.io/v1 + ResourceQuota: + - v1 + Role: + - authorization.openshift.io/v1 + - rbac.authorization.k8s.io/v1 + - rbac.authorization.k8s.io/v1beta1 + RoleBinding: + - authorization.openshift.io/v1 + - rbac.authorization.k8s.io/v1 + - rbac.authorization.k8s.io/v1beta1 + RoleBindingRestriction: + - authorization.openshift.io/v1 + Route: + - route.openshift.io/v1 + Scale: + - apps.openshift.io/v1 + - apps/v1 + - apps/v1beta1 + - apps/v1beta2 + - extensions/v1beta1 + - v1 + Secret: + - v1 + SecretList: + - image.openshift.io/v1 + SecurityContextConstraints: + - security.openshift.io/v1 + - v1 + SelfSubjectAccessReview: + - authorization.k8s.io/v1 + - authorization.k8s.io/v1beta1 + SelfSubjectRulesReview: + - authorization.openshift.io/v1 + - authorization.k8s.io/v1 + - authorization.k8s.io/v1beta1 + Service: + - v1 + ServiceAccount: + - v1 + ServiceBinding: + - servicecatalog.k8s.io/v1beta1 + ServiceBroker: + - servicecatalog.k8s.io/v1beta1 + ServiceClass: + - servicecatalog.k8s.io/v1beta1 + ServiceInstance: + - servicecatalog.k8s.io/v1beta1 + ServiceMonitor: + - monitoring.coreos.com/v1 + ServicePlan: + - servicecatalog.k8s.io/v1beta1 + StatefulSet: + - apps/v1 + - apps/v1beta1 + - apps/v1beta2 + StorageClass: + - storage.k8s.io/v1 + - storage.k8s.io/v1beta1 + SubjectAccessReview: + - authorization.openshift.io/v1 + - authorization.k8s.io/v1 + - authorization.k8s.io/v1beta1 + SubjectRulesReview: + - authorization.openshift.io/v1 + Template: + - template.openshift.io/v1 + TemplateInstance: + - template.openshift.io/v1 + TokenReview: + - authentication.k8s.io/v1 + - authentication.k8s.io/v1beta1 + User: + - user.openshift.io/v1 + UserIdentityMapping: + - user.openshift.io/v1 + ValidatingWebhookConfiguration: + - admissionregistration.k8s.io/v1beta1 + VolumeAttachment: + - storage.k8s.io/v1beta1 +`, + +} \ No newline at end of file diff --git a/internal/metadata/clusters/kubernetes.yaml b/internal/metadata/clusters/kubernetes.yaml new file mode 100644 index 000000000..035cb2bc8 --- /dev/null +++ b/internal/metadata/clusters/kubernetes.yaml @@ -0,0 +1,162 @@ +apiVersion: move2kube.io/v1alpha1 +kind: ClusterMetadata +metadata: + name: Kubernetes +spec: + storageClasses: + - default + - ibmc-block-bronze + - ibmc-block-custom + - ibmc-block-gold + - ibmc-block-retain-bronze + - ibmc-block-retain-custom + - ibmc-block-retain-gold + - ibmc-block-retain-silver + - ibmc-block-silver + - ibmc-file-bronze + - ibmc-file-bronze-gid + - ibmc-file-custom + - ibmc-file-gold + - ibmc-file-gold-gid + - ibmc-file-retain-bronze + - ibmc-file-retain-custom + - ibmc-file-retain-gold + - ibmc-file-retain-silver + - ibmc-file-silver + - ibmc-file-silver-gid + apiKindVersionMap: + APIService: + - apiregistration.k8s.io/v1 + Binding: + - v1 + CSIDriver: + - storage.k8s.io/v1beta1 + CSINode: + - storage.k8s.io/v1 + - storage.k8s.io/v1beta1 + CatalogSource: + - operators.coreos.com/v1alpha1 + CertificateSigningRequest: + - certificates.k8s.io/v1beta1 + ClusterImagePolicy: + - securityenforcement.admission.cloud.ibm.com/v1beta1 + ClusterRole: + - rbac.authorization.k8s.io/v1 + - rbac.authorization.k8s.io/v1beta1 + ClusterRoleBinding: + - rbac.authorization.k8s.io/v1 + - rbac.authorization.k8s.io/v1beta1 + ClusterServiceVersion: + - operators.coreos.com/v1alpha1 + ComponentStatus: + - v1 + ConfigMap: + - v1 + ControllerRevision: + - apps/v1 + CronJob: + - batch/v1beta1 + - batch/v2alpha1 + CustomResourceDefinition: + - apiextensions.k8s.io/v1 + DaemonSet: + - apps/v1 + Deployment: + - apps/v1 + EndpointSlice: + - discovery.k8s.io/v1beta1 + Endpoints: + - v1 + Event: + - events.k8s.io/v1beta1 + - v1 + HorizontalPodAutoscaler: + - autoscaling/v1 + - autoscaling/v2beta1 + - autoscaling/v2beta2 + ImagePolicy: + - securityenforcement.admission.cloud.ibm.com/v1beta1 + Ingress: + - networking.k8s.io/v1beta1 + - extensions/v1beta1 + InstallPlan: + - operators.coreos.com/v1alpha1 + Job: + - batch/v1 + Lease: + - coordination.k8s.io/v1beta1 + - coordination.k8s.io/v1 + LimitRange: + - v1 + LocalSubjectAccessReview: + - authorization.k8s.io/v1 + - authorization.k8s.io/v1beta1 + MutatingWebhookConfiguration: + - admissionregistration.k8s.io/v1beta1 + - admissionregistration.k8s.io/v1 + Namespace: + - v1 + NetworkPolicy: + - networking.k8s.io/v1 + Node: + - v1 + OperatorGroup: + - operators.coreos.com/v1 + PersistentVolume: + - v1 + PersistentVolumeClaim: + - v1 + Pod: + - v1 + PodDisruptionBudget: + - policy/v1beta1 + PodSecurityPolicy: + - policy/v1beta1 + PodTemplate: + - v1 + PriorityClass: + - scheduling.k8s.io/v1beta1 + - scheduling.k8s.io/v1 + ReplicaSet: + - apps/v1 + ReplicationController: + - v1 + ResourceQuota: + - v1 + Role: + - rbac.authorization.k8s.io/v1 + - rbac.authorization.k8s.io/v1beta1 + RoleBinding: + - rbac.authorization.k8s.io/v1 + - rbac.authorization.k8s.io/v1beta1 + Secret: + - v1 + SelfSubjectAccessReview: + - authorization.k8s.io/v1 + - authorization.k8s.io/v1beta1 + SelfSubjectRulesReview: + - authorization.k8s.io/v1 + - authorization.k8s.io/v1beta1 + Service: + - v1 + ServiceAccount: + - v1 + StatefulSet: + - apps/v1 + StorageClass: + - storage.k8s.io/v1 + - storage.k8s.io/v1beta1 + SubjectAccessReview: + - authorization.k8s.io/v1 + - authorization.k8s.io/v1beta1 + Subscription: + - operators.coreos.com/v1alpha1 + TokenReview: + - authentication.k8s.io/v1 + - authentication.k8s.io/v1beta1 + ValidatingWebhookConfiguration: + - admissionregistration.k8s.io/v1beta1 + - admissionregistration.k8s.io/v1 + VolumeAttachment: + - storage.k8s.io/v1 + - storage.k8s.io/v1beta1 diff --git a/internal/metadata/clusters/openshift.yaml b/internal/metadata/clusters/openshift.yaml new file mode 100644 index 000000000..88dd95569 --- /dev/null +++ b/internal/metadata/clusters/openshift.yaml @@ -0,0 +1,291 @@ +apiVersion: move2kube.io/v1alpha1 +kind: ClusterMetadata +metadata: + name: Openshift +spec: + storageClasses: + - default + - ibmc-block-bronze + - ibmc-block-custom + - ibmc-block-gold + - ibmc-block-retain-bronze + - ibmc-block-retain-custom + - ibmc-block-retain-gold + - ibmc-block-retain-silver + - ibmc-block-silver + - ibmc-file-bronze + - ibmc-file-bronze-gid + - ibmc-file-custom + - ibmc-file-gold + - ibmc-file-gold-gid + - ibmc-file-retain-bronze + - ibmc-file-retain-custom + - ibmc-file-retain-gold + - ibmc-file-retain-silver + - ibmc-file-silver + - ibmc-file-silver-gid + apiKindVersionMap: + APIService: + - apiregistration.k8s.io/v1 + - apiregistration.k8s.io/v1beta1 + Alertmanager: + - monitoring.coreos.com/v1 + AppliedClusterResourceQuota: + - quota.openshift.io/v1 + BinaryBuildRequestOptions: + - build.openshift.io/v1 + Binding: + - v1 + BrokerTemplateInstance: + - template.openshift.io/v1 + Build: + - build.openshift.io/v1 + BuildConfig: + - build.openshift.io/v1 + BuildLog: + - build.openshift.io/v1 + BuildRequest: + - build.openshift.io/v1 + Bundle: + - automationbroker.io/v1alpha1 + BundleBinding: + - automationbroker.io/v1alpha1 + BundleInstance: + - automationbroker.io/v1alpha1 + CertificateSigningRequest: + - certificates.k8s.io/v1beta1 + ClusterNetwork: + - network.openshift.io/v1 + ClusterResourceQuota: + - quota.openshift.io/v1 + ClusterRole: + - authorization.openshift.io/v1 + - rbac.authorization.k8s.io/v1 + - rbac.authorization.k8s.io/v1beta1 + ClusterRoleBinding: + - authorization.openshift.io/v1 + - rbac.authorization.k8s.io/v1 + - rbac.authorization.k8s.io/v1beta1 + ClusterServiceBroker: + - servicecatalog.k8s.io/v1beta1 + ClusterServiceClass: + - servicecatalog.k8s.io/v1beta1 + ClusterServicePlan: + - servicecatalog.k8s.io/v1beta1 + ComponentStatus: + - v1 + ConfigMap: + - v1 + ControllerRevision: + - apps/v1 + - apps/v1beta1 + - apps/v1beta2 + CronJob: + - batch/v1beta1 + CustomResourceDefinition: + - apiextensions.k8s.io/v1beta1 + DaemonSet: + - apps/v1 + - apps/v1beta2 + - extensions/v1beta1 + Deployment: + - apps/v1 + - apps/v1beta1 + - apps/v1beta2 + - extensions/v1beta1 + DeploymentConfig: + - apps.openshift.io/v1 + DeploymentConfigRollback: + - apps.openshift.io/v1 + DeploymentLog: + - apps.openshift.io/v1 + DeploymentRequest: + - apps.openshift.io/v1 + DeploymentRollback: + - apps/v1beta1 + - extensions/v1beta1 + EgressNetworkPolicy: + - network.openshift.io/v1 + Endpoints: + - v1 + Event: + - events.k8s.io/v1beta1 + - v1 + Eviction: + - v1 + Group: + - user.openshift.io/v1 + HorizontalPodAutoscaler: + - autoscaling/v1 + - autoscaling/v2beta1 + HostSubnet: + - network.openshift.io/v1 + Identity: + - user.openshift.io/v1 + Image: + - image.openshift.io/v1 + ImageSignature: + - image.openshift.io/v1 + ImageStream: + - image.openshift.io/v1 + ImageStreamImage: + - image.openshift.io/v1 + ImageStreamImport: + - image.openshift.io/v1 + ImageStreamLayers: + - image.openshift.io/v1 + ImageStreamMapping: + - image.openshift.io/v1 + ImageStreamTag: + - image.openshift.io/v1 + Ingress: + - extensions/v1beta1 + Job: + - batch/v1 + LimitRange: + - v1 + LocalResourceAccessReview: + - authorization.openshift.io/v1 + LocalSubjectAccessReview: + - authorization.openshift.io/v1 + - authorization.k8s.io/v1 + - authorization.k8s.io/v1beta1 + MutatingWebhookConfiguration: + - admissionregistration.k8s.io/v1beta1 + Namespace: + - v1 + NetNamespace: + - network.openshift.io/v1 + NetworkPolicy: + - networking.k8s.io/v1 + - extensions/v1beta1 + Node: + - v1 + OAuthAccessToken: + - oauth.openshift.io/v1 + OAuthAuthorizeToken: + - oauth.openshift.io/v1 + OAuthClient: + - oauth.openshift.io/v1 + OAuthClientAuthorization: + - oauth.openshift.io/v1 + PersistentVolume: + - v1 + PersistentVolumeClaim: + - v1 + Pod: + - v1 + PodDisruptionBudget: + - policy/v1beta1 + PodSecurityPolicy: + - extensions/v1beta1 + - policy/v1beta1 + PodSecurityPolicyReview: + - security.openshift.io/v1 + PodSecurityPolicySelfSubjectReview: + - security.openshift.io/v1 + PodSecurityPolicySubjectReview: + - security.openshift.io/v1 + PodTemplate: + - v1 + PriorityClass: + - scheduling.k8s.io/v1beta1 + Project: + - project.openshift.io/v1 + ProjectRequest: + - project.openshift.io/v1 + Prometheus: + - monitoring.coreos.com/v1 + PrometheusRule: + - monitoring.coreos.com/v1 + RangeAllocation: + - security.openshift.io/v1 + ReplicaSet: + - apps/v1 + - apps/v1beta2 + - extensions/v1beta1 + ReplicationController: + - v1 + ReplicationControllerDummy: + - extensions/v1beta1 + ResourceAccessReview: + - authorization.openshift.io/v1 + ResourceQuota: + - v1 + Role: + - authorization.openshift.io/v1 + - rbac.authorization.k8s.io/v1 + - rbac.authorization.k8s.io/v1beta1 + RoleBinding: + - authorization.openshift.io/v1 + - rbac.authorization.k8s.io/v1 + - rbac.authorization.k8s.io/v1beta1 + RoleBindingRestriction: + - authorization.openshift.io/v1 + Route: + - route.openshift.io/v1 + Scale: + - apps.openshift.io/v1 + - apps/v1 + - apps/v1beta1 + - apps/v1beta2 + - extensions/v1beta1 + - v1 + Secret: + - v1 + SecretList: + - image.openshift.io/v1 + SecurityContextConstraints: + - security.openshift.io/v1 + - v1 + SelfSubjectAccessReview: + - authorization.k8s.io/v1 + - authorization.k8s.io/v1beta1 + SelfSubjectRulesReview: + - authorization.openshift.io/v1 + - authorization.k8s.io/v1 + - authorization.k8s.io/v1beta1 + Service: + - v1 + ServiceAccount: + - v1 + ServiceBinding: + - servicecatalog.k8s.io/v1beta1 + ServiceBroker: + - servicecatalog.k8s.io/v1beta1 + ServiceClass: + - servicecatalog.k8s.io/v1beta1 + ServiceInstance: + - servicecatalog.k8s.io/v1beta1 + ServiceMonitor: + - monitoring.coreos.com/v1 + ServicePlan: + - servicecatalog.k8s.io/v1beta1 + StatefulSet: + - apps/v1 + - apps/v1beta1 + - apps/v1beta2 + StorageClass: + - storage.k8s.io/v1 + - storage.k8s.io/v1beta1 + SubjectAccessReview: + - authorization.openshift.io/v1 + - authorization.k8s.io/v1 + - authorization.k8s.io/v1beta1 + SubjectRulesReview: + - authorization.openshift.io/v1 + Template: + - template.openshift.io/v1 + TemplateInstance: + - template.openshift.io/v1 + TokenReview: + - authentication.k8s.io/v1 + - authentication.k8s.io/v1beta1 + User: + - user.openshift.io/v1 + UserIdentityMapping: + - user.openshift.io/v1 + ValidatingWebhookConfiguration: + - admissionregistration.k8s.io/v1beta1 + VolumeAttachment: + - storage.k8s.io/v1beta1 diff --git a/internal/metadata/k8sfiles.go b/internal/metadata/k8sfiles.go new file mode 100644 index 000000000..dae390a5f --- /dev/null +++ b/internal/metadata/k8sfiles.go @@ -0,0 +1,80 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package metadata + +import ( + "io/ioutil" + + log "github.com/sirupsen/logrus" + "k8s.io/apimachinery/pkg/runtime/serializer" + + "github.com/konveyor/move2kube/internal/apiresourceset" + common "github.com/konveyor/move2kube/internal/common" + irtypes "github.com/konveyor/move2kube/internal/types" + plantypes "github.com/konveyor/move2kube/types/plan" +) + +//K8sFilesLoader Implements Loader interface +type K8sFilesLoader struct { +} + +// UpdatePlan - output a plan based on the input directory contents +func (i K8sFilesLoader) UpdatePlan(inputPath string, plan *plantypes.Plan) error { + codecs := serializer.NewCodecFactory((&apiresourceset.K8sAPIResourceSet{}).GetScheme()) + + files, err := common.GetFilesByExt(inputPath, []string{".yml", ".yaml"}) + if err != nil { + log.Warnf("Unable to fetch yaml files and recognize k8 yamls : %s", err) + } + for _, path := range files { + relpath, _ := plan.GetRelativePath(path) + data, err := ioutil.ReadFile(path) + if err != nil { + log.Debugf("ignoring file %s", path) + continue + } + _, _, err = codecs.UniversalDeserializer().Decode(data, nil, nil) + if err != nil { + log.Debugf("ignoring file %s since serialization failed", path) + continue + } else { + plan.Spec.Inputs.K8sFiles = append(plan.Spec.Inputs.K8sFiles, relpath) + } + } + return nil +} + +// LoadToIR loads k8s files as cached objects +func (i K8sFilesLoader) LoadToIR(p plantypes.Plan, ir *irtypes.IR) error { + codecs := serializer.NewCodecFactory((&apiresourceset.K8sAPIResourceSet{}).GetScheme()) + for _, path := range p.Spec.Inputs.K8sFiles { + fullpath := p.GetFullPath(path) + data, err := ioutil.ReadFile(fullpath) + if err != nil { + log.Debugf("ignoring file %s", path) + continue + } + obj, _, err := codecs.UniversalDeserializer().Decode(data, nil, nil) + if err != nil { + log.Debugf("ignoring file %s since serialization failed", path) + continue + } else { + ir.CachedObjects = append(ir.CachedObjects, obj) + } + } + return nil +} diff --git a/internal/metadata/metadata.go b/internal/metadata/metadata.go new file mode 100644 index 000000000..acf6b8b83 --- /dev/null +++ b/internal/metadata/metadata.go @@ -0,0 +1,34 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package metadata + +import ( + irtypes "github.com/konveyor/move2kube/internal/types" + plantypes "github.com/konveyor/move2kube/types/plan" +) + +// Loader handles loading of various metadata +type Loader interface { + UpdatePlan(inputPath string, p *plantypes.Plan) error + LoadToIR(p plantypes.Plan, ir *irtypes.IR) error +} + +// GetLoaders returns planner for given format +func GetLoaders() []Loader { + var planners = []Loader{new(ClusterMDLoader), new(K8sFilesLoader), new(QACacheLoader)} + return planners +} diff --git a/internal/metadata/qacaches.go b/internal/metadata/qacaches.go new file mode 100644 index 000000000..54bf375c7 --- /dev/null +++ b/internal/metadata/qacaches.go @@ -0,0 +1,57 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package metadata + +import ( + log "github.com/sirupsen/logrus" + + common "github.com/konveyor/move2kube/internal/common" + "github.com/konveyor/move2kube/internal/qaengine" + irtypes "github.com/konveyor/move2kube/internal/types" + plantypes "github.com/konveyor/move2kube/types/plan" + qatypes "github.com/konveyor/move2kube/types/qaengine" +) + +// QACacheLoader loads the qa caches +type QACacheLoader struct { +} + +// UpdatePlan - output a plan based on the input directory contents +func (i QACacheLoader) UpdatePlan(inputPath string, plan *plantypes.Plan) error { + files, err := common.GetFilesByExt(inputPath, []string{".yml", ".yaml"}) + if err != nil { + log.Warnf("Unable to fetch yaml files and recognize qacache metadata yamls : %s", err) + } + for _, path := range files { + cm := new(qatypes.Cache) + if common.ReadYaml(path, &cm) == nil && cm.Kind == string(qatypes.QACacheKind) { + relpath, _ := plan.GetRelativePath(path) + plan.Spec.Inputs.QACaches = append(plan.Spec.Inputs.QACaches, relpath) + } + } + return nil +} + +// LoadToIR starts the cache responders +func (i QACacheLoader) LoadToIR(p plantypes.Plan, ir *irtypes.IR) error { + cachepaths := []string{} + for i := len(p.Spec.Inputs.QACaches) - 1; i >= 0; i-- { + cachepaths = append(cachepaths, p.GetFullPath(p.Spec.Inputs.QACaches[i])) + } + qaengine.AddCaches(cachepaths) + return nil +} diff --git a/internal/metadata/testdata/emptyfiles/test1.yaml b/internal/metadata/testdata/emptyfiles/test1.yaml new file mode 100644 index 000000000..e69de29bb diff --git a/internal/metadata/testdata/emptyfiles/test2.yml b/internal/metadata/testdata/emptyfiles/test2.yml new file mode 100644 index 000000000..e69de29bb diff --git a/internal/metadata/testdata/invalidfiles/test1.yaml b/internal/metadata/testdata/invalidfiles/test1.yaml new file mode 100644 index 000000000..a2eebca9c --- /dev/null +++ b/internal/metadata/testdata/invalidfiles/test1.yaml @@ -0,0 +1,10 @@ +--- +american: + - Boston Red Sox + - Detroit Tigers + - New York Yankees +national: + - New York Mets + - Chicago Cubs + - Atlanta Braves +... \ No newline at end of file diff --git a/internal/metadata/testdata/invalidfiles/test2.yml b/internal/metadata/testdata/invalidfiles/test2.yml new file mode 100644 index 000000000..5c9bba174 --- /dev/null +++ b/internal/metadata/testdata/invalidfiles/test2.yml @@ -0,0 +1,10 @@ +--- +- + name: Mark McGwire + hr: 65 + avg: 0.278 +- + name: Sammy Sosa + hr: 63 + avg: 0.288 +... \ No newline at end of file diff --git a/internal/metadata/testdata/validfiles/test1.yaml b/internal/metadata/testdata/validfiles/test1.yaml new file mode 100644 index 000000000..99eaa5077 --- /dev/null +++ b/internal/metadata/testdata/validfiles/test1.yaml @@ -0,0 +1,19 @@ +--- +apiVersion: move2kube.io/v1alpha1 +kind: ClusterMetadata +metadata: + name: name1 +spec: + storageClasses: + - class1 + - class2 + apiKindVersionMap: + key1: + - 1.0.0 + - 1.1.0 + - 1.1.1 + key2: + - 2.0.0 + - 2.2.0 + - 2.2.2 +... diff --git a/internal/metadata/testdata/validfiles/test2.yml b/internal/metadata/testdata/validfiles/test2.yml new file mode 100644 index 000000000..99eaa5077 --- /dev/null +++ b/internal/metadata/testdata/validfiles/test2.yml @@ -0,0 +1,19 @@ +--- +apiVersion: move2kube.io/v1alpha1 +kind: ClusterMetadata +metadata: + name: name1 +spec: + storageClasses: + - class1 + - class2 + apiKindVersionMap: + key1: + - 1.0.0 + - 1.1.0 + - 1.1.1 + key2: + - 2.0.0 + - 2.2.0 + - 2.2.2 +... diff --git a/internal/metadata/testdata/validfilesnostorageclasses/test1.yaml b/internal/metadata/testdata/validfilesnostorageclasses/test1.yaml new file mode 100644 index 000000000..d58236fb6 --- /dev/null +++ b/internal/metadata/testdata/validfilesnostorageclasses/test1.yaml @@ -0,0 +1,16 @@ +--- +apiVersion: move2kube.io/v1alpha1 +kind: ClusterMetadata +metadata: + name: name1 +spec: + apiKindVersionMap: + key1: + - 1.0.0 + - 1.1.0 + - 1.1.1 + key2: + - 2.0.0 + - 2.2.0 + - 2.2.2 +... diff --git a/internal/metadata/testdata/validfilesnostorageclasses/test2.yml b/internal/metadata/testdata/validfilesnostorageclasses/test2.yml new file mode 100644 index 000000000..2d323e0a1 --- /dev/null +++ b/internal/metadata/testdata/validfilesnostorageclasses/test2.yml @@ -0,0 +1,16 @@ +--- +apiVersion: move2kube.io/v1alpha1 +kind: ClusterMetadata +metadata: + name: name1 +spec: + apiKindVersionMap: + key1: + - 1.0.0 + - 1.1.0 + - 1.1.1 + key2: + - 2.0.0 + - 2.2.0 + - 2.2.2 +... diff --git a/internal/move2kube/collector.go b/internal/move2kube/collector.go new file mode 100644 index 000000000..85fcda564 --- /dev/null +++ b/internal/move2kube/collector.go @@ -0,0 +1,68 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package move2kube + +import ( + "os" + "strings" + + log "github.com/sirupsen/logrus" + + collector "github.com/konveyor/move2kube/internal/collector" + common "github.com/konveyor/move2kube/internal/common" +) + +//Collect gets the metadata from multiple sources, filters it and dumps it into files within source directory +func Collect(inputPath string, outputPath string, annotations []string) { + var collectors, err = collector.GetCollectors() + if err != nil { + log.Fatal(err) + } + //Creating the output directory if it does not exist + err = os.MkdirAll(outputPath, common.DefaultDirectoryPermission) + if err != nil { + log.Fatalf("Unable to create output directory %s : %s", outputPath, err) + } + log.Infoln("Begin collection") + for _, l := range collectors { + if len(annotations) != 0 { + collectorannotations := l.GetAnnotations() + if !hasOverlap(annotations, collectorannotations) { + continue + } + } + log.Infof("[%T] Begin collection", l) + err = l.Collect(inputPath, outputPath) + if err != nil { + log.Warnf("[%T] Failed : %s", l, err.Error()) + } else { + log.Infof("[%T] Done", l) + } + } + log.Infoln("Collection done") +} + +func hasOverlap(a []string, b []string) bool { + for _, val1 := range a { + for _, val2 := range b { + if strings.EqualFold(val1, val2) { + return true + } + } + } + return false +} diff --git a/internal/move2kube/planner.go b/internal/move2kube/planner.go new file mode 100644 index 000000000..aa35d4f71 --- /dev/null +++ b/internal/move2kube/planner.go @@ -0,0 +1,224 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package move2kube + +import ( + log "github.com/sirupsen/logrus" + + common "github.com/konveyor/move2kube/internal/common" + "github.com/konveyor/move2kube/internal/metadata" + "github.com/konveyor/move2kube/internal/qaengine" + "github.com/konveyor/move2kube/internal/source" + plantypes "github.com/konveyor/move2kube/types/plan" + qatypes "github.com/konveyor/move2kube/types/qaengine" +) + +//CreatePlan creates the plan from all planners +func CreatePlan(inputPath string, prjName string) plantypes.Plan { + var p = plantypes.NewPlan() + p.Name = prjName + // Setup rootdir. + p.Spec.Inputs.RootDir = inputPath + + translationPlanners := source.GetSourceLoaders() + log.Infoln("Planning Translation") + for _, l := range translationPlanners { + log.Infof("[%T] Planning translation", l) + services, err := l.GetServiceOptions(inputPath, p) + if err != nil { + log.Warnf("[%T] Failed : %s", l, err) + } else { + p.AddServicesToPlan(services) + log.Infof("[%T] Done", l) + } + } + log.Infoln("Translation planning done") + + log.Infoln("Planning Metadata") + metadataPlanners := metadata.GetLoaders() + for _, l := range metadataPlanners { + log.Infof("[%T] Planning metadata", l) + err := l.UpdatePlan(inputPath, &p) + if err != nil { + log.Warnf("[%T] Failed : %s", l, err) + } else { + log.Infof("[%T] Done", l) + } + } + log.Infoln("Metadata planning done") + return p +} + +// CuratePlan allows curation the plan with the qa engine +func CuratePlan(p plantypes.Plan) plantypes.Plan { + // Load qa caches + cachepaths := []string{} + for i := len(p.Spec.Inputs.QACaches) - 1; i >= 0; i-- { + cachepaths = append(cachepaths, p.GetFullPath(p.Spec.Inputs.QACaches[i])) + } + qaengine.AddCaches(cachepaths) + // Identify services of interest + servicenames := []string{} + for sn := range p.Spec.Inputs.Services { + servicenames = append(servicenames, sn) + } + problem, err := qatypes.NewMultiSelectProblem("Select all services that are needed:", []string{"The services unselected here will be ignored."}, servicenames, servicenames) + if err != nil { + log.Fatalf("Unable to create problem : %s", err) + } + problem, err = qaengine.FetchAnswer(problem) + if err != nil { + log.Fatalf("Unable to fetch answer : %s", err) + } + selectedServices, err := problem.GetSliceAnswer() + if err != nil { + log.Fatalf("Unable to get answer : %s", err) + } + planservices := make(map[string][]plantypes.Service) + for _, s := range selectedServices { + planservices[s] = p.Spec.Inputs.Services[s] + } + p.Spec.Inputs.Services = planservices + + // Identify containerization techniques of interest + conTypes := []string{} + for _, s := range p.Spec.Inputs.Services { + for _, so := range s { + if !common.IsStringPresent(conTypes, string(so.ContainerBuildType)) { + conTypes = append(conTypes, string(so.ContainerBuildType)) + } + } + } + problem, err = qatypes.NewMultiSelectProblem("Select all containerization modes that is of interest:", []string{"The services which does not support any of the containerization technique you are interested will be ignored."}, conTypes, conTypes) + if err != nil { + log.Fatalf("Unable to create problem : %s", err) + } + problem, err = qaengine.FetchAnswer(problem) + if err != nil { + log.Fatalf("Unable to fetch answer : %s", err) + } + selectedConTypes, err := problem.GetSliceAnswer() + if err != nil { + log.Fatalf("Unable to get answer : %s", err) + } + if len(selectedConTypes) == 0 { + log.Fatalf("No containerization technique was selected; Terminating.") + } + services := make(map[string][]plantypes.Service) + for sn, s := range p.Spec.Inputs.Services { + sConTypes := []string{} + for _, so := range s { + if common.IsStringPresent(selectedConTypes, string(so.ContainerBuildType)) { + sConTypes = append(sConTypes, string(so.ContainerBuildType)) + } + } + if len(sConTypes) == 0 { + log.Warnf("Ignoring service %s, since it does not support any selected containerization technique.", sn) + continue + } + selectedSConType := sConTypes[0] + if len(sConTypes) > 1 { + problem, err := qatypes.NewSelectProblem("Select containerization technique for service "+sn+":", []string{"Choose the containerization technique of interest."}, selectedSConType, sConTypes) + if err != nil { + log.Fatalf("Unable to create problem : %s", err) + } + problem, err = qaengine.FetchAnswer(problem) + if err != nil { + log.Fatalf("Unable to fetch answer : %s", err) + } + selectedSConType, err = problem.GetStringAnswer() + if err != nil { + log.Fatalf("Unable to get answer : %s", err) + } + } + for _, so := range s { + if selectedSConType == string(so.ContainerBuildType) { + if len(so.ContainerizationTargetOptions) > 1 { + problem, err := qatypes.NewSelectProblem("Select containerization technique's mode for service "+sn+":", []string{"Choose the containerization technique mode of interest."}, so.ContainerizationTargetOptions[0], so.ContainerizationTargetOptions) + if err != nil { + log.Fatalf("Unable to create problem : %s", err) + } + problem, err = qaengine.FetchAnswer(problem) + if err != nil { + log.Fatalf("Unable to fetch answer : %s", err) + } + selectedSConMode, err := problem.GetStringAnswer() + if err != nil { + log.Fatalf("Unable to get answer : %s", err) + } + so.ContainerizationTargetOptions = []string{selectedSConMode} + } + services[sn] = []plantypes.Service{so} + break + } + } + } + p.Spec.Inputs.Services = services + + // Choose output artifact type + artifactTypeList := make([]string, 3) + artifactTypeList[0] = string(plantypes.Yamls) + artifactTypeList[1] = string(plantypes.Helm) + artifactTypeList[2] = string(plantypes.Knative) + problem, err = qatypes.NewSelectProblem("Choose the artifact type:", []string{"Yamls - Generate Kubernetes Yamls", "Helm - Generate Helm chart", "Knative - Create Knative artifacts"}, string(plantypes.Yamls), artifactTypeList) + if err != nil { + log.Fatalf("Unable to create problem : %s", err) + } + problem, err = qaengine.FetchAnswer(problem) + if err != nil { + log.Fatalf("Unable to fetch answer : %s", err) + } + artifactType, err := problem.GetStringAnswer() + if err != nil { + log.Fatalf("Unable to get answer : %s", err) + } + p.Spec.Outputs.Kubernetes.ArtifactType = plantypes.TargetArtifactTypeValue(artifactType) + + // Choose cluster type to target + clusters := metadata.ClusterMDLoader{}.GetClusters(p) + clusterTypeList := []string{} + for c := range clusters { + clusterTypeList = append(clusterTypeList, c) + } + problem, err = qatypes.NewSelectProblem("Choose the cluster type:", []string{"Choose the cluster type you would like to target"}, string(common.DefaultClusterType), clusterTypeList) + if err != nil { + log.Fatalf("Unable to create problem : %s", err) + } + problem, err = qaengine.FetchAnswer(problem) + if err != nil { + log.Fatalf("Unable to fetch answer : %s", err) + } + p.Spec.Outputs.Kubernetes.ClusterType, err = problem.GetStringAnswer() + if err != nil { + log.Fatalf("Unable to get answer : %s", err) + } + + return p +} + +//WritePlan writes the plan +func WritePlan(plan plantypes.Plan, outputPath string) error { + err := common.WriteYaml(outputPath, plan) + return err +} + +//ReadPlan reads the plan +func ReadPlan(planFile string) (plantypes.Plan, error) { + var plan plantypes.Plan + err := common.ReadYaml(planFile, &plan) + return plan, err +} diff --git a/internal/move2kube/planner_test.go b/internal/move2kube/planner_test.go new file mode 100644 index 000000000..89f178bce --- /dev/null +++ b/internal/move2kube/planner_test.go @@ -0,0 +1,106 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package move2kube_test + +import ( + "os" + "reflect" + "testing" + + log "github.com/sirupsen/logrus" + + "github.com/konveyor/move2kube/internal/common" + "github.com/konveyor/move2kube/internal/move2kube" + plantypes "github.com/konveyor/move2kube/types/plan" +) + +func TestCreatePlan(t *testing.T) { + log.SetLevel(log.DebugLevel) + + t.Run("create plan for empty app and without the cache folder", func(t *testing.T) { + // Setup + inputPath := t.TempDir() + prjName := "project1" + + want := plantypes.NewPlan() + want.Name = prjName + want.Spec.Inputs.RootDir = inputPath + + // Test + p := move2kube.CreatePlan(inputPath, prjName) + if !reflect.DeepEqual(p, want) { + t.Fatal("Failed to create the plan properly. Expected:", want, "Actual", p) + } + }) + + t.Run("create plan for empty app", func(t *testing.T) { + // Setup + inputPath := t.TempDir() + prjName := "project1" + + // If the cache folder exists delete it + if _, err := os.Stat(common.AssetsPath); !os.IsNotExist(err) { + if err := os.RemoveAll(common.AssetsPath); err != nil { + t.Fatal("Failed to remove the cache folder from previous runs. Error:", err) + } + } + // Create the cache folder (.m2k) it expects to find. + if err := os.MkdirAll(common.AssetsPath, os.ModeDir|os.ModePerm); err != nil { + t.Fatal("Failed to make the common.AssetsPath directory:", common.AssetsPath, "Error:", err) + } + defer os.RemoveAll(common.AssetsPath) + + want := plantypes.NewPlan() + want.Name = prjName + want.Spec.Inputs.RootDir = inputPath + + // Test + p := move2kube.CreatePlan(inputPath, prjName) + if !reflect.DeepEqual(p, want) { + t.Fatal("Failed to create the plan properly. Expected:", want, "Actual", p) + } + }) + + t.Run("create plan for a simple nodejs app", func(t *testing.T) { + // Setup + inputPath := "../../samples/nodejs" + prjName := "nodejs-app" + + // If the cache folder exists delete it + if _, err := os.Stat(common.AssetsPath); !os.IsNotExist(err) { + if err := os.RemoveAll(common.AssetsPath); err != nil { + t.Fatal("Failed to remove the cache folder from previous runs. Error:", err) + } + } + // Create the cache folder (.m2k) it expects to find. + if err := os.Mkdir(common.AssetsPath, os.ModeDir|os.ModePerm); err != nil { + t.Fatal("Failed to make the common.AssetsPath directory:", common.AssetsPath, "Error:", err) + } + defer os.RemoveAll(common.AssetsPath) + + want := plantypes.NewPlan() + if err := common.ReadYaml("testdata/expectedplanfornodejsapp.yaml", &want); err != nil { + t.Fatal("failed to read the expected output plan from yaml. Error:", err) + } + + // Test + p := move2kube.CreatePlan(inputPath, prjName) + if !reflect.DeepEqual(p, want) { + t.Fatal("Failed to create the plan properly. Expected:", want, "Actual", p) + } + }) +} diff --git a/internal/move2kube/testdata/expectedplanfornodejsapp.yaml b/internal/move2kube/testdata/expectedplanfornodejsapp.yaml new file mode 100644 index 000000000..c4aae3d00 --- /dev/null +++ b/internal/move2kube/testdata/expectedplanfornodejsapp.yaml @@ -0,0 +1,29 @@ +apiVersion: move2kube.io/v1alpha1 +kind: Plan +metadata: + name: nodejs-app +spec: + inputs: + rootDir: ../../samples/nodejs + services: + nodejs: + - serviceName: nodejs + image: nodejs:latest + translationType: Any2Kube + containerBuildType: CNB + sourceType: + - Directory + targetOptions: + - cloudfoundry/cnb:cflinuxfs3 + sourceArtifacts: + SourceCode: + - . + buildArtifacts: + SourceCode: + - . + updateContainerBuildPipeline: true + updateDeployPipeline: true + outputs: + kubernetes: + artifactType: Yamls + clusterType: Kubernetes diff --git a/internal/move2kube/translator.go b/internal/move2kube/translator.go new file mode 100644 index 000000000..07d74c4cb --- /dev/null +++ b/internal/move2kube/translator.go @@ -0,0 +1,85 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package move2kube + +import ( + "os" + + customize "github.com/konveyor/move2kube/internal/customizer" + "github.com/konveyor/move2kube/internal/metadata" + optimize "github.com/konveyor/move2kube/internal/optimizer" + parameterize "github.com/konveyor/move2kube/internal/parameterizer" + "github.com/konveyor/move2kube/internal/source" + transform "github.com/konveyor/move2kube/internal/transformer" + plantypes "github.com/konveyor/move2kube/types/plan" + + log "github.com/sirupsen/logrus" +) + +// Translate translates the artifacts and writes output +func Translate(p plantypes.Plan, outpath string) { + sourceir, _ := source.Translate(p) + + log.Debugf("Total storages loaded : %d", len(sourceir.Storages)) + + log.Infoln("Begin Metadata loading") + metadataPlanners := metadata.GetLoaders() + for _, l := range metadataPlanners { + log.Debugf("[%T] Begin metadata loading", l) + err := l.LoadToIR(p, &sourceir) + if err != nil { + log.Warnf("[%T] Failed : %s", l, err.Error()) + } else { + log.Debugf("[%T] Done", l) + } + } + log.Infoln("Metadata loading done") + + log.Debugf("Total services loaded : %d", len(sourceir.Services)) + log.Debugf("Total containers loaded : %d", len(sourceir.Containers)) + optimizedir, _ := optimize.Optimize(sourceir) + + os.RemoveAll(outpath) + dct := transform.ComposeTransformer{} + err := dct.Transform(optimizedir) + if err != nil { + log.Errorf("Error during translate docker compose file : %s", err) + } + err = dct.WriteObjects(outpath) + if err != nil { + log.Errorf("Unable to write docker compose objects : %s", err) + } + + log.Debugf("Total services optimized : %d", len(optimizedir.Services)) + ir, _ := customize.Customize(optimizedir) + log.Debugf("Total storages customized : %d", len(optimizedir.Storages)) + if p.Spec.Outputs.Kubernetes.ArtifactType != plantypes.Yamls && p.Spec.Outputs.Kubernetes.ArtifactType != plantypes.Knative { + ir, _ = parameterize.Parameterize(ir) + } + + t := transform.GetTransformer(ir) + err = t.Transform(ir) + if err != nil { + log.Errorf("Error during translate : %s", err) + } + err = t.WriteObjects(outpath) + if err != nil { + log.Errorf("Unable to write objects : %s", err) + } + + log.Info("Execution completed") +} diff --git a/internal/move2kube/version.go b/internal/move2kube/version.go new file mode 100644 index 000000000..df0c76321 --- /dev/null +++ b/internal/move2kube/version.go @@ -0,0 +1,33 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package move2kube + +import ( + "gopkg.in/yaml.v3" + + "github.com/konveyor/move2kube/types/info" +) + +// GetVersion returns the version +func GetVersion(long bool) string { + if !long { + return info.GetVersion() + } + v := info.GetVersionInfo() + ver, _ := yaml.Marshal(v) + return string(ver) +} diff --git a/internal/optimizer/imagepullpolicyoptimizer.go b/internal/optimizer/imagepullpolicyoptimizer.go new file mode 100644 index 000000000..1a4737940 --- /dev/null +++ b/internal/optimizer/imagepullpolicyoptimizer.go @@ -0,0 +1,38 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package optimize + +import ( + irtypes "github.com/konveyor/move2kube/internal/types" + v1 "k8s.io/api/core/v1" +) + +// imagePullPolicyOptimizer sets the pull policy to be always +type imagePullPolicyOptimizer struct { +} + +func (ep imagePullPolicyOptimizer) optimize(ir irtypes.IR) (irtypes.IR, error) { + for k, scObj := range ir.Services { + for ci, container := range scObj.Containers { + container.ImagePullPolicy = v1.PullAlways + scObj.Containers[ci] = container + } + ir.Services[k] = scObj + } + + return ir, nil +} diff --git a/internal/optimizer/ingressoptimizer.go b/internal/optimizer/ingressoptimizer.go new file mode 100644 index 000000000..d6ece4210 --- /dev/null +++ b/internal/optimizer/ingressoptimizer.go @@ -0,0 +1,72 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package optimize + +import ( + "log" + + "github.com/konveyor/move2kube/internal/qaengine" + irtypes "github.com/konveyor/move2kube/internal/types" + qatypes "github.com/konveyor/move2kube/types/qaengine" +) + +// ingressOptimizer identifies the services that needs to be externally exposed +type ingressOptimizer struct { +} + +func (ingresso ingressOptimizer) optimize(ir irtypes.IR) (irtypes.IR, error) { + + if len(ir.Services) == 0 { + return ir, nil + } + + // Obtain a listing of services. + i := 0 + servicesList := make([]string, len(ir.Services)) + for k := range ir.Services { + servicesList[i] = k + i++ + } + + problem, err := qatypes.NewMultiSelectProblem("Which services should we expose?", []string{"An Ingress object will be created for every exposed service."}, servicesList, servicesList) + if err != nil { + log.Fatalf("Unable to create problem : %s", err) + } + problem, err = qaengine.FetchAnswer(problem) + if err != nil { + log.Fatalf("Unable to fetch answer : %s", err) + } + services, err := problem.GetSliceAnswer() + if err != nil { + log.Fatalf("Unable to get answer : %s", err) + } + + for _, k := range services { + tempService := ir.Services[k] + + // Set the line in annotations + if tempService.Annotations == nil { + tempService.Annotations = make(map[string]string) + } + tempService.Annotations["move2kube.service.expose"] = "true" + // Also set the special field + tempService.ExposeService = true + ir.Services[k] = tempService + } + + return ir, nil +} diff --git a/internal/optimizer/normalizecharactersoptimizer.go b/internal/optimizer/normalizecharactersoptimizer.go new file mode 100644 index 000000000..90449b47d --- /dev/null +++ b/internal/optimizer/normalizecharactersoptimizer.go @@ -0,0 +1,64 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package optimize + +import ( + "regexp" + "strings" + + corev1 "k8s.io/api/core/v1" + + irtypes "github.com/konveyor/move2kube/internal/types" +) + +// normalizeCharacterOptimizer identifies non-allowed characters and replaces them +type normalizeCharacterOptimizer struct { +} + +func (po normalizeCharacterOptimizer) optimize(ir irtypes.IR) (irtypes.IR, error) { + //TODO: Make this generic to ensure all fields have valid names + for k := range ir.Services { + scObj := ir.Services[k] + for _, serviceContainer := range scObj.Containers { + var tmpEnvArray []corev1.EnvVar + for _, env := range serviceContainer.Env { + if !strings.Contains(env.Name, "affinity") { + env.Name = strings.Trim(env.Name, "\t \n") + env.Value = strings.Trim(env.Value, "\t \n") + tmpString, err := stripQuotation(env.Name) + if err == nil { + env.Name = tmpString + } + tmpString, err = stripQuotation(env.Value) + if err == nil { + env.Value = tmpString + } + tmpEnvArray = append(tmpEnvArray, env) + } + } + serviceContainer.Env = tmpEnvArray + } + ir.Services[k] = scObj + } + return ir, nil +} + +func stripQuotation(inputString string) (string, error) { + regex := regexp.MustCompile(`^[',"](.*)[',"]$`) + + return regex.ReplaceAllString(inputString, `$1`), nil +} diff --git a/internal/optimizer/optimizer.go b/internal/optimizer/optimizer.go new file mode 100644 index 000000000..5981d6df4 --- /dev/null +++ b/internal/optimizer/optimizer.go @@ -0,0 +1,52 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package optimize + +import ( + log "github.com/sirupsen/logrus" + + irtypes "github.com/konveyor/move2kube/internal/types" +) + +// optimizer optimizes the configuration +type optimizer interface { + optimize(sourceir irtypes.IR) (irtypes.IR, error) +} + +// getOptimizers returns loader for given format +func getOptimizers() []optimizer { + var l = []optimizer{new(ingressOptimizer), new(normalizeCharacterOptimizer), new(replicaOptimizer), new(imagePullPolicyOptimizer), new(portMergeOptimizer)} + return l +} + +// Optimize optimizes the application artifacts +func Optimize(ir irtypes.IR) (irtypes.IR, error) { + optimizers := getOptimizers() + log.Infoln("Begin Optimization") + for _, o := range optimizers { + log.Debugf("[%T] Begin Optimization", o) + var err error + ir, err = o.optimize(ir) + if err != nil { + log.Warnf("[%T] Failed : %s", o, err.Error()) + } else { + log.Debugf("[%T] Done", o) + } + } + log.Infoln("Optimization done") + return ir, nil +} diff --git a/internal/optimizer/portmergeoptimizer.go b/internal/optimizer/portmergeoptimizer.go new file mode 100644 index 000000000..6309b842f --- /dev/null +++ b/internal/optimizer/portmergeoptimizer.go @@ -0,0 +1,44 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package optimize + +import ( + irtypes "github.com/konveyor/move2kube/internal/types" + corev1 "k8s.io/api/core/v1" +) + +//PortMergeOptimizer implements Optimizer interface +type portMergeOptimizer struct { +} + +//Optimize uses data from ir containers to fill ir.services +func (ep portMergeOptimizer) optimize(ir irtypes.IR) (irtypes.IR, error) { + for k, scObj := range ir.Services { + for csIndex, containerSection := range scObj.Containers { + if c, ok := ir.GetContainer(containerSection.Image); ok { + for _, exposedPort := range c.ExposedPorts { + containerSection.Ports = append(containerSection.Ports, corev1.ContainerPort{ContainerPort: int32(exposedPort)}) + } + scObj.Containers[csIndex] = containerSection + } + } + + ir.Services[k] = scObj + } + + return ir, nil +} diff --git a/internal/optimizer/replicaoptimizer.go b/internal/optimizer/replicaoptimizer.go new file mode 100644 index 000000000..47614e52a --- /dev/null +++ b/internal/optimizer/replicaoptimizer.go @@ -0,0 +1,40 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package optimize + +import ( + irtypes "github.com/konveyor/move2kube/internal/types" +) + +// replicaOptimizer sets the minimum number of replicas +type replicaOptimizer struct { +} + +const ( + minReplicas = 2 +) + +func (ep replicaOptimizer) optimize(ir irtypes.IR) (irtypes.IR, error) { + for k, scObj := range ir.Services { + if scObj.Replicas < minReplicas { + scObj.Replicas = minReplicas + } + ir.Services[k] = scObj + } + + return ir, nil +} diff --git a/internal/parameterizer/imagenameparameterizer.go b/internal/parameterizer/imagenameparameterizer.go new file mode 100644 index 000000000..e458d2741 --- /dev/null +++ b/internal/parameterizer/imagenameparameterizer.go @@ -0,0 +1,69 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package parameterize + +import ( + "strings" + + "github.com/konveyor/move2kube/internal/common" + irtypes "github.com/konveyor/move2kube/internal/types" + outputtypes "github.com/konveyor/move2kube/types/output" +) + +// imageNameParameterizer parameterizes the image names +type imageNameParameterizer struct { +} + +func (it imageNameParameterizer) parameterize(ir *irtypes.IR) error { + newimages := []string{} + for _, container := range ir.Containers { + if container.New { + for _, img := range container.ImageNames { + newimages = append(newimages, ir.Kubernetes.RegistryURL+"/"+ir.Kubernetes.RegistryNamespace+"/"+img) + } + } + } + + ir.Values.Services = make(map[string]outputtypes.Service) + for _, service := range ir.Services { + ir.Values.Services[service.Name] = outputtypes.Service{ + Containers: make(map[string]outputtypes.Container), + } + for ci, serviceContainer := range service.Containers { + nImageName := "" + parts := strings.Split(serviceContainer.Image, "/") + if len(parts) == 3 { + nImageName += parts[0] + "/" + } + if len(parts) > 1 { + nImageName += parts[1] + "/" + } + if common.IsStringPresent(newimages, serviceContainer.Image) { + nImageName = outputtypes.ParameterRegistryPrefix + } + imageName := parts[len(parts)-1] + im, tag := common.GetImageNameAndTag(imageName) + ir.Values.Services[service.Name].Containers[serviceContainer.Name] = outputtypes.Container{TagName: tag} + newTag := "{{ index .Values." + outputtypes.ServicesTag + " \"" + service.Name + "\" \"" + outputtypes.ContainersTag + "\" \"" + serviceContainer.Name + "\" \"" + outputtypes.ImageTagTag + "\" }}" + nImageName += im + ":" + newTag + serviceContainer.Image = nImageName + service.Containers[ci] = serviceContainer + } + ir.Services[service.Name] = service + } + return nil +} diff --git a/internal/parameterizer/parameterizer.go b/internal/parameterizer/parameterizer.go new file mode 100644 index 000000000..fba627551 --- /dev/null +++ b/internal/parameterizer/parameterizer.go @@ -0,0 +1,51 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package parameterize + +import ( + log "github.com/sirupsen/logrus" + + irtypes "github.com/konveyor/move2kube/internal/types" +) + +// Parameterizer paramertizers the configuration for helm +type Parameterizer interface { + parameterize(ir *irtypes.IR) error +} + +// getParameterizers returns different supported paramterizers +func getParameterizers() []Parameterizer { + return []Parameterizer{new(imageNameParameterizer), new(storageClassParameterizer)} +} + +// Parameterize parameterizes for usage as a helm chart +func Parameterize(ir irtypes.IR) (irtypes.IR, error) { + var parameterizers = getParameterizers() + log.Infoln("Begin Parameterization") + for _, p := range parameterizers { + log.Debugf("[%T] Begin Parameterization", p) + //TODO: Handle conflicting service names and invalid characters in objects + err := p.parameterize(&ir) + if err != nil { + log.Warnf("[%T] Failed : %s", p, err.Error()) + } else { + log.Debugf("[%T] Done", p) + } + } + log.Infoln("Parameterization done") + return ir, nil +} diff --git a/internal/parameterizer/storageclassparameterizer.go b/internal/parameterizer/storageclassparameterizer.go new file mode 100644 index 000000000..221ab7b6c --- /dev/null +++ b/internal/parameterizer/storageclassparameterizer.go @@ -0,0 +1,59 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package parameterize + +import ( + irtypes "github.com/konveyor/move2kube/internal/types" + log "github.com/sirupsen/logrus" +) + +// StorageClassParameterizer parameterizes the storage class +type storageClassParameterizer struct { +} + +// Parameterize parameterizes the storage class +func (sc storageClassParameterizer) parameterize(ir *irtypes.IR) error { + scMap := make(map[string][]int) + + for i, storage := range ir.Storages { + if storage.StorageType == irtypes.PVCKind { + scName := *storage.PersistentVolumeClaimSpec.StorageClassName + if indices, ok := scMap[scName]; ok { + indices = append(indices, i) + scMap[scName] = indices + } else { + scMap[scName] = []int{i} + } + } + } + + if len(scMap) > 1 { + log.Warnf("Storage class not common across all PVC. Hence, parameterization is skipped.") + return nil + } + + paramSC := "{{ .Values.storageclass }}" + + for scName, indexList := range scMap { + ir.Values.StorageClass = scName + for _, i := range indexList { + ir.Storages[i].PersistentVolumeClaimSpec.StorageClassName = ¶mSC + } + } + + return nil +} diff --git a/internal/qaengine/cacheengine.go b/internal/qaengine/cacheengine.go new file mode 100644 index 000000000..29e98bbcf --- /dev/null +++ b/internal/qaengine/cacheengine.go @@ -0,0 +1,43 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package qaengine + +import ( + qatypes "github.com/konveyor/move2kube/types/qaengine" +) + +// CacheEngine handles cache +type CacheEngine struct { + cache qatypes.Cache +} + +// NewCacheEngine creates a new cache instance +func NewCacheEngine(cf string) Engine { + ce := new(CacheEngine) + ce.cache = qatypes.NewCache(cf) + return ce +} + +// StartEngine starts the cache engine +func (c *CacheEngine) StartEngine() error { + return c.cache.Load() +} + +// FetchAnswer fetches the answer using cache +func (c *CacheEngine) FetchAnswer(prob qatypes.Problem) (ans qatypes.Problem, err error) { + return c.cache.GetSolution(prob) +} diff --git a/internal/qaengine/cliengine.go b/internal/qaengine/cliengine.go new file mode 100644 index 000000000..cc09405be --- /dev/null +++ b/internal/qaengine/cliengine.go @@ -0,0 +1,177 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package qaengine + +import ( + "fmt" + "strconv" + + "github.com/AlecAivazis/survey/v2" + log "github.com/sirupsen/logrus" + + qatypes "github.com/konveyor/move2kube/types/qaengine" +) + +// CliEngine handles the CLI based qa +type CliEngine struct { +} + +// NewCliEngine creates a new instance of cli engine +func NewCliEngine() Engine { + ce := new(CliEngine) + return ce +} + +// StartEngine starts the cli engine +func (c *CliEngine) StartEngine() error { + return nil +} + +// FetchAnswer fetches the answer using cli +func (c *CliEngine) FetchAnswer(prob qatypes.Problem) (answer qatypes.Problem, err error) { + switch prob.Solution.Type { + case qatypes.SelectSolutionFormType: + return c.fetchSelectAnswer(prob) + case qatypes.MultiSelectSolutionFormType: + return c.fetchMultiSelectAnswer(prob) + case qatypes.ConfirmSolutionFormType: + return c.fetchConfirmAnswer(prob) + case qatypes.InputSolutionFormType: + return c.fetchInputAnswer(prob) + case qatypes.MultilineSolutionFormType: + return c.fetchMultilineAnswer(prob) + case qatypes.PasswordSolutionFormType: + return c.fetchPasswordAnswer(prob) + default: + log.Fatalf("Unknown type found: %s", prob.Solution.Type) + } + return prob, fmt.Errorf("Unknown type found : %s", prob.Solution.Type) +} + +func (c *CliEngine) fetchSelectAnswer(prob qatypes.Problem) (answer qatypes.Problem, err error) { + var ans string = "" + d := "" + if len(prob.Solution.Default) > 0 { + d = prob.Solution.Default[0] + } else { + d = prob.Solution.Options[0] + } + prompt := &survey.Select{ + Message: fmt.Sprintf("%d. %s \nHints: \n %s\n", prob.ID, prob.Desc, prob.Context), + Options: prob.Solution.Options, + Default: d, + } + err = survey.AskOne(prompt, &ans) + if err != nil { + log.Fatalf("Error while asking a question : %s", err) + return prob, err + } + err = prob.SetAnswer([]string{ans}) + return prob, err +} + +func (c *CliEngine) fetchMultiSelectAnswer(prob qatypes.Problem) (answer qatypes.Problem, err error) { + ans := []string{} + prompt := &survey.MultiSelect{ + Message: fmt.Sprintf("%d. %s \nHints: \n %s\n", prob.ID, prob.Desc, prob.Context), + Options: prob.Solution.Options, + Default: prob.Solution.Default, + } + err = survey.AskOne(prompt, &ans, survey.WithIcons(func(icons *survey.IconSet) { + icons.MarkedOption.Text = "[\u2713]" + })) + if err != nil { + log.Fatalf("Error while asking a question : %s", err) + return prob, err + } + err = prob.SetAnswer(ans) + return prob, err +} + +func (c *CliEngine) fetchConfirmAnswer(prob qatypes.Problem) (answer qatypes.Problem, err error) { + ans := []string{} + var d bool + if len(prob.Solution.Default) > 0 { + d, err = strconv.ParseBool(prob.Solution.Default[0]) + if err != nil { + log.Warnf("Unable to parse default value : %s", err) + } + } + prompt := &survey.Confirm{ + Message: fmt.Sprintf("%d. %s \nHints: \n %s\n", prob.ID, prob.Desc, prob.Context), + Default: d, + } + err = survey.AskOne(prompt, &ans) + if err != nil { + log.Fatalf("Error while asking a question : %s", err) + return prob, err + } + err = prob.SetAnswer(ans) + return prob, err +} + +func (c *CliEngine) fetchInputAnswer(prob qatypes.Problem) (answer qatypes.Problem, err error) { + var ans string + d := "" + if len(prob.Solution.Default) > 0 { + d = prob.Solution.Default[0] + } + prompt := &survey.Input{ + Message: fmt.Sprintf("%d. %s \nHints: \n %s\n", prob.ID, prob.Desc, prob.Context), + Default: d, + } + err = survey.AskOne(prompt, &ans) + if err != nil { + log.Fatalf("Error while asking a question : %s", err) + return prob, err + } + err = prob.SetAnswer([]string{ans}) + return prob, err +} + +func (c *CliEngine) fetchMultilineAnswer(prob qatypes.Problem) (answer qatypes.Problem, err error) { + var ans string + d := "" + if len(prob.Solution.Default) > 0 { + d = prob.Solution.Default[0] + } + prompt := &survey.Multiline{ + Message: fmt.Sprintf("%d. %s \nHints: \n %s\n", prob.ID, prob.Desc, prob.Context), + Default: d, + } + err = survey.AskOne(prompt, &ans) + if err != nil { + log.Fatalf("Error while asking a question : %s", err) + return prob, err + } + err = prob.SetAnswer([]string{ans}) + return prob, err +} + +func (c *CliEngine) fetchPasswordAnswer(prob qatypes.Problem) (answer qatypes.Problem, err error) { + var ans string + prompt := &survey.Password{ + Message: fmt.Sprintf("%d. %s \nHints: \n %s\n", prob.ID, prob.Desc, prob.Context), + } + err = survey.AskOne(prompt, &ans) + if err != nil { + log.Fatalf("Error while asking a question : %s", err) + return prob, err + } + err = prob.SetAnswer([]string{ans}) + return prob, err +} diff --git a/internal/qaengine/defaultengine.go b/internal/qaengine/defaultengine.go new file mode 100644 index 000000000..f34043bbd --- /dev/null +++ b/internal/qaengine/defaultengine.go @@ -0,0 +1,40 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package qaengine + +import qatypes "github.com/konveyor/move2kube/types/qaengine" + +// DefaultEngine returns default values for all questions +type DefaultEngine struct { +} + +// NewDefaultEngine creates a new instance of default engine +func NewDefaultEngine() Engine { + ce := new(DefaultEngine) + return ce +} + +// StartEngine starts the default qa engine +func (c *DefaultEngine) StartEngine() error { + return nil +} + +// FetchAnswer fetches the default answers +func (c *DefaultEngine) FetchAnswer(prob qatypes.Problem) (ans qatypes.Problem, err error) { + err = prob.SetAnswer(prob.Solution.Default) + return prob, err +} diff --git a/internal/qaengine/engine.go b/internal/qaengine/engine.go new file mode 100644 index 000000000..beb3d2b3b --- /dev/null +++ b/internal/qaengine/engine.go @@ -0,0 +1,123 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package qaengine + +import ( + "os" + "path/filepath" + + "github.com/konveyor/move2kube/internal/common" + qatypes "github.com/konveyor/move2kube/types/qaengine" + log "github.com/sirupsen/logrus" +) + +// Engine defines interface for qa engines +type Engine interface { + StartEngine() error + FetchAnswer(prob qatypes.Problem) (ans qatypes.Problem, err error) +} + +var ( + engines []Engine + writeCache qatypes.Cache +) + +// StartEngine starts the QA Engines +func StartEngine(qaskip bool, qaport int, qadisablecli bool) { + if qaskip { + e := NewDefaultEngine() + err := e.StartEngine() + if err != nil { + log.Errorf("Ignoring engine %T due to error : %s", e, err) + } else { + engines = append(engines, e) + } + } else if !qadisablecli { + e := NewCliEngine() + err := e.StartEngine() + if err != nil { + log.Errorf("Ignoring engine %T due to error : %s", e, err) + } else { + engines = append(engines, e) + } + } else { + e := NewHTTPRESTEngine(qaport) + err := e.StartEngine() + if err != nil { + log.Errorf("Ignoring engine %T due to error : %s", e, err) + } else { + engines = append(engines, e) + } + } +} + +// AddCaches adds cache responders +func AddCaches(cacheFiles []string) { + cengines := []Engine{} + for _, cacheFile := range cacheFiles { + e := NewCacheEngine(cacheFile) + err := e.StartEngine() + if err != nil { + log.Errorf("Ignoring engine %T due to error : %s", e, err) + } else { + cengines = append(cengines, e) + } + } + engines = append(cengines, engines...) +} + +// FetchAnswer fetches the answer for the question +func FetchAnswer(prob qatypes.Problem) (ans qatypes.Problem, err error) { + for _, e := range engines { + ans, err = e.FetchAnswer(prob) + if err != nil { + log.Warnf("Error while fetching answer using engine %s : %s", e, err) + } else if ans.Resolved { + break + } + } + if !ans.Resolved { + for { + ans, err = engines[len(engines)-1].FetchAnswer(prob) + if err != nil { + log.Fatalf("Unable to get answer to %s : %s", ans.Desc, err) + } + if ans.Resolved { + break + } + } + } + if err == nil && ans.Resolved { + writeCache.AddProblemSolutionToCache(ans) + } else if err != nil { + log.Errorf("Unable to fetch answer : %s", err) + } + return ans, err +} + +// SetWriteCache sets the write cache +func SetWriteCache(cacheFile string) error { + dirpath := filepath.Dir(cacheFile) + if err := os.MkdirAll(dirpath, common.DefaultDirectoryPermission); err != nil { + // Create the qacache directory if it is missing + log.Errorf("Failed to create the qacache directory at path %q. Error: %q", dirpath, err) + return err + } + + writeCache = qatypes.NewCache(cacheFile) + return writeCache.Write() +} diff --git a/internal/qaengine/httprestengine.go b/internal/qaengine/httprestengine.go new file mode 100644 index 000000000..6c581994d --- /dev/null +++ b/internal/qaengine/httprestengine.go @@ -0,0 +1,143 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package qaengine + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "net" + "net/http" + "strconv" + + "github.com/gorilla/mux" + qatypes "github.com/konveyor/move2kube/types/qaengine" + "github.com/phayes/freeport" + log "github.com/sirupsen/logrus" +) + +const ( + problemsURLPrefix = "/problems" + currentProblemURLPrefix = problemsURLPrefix + "/current" + currentSolutionURLPrefix = currentProblemURLPrefix + "/solution" +) + +// HTTPRESTEngine handles qa using HTTP REST services +type HTTPRESTEngine struct { + port int + currentProblem qatypes.Problem + problemChan chan qatypes.Problem + answerChan chan qatypes.Problem +} + +// NewHTTPRESTEngine creates a new instance of Http REST engine +func NewHTTPRESTEngine(qaport int) Engine { + e := new(HTTPRESTEngine) + e.port = qaport + e.currentProblem = qatypes.Problem{ID: 0, Resolved: true} + e.problemChan = make(chan qatypes.Problem) + e.answerChan = make(chan qatypes.Problem) + return e +} + +// StartEngine starts the QA Engine +func (h *HTTPRESTEngine) StartEngine() error { + if h.port == 0 { + var err error + h.port, err = freeport.GetFreePort() + if err != nil { + return fmt.Errorf("Unable to find a free port : %s", err) + } + } + // Create the REST router. + r := mux.NewRouter() + r.HandleFunc(currentProblemURLPrefix, h.problemHandler).Methods("GET") + r.HandleFunc(currentSolutionURLPrefix, h.solutionHandler).Methods("POST") + + http.Handle("/", r) + qaportstr := strconv.Itoa(h.port) + + listener, err := net.Listen("tcp", ":"+qaportstr) + if err != nil { + return fmt.Errorf("Unable to listen on port %d : %s", h.port, err) + } + go func(listener net.Listener) { + err := http.Serve(listener, nil) + if err != nil { + log.Fatalf("Unable to start qa server : %s", err) + } + }(listener) + log.Info("Started QA engine on: localhost:" + qaportstr) + return nil +} + +// FetchAnswer fetches the answer using a REST service +func (h *HTTPRESTEngine) FetchAnswer(prob qatypes.Problem) (ans qatypes.Problem, err error) { + if prob.ID == 0 { + prob.Resolved = true + } + if !prob.Resolved { + log.Debugf("Passing problem to HTTP REST QA Engine ID: %d, desc: %s", prob.ID, prob.Desc) + h.problemChan <- prob + prob = <-h.answerChan + if !prob.Resolved { + return prob, fmt.Errorf("Unable to resolve question %s", prob.Desc) + } + } + return prob, nil +} + +// problemHandler returns the current problem being handled +func (h *HTTPRESTEngine) problemHandler(w http.ResponseWriter, r *http.Request) { + log.Debug("Looking for a problem fron HTTP REST service") + // if currently problem is resolved + if h.currentProblem.Resolved || h.currentProblem.ID == 0 { + // Pick the next problem off the channel + h.currentProblem = <-h.problemChan + } + log.Debugf("QA Engine serves problem id: %d, desc: %s", h.currentProblem.ID, h.currentProblem.Desc) + // Send the problem to the request. + _ = json.NewEncoder(w).Encode(h.currentProblem) +} + +// solutionHandler accepts solution for a single open problem. +func (h *HTTPRESTEngine) solutionHandler(w http.ResponseWriter, r *http.Request) { + log.Debugf("QA Engine reading solution: %s", r.Body) + // Read out the solution + body, err := ioutil.ReadAll(r.Body) + if err != nil { + errstr := fmt.Sprintf("Error in reading posted solution: %s", err) + http.Error(w, "errstr", http.StatusInternalServerError) + log.Errorf(errstr) + } + var sol []string + err = json.Unmarshal(body, &sol) + if err != nil { + errstr := fmt.Sprintf("Error in un-marshalling solution in QA engine: %s", err) + http.Error(w, errstr, http.StatusInternalServerError) + log.Errorf(errstr) + } + log.Debugf("QA Engine receives solution: %s", sol) + err = h.currentProblem.SetAnswer(sol) + if err != nil { + errstr := fmt.Sprintf("Unsuitable answer : %s", err) + http.Error(w, errstr, http.StatusInternalServerError) + log.Errorf(errstr) + } else { + h.answerChan <- h.currentProblem + } +} diff --git a/internal/source/any2kube.go b/internal/source/any2kube.go new file mode 100644 index 000000000..c3cd5865f --- /dev/null +++ b/internal/source/any2kube.go @@ -0,0 +1,177 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package source + +import ( + "bufio" + "os" + "path/filepath" + "strings" + + log "github.com/sirupsen/logrus" + corev1 "k8s.io/api/core/v1" + + common "github.com/konveyor/move2kube/internal/common" + "github.com/konveyor/move2kube/internal/containerizer" + irtypes "github.com/konveyor/move2kube/internal/types" + "github.com/konveyor/move2kube/types" + plantypes "github.com/konveyor/move2kube/types/plan" +) + +// Any2KubeTranslator implements Translator interface for loading any source folder that can be containerized +type Any2KubeTranslator struct { +} + +// GetTranslatorType returns translator type +func (c Any2KubeTranslator) GetTranslatorType() plantypes.TranslationTypeValue { + return plantypes.Any2KubeTranslation +} + +// GetServiceOptions - output a plan based on the input directory contents +func (c Any2KubeTranslator) GetServiceOptions(inputPath string, plan plantypes.Plan) ([]plantypes.Service, error) { + services := make([]plantypes.Service, 0) + containerizers := new(containerizer.Containerizers) + containerizers.InitContainerizers(inputPath) + preContainerizedSourcePaths := []string{} + for _, existingservices := range plan.Spec.Inputs.Services { + for _, existingservice := range existingservices { + if len(existingservice.SourceArtifacts[plantypes.SourceDirectoryArtifactType]) > 0 { + preContainerizedSourcePaths = append(preContainerizedSourcePaths, existingservice.SourceArtifacts[plantypes.SourceDirectoryArtifactType][0]) + } + } + } + ignoreDirectories, ignoreContents := c.getIgnorePaths(inputPath) + err := filepath.Walk(inputPath, func(fullpath string, info os.FileInfo, err error) error { + if err != nil { + log.Warnf("Skipping path %s due to error: %s", fullpath, err) + return nil + } + if info.IsDir() { + path, _ := plan.GetRelativePath(fullpath) + if common.IsStringPresent(preContainerizedSourcePaths, path) { + return filepath.SkipDir //TODO: Should we go inside the directory in this case? + } + fullcleanpath, err := filepath.Abs(fullpath) + if err != nil { + log.Errorf("Unable to resolve full path of directory %s : %s", fullcleanpath, err) + } + if common.IsStringPresent(ignoreDirectories, fullcleanpath) { + if common.IsStringPresent(ignoreContents, fullcleanpath) { + return filepath.SkipDir + } + return nil + } + containerizationoptions := containerizers.GetContainerizationOptions(plan, fullpath) + if len(containerizationoptions) == 0 { + log.Debugf("No known containerization approach is supported for %s", fullpath) + if common.IsStringPresent(ignoreContents, fullcleanpath) { + return filepath.SkipDir + } + return nil + } + for _, co := range containerizationoptions { + expandedPath, err := filepath.Abs(fullpath) // If fullpath is "." it will expand to the absolute path. + if err != nil { + log.Warnf("Failed to get the absolute path for %s", fullpath) + continue + } + service := c.newService(filepath.Base(expandedPath)) + service.ContainerBuildType = co.ContainerizationType + service.ContainerizationTargetOptions = co.TargetOptions + if !common.IsStringPresent(service.BuildArtifacts[plantypes.SourceDirectoryBuildArtifactType], path) { + service.SourceArtifacts[plantypes.SourceDirectoryArtifactType] = append(service.SourceArtifacts[plantypes.SourceDirectoryArtifactType], path) + service.BuildArtifacts[plantypes.SourceDirectoryBuildArtifactType] = append(service.BuildArtifacts[plantypes.SourceDirectoryBuildArtifactType], path) + } + services = append(services, service) + } + //return nil + return filepath.SkipDir // Skipping all subdirectories when base directory is a valid package + } + return nil + }) + return services, err +} + +// Translate translates artifacts to IR +func (c Any2KubeTranslator) Translate(services []plantypes.Service, p plantypes.Plan) (irtypes.IR, error) { + ir := irtypes.NewIR(p) + containerizers := new(containerizer.Containerizers) + containerizers.InitContainerizers(p.Spec.Inputs.RootDir) + for _, service := range services { + if service.TranslationType != c.GetTranslatorType() { + continue + } + log.Debugf("Translating %s", service.ServiceName) + serviceConfig := irtypes.Service{Name: service.ServiceName} + container, err := containerizers.GetContainer(p, service) + if err != nil { + log.Errorf("Unable to translate service %s : %s", service.ServiceName, err) + continue + } + ir.AddContainer(container) + serviceContainer := corev1.Container{Name: service.ServiceName} + serviceContainer.Image = service.Image + serviceConfig.Containers = []corev1.Container{serviceContainer} + ir.Services[service.ServiceName] = serviceConfig + } + return ir, nil +} + +func (c Any2KubeTranslator) newService(serviceName string) plantypes.Service { + service := plantypes.NewService(serviceName, c.GetTranslatorType()) + service.AddSourceType(plantypes.DirectorySourceTypeValue) + service.UpdateContainerBuildPipeline = true + service.UpdateDeployPipeline = true + return service +} + +func (c Any2KubeTranslator) getIgnorePaths(inputPath string) (ignoreDirectories []string, ignoreContents []string) { + ignorefiles, err := common.GetFilesByName(inputPath, []string{"." + types.AppNameShort + "ignore"}) + if err != nil { + log.Warnf("Unable to fetch files to recognize ignore files : %s", err) + } + for _, ignorefile := range ignorefiles { + file, err := os.Open(ignorefile) + if err != nil { + log.Warnf("Failed opening ignore file: %s", err) + continue + } + defer file.Close() + + scanner := bufio.NewScanner(file) + scanner.Split(bufio.ScanLines) + + for scanner.Scan() { + line := strings.TrimSpace(scanner.Text()) + if strings.HasSuffix(line, "*") { + line = strings.TrimSuffix(line, "*") + path, err := filepath.Abs(filepath.Join(filepath.Dir(ignorefile), line)) + if err != nil { + log.Errorf("Unable to resolve full path of directory %s : %s", path, err) + } + ignoreContents = append(ignoreContents, path) + } else { + path, err := filepath.Abs(filepath.Join(filepath.Dir(ignorefile), line)) + if err != nil { + log.Errorf("Unable to resolve full path of directory %s : %s", path, err) + } + ignoreDirectories = append(ignoreDirectories, path) + } + } + } + return ignoreDirectories, ignoreContents +} diff --git a/internal/source/any2kube_test.go b/internal/source/any2kube_test.go new file mode 100644 index 000000000..b997c61c4 --- /dev/null +++ b/internal/source/any2kube_test.go @@ -0,0 +1,401 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package source_test + +import ( + "encoding/base64" + "io/ioutil" + "os" + "path/filepath" + "reflect" + "testing" + + log "github.com/sirupsen/logrus" + + common "github.com/konveyor/move2kube/internal/common" + "github.com/konveyor/move2kube/internal/source" + irtypes "github.com/konveyor/move2kube/internal/types" + plantypes "github.com/konveyor/move2kube/types/plan" + yaml "gopkg.in/yaml.v3" +) + +func TestGetServiceOptions(t *testing.T) { + log.SetLevel(log.DebugLevel) + + t.Run("get services with a non existent directory and empty plan", func(t *testing.T) { + // Setup + inputpath := "this/does/not/exit/foobar/" + translator := source.Any2KubeTranslator{} + plan := plantypes.NewPlan() + want := []plantypes.Service{} + + // Test + services, err := translator.GetServiceOptions(inputpath, plan) + if err != nil { + t.Fatal("Failed to get the services. Error:", err) + } + if !reflect.DeepEqual(services, want) { + t.Fatal("Failed to get the services properly. Expected:", want, "actual:", services) + } + }) + + t.Run("get services with empty directory and empty plan", func(t *testing.T) { + // Setup + inputpath := t.TempDir() + translator := source.Any2KubeTranslator{} + plan := plantypes.NewPlan() + want := []plantypes.Service{} + + // Test + services, err := translator.GetServiceOptions(inputpath, plan) + if err != nil { + t.Fatal("Failed to get the services. Error:", err) + } + if !reflect.DeepEqual(services, want) { + t.Fatal("Failed to get the services properly. Expected:", want, "actual:", services) + } + }) + + t.Run("get services when the directory contains files and directories we can't read", func(t *testing.T) { + // Setup + inputpath := t.TempDir() + subdirpath := filepath.Join(inputpath, "nopermstoread") + if err := os.Mkdir(subdirpath, 0); err != nil { + t.Fatal("Failed to create a temporary directory for testing at path", subdirpath, "Error:", err) + } + ignorefilepath := filepath.Join(inputpath, common.IgnoreFilename) + if err := ioutil.WriteFile(ignorefilepath, []byte("foo/"), 0); err != nil { + t.Fatal("Failed to create a temporary file for testing at path", ignorefilepath, "Error:", err) + } + translator := source.Any2KubeTranslator{} + plan := plantypes.NewPlan() + want := []plantypes.Service{} + + // Test + services, err := translator.GetServiceOptions(inputpath, plan) + if err != nil { + t.Fatal("Failed to get the services. Error:", err) + } + if !reflect.DeepEqual(services, want) { + t.Fatal("Failed to get the services properly. Expected:", want, "actual:", services) + } + }) + + t.Run("get services from a simple nodejs app and empty plan", func(t *testing.T) { + // Setup + inputPath := "../../samples/nodejs" + translator := source.Any2KubeTranslator{} + + plan := plantypes.NewPlan() + plan.Name = "nodejs-app" + plan.Spec.Inputs.RootDir = inputPath + + want := []plantypes.Service{} + if err := common.ReadYaml("testdata/expectedservicesfornodejsapp.yaml", &want); err != nil { + t.Fatal("Failed to read the expected output services from yaml. Error:", err) + } + + // Test + services, err := translator.GetServiceOptions(inputPath, plan) + if err != nil { + t.Fatal("Failed to get the services. Error:", err) + } + if !reflect.DeepEqual(services, want) { + t.Fatal("Failed to create the services properly. Expected:", want, "Actual", services) + } + }) + + t.Run("get services from a simple nodejs app and filled plan", func(t *testing.T) { + // Setup + inputPath := "../../samples/nodejs" + translator := source.Any2KubeTranslator{} + + // services + svc1 := plantypes.NewService("svc1", "Any2Kube") + svc1.SourceArtifacts[plantypes.SourceDirectoryArtifactType] = []string{"foo/"} + svc2 := plantypes.NewService("svc2", "Any2Kube") + svc2.SourceArtifacts[plantypes.SourceDirectoryArtifactType] = []string{"bar/"} + + plan := plantypes.NewPlan() + plan.Name = "nodejs-app" + plan.Spec.Inputs.RootDir = inputPath + plan.Spec.Inputs.Services = map[string][]plantypes.Service{ + "svc1": {svc1}, + "svc2": {svc2}, + } + + want := []plantypes.Service{} + if err := common.ReadYaml("testdata/expectedservicesfornodejsapp.yaml", &want); err != nil { + t.Fatal("Failed to read the expected output services from yaml. Error:", err) + } + + // Test + services, err := translator.GetServiceOptions(inputPath, plan) + if err != nil { + t.Fatal("Failed to get the services. Error:", err) + } + if !reflect.DeepEqual(services, want) { + t.Fatal("Failed to create the services properly. Expected:", want, "Actual", services) + } + }) + + t.Run("get services from a simple nodejs app that we already containerized", func(t *testing.T) { + // Setup + inputPath := "../../samples/nodejs" + translator := source.Any2KubeTranslator{} + + // services + svc1 := plantypes.NewService("svc1", "Any2Kube") + svc1.SourceArtifacts[plantypes.SourceDirectoryArtifactType] = []string{"."} + + plan := plantypes.NewPlan() + plan.Name = "nodejs-app" + plan.Spec.Inputs.RootDir = inputPath + plan.Spec.Inputs.Services = map[string][]plantypes.Service{ + "svc1": {svc1}, + } + + want := []plantypes.Service{} + // if err := common.ReadYaml("testdata/expectedservicesfornodejsapp.yaml", &want); err != nil { + // t.Fatal("Failed to read the expected output services from yaml. Error:", err) + // } + + // Test + services, err := translator.GetServiceOptions(inputPath, plan) + if err != nil { + t.Fatal("Failed to get the services. Error:", err) + } + if !reflect.DeepEqual(services, want) { + t.Fatal("Failed to create the services properly. Expected:", want, "Actual", services) + } + }) + + t.Run("test m2kignore can ignore a directory but include its subdirectories", func(t *testing.T) { + // 1. Ignore a directory, but include all subdirectories + + // Setup + inputPath := "testdata/nodejsappwithm2kignorecase1" + translator := source.Any2KubeTranslator{} + + plan := plantypes.NewPlan() + plan.Name = "nodejs-app" + plan.Spec.Inputs.RootDir = inputPath + + want := []plantypes.Service{} + if err := common.ReadYaml("testdata/expectedservicesfornodejsappwithm2kignorecase1.yaml", &want); err != nil { + t.Fatal("Failed to read the expected output services from yaml. Error:", err) + } + + // Test + services, err := translator.GetServiceOptions(inputPath, plan) + if err != nil { + t.Fatal("Failed to get the services. Error:", err) + } + if !reflect.DeepEqual(services, want) { + t.Fatal("Failed to create the services properly. Expected:", want, "Actual", services) + } + }) + + t.Run("test m2kignore can be used to ignore everything but a very specific subdirectory", func(t *testing.T) { + // Setup + inputPath := "testdata/javamavenappwithm2kignorecase2" + translator := source.Any2KubeTranslator{} + + plan := plantypes.NewPlan() + plan.Name = "nodejs-app" + plan.Spec.Inputs.RootDir = inputPath + + want := []plantypes.Service{} + if err := common.ReadYaml("testdata/expectedservicesforjavamavenappwithm2kignorecase2.yaml", &want); err != nil { + t.Fatal("Failed to read the expected output services from yaml. Error:", err) + } + + // Test + services, err := translator.GetServiceOptions(inputPath, plan) + if err != nil { + t.Fatal("Failed to get the services. Error:", err) + } + // if err := common.WriteYaml("testdata/hmm.yaml", services); err != nil { + // t.Fatal("error", err) + // } + if !reflect.DeepEqual(services, want) { + t.Fatal("Failed to create the services properly. Expected:", want, "Actual", services) + } + }) + + t.Run("test m2kignore can include a directory but ignore all subdirectories", func(t *testing.T) { + // 2. Include a directory, ignore all subdirectories or a subset of subdirectories + // TODO: Note that while m2kignore might work as expected, the buildpacks do not. + // The CNB buildpacks when run on a directory will ALWAYS look inside all of its subdirectories as well. + + // Setup + // We create the following directory structure: + // . + inputpath := t.TempDir() + // ./includeme/ + // ./includeme/excludeme/ + subdirpath := filepath.Join(inputpath, "includeme") + subsubdirpath := filepath.Join(subdirpath, "excludeme") + if err := os.MkdirAll(subsubdirpath, common.DefaultDirectoryPermission); err != nil { + t.Fatal("Failed to create a temporary directory for testing at path", subsubdirpath, "Error:", err) + } + // .m2kignore + testdatapath := "testdata/m2kignoreforignorecontents" + ignorerules, err := ioutil.ReadFile(testdatapath) + if err != nil { + t.Fatal("Failed to read the testdata at", testdatapath, "Error:", err) + } + ignorefilepath := filepath.Join(inputpath, common.IgnoreFilename) + if err := ioutil.WriteFile(ignorefilepath, ignorerules, common.DefaultFilePermission); err != nil { + t.Fatal("Failed to create a temporary file for testing at path", ignorefilepath, "Error:", err) + } + // ./includeme/excludeme/index.php + fpath := filepath.Join(subsubdirpath, "package.json") + if err := ioutil.WriteFile(fpath, []byte("this is ' invalid json"), common.DefaultFilePermission); err != nil { + t.Fatal("Failed to create a temporary file for testing at path", fpath, "Error:", err) + } + + translator := source.Any2KubeTranslator{} + plan := plantypes.NewPlan() + want := []plantypes.Service{} + + // Test + services, err := translator.GetServiceOptions(inputpath, plan) + if err != nil { + t.Fatal("Failed to get the services. Error:", err) + } + if !reflect.DeepEqual(services, want) { + t.Fatal("Failed to get the services properly. Expected:", want, "actual:", services) + } + }) + + t.Run("test multiple hierarchical m2kignores", func(t *testing.T) { + // TODO: Note that while m2kignore might work as expected, the buildpacks do not. + // The CNB buildpacks when run on a directory will ALWAYS look inside all of its subdirectories as well. + // The behaviour of the CNB buildpacks makes it virtually impossible to test this scenario. + // This test can really only be checked through vscode debugging to make sure the correct directories are being ignored. + + // Setup + // We create the following directory structure: + /* + . + ├── .m2kignore + ├── a + │   └── a + │   ├── .m2kignore + │   ├── a + │   │   ├── a + │   │   ├── b + │   │   ├── c + │   │   └── d + │   └── b + │   ├── a + │   └── b + ├── b + │   ├── .m2kignore + │   └── a + │   ├── a + │   └── b + └── c + └── a + */ + tempdir := t.TempDir() + testdatapath := "testdata/testmultiplem2kignores.tar" + + tarbytes, err := ioutil.ReadFile(testdatapath) + if err != nil { + t.Fatalf("Failed to read the test data at path %q Error: %q", testdatapath, err) + } + + tarstring := base64.StdEncoding.EncodeToString(tarbytes) + err = common.UnTarString(tarstring, tempdir) + if err != nil { + t.Fatalf("Failed to untar the test data into path %q Error: %q", tempdir, err) + } + + inputpath := filepath.Join(tempdir, "testmultiplem2kignores") + translator := source.Any2KubeTranslator{} + plan := plantypes.NewPlan() + want := []plantypes.Service{} + + // Test + services, err := translator.GetServiceOptions(inputpath, plan) + if err != nil { + t.Fatal("Failed to get the services. Error:", err) + } + if !reflect.DeepEqual(services, want) { + t.Fatal("Failed to get the services properly. Expected:", want, "actual:", services) + } + }) +} + +func TestTranslate(t *testing.T) { + log.SetLevel(log.DebugLevel) + + t.Run("get intermediate representation with no services and an empty plan", func(t *testing.T) { + // Setup + // inputpath := "this/does/not/exit/foobar/" + translator := source.Any2KubeTranslator{} + services := []plantypes.Service{} + plan := plantypes.NewPlan() + want := irtypes.NewIR(plan) + + // Test + ir, err := translator.Translate(services, plan) + if err != nil { + t.Fatal("Failed to get the intermediate representation. Error:", err) + } + if !reflect.DeepEqual(ir, want) { + t.Fatal("Failed to get the intermediate representation properly. Expected:", want, "actual:", ir) + } + }) + + t.Run("get intermediate representation with some services and an empty plan", func(t *testing.T) { + // Setup + translator := source.Any2KubeTranslator{} + + // Input + services := []plantypes.Service{} + testdataservices := "testdata/datafortestingtranslate/servicesfromnodejsapp.yaml" + if err := common.ReadYaml(testdataservices, &services); err != nil { + t.Fatalf("Failed to read the testdata at path %q Error: %q", testdataservices, err) + } + plan := plantypes.NewPlan() + + // Output + testdataoutput := "testdata/datafortestingtranslate/expectedirfornodejsapp.yaml" + wantbytes, err := ioutil.ReadFile(testdataoutput) + if err != nil { + t.Fatalf("Failed to read the testdata at path %q Error: %q", testdataoutput, err) + } + wantyaml := string(wantbytes) + + // Test + ir, err := translator.Translate(services, plan) + if err != nil { + t.Fatal("Failed to get the intermediate representation. Error:", err) + } + irbytes, err := yaml.Marshal(ir) + if err != nil { + t.Fatal("Failed to marshal the intermediate representation to yaml for comparison. Error:", err) + } + iryaml := string(irbytes) + if iryaml != wantyaml { + t.Fatal("Failed to get the intermediate representation properly. Expected:", wantyaml, "actual:", iryaml) + } + }) +} diff --git a/internal/source/cfmanifest2kube.go b/internal/source/cfmanifest2kube.go new file mode 100644 index 000000000..45874143b --- /dev/null +++ b/internal/source/cfmanifest2kube.go @@ -0,0 +1,473 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package source + +import ( + "io/ioutil" + "path/filepath" + "strings" + + "code.cloudfoundry.org/cli/util/manifest" + "github.com/cloudfoundry/bosh-cli/director/template" + log "github.com/sirupsen/logrus" + "gopkg.in/yaml.v3" + v1 "k8s.io/api/core/v1" + + common "github.com/konveyor/move2kube/internal/common" + "github.com/konveyor/move2kube/internal/containerizer" + "github.com/konveyor/move2kube/internal/source/data" + irtypes "github.com/konveyor/move2kube/internal/types" + collecttypes "github.com/konveyor/move2kube/types/collection" + plantypes "github.com/konveyor/move2kube/types/plan" +) + +//go:generate go run github.com/konveyor/move2kube/internal/common/generator data + +// CfManifestTranslator implements Translator interface for CfManifest files +type CfManifestTranslator struct { +} + +// GetTranslatorType returns the translator type +func (c CfManifestTranslator) GetTranslatorType() plantypes.TranslationTypeValue { + return plantypes.CfManifest2KubeTranslation +} + +// GetServiceOptions - output a plan based on the input directory contents +func (c CfManifestTranslator) GetServiceOptions(inputPath string, plan plantypes.Plan) ([]plantypes.Service, error) { + services := make([]plantypes.Service, 0) + allcontainerizers := new(containerizer.Containerizers) + allcontainerizers.InitContainerizers(inputPath) + containerizers := collecttypes.CfContainerizers{} + + var files, err = common.GetFilesByExt(inputPath, []string{".yml", ".yaml"}) + if err != nil { + log.Warnf("Unable to fetch yaml files and recognize cf manifest yamls : %s", err) + } + // Load buildpack mappings, if available + containerizersmetadata := collecttypes.CfContainerizers{} + err = yaml.Unmarshal([]byte(data.Cfbuildpacks_yaml), &containerizersmetadata) + if err != nil { + log.Debugf("Not valid containerizer option data : %s", err) + } + containerizers.Spec.BuildpackContainerizers = append(containerizers.Spec.BuildpackContainerizers, containerizersmetadata.Spec.BuildpackContainerizers...) + for _, fullpath := range files { + containerizersmetadata := collecttypes.CfContainerizers{} + err := common.ReadYaml(fullpath, &containerizersmetadata) + if err != nil { + log.Debugf("Not a valid containerizer option file : %s %s", fullpath, err) + continue + } + containerizers.Spec.BuildpackContainerizers = append(containerizers.Spec.BuildpackContainerizers, containerizersmetadata.Spec.BuildpackContainerizers...) + } + log.Debugf("Containerizers %+v", containerizers) + + // Load instance apps, if available + cfinstanceapps := map[string][]collecttypes.CfApplication{} //path + for _, fullpath := range files { + cfinstanceappsfile := collecttypes.CfInstanceApps{} + err := common.ReadYaml(fullpath, &cfinstanceappsfile) + if err != nil || cfinstanceappsfile.Kind != string(collecttypes.CfInstanceAppsMetadataKind) { + log.Debugf("Not a valid apps file : %s %s", fullpath, err) + continue + } + relpath, _ := plan.GetRelativePath(fullpath) + cfinstanceapps[relpath] = append(cfinstanceapps[relpath], cfinstanceappsfile.Spec.CfApplications...) + } + log.Debugf("Cf Instances %+v", cfinstanceapps) + + appsCovered := []string{} + + for _, fullpath := range files { + applications, _, err := ReadApplicationManifest(fullpath, "", plantypes.Yamls) + if err != nil { + log.Debugf("Error while trying to parse manifest : %s", err) + continue + } + path, _ := plan.GetRelativePath(fullpath) + for _, application := range applications { + containerizationoptionsfound := false + fullbuilddirectory := filepath.Dir(fullpath) + if application.Path != "" { + fullbuilddirectory = filepath.Join(fullpath, application.Path) + } + applicationName := application.Name + if applicationName == "" { + basename := filepath.Base(fullpath) + applicationName = strings.TrimSuffix(basename, filepath.Ext(basename)) + } + appinstancefilepath, appinstance := getCfInstanceApp(cfinstanceapps, applicationName) + builddirectory, _ := plan.GetRelativePath(fullbuilddirectory) + if application.DockerImage != "" || appinstance.DockerImage != "" { + service := c.newService(applicationName) + service.ContainerBuildType = plantypes.ReuseContainerBuildTypeValue + if application.DockerImage != "" { + service.Image = application.DockerImage + } else { + service.Image = appinstance.DockerImage + } + service.UpdateContainerBuildPipeline = false + services = append(services, service) + appsCovered = append(appsCovered, applicationName) + containerizationoptionsfound = true + } else { + for _, cop := range allcontainerizers.GetContainerizationOptions(plan, fullbuilddirectory) { + service := c.newService(applicationName) + service.ContainerBuildType = cop.ContainerizationType + service.ContainerizationTargetOptions = cop.TargetOptions + service.AddSourceArtifact(plantypes.CfManifestArtifactType, path) + if appinstance.Name != "" { + service.AddSourceArtifact(plantypes.CfRunningManifestArtifactType, appinstancefilepath) + } + if !common.IsStringPresent(service.BuildArtifacts[plantypes.SourceDirectoryBuildArtifactType], builddirectory) { + service.AddSourceArtifact(plantypes.SourceDirectoryArtifactType, builddirectory) + service.AddBuildArtifact(plantypes.SourceDirectoryBuildArtifactType, builddirectory) + } + services = append(services, service) + appsCovered = append(appsCovered, applicationName) + containerizationoptionsfound = true + } + for _, containerizer := range containerizers.Spec.BuildpackContainerizers { + isbuildpackmatched := false + if application.Buildpack.IsSet && containerizer.BuildpackName == application.Buildpack.Value { + isbuildpackmatched = true + } + for _, bpname := range application.Buildpacks { + if bpname == containerizer.BuildpackName { + isbuildpackmatched = true + break + } + } + if !isbuildpackmatched { + if (appinstance.Buildpack != "" && containerizer.BuildpackName == appinstance.Buildpack) || (appinstance.DetectedBuildpack != "" && containerizer.BuildpackName == appinstance.DetectedBuildpack) { + isbuildpackmatched = true + } + } + if isbuildpackmatched { + service := c.newService(applicationName) + service.ContainerBuildType = containerizer.ContainerBuildType + service.ContainerizationTargetOptions = containerizer.ContainerizationTargetOptions + service.AddSourceArtifact(plantypes.CfManifestArtifactType, path) + if appinstance.Name != "" { + service.AddSourceArtifact(plantypes.CfRunningManifestArtifactType, appinstancefilepath) + } + if !common.IsStringPresent(service.BuildArtifacts[plantypes.SourceDirectoryBuildArtifactType], builddirectory) { + service.AddSourceArtifact(plantypes.SourceDirectoryArtifactType, builddirectory) + service.AddBuildArtifact(plantypes.SourceDirectoryBuildArtifactType, builddirectory) + } + services = append(services, service) + appsCovered = append(appsCovered, applicationName) + containerizationoptionsfound = true + } + } + if !containerizationoptionsfound { + log.Warnf("No known containerization approach for %s even though it has a cf manifest %s; Defaulting to manual", fullbuilddirectory, filepath.Base(fullpath)) + service := c.newService(applicationName) + service.ContainerBuildType = plantypes.ManualContainerBuildTypeValue + service.AddSourceArtifact(plantypes.CfManifestArtifactType, path) + if !common.IsStringPresent(service.BuildArtifacts[plantypes.SourceDirectoryBuildArtifactType], builddirectory) { + service.AddSourceArtifact(plantypes.SourceDirectoryArtifactType, builddirectory) + service.AddBuildArtifact(plantypes.SourceDirectoryBuildArtifactType, builddirectory) + } + appsCovered = append(appsCovered, applicationName) + services = append(services, service) + } + } + } + + for appfilepath, apps := range cfinstanceapps { + for _, application := range apps { + applicationName := application.Name + if !common.IsStringPresent(appsCovered, applicationName) { + containerizationoptionsfound := false + fullbuilddirectory := filepath.Dir(appfilepath) + applicationName := application.Name + if applicationName == "" { + continue + } + builddirectory, _ := plan.GetRelativePath(fullbuilddirectory) + if application.DockerImage != "" { + service := c.newService(applicationName) + service.ContainerBuildType = plantypes.ReuseContainerBuildTypeValue + if application.DockerImage != "" { + service.Image = application.DockerImage + } + service.UpdateContainerBuildPipeline = false + services = append(services, service) + containerizationoptionsfound = true + } else { + //TODO: Think whether we should include this for only runtime manifest file + for _, cop := range allcontainerizers.GetContainerizationOptions(plan, fullbuilddirectory) { + service := c.newService(applicationName) + service.ContainerBuildType = cop.ContainerizationType + service.ContainerizationTargetOptions = cop.TargetOptions + service.AddSourceArtifact(plantypes.CfRunningManifestArtifactType, appfilepath) + if !common.IsStringPresent(service.BuildArtifacts[plantypes.SourceDirectoryBuildArtifactType], builddirectory) { + service.AddSourceArtifact(plantypes.SourceDirectoryArtifactType, builddirectory) + service.AddBuildArtifact(plantypes.SourceDirectoryBuildArtifactType, builddirectory) + } + services = append(services, service) + containerizationoptionsfound = true + } + for _, containerizer := range containerizers.Spec.BuildpackContainerizers { + isbuildpackmatched := false + if !isbuildpackmatched { + if (application.Buildpack != "" && containerizer.BuildpackName == application.Buildpack) || (application.DetectedBuildpack != "" && containerizer.BuildpackName == application.DetectedBuildpack) { + isbuildpackmatched = true + } + } + if isbuildpackmatched { + service := c.newService(applicationName) + service.ContainerBuildType = containerizer.ContainerBuildType + service.ContainerizationTargetOptions = containerizer.ContainerizationTargetOptions + service.AddSourceArtifact(plantypes.CfRunningManifestArtifactType, appfilepath) + if !common.IsStringPresent(service.BuildArtifacts[plantypes.SourceDirectoryBuildArtifactType], builddirectory) { + service.AddSourceArtifact(plantypes.SourceDirectoryArtifactType, builddirectory) + service.AddBuildArtifact(plantypes.SourceDirectoryBuildArtifactType, builddirectory) + } + services = append(services, service) + containerizationoptionsfound = true + } + } + if !containerizationoptionsfound { + log.Warnf("No known containerization approach for %s even though it has a cf manifest %s; Defaulting to manual", fullbuilddirectory, filepath.Base(fullpath)) + service := c.newService(applicationName) + service.ContainerBuildType = plantypes.ManualContainerBuildTypeValue + service.AddSourceArtifact(plantypes.CfRunningManifestArtifactType, appfilepath) + if !common.IsStringPresent(service.BuildArtifacts[plantypes.SourceDirectoryBuildArtifactType], builddirectory) { + service.AddSourceArtifact(plantypes.SourceDirectoryArtifactType, builddirectory) + service.AddBuildArtifact(plantypes.SourceDirectoryBuildArtifactType, builddirectory) + } + services = append(services, service) + } + } + + } + } + } + } + return services, nil +} + +// Translate translates servies to IR +func (c CfManifestTranslator) Translate(services []plantypes.Service, p plantypes.Plan) (irtypes.IR, error) { + ir := irtypes.NewIR(p) + containerizers := new(containerizer.Containerizers) + containerizers.InitContainerizers(p.Spec.Inputs.RootDir) + for _, service := range services { + if service.TranslationType == c.GetTranslatorType() { + log.Debugf("Translating %s", service.ServiceName) + + var cfinstanceapp collecttypes.CfApplication + if runninginstancefile, ok := service.SourceArtifacts[plantypes.CfRunningManifestArtifactType]; ok { + cfinstanceapp = getCfAppInstance(p.GetFullPath(runninginstancefile[0]), service.ServiceName) + } + + if paths, ok := service.SourceArtifacts[plantypes.CfManifestArtifactType]; ok { + path := paths[0] + applications, variables, err := ReadApplicationManifest(p.GetFullPath(path), service.ServiceName, p.Spec.Outputs.Kubernetes.ArtifactType) + if err != nil { + log.Debugf("Error while trying to parse manifest : %s", err) + continue + } + application := applications[0] + serviceConfig := irtypes.Service{Name: service.ServiceName} + serviceContainer := v1.Container{Name: service.ServiceName} + serviceContainer.Image = service.Image + //TODO: Add support for services, health check, memory + if application.Instances.IsSet { + serviceConfig.Replicas = application.Instances.Value + } else if cfinstanceapp.Instances != 0 { + serviceConfig.Replicas = cfinstanceapp.Instances + } + for varname, value := range application.EnvironmentVariables { + envvar := v1.EnvVar{Name: varname, Value: value} + serviceContainer.Env = append(serviceContainer.Env, envvar) + } + for varname, value := range cfinstanceapp.Env { + envvar := v1.EnvVar{Name: varname, Value: value} + serviceContainer.Env = append(serviceContainer.Env, envvar) + } + for _, variable := range variables { + ir.Values.GlobalVariables[variable] = variable + } + if cfinstanceapp.Ports != nil && len(cfinstanceapp.Ports) > 0 { + serviceContainer.Ports = []v1.ContainerPort{} + for _, port := range cfinstanceapp.Ports { + serviceContainer.Ports = append(serviceContainer.Ports, v1.ContainerPort{ContainerPort: port, + Protocol: v1.ProtocolTCP, + }) + } + envvar := v1.EnvVar{Name: "PORT", Value: string(cfinstanceapp.Ports[0])} + serviceContainer.Env = append(serviceContainer.Env, envvar) + } else { + serviceContainer.Ports = []v1.ContainerPort{ + {ContainerPort: 8080, + Protocol: v1.ProtocolTCP, + }} + envvar := v1.EnvVar{Name: "PORT", Value: "8080"} + serviceContainer.Env = append(serviceContainer.Env, envvar) + } + serviceConfig.Containers = []v1.Container{serviceContainer} + container, err := containerizers.GetContainer(p, service) + if err == nil { + ir.AddContainer(container) + ir.Services[service.ServiceName] = serviceConfig + } else { + log.Errorf("Unable to translate service %s using cfmanifest at %s : %s", service.ServiceName, path, err) + } + } else { + serviceConfig := irtypes.Service{Name: service.ServiceName} + serviceContainer := v1.Container{Name: service.ServiceName} + serviceContainer.Image = service.Image + if cfinstanceapp.Instances != 0 { + serviceConfig.Replicas = cfinstanceapp.Instances + } + for varname, value := range cfinstanceapp.Env { + envvar := v1.EnvVar{Name: varname, Value: value} + serviceContainer.Env = append(serviceContainer.Env, envvar) + } + if cfinstanceapp.Ports != nil && len(cfinstanceapp.Ports) > 0 { + serviceContainer.Ports = []v1.ContainerPort{} + for _, port := range cfinstanceapp.Ports { + serviceContainer.Ports = append(serviceContainer.Ports, v1.ContainerPort{ContainerPort: port, + Protocol: v1.ProtocolTCP, + }) + } + } else { + serviceContainer.Ports = []v1.ContainerPort{ + { + ContainerPort: 8080, + Protocol: v1.ProtocolTCP, + }} + } + serviceConfig.Containers = []v1.Container{serviceContainer} + container, err := containerizers.GetContainer(p, service) + if err == nil { + ir.AddContainer(container) + ir.Services[service.ServiceName] = serviceConfig + } else { + log.Errorf("Unable to translate service %s using cfinstancemanifest : %s", service.ServiceName, err) + } + } + } + } + return ir, nil +} + +func (c CfManifestTranslator) newService(serviceName string) plantypes.Service { + service := plantypes.NewService(serviceName, c.GetTranslatorType()) + service.AddSourceType(plantypes.DirectorySourceTypeValue) + service.AddSourceType(plantypes.CfManifestSourceTypeValue) + service.UpdateContainerBuildPipeline = true + service.UpdateDeployPipeline = true + return service +} + +// ReadApplicationManifest reads an application manifest +func ReadApplicationManifest(path string, serviceName string, artifactType plantypes.TargetArtifactTypeValue) ([]manifest.Application, []string, error) { // manifest, parameters + trimmedvariables, err := getMissingVariables(path) + if err != nil { + log.Debugf("Unable to read as cf manifest %s : %s", path, err) + return []manifest.Application{}, []string{}, err + } + + rawManifest, err := ioutil.ReadFile(path) + if err != nil { + log.Errorf("Unable to read manifest file %s", path) + return []manifest.Application{}, []string{}, err + } + tpl := template.NewTemplate(rawManifest) + fileVars := template.StaticVariables{} + for _, variable := range trimmedvariables { + if artifactType == plantypes.Helm { + fileVars[variable] = "{{ index .Values " + `"globalvariables" "` + variable + `"}}` + } else { + fileVars[variable] = "{{ $" + variable + " }}" + } + } + rawManifest, err = tpl.Evaluate(fileVars, nil, template.EvaluateOpts{ExpectAllKeys: true}) + if err != nil { + log.Errorf("Interpolation Error %s", err) + return []manifest.Application{}, []string{}, err + } + + var m manifest.Manifest + err = yaml.Unmarshal(rawManifest, &m) + if err != nil { + log.Errorf("UnMarshalling error %s", err) + return []manifest.Application{}, []string{}, err + } + if len(m.Applications) == 1 { + //If the service name is missing, use the directory name + return m.Applications, trimmedvariables, nil + } + applications := []manifest.Application{} + if serviceName != "" { + for _, application := range m.Applications { + if application.Name == serviceName { + applications = append(applications, application) + } + } + } else { + applications = m.Applications + } + return applications, trimmedvariables, nil +} + +func getMissingVariables(path string) ([]string, error) { + trimmedvariables := []string{} + _, err := manifest.ReadAndInterpolateManifest(path, []string{}, []template.VarKV{}) + if err != nil { + errstring := err.Error() + if strings.Contains(errstring, "Expected to find variables:") { + variablesstr := strings.Split(errstring, ":")[1] + variables := strings.Split(variablesstr, ",") + for _, variable := range variables { + trimmedvariables = append(trimmedvariables, strings.TrimSpace(variable)) + } + } else { + log.Debugf("Error %s", err) + return []string{}, err + } + } + return trimmedvariables, nil +} + +func getCfInstanceApp(apps map[string][]collecttypes.CfApplication, name string) (string, collecttypes.CfApplication) { + for path, apps := range apps { + for _, app := range apps { + if app.Name == name { + return path, app + } + } + } + return "", collecttypes.CfApplication{} +} + +func getCfAppInstance(path string, appname string) collecttypes.CfApplication { + cfinstanceappsfile := collecttypes.CfInstanceApps{} + err := common.ReadYaml(path, &cfinstanceappsfile) + if err != nil { + log.Debugf("Not a valid apps file : %s %s", path, err) + } + for _, app := range cfinstanceappsfile.Spec.CfApplications { + if app.Name == appname { + return app + } + } + return collecttypes.CfApplication{} +} diff --git a/internal/source/compose/utils.go b/internal/source/compose/utils.go new file mode 100644 index 000000000..d2ee5dc31 --- /dev/null +++ b/internal/source/compose/utils.go @@ -0,0 +1,58 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package compose + +import ( + "fmt" + "strings" + + corev1 "k8s.io/api/core/v1" +) + +const ( + modeReadOnly string = "ro" + tmpFsPath string = "tmpfs" + defaultSecretBasePath string = "/var/secrets" + envFile string = "env_file" +) + +func makeVolumesFromTmpFS(serviceName string, tfsList []string) ([]corev1.VolumeMount, []corev1.Volume) { + var vmList []corev1.VolumeMount + var vList []corev1.Volume + + for index, tfsObj := range tfsList { + volumeName := fmt.Sprintf("%s-%s-%d", serviceName, tmpFsPath, index) + + vmList = append(vmList, corev1.VolumeMount{ + Name: volumeName, + MountPath: strings.Split(tfsObj, ":")[0], + }) + + vList = append(vList, corev1.Volume{ + Name: volumeName, + VolumeSource: corev1.VolumeSource{ + EmptyDir: &corev1.EmptyDirVolumeSource{Medium: corev1.StorageMediumMemory}, + }, + }) + } + + return vmList, vList +} + +func isPath(substring string) bool { + return strings.Contains(substring, "/") || substring == "." +} diff --git a/internal/source/compose/v1v2.go b/internal/source/compose/v1v2.go new file mode 100755 index 000000000..4eb10657e --- /dev/null +++ b/internal/source/compose/v1v2.go @@ -0,0 +1,389 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package compose + +import ( + "fmt" + "io/ioutil" + "os" + "path/filepath" + "reflect" + "regexp" + "strconv" + "strings" + "time" + + "github.com/pkg/errors" + log "github.com/sirupsen/logrus" + + "github.com/docker/libcompose/config" + "github.com/docker/libcompose/lookup" + "github.com/docker/libcompose/project" + + corev1 "k8s.io/api/core/v1" + v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/resource" + + "github.com/konveyor/move2kube/internal/common" + "github.com/konveyor/move2kube/internal/containerizer" + irtypes "github.com/konveyor/move2kube/internal/types" +) + +// V1V2Loader loads a compoose file of versions 1 or 2 +type V1V2Loader struct { +} + +// ConvertToIR loads a compose file to IR +func (c *V1V2Loader) ConvertToIR(composefilepath string, serviceName string) (ir irtypes.IR, err error) { + filedata, err := ioutil.ReadFile(composefilepath) + if err != nil { + return + } + re := regexp.MustCompile(`(?s)\n\s+env_file:.*?(\n\s*[a-zA-Z]|$)`) + envFileStrings := re.FindAllString(string(filedata), -1) + for _, envFileString := range envFileStrings { + lines := strings.Split(envFileString, "\n") + for _, line := range lines { + line = strings.TrimSpace(line) + if strings.HasPrefix(line, "-") { + line = strings.TrimSpace(strings.TrimPrefix(line, "-")) + envfilere := regexp.MustCompile(`[^\s+]+`) + envfile := envfilere.FindString(line) + if !filepath.IsAbs(envfile) { + envfile = filepath.Join(filepath.Dir(composefilepath), envfile) + } + _, err := os.Stat(envfile) + if os.IsNotExist(err) { + log.Warnf("Unable to find env config file %s referred in service %s in file %s. Ignoring it.", envfile, serviceName, composefilepath) + err = ioutil.WriteFile(envfile, []byte{}, common.DefaultFilePermission) + if err != nil { + log.Errorf("Unable to write temp env file %s : %s", envfile, err) + } else { + defer os.Remove(envfile) + } + } + } + } + } + + context := &project.Context{} + context.ComposeFiles = []string{composefilepath} + if context.ResourceLookup == nil { + context.ResourceLookup = &lookup.FileResourceLookup{} + } + if context.EnvironmentLookup == nil { + //TODO: Check if any variable is mandatory + cwd := "" + if !common.IgnoreEnvironment { + cwd, err = os.Getwd() + if err != nil { + return irtypes.IR{}, nil + } + } + context.EnvironmentLookup = &lookup.ComposableEnvLookup{ + Lookups: []config.EnvironmentLookup{ + &lookup.EnvfileLookup{ + Path: filepath.Join(cwd, ".env"), + }, + &lookup.OsEnvLookup{}, + }, + } + } + proj := project.NewProject(context, nil, nil) + err = proj.Parse() + if err != nil { + log.Errorf("Failed to load compose file %s : %s", composefilepath, err) + return irtypes.IR{}, errors.Wrap(err, "Failed to load compose file") + } + ir, err = c.convertToIR(filepath.Dir(composefilepath), proj, serviceName) + if err != nil { + return irtypes.IR{}, err + } + + return ir, nil +} + +func (c *V1V2Loader) convertToIR(filedir string, composeObject *project.Project, serviceName string) (ir irtypes.IR, err error) { + ir = irtypes.IR{ + Services: make(map[string]irtypes.Service), + } + + for name, composeServiceConfig := range composeObject.ServiceConfigs.All() { + serviceConfig := irtypes.Service{Name: common.NormalizeForServiceName(name)} + if serviceName != serviceConfig.Name { + continue + } + serviceConfig.Annotations = map[string]string(composeServiceConfig.Labels) + if composeServiceConfig.Hostname != "" { + serviceConfig.Hostname = composeServiceConfig.Hostname + } + if composeServiceConfig.DomainName != "" { + serviceConfig.Subdomain = composeServiceConfig.DomainName + } + serviceContainer := corev1.Container{} + serviceContainer.Image = composeServiceConfig.Image + if serviceContainer.Image == "" { + serviceContainer.Image = name + ":latest" + } + if composeServiceConfig.Build.Dockerfile != "" && composeServiceConfig.Build.Context != "" { + //TODO: Add support for args and labels + c := containerizer.ReuseDockerfileContainerizer{} + con, err := c.GetContainer(filedir, name, serviceContainer.Image, composeServiceConfig.Build.Dockerfile, composeServiceConfig.Build.Context) + if err != nil { + log.Warnf("Unable to get containization script even though build parameters are present : %s", err) + } else { + ir.AddContainer(con) + } + } + serviceContainer.Name = strings.ToLower(composeServiceConfig.ContainerName) + if serviceContainer.Name != composeServiceConfig.ContainerName { + log.Debugf("Container name in service %q has been changed from %q to %q", name, composeServiceConfig.ContainerName, serviceContainer.Name) + } + if serviceContainer.Name == "" { + serviceContainer.Name = serviceConfig.Name + } + serviceContainer.Command = composeServiceConfig.Entrypoint + serviceContainer.Args = composeServiceConfig.Command + serviceContainer.Env = c.getEnvs(composeServiceConfig.Environment) + serviceContainer.WorkingDir = composeServiceConfig.WorkingDir + serviceContainer.Stdin = composeServiceConfig.StdinOpen + serviceContainer.TTY = composeServiceConfig.Tty + ports := c.getPorts(composeServiceConfig.Ports, composeServiceConfig.Expose) + serviceContainer.Ports = ports + podSecurityContext := &corev1.PodSecurityContext{} + securityContext := &corev1.SecurityContext{} + if composeServiceConfig.Privileged { + securityContext.Privileged = &composeServiceConfig.Privileged + } + if composeServiceConfig.User != "" { + uid, err := strconv.ParseInt(composeServiceConfig.User, 10, 64) + if err != nil { + log.Warn("Ignoring user directive. User to be specified as a UID (numeric).") + } else { + securityContext.RunAsUser = &uid + } + + } + capsAdd := []corev1.Capability{} + capsDrop := []corev1.Capability{} + for _, capAdd := range composeServiceConfig.CapAdd { + capsAdd = append(capsAdd, corev1.Capability(capAdd)) + } + for _, capDrop := range composeServiceConfig.CapDrop { + capsDrop = append(capsDrop, corev1.Capability(capDrop)) + } + if len(capsAdd) > 0 || len(capsDrop) > 0 { + securityContext.Capabilities = &corev1.Capabilities{ + Add: capsAdd, + Drop: capsDrop, + } + } + if *securityContext != (corev1.SecurityContext{}) { + serviceContainer.SecurityContext = securityContext + } + if !reflect.DeepEqual(*podSecurityContext, corev1.PodSecurityContext{}) { + serviceConfig.SecurityContext = podSecurityContext + } + // group should be in gid format not group name + groupAdd, err := getGroupAdd(composeServiceConfig.GroupAdd) + if err != nil { + log.Warnf("GroupAdd should be in gid format, not as group name : %s", err) + } + if groupAdd != nil { + podSecurityContext.SupplementalGroups = groupAdd + } + if composeServiceConfig.StopGracePeriod != "" { + serviceConfig.TerminationGracePeriodSeconds, err = durationInSeconds(composeServiceConfig.StopGracePeriod) + if err != nil { + log.Warnf("Failed to parse duration %v for service %v", composeServiceConfig.StopGracePeriod, name) + } + } + if composeServiceConfig.MemLimit != 0 { + resourceLimit := corev1.ResourceList{} + if composeServiceConfig.MemLimit != 0 { + resourceLimit[corev1.ResourceMemory] = *resource.NewQuantity(int64(composeServiceConfig.MemLimit), "RandomStringForFormat") + } + serviceContainer.Resources.Limits = resourceLimit + } + + restart := composeServiceConfig.Restart + if restart == "unless-stopped" { + log.Warnf("Restart policy 'unless-stopped' in service %s is not supported, convert it to 'always'", name) + serviceConfig.RestartPolicy = corev1.RestartPolicyAlways + } + + if composeServiceConfig.Networks != nil && len(composeServiceConfig.Networks.Networks) > 0 { + for _, value := range composeServiceConfig.Networks.Networks { + if value.Name != "default" { + serviceConfig.Networks = append(serviceConfig.Networks, value.RealName) + } + } + } + + vml, vl := makeVolumesFromTmpFS(name, composeServiceConfig.Tmpfs) + for _, v := range vl { + serviceConfig.AddVolume(v) + } + serviceContainer.VolumeMounts = append(serviceContainer.VolumeMounts, vml...) + + if composeServiceConfig.VolumesFrom != nil { + log.Warnf("Ignoring VolumeFrom in compose for service %s : %s", serviceName, composeServiceConfig.VolumesFrom) + } + + if composeServiceConfig.Volumes != nil { + for index, vol := range composeServiceConfig.Volumes.Volumes { + if isPath(vol.Source) { + volumeName := fmt.Sprintf("%s%d", common.VolumePrefix, index) + serviceContainer.VolumeMounts = append(serviceContainer.VolumeMounts, corev1.VolumeMount{ + Name: volumeName, + ReadOnly: vol.AccessMode == modeReadOnly, + MountPath: vol.Destination, + }) + + serviceConfig.AddVolume(corev1.Volume{ + Name: volumeName, + VolumeSource: corev1.VolumeSource{ + HostPath: &corev1.HostPathVolumeSource{Path: vol.Source}, + }, + }) + } else { + serviceContainer.VolumeMounts = append(serviceContainer.VolumeMounts, corev1.VolumeMount{ + Name: vol.Source, + ReadOnly: vol.AccessMode == modeReadOnly, + MountPath: vol.Destination, + }) + + serviceConfig.AddVolume(corev1.Volume{ + Name: vol.Source, + VolumeSource: corev1.VolumeSource{ + PersistentVolumeClaim: &corev1.PersistentVolumeClaimVolumeSource{ + ClaimName: vol.Source, + ReadOnly: vol.AccessMode == modeReadOnly, + }, + }, + }) + accessMode := corev1.ReadWriteMany + if vol.AccessMode == modeReadOnly { + accessMode = corev1.ReadOnlyMany + } + storageObj := irtypes.Storage{StorageType: irtypes.PVCKind, Name: vol.Source, Content: nil} + storageObj.PersistentVolumeClaimSpec = corev1.PersistentVolumeClaimSpec{ + AccessModes: []corev1.PersistentVolumeAccessMode{accessMode}, + } + ir.AddStorage(storageObj) + } + } + } + + serviceConfig.Containers = []v1.Container{serviceContainer} + ir.Services[name] = serviceConfig + } + + return ir, nil +} + +func (c *V1V2Loader) getEnvs(envars []string) []corev1.EnvVar { + envs := []corev1.EnvVar{} + for _, e := range envars { + m := regexp.MustCompile(`[=:]`) + locs := m.FindStringIndex(e) + if locs == nil || len(locs) < 1 { + envs = append(envs, corev1.EnvVar{ + Name: e, + Value: "unknown", + }) + } else { + envs = append(envs, corev1.EnvVar{ + Name: e[locs[0]+1:], + Value: e[:locs[0]], + }) + } + } + return envs +} + +func (c *V1V2Loader) getPorts(composePorts []string, expose []string) []corev1.ContainerPort { + ports := []corev1.ContainerPort{} + exist := map[int32]bool{} + for _, port := range composePorts { + cp := c.getContainerPort(port) + if !exist[cp.ContainerPort] && cp != (corev1.ContainerPort{}) { + ports = append(ports, cp) + exist[cp.ContainerPort] = true + } + } + for _, port := range expose { + cp := c.getContainerPort(port) + if !exist[cp.ContainerPort] && cp != (corev1.ContainerPort{}) { + ports = append(ports, cp) + exist[cp.ContainerPort] = true + } + } + + return ports +} + +func (c *V1V2Loader) getContainerPort(value string) (cp corev1.ContainerPort) { + // 15000:15000/tcp Default protocol TCP + proto := corev1.ProtocolTCP + parts := strings.Split(value, "/") + if len(parts) == 2 && strings.EqualFold(string(corev1.ProtocolUDP), parts[1]) { + proto = corev1.ProtocolUDP + } + // Split up the ports and IP + justPorts := strings.Split(parts[0], ":") + if len(justPorts) > 0 { + // ex. 127.0.0.1:80:80 + // Get the container port + portStr := justPorts[len(justPorts)-1] + p, err := strconv.Atoi(portStr) + if err != nil { + log.Warnf("Invalid container port in %s ; Example: 127.0.0.1:80:80 or 80:80 or 80", parts[0]) + } else { + cp = corev1.ContainerPort{ + ContainerPort: int32(p), + Protocol: proto, + } + } + } + return +} + +func getGroupAdd(group []string) ([]int64, error) { + var groupAdd []int64 + for _, i := range group { + j, err := strconv.Atoi(i) + if err != nil { + return nil, errors.Wrap(err, "unable to get group_add") + } + groupAdd = append(groupAdd, int64(j)) + + } + return groupAdd, nil +} + +func durationInSeconds(s string) (*int64, error) { + if s == "" { + return nil, nil + } + duration, err := time.ParseDuration(s) + if err != nil { + return nil, err + } + r := (int64)(duration.Seconds()) + return &r, nil +} diff --git a/internal/source/compose/v3.go b/internal/source/compose/v3.go new file mode 100755 index 000000000..d67276596 --- /dev/null +++ b/internal/source/compose/v3.go @@ -0,0 +1,607 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package compose + +import ( + "fmt" + "io/ioutil" + "os" + "path/filepath" + "reflect" + "strconv" + "strings" + "time" + + "github.com/pkg/errors" + log "github.com/sirupsen/logrus" + "github.com/spf13/cast" + + "github.com/docker/cli/cli/compose/loader" + "github.com/docker/cli/cli/compose/types" + libcomposeyaml "github.com/docker/libcompose/yaml" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/resource" + + "github.com/konveyor/move2kube/internal/containerizer" + + "github.com/konveyor/move2kube/internal/common" + irtypes "github.com/konveyor/move2kube/internal/types" +) + +// V3Loader loads a v3 compose file +type V3Loader struct { +} + +// ConvertToIR loads an v3 compose file into IR +func (c *V3Loader) ConvertToIR(composefilepath string, serviceName string) (irtypes.IR, error) { + loadedFile, err := ioutil.ReadFile(composefilepath) + if err != nil { + log.Warnf("Unable to load Compose file : %s", err) + return irtypes.IR{}, err + } + // Parse the Compose File + parsedComposeFile, err := loader.ParseYAML(loadedFile) + if err != nil { + log.Warnf("Unable to parse Compose file : %s", err) + return irtypes.IR{}, err + } + // Remove unresolvable env files, so that the parser does not throw error + if val, ok := parsedComposeFile["services"]; ok { + if services, ok := val.(map[string]interface{}); ok { + if val, ok := services[serviceName]; ok { + if vals, ok := val.(map[string]interface{}); ok { + envfiles := make([]interface{}, 0) + if envfilesvals, ok := vals[envFile]; ok { + if envfilesvalsint, ok := envfilesvals.([]interface{}); ok { + for _, envfilesval := range envfilesvalsint { + if envfilesstr, ok := envfilesval.(string); ok { + path := envfilesstr + if !filepath.IsAbs(path) { + path = filepath.Join(filepath.Dir(composefilepath), path) + } + info, err := os.Stat(path) + if os.IsNotExist(err) || info.IsDir() { + log.Warnf("Unable to find env config file %s referred in service %s in file %s. Ignoring it.", path, serviceName, composefilepath) + } else { + envfiles = append(envfiles, envfilesstr) + } + } + } + } + } + vals[envFile] = envfiles + services = make(map[string]interface{}) + services[serviceName] = vals + parsedComposeFile["services"] = services + } + } + } + } + workingDir, err := filepath.Abs(filepath.Dir(composefilepath)) + if err != nil { + log.Errorf("Unable to compute full path of %s", composefilepath) + workingDir = filepath.Dir(composefilepath) + } + // Config details + configDetails := types.ConfigDetails{ + WorkingDir: workingDir, + ConfigFiles: []types.ConfigFile{{ + Filename: composefilepath, + Config: parsedComposeFile, + }}, + Environment: c.buildEnvironment(), + } + log.Debugf("About to load docker compose configuration") + config, err := loader.Load(configDetails) + if err != nil { + log.Warnf("Error while loading docker compose config : %s", err) + return irtypes.IR{}, err + } + + log.Debugf("About to start loading docker compose to intermediate rep") + ir, err := c.convertToIR(workingDir, *config) + if err != nil { + return irtypes.IR{}, err + } + + return ir, nil +} + +func (c *V3Loader) convertToIR(filedir string, composeObject types.Config) (irtypes.IR, error) { + ir := irtypes.IR{ + Services: make(map[string]irtypes.Service), + } + + //Secret volumes translated to IR + ir.Storages = c.getSecretStorages(composeObject.Secrets) + + //ConfigMap volumes translated to IR + ir.Storages = append(ir.Storages, c.getConfigStorages(composeObject.Configs)...) + + for _, composeServiceConfig := range composeObject.Services { + name := common.NormalizeForServiceName(composeServiceConfig.Name) + serviceConfig := irtypes.Service{Name: name} + serviceContainer := corev1.Container{} + + serviceContainer.Image = composeServiceConfig.Image + if serviceContainer.Image == "" { + serviceContainer.Image = name + ":latest" + } + if composeServiceConfig.Build.Dockerfile != "" && composeServiceConfig.Build.Context != "" { + //TODO: Add support for args and labels + c := containerizer.ReuseDockerfileContainerizer{} + con, err := c.GetContainer(filedir, name, serviceContainer.Image, composeServiceConfig.Build.Dockerfile, composeServiceConfig.Build.Context) + if err != nil { + log.Warnf("Unable to get containization script even though build parameters are present : %s", err) + } else { + ir.AddContainer(con) + } + } + serviceContainer.WorkingDir = composeServiceConfig.WorkingDir + serviceContainer.Command = composeServiceConfig.Entrypoint + serviceContainer.Args = composeServiceConfig.Command + serviceContainer.Stdin = composeServiceConfig.StdinOpen + serviceContainer.Name = strings.ToLower(composeServiceConfig.ContainerName) + if serviceContainer.Name == "" { + serviceContainer.Name = strings.ToLower(serviceConfig.Name) + } + serviceContainer.TTY = composeServiceConfig.Tty + serviceContainer.Ports = c.getPorts(composeServiceConfig.Ports, composeServiceConfig.Expose) + + serviceConfig.Annotations = map[string]string(composeServiceConfig.Labels) + serviceConfig.Labels = common.MergeStringMaps(composeServiceConfig.Labels, composeServiceConfig.Deploy.Labels) + if composeServiceConfig.Hostname != "" { + serviceConfig.Hostname = composeServiceConfig.Hostname + } + if composeServiceConfig.DomainName != "" { + serviceConfig.Subdomain = composeServiceConfig.DomainName + } + if composeServiceConfig.Pid != "" { + if composeServiceConfig.Pid == "host" { + serviceConfig.HostPID = true + } else { + log.Warnf("Ignoring PID key for service \"%v\". Invalid value \"%v\".", name, composeServiceConfig.Pid) + } + } + securityContext := &corev1.SecurityContext{} + if composeServiceConfig.Privileged { + securityContext.Privileged = &composeServiceConfig.Privileged + } + if composeServiceConfig.User != "" { + uid, err := strconv.ParseInt(composeServiceConfig.User, 10, 64) + if err != nil { + log.Warn("Ignoring user directive. User to be specified as a UID (numeric).") + } else { + securityContext.RunAsUser = &uid + } + } + capsAdd := []corev1.Capability{} + capsDrop := []corev1.Capability{} + for _, capAdd := range composeServiceConfig.CapAdd { + capsAdd = append(capsAdd, corev1.Capability(capAdd)) + } + for _, capDrop := range composeServiceConfig.CapDrop { + capsDrop = append(capsDrop, corev1.Capability(capDrop)) + } + //set capabilities if it is not empty + if len(capsAdd) > 0 || len(capsDrop) > 0 { + securityContext.Capabilities = &corev1.Capabilities{ + Add: capsAdd, + Drop: capsDrop, + } + } + // update template only if securityContext is not empty + if *securityContext != (corev1.SecurityContext{}) { + serviceContainer.SecurityContext = securityContext + } + podSecurityContext := &corev1.PodSecurityContext{} + if !reflect.DeepEqual(*podSecurityContext, corev1.PodSecurityContext{}) { + serviceConfig.SecurityContext = podSecurityContext + } + + if composeServiceConfig.Deploy.Mode == "global" { + serviceConfig.Daemon = true + } + + serviceConfig.Networks = c.getNetworks(composeServiceConfig, composeObject) + + if (composeServiceConfig.Deploy.Resources != types.Resources{}) { + if composeServiceConfig.Deploy.Resources.Limits != nil { + resourceLimit := corev1.ResourceList{} + memLimit := libcomposeyaml.MemStringorInt(composeServiceConfig.Deploy.Resources.Limits.MemoryBytes) + if memLimit != 0 { + resourceLimit[corev1.ResourceMemory] = *resource.NewQuantity(int64(memLimit), "RandomStringForFormat") + } + if composeServiceConfig.Deploy.Resources.Limits.NanoCPUs != "" { + cpuLimit, err := strconv.ParseFloat(composeServiceConfig.Deploy.Resources.Limits.NanoCPUs, 64) + if err != nil { + log.Warnf("Unable to convert cpu limits resources value : %s", err) + } + CPULimit := int64(cpuLimit * 1000) + if CPULimit != 0 { + resourceLimit[corev1.ResourceCPU] = *resource.NewMilliQuantity(CPULimit, resource.DecimalSI) + } + } + serviceContainer.Resources.Limits = resourceLimit + } + if composeServiceConfig.Deploy.Resources.Reservations != nil { + resourceRequests := corev1.ResourceList{} + MemReservation := libcomposeyaml.MemStringorInt(composeServiceConfig.Deploy.Resources.Reservations.MemoryBytes) + if MemReservation != 0 { + resourceRequests[corev1.ResourceMemory] = *resource.NewQuantity(int64(MemReservation), "RandomStringForFormat") + } + if composeServiceConfig.Deploy.Resources.Reservations.NanoCPUs != "" { + cpuReservation, err := strconv.ParseFloat(composeServiceConfig.Deploy.Resources.Reservations.NanoCPUs, 64) + if err != nil { + log.Warnf("Unable to convert cpu limits reservation value : %s", err) + } + CPUReservation := int64(cpuReservation * 1000) + if CPUReservation != 0 { + resourceRequests[corev1.ResourceCPU] = *resource.NewMilliQuantity(CPUReservation, resource.DecimalSI) + } + } + serviceContainer.Resources.Requests = resourceRequests + } + } + + // HealthCheck + if composeServiceConfig.HealthCheck != nil && !composeServiceConfig.HealthCheck.Disable { + probe, err := c.getHealthCheck(*composeServiceConfig.HealthCheck) + if err != nil { + log.Warnf("Unable to parse health check : %s", err) + } else { + serviceContainer.LivenessProbe = &probe + } + } + restart := composeServiceConfig.Restart + if composeServiceConfig.Deploy.RestartPolicy != nil { + restart = composeServiceConfig.Deploy.RestartPolicy.Condition + } + if restart == "unless-stopped" { + log.Warnf("Restart policy 'unless-stopped' in service %s is not supported, convert it to 'always'", name) + serviceConfig.RestartPolicy = corev1.RestartPolicyAlways + } + // replicas: + if composeServiceConfig.Deploy.Replicas != nil { + serviceConfig.Replicas = int(*composeServiceConfig.Deploy.Replicas) + } + serviceContainer.Env = c.getEnvs(composeServiceConfig) + + vml, vl := makeVolumesFromTmpFS(name, composeServiceConfig.Tmpfs) + for _, v := range vl { + serviceConfig.AddVolume(v) + } + serviceContainer.VolumeMounts = append(serviceContainer.VolumeMounts, vml...) + + for _, secret := range composeServiceConfig.Secrets { + target := filepath.Join(defaultSecretBasePath, secret.Source) + src := secret.Source + if secret.Target != "" { + tokens := strings.Split(secret.Source, "/") + var prefix string + if !strings.HasPrefix(secret.Target, "/") { + prefix = defaultSecretBasePath + "/" + } + if tokens[len(tokens)-1] == secret.Target { + target = prefix + secret.Source + } else { + target = prefix + strings.TrimSuffix(secret.Target, "/"+tokens[len(tokens)-1]) + } + src = tokens[len(tokens)-1] + } + + vSrc := corev1.VolumeSource{ + Secret: &corev1.SecretVolumeSource{ + SecretName: secret.Source, + Items: []corev1.KeyToPath{{ + Key: secret.Source, + Path: src, + }}, + }, + } + + if secret.Mode != nil { + mode := cast.ToInt32(*secret.Mode) + vSrc.Secret.DefaultMode = &mode + } + + serviceConfig.AddVolume(corev1.Volume{ + Name: secret.Source, + VolumeSource: vSrc, + }) + + serviceContainer.VolumeMounts = append(serviceContainer.VolumeMounts, corev1.VolumeMount{ + Name: secret.Source, + MountPath: target, + }) + } + + for _, c := range composeServiceConfig.Configs { + target := c.Target + if target == "" { + target = "/" + c.Source + } + vSrc := corev1.ConfigMapVolumeSource{} + vSrc.Name = common.MakeFileNameCompliant(c.Source) + if o, ok := composeObject.Configs[c.Source]; ok { + if o.External.External { + log.Errorf("Config metadata %s has an external source", c.Source) + } else { + srcBaseName := filepath.Base(o.File) + vSrc.Items = []corev1.KeyToPath{{Key: srcBaseName, Path: filepath.Base(target)}} + if c.Mode != nil { + signedMode := int32(*c.Mode) + vSrc.DefaultMode = &signedMode + } + } + } else { + log.Errorf("Unable to find configmap object for %s", vSrc.Name) + } + serviceConfig.AddVolume(corev1.Volume{ + Name: vSrc.Name, + VolumeSource: corev1.VolumeSource{ConfigMap: &vSrc}, + }) + + serviceContainer.VolumeMounts = append(serviceContainer.VolumeMounts, + corev1.VolumeMount{ + Name: vSrc.Name, + MountPath: target, + SubPath: filepath.Base(target), + }) + } + + for index, vol := range composeServiceConfig.Volumes { + if isPath(vol.Source) { + volumeName := fmt.Sprintf("%s%d", common.VolumePrefix, index) + serviceContainer.VolumeMounts = append(serviceContainer.VolumeMounts, corev1.VolumeMount{ + Name: volumeName, + MountPath: vol.Target, + }) + + serviceConfig.AddVolume(corev1.Volume{ + Name: volumeName, + VolumeSource: corev1.VolumeSource{ + HostPath: &corev1.HostPathVolumeSource{Path: vol.Source}, + }, + }) + } else { + serviceContainer.VolumeMounts = append(serviceContainer.VolumeMounts, corev1.VolumeMount{ + Name: vol.Source, + MountPath: vol.Target, + }) + + serviceConfig.AddVolume(corev1.Volume{ + Name: vol.Source, + VolumeSource: corev1.VolumeSource{ + PersistentVolumeClaim: &corev1.PersistentVolumeClaimVolumeSource{ + ClaimName: vol.Source, + }, + }, + }) + storageObj := irtypes.Storage{StorageType: irtypes.PVCKind, Name: vol.Source, Content: nil} + ir.AddStorage(storageObj) + } + } + + serviceConfig.Containers = []corev1.Container{serviceContainer} + ir.Services[name] = serviceConfig + } + + return ir, nil +} + +func (c *V3Loader) buildEnvironment() map[string]string { + result := make(map[string]string) + //TODO: Check if any variable is mandatory and fill it with dummy value + if !common.IgnoreEnvironment { + env := os.Environ() + for _, s := range env { + if !strings.Contains(s, "=") { + log.Debugf("unexpected environment %q", s) + continue + } + kv := strings.SplitN(s, "=", 2) + result[kv[0]] = kv[1] + } + } + return result +} + +func (c *V3Loader) getSecretStorages(secrets map[string]types.SecretConfig) []irtypes.Storage { + storages := make([]irtypes.Storage, len(secrets)) + for secretName, secretObj := range secrets { + storage := irtypes.Storage{ + Name: secretName, + StorageType: irtypes.SecretKind, + } + + if !secretObj.External.External { + content, err := ioutil.ReadFile(secretObj.File) + if err != nil { + log.Warnf("Could not read the secret file [%s]", secretObj.File) + } else { + storage.Content = map[string][]byte{secretName: content} + } + } + + storages = append(storages, storage) + } + + return storages +} + +func (c *V3Loader) getConfigStorages(configs map[string]types.ConfigObjConfig) []irtypes.Storage { + Storages := make([]irtypes.Storage, len(configs)) + + for cfgName, cfgObj := range configs { + storage := irtypes.Storage{ + Name: cfgName, + StorageType: irtypes.ConfigMapKind, + } + + if !cfgObj.External.External { + fileInfo, err := os.Stat(cfgObj.File) + if err != nil { + log.Warnf("Could not identify the type of secret artifact [%s]. Encountered [%s]", cfgObj.File, err) + } else { + if !fileInfo.IsDir() { + content, err := ioutil.ReadFile(cfgObj.File) + if err != nil { + log.Warnf("Could not read the secret file [%s]. Encountered [%s]", cfgObj.File, err) + } else { + storage.Content = map[string][]byte{cfgName: content} + } + } else { + dataMap, err := c.getAllDirContentAsMap(cfgObj.File) + if err != nil { + log.Warnf("Could not read the secret directory [%s]. Encountered [%s]", cfgObj.File, err) + } else { + storage.Content = dataMap + } + } + } + } + Storages = append(Storages, storage) + } + + return Storages +} + +func (c *V3Loader) getPorts(ports []types.ServicePortConfig, expose []string) []corev1.ContainerPort { + containerPorts := []corev1.ContainerPort{} + exist := map[string]bool{} + for _, port := range ports { + proto := corev1.ProtocolTCP + if strings.EqualFold(string(corev1.ProtocolUDP), port.Protocol) { + proto = corev1.ProtocolUDP + } + containerPorts = append(containerPorts, corev1.ContainerPort{ + ContainerPort: int32(port.Target), + Protocol: proto, + }) + exist[cast.ToString(port.Target)] = true + } + for _, port := range expose { + portValue := port + protocol := corev1.ProtocolTCP + if strings.Contains(portValue, "/") { + splits := strings.Split(port, "/") + portValue = splits[0] + protocol = corev1.Protocol(strings.ToUpper(splits[1])) + } + if exist[portValue] { + continue + } + containerPorts = append(containerPorts, corev1.ContainerPort{ + ContainerPort: cast.ToInt32(portValue), + Protocol: protocol, + }) + } + + return containerPorts +} + +func (c *V3Loader) getNetworks(composeServiceConfig types.ServiceConfig, composeObject types.Config) (networks []string) { + networks = []string{} + for key := range composeServiceConfig.Networks { + netName := composeObject.Networks[key].Name + if netName == "" { + netName = key + } + networks = append(networks, netName) + } + return networks +} + +func (c *V3Loader) getHealthCheck(composeHealthCheck types.HealthCheckConfig) (corev1.Probe, error) { + probe := corev1.Probe{} + + if len(composeHealthCheck.Test) > 1 { + probe.Handler = corev1.Handler{ + Exec: &corev1.ExecAction{ + // docker/cli adds "CMD-SHELL" to the struct, hence we remove the first element of composeHealthCheck.Test + Command: composeHealthCheck.Test[1:], + }, + } + } else { + log.Warnf("Could not find command to execute in probe : %s", composeHealthCheck.Test) + } + if composeHealthCheck.Timeout != nil { + parse, err := time.ParseDuration(composeHealthCheck.Timeout.String()) + if err != nil { + return probe, errors.Wrap(err, "unable to parse health check timeout variable") + } + probe.TimeoutSeconds = int32(parse.Seconds()) + } + if composeHealthCheck.Interval != nil { + parse, err := time.ParseDuration(composeHealthCheck.Interval.String()) + if err != nil { + return probe, errors.Wrap(err, "unable to parse health check interval variable") + } + probe.PeriodSeconds = int32(parse.Seconds()) + } + if composeHealthCheck.Retries != nil { + probe.FailureThreshold = int32(*composeHealthCheck.Retries) + } + if composeHealthCheck.StartPeriod != nil { + parse, err := time.ParseDuration(composeHealthCheck.StartPeriod.String()) + if err != nil { + return probe, errors.Wrap(err, "unable to parse health check startPeriod variable") + } + probe.InitialDelaySeconds = int32(parse.Seconds()) + } + + return probe, nil +} + +func (c *V3Loader) getEnvs(composeServiceConfig types.ServiceConfig) (envs []corev1.EnvVar) { + for name, value := range composeServiceConfig.Environment { + var env corev1.EnvVar + if value != nil { + env = corev1.EnvVar{Name: name, Value: *value} + } else { + env = corev1.EnvVar{Name: name, Value: "unknown"} + } + envs = append(envs, env) + } + return envs +} + +func (c *V3Loader) getAllDirContentAsMap(directoryPath string) (map[string][]byte, error) { + fileList, err := ioutil.ReadDir(directoryPath) + if err != nil { + return nil, err + } + dataMap := make(map[string][]byte) + count := 0 + for _, file := range fileList { + if file.IsDir() { + continue + } + fileName := file.Name() + log.Debugf("Reading file into the data map: [%s]", fileName) + data, err := ioutil.ReadFile(filepath.Join(directoryPath, fileName)) + if err != nil { + log.Debugf("Unable to read file data : %s", fileName) + continue + } + dataMap[fileName] = data + count = count + 1 + } + log.Debugf("Read %d files into the data map", count) + return dataMap, nil +} diff --git a/internal/source/compose2kube.go b/internal/source/compose2kube.go new file mode 100644 index 000000000..f8e730bff --- /dev/null +++ b/internal/source/compose2kube.go @@ -0,0 +1,148 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package source + +import ( + log "github.com/sirupsen/logrus" + + sourcetypes "github.com/konveyor/move2kube/internal/collector/sourcetypes" + common "github.com/konveyor/move2kube/internal/common" + "github.com/konveyor/move2kube/internal/source/compose" + irtypes "github.com/konveyor/move2kube/internal/types" + collecttypes "github.com/konveyor/move2kube/types/collection" + plantypes "github.com/konveyor/move2kube/types/plan" +) + +// ComposeTranslator implements Translator interface +type ComposeTranslator struct { +} + +// GetTranslatorType returns the translator type +func (c ComposeTranslator) GetTranslatorType() plantypes.TranslationTypeValue { + return plantypes.Compose2KubeTranslation +} + +// GetServiceOptions returns the service options for inputPath +func (c ComposeTranslator) GetServiceOptions(inputPath string, plan plantypes.Plan) ([]plantypes.Service, error) { + servicesMap := make(map[string]plantypes.Service) + + //Load images + yamlpaths, err := common.GetFilesByExt(inputPath, []string{".yaml", ".yml"}) + if err != nil { + log.Warnf("Unable to fetch yaml files and recognize compose yamls : %s", err) + } + imagemetadatapaths := make(map[string]string) + for _, path := range yamlpaths { + im := new(collecttypes.ImageInfo) + if common.ReadYaml(path, &im) == nil && im.Kind == string(collecttypes.ImageMetadataKind) { + for _, imagetag := range im.Spec.Tags { + imagemetadatapaths[imagetag] = path + } + } + } + + //Fill data into plan + for _, path := range yamlpaths { + dc := new(sourcetypes.DockerCompose) + if common.ReadYaml(path, &dc) == nil { + path, _ = plan.GetRelativePath(path) + for serviceName, dcservice := range dc.DCServices { + log.Debugf("Found a Docker compose service : %s", serviceName) + serviceName = common.NormalizeForServiceName(serviceName) + if _, ok := servicesMap[serviceName]; !ok { + servicesMap[serviceName] = c.newService(serviceName) + } + service := servicesMap[serviceName] + service.Image = dcservice.Image + service.UpdateContainerBuildPipeline = false + service.UpdateDeployPipeline = true + service.AddSourceArtifact(plantypes.ComposeFileArtifactType, path) + if imagepath, ok := imagemetadatapaths[dcservice.Image]; ok { + imagepath, _ = plan.GetRelativePath(imagepath) + service.AddSourceArtifact(plantypes.ImageInfoArtifactType, imagepath) + } + servicesMap[serviceName] = service + } + } + } + + services := make([]plantypes.Service, len(servicesMap)) + i := 0 + for _, service := range servicesMap { + services[i] = service + i++ + } + return services, nil +} + +type composeIRTranslator interface { + ConvertToIR(filepath string, serviceName string) (irtypes.IR, error) +} + +// Translate translates the service to IR +func (c ComposeTranslator) Translate(services []plantypes.Service, p plantypes.Plan) (irtypes.IR, error) { + ir := irtypes.NewIR(p) + + for _, service := range services { + if service.TranslationType == c.GetTranslatorType() { + for _, path := range service.SourceArtifacts[plantypes.ComposeFileArtifactType] { + fullpath := p.GetFullPath(path) + log.Debugf("File %s being loaded from compose service : %s", fullpath, service.ServiceName) + var dcfile sourcetypes.DockerCompose + err := common.ReadYaml(fullpath, &dcfile) + if err != nil { + log.Errorf("Unable to read docker compose yaml %s for version : %s", path, err) + } + log.Debugf("Docker Compose version: %s", dcfile.Version) + var t composeIRTranslator + switch dcfile.Version { + case "", "1", "1.0", "2", "2.0", "2.1": + t = new(compose.V1V2Loader) + case "3", "3.0", "3.1", "3.2", "3.3", "3.4", "3.5", "3.6", "3.7", "3.8": + t = new(compose.V3Loader) + default: + log.Errorf("Version %s of Docker Compose is not supported (%s). Please use version 1, 2 or 3.", dcfile.Version, fullpath) + } + cir, err := t.ConvertToIR(fullpath, service.ServiceName) + if err != nil { + log.Errorf("Unable to parse docker compose file %s using %T : %s", fullpath, t, err) + } else { + ir.Merge(cir) + } + log.Debugf("Services returned by compose translator : %d", len(ir.Services)) + } + for _, path := range service.SourceArtifacts[plantypes.ImageInfoArtifactType] { + var imgMD collecttypes.ImageInfo + err := common.ReadYaml(p.GetFullPath(path), &imgMD) + if err != nil { + log.Errorf("Unable to read image yaml %s : %s", path, err) + } else { + ir.AddContainer(irtypes.NewContainerFromImageInfo(imgMD)) + } + } + } + } + + return ir, nil +} + +func (c ComposeTranslator) newService(serviceName string) plantypes.Service { + service := plantypes.NewService(serviceName, c.GetTranslatorType()) + service.AddSourceType(plantypes.ComposeSourceTypeValue) + service.ContainerBuildType = plantypes.ReuseContainerBuildTypeValue //TODO: Identify when to use enhance + return service +} diff --git a/internal/source/data/Cfbuildpacks.yaml b/internal/source/data/Cfbuildpacks.yaml new file mode 100644 index 000000000..b3adc026e --- /dev/null +++ b/internal/source/data/Cfbuildpacks.yaml @@ -0,0 +1,18 @@ +kind: cfcontainerizers +buildpackcontainerizers: + - buildpackname: binary_buildpack + containerbuildtype: cnb + targetoptions: + - cloudfoundry/cnb:cflinuxfs3 + - buildpackname: java_buildpack_offline + containerbuildtype: cnb + targetoptions: + - cloudfoundry/cnb:cflinuxfs3 + - buildpackname: hwc_buildpack + containerbuildtype: cnb + targetoptions: + - cloudfoundry/cnb:cflinuxfs3 + - buildpackname: dotnet_core_buildpack + containerbuildtype: cnb + targetoptions: + - cloudfoundry/cnb:cflinuxfs3 diff --git a/internal/source/data/constants.go b/internal/source/data/constants.go new file mode 100644 index 000000000..e9591aa60 --- /dev/null +++ b/internal/source/data/constants.go @@ -0,0 +1,45 @@ +// Code generated by go generate; DO NOT EDIT. +// This file was generated by robots at +// 2020-09-14 15:52:48.575322 +0530 IST m=+0.000974414 + +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package data + +const ( + + Cfbuildpacks_yaml = `kind: cfcontainerizers +buildpackcontainerizers: + - buildpackname: binary_buildpack + containerbuildtype: cnb + targetoptions: + - cloudfoundry/cnb:cflinuxfs3 + - buildpackname: java_buildpack_offline + containerbuildtype: cnb + targetoptions: + - cloudfoundry/cnb:cflinuxfs3 + - buildpackname: hwc_buildpack + containerbuildtype: cnb + targetoptions: + - cloudfoundry/cnb:cflinuxfs3 + - buildpackname: dotnet_core_buildpack + containerbuildtype: cnb + targetoptions: + - cloudfoundry/cnb:cflinuxfs3 +` + +) \ No newline at end of file diff --git a/internal/source/dockerfile2kube.go b/internal/source/dockerfile2kube.go new file mode 100644 index 000000000..a87d7bbbf --- /dev/null +++ b/internal/source/dockerfile2kube.go @@ -0,0 +1,324 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package source + +import ( + "fmt" + "net/url" + "os" + "path/filepath" + "regexp" + "strings" + + git "github.com/go-git/go-git/v5" + dockerparser "github.com/moby/buildkit/frontend/dockerfile/parser" + log "github.com/sirupsen/logrus" + corev1 "k8s.io/api/core/v1" + + "github.com/konveyor/move2kube/internal/common" + "github.com/konveyor/move2kube/internal/containerizer" + irtypes "github.com/konveyor/move2kube/internal/types" + plantypes "github.com/konveyor/move2kube/types/plan" +) + +// DockerfileTranslator implements Translator interface for using preexisting dockerfiles +type DockerfileTranslator struct { +} + +// GetTranslatorType returns translator type +func (c DockerfileTranslator) GetTranslatorType() plantypes.TranslationTypeValue { + return plantypes.Dockerfile2KubeTranslation +} + +// GetServiceOptions - output a plan based on the input directory contents +func (c DockerfileTranslator) GetServiceOptions(inputPath string, plan plantypes.Plan) ([]plantypes.Service, error) { + services := make([]plantypes.Service, 0) + sdfs, err := getDockerfileServices(inputPath, plan.Name) + if err != nil { + log.Errorf("Unable to get Dockerfiles : %s", err) + } else { + for sn, dfs := range sdfs { + ns := c.newService(sn) + ns.Image = sn + ":latest" + ns.ContainerizationTargetOptions = []string{} + relpath, err := plan.GetRelativePath(dfs[0].context) + if err != nil { + log.Warnf("Unable to get relative path of context %s : %s", dfs[0].context, err) + } + ns.AddBuildArtifact(plantypes.SourceDirectoryBuildArtifactType, relpath) + for _, df := range dfs { + p, err := plan.GetRelativePath(df.path) + if err != nil { + log.Warnf("Unable to get relative path of context %s : %s", df.path, err) + } + ns.AddSourceArtifact(plantypes.DockerfileArtifactType, p) + ns.ContainerizationTargetOptions = append(ns.ContainerizationTargetOptions, p) + } + services = append(services, ns) + } + } + return services, err +} + +// Translate translates artifacts to IR +func (c DockerfileTranslator) Translate(services []plantypes.Service, p plantypes.Plan) (irtypes.IR, error) { + ir := irtypes.NewIR(p) + for _, service := range services { + if service.TranslationType == c.GetTranslatorType() { + log.Debugf("Translating %s", service.ServiceName) + if len(service.ContainerizationTargetOptions) == 0 { + log.Warnf("No target options for service %s. Ignoring service.", service.ServiceName) + continue + } + serviceConfig := irtypes.Service{Name: service.ServiceName} + c := containerizer.ReuseDockerfileContainerizer{} + dfp := p.GetFullPath(service.ContainerizationTargetOptions[0]) + fp := filepath.Dir(dfp) + context := "." + if sc, ok := service.BuildArtifacts[plantypes.SourceDirectoryBuildArtifactType]; ok { + if len(sc) > 0 { + curcontext, err := filepath.Rel(fp, p.GetFullPath(sc[0])) + if err == nil { + context = curcontext + } + } + } + con, err := c.GetContainer(fp, service.ServiceName, service.Image, filepath.Base(dfp), context) + if err != nil { + log.Warnf("Unable to get containization script even though build parameters are present : %s", err) + } else { + ir.AddContainer(con) + serviceContainer := corev1.Container{Name: service.ServiceName} + serviceContainer.Image = service.Image + serviceConfig.Containers = []corev1.Container{serviceContainer} + ir.Services[service.ServiceName] = serviceConfig + } + } + } + return ir, nil +} + +func (c DockerfileTranslator) newService(serviceName string) plantypes.Service { + service := plantypes.NewService(serviceName, c.GetTranslatorType()) + service.AddSourceType(plantypes.DirectorySourceTypeValue) + service.UpdateContainerBuildPipeline = true + service.UpdateDeployPipeline = true + return service +} + +func isDockerFile(path string) (isDockerfile bool, err error) { + f, err := os.Open(path) + if err != nil { + log.Debugf("Unable to open file %s : %s", path, err) + return false, err + } + defer f.Close() + res, err := dockerparser.Parse(f) + if err != nil { + log.Debugf("Unable to parse file %s as Docker files : %s", path, err) + return false, err + } + for _, dfchild := range res.AST.Children { + if dfchild.Value == "from" { + r := regexp.MustCompile(`(?i)FROM\s+(--platform=[^\s]+)?[^\s]+(\s+AS\s+[^\s]+)?\s*(#.+)?$`) + if r.MatchString(dfchild.Original) { + log.Debugf("Identified a docker file : " + path) + return true, nil + } + return false, nil + } + if dfchild.Value == "arg" { + continue + } + return false, fmt.Errorf("%s is not a valid Dockerfile", path) + } + return false, fmt.Errorf("%s is not a valid Dockerfile", path) +} + +func getGitRepoName(path string) (repo string, root string) { + r, err := git.PlainOpenWithOptions(filepath.Dir(path), &git.PlainOpenOptions{ + DetectDotGit: true, + }) + if err != nil { + log.Debugf("Unable to open %s as a git repo : %s", path, err) + return "", "" + } + remote, err := r.Remote("origin") + if err != nil { + log.Debugf("Unable to get origin remote : %s", err) + return "", "" + } + if len(remote.Config().URLs) == 0 { + log.Debugf("Unable to get origins") + return "", "" + } + u := remote.Config().URLs[0] + if strings.HasPrefix(u, "git") { + parts := strings.Split(u, ":") + if len(parts) != 2 { + // Unable to find git repo name + return "", "" + } + u = parts[1] + } + giturl, err := url.Parse(u) + if err != nil { + log.Debugf("Unable to get origin remote host : %s", err) + return "", "" + } + name := filepath.Base(giturl.Path) + name = strings.TrimSuffix(name, filepath.Ext(name)) + w, err := r.Worktree() + if err != nil { + log.Warnf("Unable to get root of repo : %s", err) + } + return name, w.Filesystem.Root() +} + +func getDockerfileServices(inputpath string, projName string) (sDockerfiles map[string][]dockerfile, err error) { + if info, err := os.Stat(inputpath); os.IsNotExist(err) { + log.Warnf("Error in walking through files due to : %s", err) + return sDockerfiles, err + } else if !info.IsDir() { + log.Warnf("The path %q is not a directory.", inputpath) + } + files := []string{} + err = filepath.Walk(inputpath, func(path string, info os.FileInfo, err error) error { + if err != nil { + log.Warnf("Skipping path %s due to error: %s", path, err) + return nil + } + // Skip directories + if info.IsDir() { + return nil + } + if isdf, _ := isDockerFile(path); isdf { + files = append(files, path) + } + return nil + }) + if err != nil { + log.Warnf("Error in walking through files due to : %s", err) + } + log.Debugf("No of dockerfiles identified : %d", len(files)) + repoDockerfiles := make(map[string][]dockerfile) + for _, f := range files { + repo, context := getGitRepoName(f) + if repo == "" { + repo = projName + context = inputpath + } + df := dockerfile{f, f, context} + if dfs, ok := repoDockerfiles[repo]; !ok { + repoDockerfiles[repo] = []dockerfile{df} + } else { + repoDockerfiles[repo] = append(dfs, df) + } + } + sDockerfiles = make(map[string][]dockerfile) + for repo, dfs := range repoDockerfiles { + if len(dfs) == 1 { + sDockerfiles[repo] = []dockerfile{dfs[0]} + continue + } + for k, v := range bucketDFs(dfs) { + separator := "-" + if repo == "" || k == "" { + separator = "" + } + nk := repo + separator + k + if v1, ok := sDockerfiles[nk]; ok { + sDockerfiles[nk] = append(v, v1...) + } else { + sDockerfiles[nk] = v + } + } + } + return sDockerfiles, nil +} + +type dockerfile struct { + path string + pathsuffix string + context string +} + +func bucketDFs(dfs []dockerfile) map[string][]dockerfile { + nDockerfiles := make(map[string][]dockerfile) + commonPath := findCommonPrefix(dfs) + if commonPath != "." { + dfs = trimPrefix(dfs, commonPath) + } + for _, df := range dfs { + parts := strings.Split(df.pathsuffix, string(filepath.Separator)) + prefix := "" + if len(parts) == 1 { + prefix = "" + } else if len(parts) > 1 { + prefix = parts[0] + df.context = strings.TrimSuffix(df.path, df.pathsuffix) + parts[0] + } + if pdfs, ok := nDockerfiles[prefix]; !ok { + nDockerfiles[prefix] = []dockerfile{df} + } else { + nDockerfiles[prefix] = append(pdfs, df) + } + } + sDockerfiles := make(map[string][]dockerfile) + for p, dfiles := range nDockerfiles { + if len(dfiles) == 1 { + sDockerfiles[p] = []dockerfile{dfiles[0]} + } else if p == "" { + for _, v := range dfiles { + if v1, ok := sDockerfiles[p]; ok { + sDockerfiles[p] = append(v1, v) + } else { + sDockerfiles[p] = []dockerfile{v} + } + } + } else { + for k, v := range bucketDFs(dfiles) { + separator := "-" + if p == "" || k == "" { + separator = "" + } + nk := p + separator + k + if v1, ok := sDockerfiles[nk]; ok { + sDockerfiles[nk] = append(v, v1...) + } else { + sDockerfiles[nk] = v + } + } + } + } + return sDockerfiles +} + +func findCommonPrefix(files []dockerfile) string { + paths := make([]string, len(files)) + for i, file := range files { + paths[i] = file.pathsuffix + } + return common.CleanAndFindCommonDirectory(paths) +} + +func trimPrefix(files []dockerfile, prefix string) []dockerfile { + for i, f := range files { + files[i].pathsuffix = strings.TrimPrefix(f.pathsuffix, prefix+string(filepath.Separator)) + } + return files +} diff --git a/internal/source/knative2kube.go b/internal/source/knative2kube.go new file mode 100644 index 000000000..7b1e303bf --- /dev/null +++ b/internal/source/knative2kube.go @@ -0,0 +1,48 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package source + +import ( + "github.com/konveyor/move2kube/internal/apiresourceset" + irtypes "github.com/konveyor/move2kube/internal/types" + plantypes "github.com/konveyor/move2kube/types/plan" +) + +// KnativeTranslator implements Translator interface +type KnativeTranslator struct { +} + +// GetTranslatorType returns the translator type +func (c KnativeTranslator) GetTranslatorType() plantypes.TranslationTypeValue { + return plantypes.Knative2KubeTranslation +} + +// GetServiceOptions returns the service options for the inputPath +func (c KnativeTranslator) GetServiceOptions(inputPath string, plan plantypes.Plan) ([]plantypes.Service, error) { + return (&apiresourceset.KnativeAPIResourceSet{}).GetServiceOptions(inputPath, plan) +} + +// Translate returns the IR for the plan service +func (c KnativeTranslator) Translate(services []plantypes.Service, p plantypes.Plan) (irtypes.IR, error) { + return (&apiresourceset.KnativeAPIResourceSet{}).Translate(services, p) +} + +func (c KnativeTranslator) newService(serviceName string) plantypes.Service { + service := plantypes.NewService(serviceName, c.GetTranslatorType()) + service.ContainerBuildType = plantypes.ReuseContainerBuildTypeValue + return service +} diff --git a/internal/source/kube2kube.go b/internal/source/kube2kube.go new file mode 100644 index 000000000..b46e295f6 --- /dev/null +++ b/internal/source/kube2kube.go @@ -0,0 +1,48 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package source + +import ( + "github.com/konveyor/move2kube/internal/apiresourceset" + irtypes "github.com/konveyor/move2kube/internal/types" + plantypes "github.com/konveyor/move2kube/types/plan" +) + +// KubeTranslator implements Translator interface +type KubeTranslator struct { +} + +// GetTranslatorType returns the translator type +func (c KubeTranslator) GetTranslatorType() plantypes.TranslationTypeValue { + return plantypes.Kube2KubeTranslation +} + +// GetServiceOptions returns the possible service options for the inputPath +func (c KubeTranslator) GetServiceOptions(inputPath string, plan plantypes.Plan) ([]plantypes.Service, error) { + return (&apiresourceset.K8sAPIResourceSet{}).GetServiceOptions(inputPath, plan) +} + +// Translate returns the IR representation for the plan service +func (c KubeTranslator) Translate(services []plantypes.Service, p plantypes.Plan) (irtypes.IR, error) { + return (&apiresourceset.K8sAPIResourceSet{}).Translate(services, p) +} + +func (c KubeTranslator) newService(serviceName string) plantypes.Service { + service := plantypes.NewService(serviceName, c.GetTranslatorType()) + service.ContainerBuildType = plantypes.ReuseContainerBuildTypeValue + return service +} diff --git a/internal/source/testdata/datafortestingtranslate/expectedirfornodejsapp.yaml b/internal/source/testdata/datafortestingtranslate/expectedirfornodejsapp.yaml new file mode 100644 index 000000000..1673c4518 --- /dev/null +++ b/internal/source/testdata/datafortestingtranslate/expectedirfornodejsapp.yaml @@ -0,0 +1,106 @@ +name: myproject +services: + nodejs: + podspec: + volumes: [] + initcontainers: [] + containers: + - name: nodejs + image: nodejs:latest + command: [] + args: [] + workingdir: "" + ports: [] + envfrom: [] + env: [] + resources: + limits: {} + requests: {} + volumemounts: [] + volumedevices: [] + livenessprobe: null + readinessprobe: null + startupprobe: null + lifecycle: null + terminationmessagepath: "" + terminationmessagepolicy: "" + imagepullpolicy: "" + securitycontext: null + stdin: false + stdinonce: false + tty: false + ephemeralcontainers: [] + restartpolicy: "" + terminationgraceperiodseconds: null + activedeadlineseconds: null + dnspolicy: "" + nodeselector: {} + serviceaccountname: "" + deprecatedserviceaccount: "" + automountserviceaccounttoken: null + nodename: "" + hostnetwork: false + hostpid: false + hostipc: false + shareprocessnamespace: null + securitycontext: null + imagepullsecrets: [] + hostname: "" + subdomain: "" + affinity: null + schedulername: "" + tolerations: [] + hostaliases: [] + priorityclassname: "" + priority: null + dnsconfig: null + readinessgates: [] + runtimeclassname: null + enableservicelinks: null + preemptionpolicy: null + overhead: {} + topologyspreadconstraints: [] + name: nodejs + annotations: {} + labels: {} + replicas: 0 + networks: [] + exposeservice: false + daemon: false +storages: [] +containers: + - imagenames: + - nodejs:latest + new: true + newfiles: + nodejscnbbuilder.sh: |- + # Copyright IBM Corporation 2020 + # + # Licensed under the Apache License, Version 2.0 (the "License"); + # you may not use this file except in compliance with the License. + # You may obtain a copy of the License at + # + # http://www.apache.org/licenses/LICENSE-2.0 + # + # Unless required by applicable law or agreed to in writing, software + # distributed under the License is distributed on an "AS IS" BASIS, + # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + # See the License for the specific language governing permissions and + # limitations under the License. + + pack build nodejs:latest -B cloudfoundry/cnb:cflinuxfs3 + exposedports: + - 8080 + userid: -1 + accesseddirs: [] +kubernetes: + artifactType: Yamls + clusterType: Kubernetes +targetclusterspec: + storageClasses: [] + apiKindVersionMap: {} +cachedobjects: [] +values: + registryurl: "" + registrynamespace: "" + services: {} diff --git a/internal/source/testdata/datafortestingtranslate/servicesfromnodejsapp.yaml b/internal/source/testdata/datafortestingtranslate/servicesfromnodejsapp.yaml new file mode 100644 index 000000000..9d6b9653b --- /dev/null +++ b/internal/source/testdata/datafortestingtranslate/servicesfromnodejsapp.yaml @@ -0,0 +1,34 @@ +--- +- serviceName: nodejs + image: nodejs:latest + translationType: Any2Kube + containerBuildType: CNB + sourceType: + - Directory + targetOptions: + - cloudfoundry/cnb:cflinuxfs3 + sourceArtifacts: + SourceCode: + - . + buildArtifacts: + SourceCode: + - . + updateContainerBuildPipeline: true + updateDeployPipeline: true +- serviceName: svc1 + image: svc1:latest + translationType: Compose2Kube + containerBuildType: NewDockerfile + sourceType: + - Directory + targetOptions: + - cloudfoundry/cnb:cflinuxfs3 + sourceArtifacts: + SourceCode: + - svc1src + buildArtifacts: + SourceCode: + - svc1src + updateContainerBuildPipeline: true + updateDeployPipeline: true +... \ No newline at end of file diff --git a/internal/source/testdata/expectedservicesforjavamavenappwithm2kignorecase2.yaml b/internal/source/testdata/expectedservicesforjavamavenappwithm2kignorecase2.yaml new file mode 100644 index 000000000..23942bbab --- /dev/null +++ b/internal/source/testdata/expectedservicesforjavamavenappwithm2kignorecase2.yaml @@ -0,0 +1,18 @@ +--- +- serviceName: java-maven + image: java-maven:latest + translationType: Any2Kube + containerBuildType: CNB + sourceType: + - Directory + targetOptions: + - cloudfoundry/cnb:cflinuxfs3 + sourceArtifacts: + SourceCode: + - includeme/includeme/java-maven + buildArtifacts: + SourceCode: + - includeme/includeme/java-maven + updateContainerBuildPipeline: true + updateDeployPipeline: true +... \ No newline at end of file diff --git a/internal/source/testdata/expectedservicesfornodejsapp.yaml b/internal/source/testdata/expectedservicesfornodejsapp.yaml new file mode 100644 index 000000000..4118ad0be --- /dev/null +++ b/internal/source/testdata/expectedservicesfornodejsapp.yaml @@ -0,0 +1,18 @@ +--- +- serviceName: nodejs + image: nodejs:latest + translationType: Any2Kube + containerBuildType: CNB + sourceType: + - Directory + targetOptions: + - cloudfoundry/cnb:cflinuxfs3 + sourceArtifacts: + SourceCode: + - . + buildArtifacts: + SourceCode: + - . + updateContainerBuildPipeline: true + updateDeployPipeline: true +... \ No newline at end of file diff --git a/internal/source/testdata/expectedservicesfornodejsappwithm2kignorecase1.yaml b/internal/source/testdata/expectedservicesfornodejsappwithm2kignorecase1.yaml new file mode 100644 index 000000000..97712dfad --- /dev/null +++ b/internal/source/testdata/expectedservicesfornodejsappwithm2kignorecase1.yaml @@ -0,0 +1,18 @@ +--- +- serviceName: includeme + image: includeme:latest + translationType: Any2Kube + containerBuildType: CNB + sourceType: + - Directory + targetOptions: + - cloudfoundry/cnb:cflinuxfs3 + sourceArtifacts: + SourceCode: + - excludeme/includeme + buildArtifacts: + SourceCode: + - excludeme/includeme + updateContainerBuildPipeline: true + updateDeployPipeline: true +... \ No newline at end of file diff --git a/internal/source/testdata/javamavenappwithm2kignorecase2/.m2kignore b/internal/source/testdata/javamavenappwithm2kignorecase2/.m2kignore new file mode 100644 index 000000000..23f658ae9 --- /dev/null +++ b/internal/source/testdata/javamavenappwithm2kignorecase2/.m2kignore @@ -0,0 +1,6 @@ +. +includeme/ +includeme/excludeme1/ +includeme/excludeme1/* +includeme/excludeme2/ +includeme/excludeme2/* diff --git a/internal/source/testdata/javamavenappwithm2kignorecase2/includeme/excludeme1/src/simplewebapp.php b/internal/source/testdata/javamavenappwithm2kignorecase2/includeme/excludeme1/src/simplewebapp.php new file mode 100644 index 000000000..15fe874fb --- /dev/null +++ b/internal/source/testdata/javamavenappwithm2kignorecase2/includeme/excludeme1/src/simplewebapp.php @@ -0,0 +1,20 @@ + + +This is a PHP App"; +?> diff --git a/internal/source/testdata/javamavenappwithm2kignorecase2/includeme/excludeme2/main.js b/internal/source/testdata/javamavenappwithm2kignorecase2/includeme/excludeme2/main.js new file mode 100644 index 000000000..b4559eaed --- /dev/null +++ b/internal/source/testdata/javamavenappwithm2kignorecase2/includeme/excludeme2/main.js @@ -0,0 +1,23 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +var serverObj = require('http'); +var PORT = 8080; + +serverObj.createServer(function (requestObj, responseObj) { + responseObj.write('

This is a node server

'); + responseObj.end(); +}).listen(PORT); diff --git a/internal/source/testdata/javamavenappwithm2kignorecase2/includeme/excludeme2/package.json b/internal/source/testdata/javamavenappwithm2kignorecase2/includeme/excludeme2/package.json new file mode 100644 index 000000000..20471ca81 --- /dev/null +++ b/internal/source/testdata/javamavenappwithm2kignorecase2/includeme/excludeme2/package.json @@ -0,0 +1,9 @@ +{ + "name" : "main", + "version" : "0.1.0", + "description": "This is a test web server", + "keywords": ["test", "webserver"], + "scripts": { + "start": "node main.js" + } +} diff --git a/internal/source/testdata/javamavenappwithm2kignorecase2/includeme/includeme/java-maven/pom.xml b/internal/source/testdata/javamavenappwithm2kignorecase2/includeme/includeme/java-maven/pom.xml new file mode 100644 index 000000000..ec00416c6 --- /dev/null +++ b/internal/source/testdata/javamavenappwithm2kignorecase2/includeme/includeme/java-maven/pom.xml @@ -0,0 +1,29 @@ + + + + 4.0.0 + com.simplewebapp + simplewebapp + war + 1.0 + simplewebapp Maven Webapp + + simplewebapp + + diff --git a/internal/source/testdata/javamavenappwithm2kignorecase2/includeme/includeme/java-maven/src/main/webapp/WEB-INF/web.xml b/internal/source/testdata/javamavenappwithm2kignorecase2/includeme/includeme/java-maven/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 000000000..9259e3a4c --- /dev/null +++ b/internal/source/testdata/javamavenappwithm2kignorecase2/includeme/includeme/java-maven/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,24 @@ + + + + + + Maven Web App For Move2Kube + diff --git a/internal/source/testdata/javamavenappwithm2kignorecase2/includeme/includeme/java-maven/src/main/webapp/index.jsp b/internal/source/testdata/javamavenappwithm2kignorecase2/includeme/includeme/java-maven/src/main/webapp/index.jsp new file mode 100644 index 000000000..6e7d8b44a --- /dev/null +++ b/internal/source/testdata/javamavenappwithm2kignorecase2/includeme/includeme/java-maven/src/main/webapp/index.jsp @@ -0,0 +1,22 @@ + + + + +

This is a java-maven web app

+ + diff --git a/internal/source/testdata/javamavenappwithm2kignorecase2/package.json b/internal/source/testdata/javamavenappwithm2kignorecase2/package.json new file mode 100644 index 000000000..08008c957 --- /dev/null +++ b/internal/source/testdata/javamavenappwithm2kignorecase2/package.json @@ -0,0 +1 @@ +this is an " invalid json file for testing diff --git a/internal/source/testdata/m2kignoreforignorecontents b/internal/source/testdata/m2kignoreforignorecontents new file mode 100644 index 000000000..26e4ffa55 --- /dev/null +++ b/internal/source/testdata/m2kignoreforignorecontents @@ -0,0 +1,2 @@ +. +includeme/* diff --git a/internal/source/testdata/nodejsappwithm2kignorecase1/.m2kignore b/internal/source/testdata/nodejsappwithm2kignorecase1/.m2kignore new file mode 100644 index 000000000..50aca6249 --- /dev/null +++ b/internal/source/testdata/nodejsappwithm2kignorecase1/.m2kignore @@ -0,0 +1 @@ +/excludeme/ diff --git a/internal/source/testdata/nodejsappwithm2kignorecase1/excludeme/includeme/main.js b/internal/source/testdata/nodejsappwithm2kignorecase1/excludeme/includeme/main.js new file mode 100644 index 000000000..b4559eaed --- /dev/null +++ b/internal/source/testdata/nodejsappwithm2kignorecase1/excludeme/includeme/main.js @@ -0,0 +1,23 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +var serverObj = require('http'); +var PORT = 8080; + +serverObj.createServer(function (requestObj, responseObj) { + responseObj.write('

This is a node server

'); + responseObj.end(); +}).listen(PORT); diff --git a/internal/source/testdata/nodejsappwithm2kignorecase1/excludeme/includeme/package.json b/internal/source/testdata/nodejsappwithm2kignorecase1/excludeme/includeme/package.json new file mode 100644 index 000000000..20471ca81 --- /dev/null +++ b/internal/source/testdata/nodejsappwithm2kignorecase1/excludeme/includeme/package.json @@ -0,0 +1,9 @@ +{ + "name" : "main", + "version" : "0.1.0", + "description": "This is a test web server", + "keywords": ["test", "webserver"], + "scripts": { + "start": "node main.js" + } +} diff --git a/internal/source/testdata/nodejsappwithm2kignorecase1/excludeme/main.js b/internal/source/testdata/nodejsappwithm2kignorecase1/excludeme/main.js new file mode 100644 index 000000000..b4559eaed --- /dev/null +++ b/internal/source/testdata/nodejsappwithm2kignorecase1/excludeme/main.js @@ -0,0 +1,23 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +var serverObj = require('http'); +var PORT = 8080; + +serverObj.createServer(function (requestObj, responseObj) { + responseObj.write('

This is a node server

'); + responseObj.end(); +}).listen(PORT); diff --git a/internal/source/testdata/nodejsappwithm2kignorecase1/excludeme/package.json b/internal/source/testdata/nodejsappwithm2kignorecase1/excludeme/package.json new file mode 100644 index 000000000..20471ca81 --- /dev/null +++ b/internal/source/testdata/nodejsappwithm2kignorecase1/excludeme/package.json @@ -0,0 +1,9 @@ +{ + "name" : "main", + "version" : "0.1.0", + "description": "This is a test web server", + "keywords": ["test", "webserver"], + "scripts": { + "start": "node main.js" + } +} diff --git a/internal/source/testdata/testmultiplem2kignores.tar b/internal/source/testdata/testmultiplem2kignores.tar new file mode 100644 index 0000000000000000000000000000000000000000..5cb3b6867162651e86ea4fc674c3632ce081089d GIT binary patch literal 12800 zcmeI2+irs}42HSxQ*gbDk#n9WupUt9K|tSs4xp~87FeW^RI5=XnidH7vz^}w{kH2* zx2CVJ&Gy8O_5OTmw_TBi+z26B$~?1sHSP%$LmPe?ww!X!G*KKrIboDjlI1ewO}MUg z>w43|tsP8TAKSV+oXxp3joDwWrg=CC4%_V>+RtC7=dce6TmJm_tG4^!`G4MhA;67; zJ(L)EJNWB6e?}GX=Zx?yCjt6iyu_RHuZm4od~6oYga`aj3pnE6gd71N{{Nc)84Ln8 z|4XJZ|Htq+2mdM+f5F+npHt+YkbjwoKL_PE#=k`VN%;p$}Yi|6m^A$KU3EZ~)YQ>%)g0X7~rw zfPVaK`~!c1@gKth9Q>m}H{|meR z!kb8U9K1KW8I<1@nJc|F7=? zv-|^P0H68~R{m}L3xf6E`tYHLS^j}CfFJ)M{sqDH-_-nrDF7e-l-c)xApVhmdj5gl y0`TIm#`vdL|EK5w73M7fFaD$c7Zlfj((_L+{!>2bKja^UKX!r^KnuLD1-=31@aKg9 literal 0 HcmV?d00001 diff --git a/internal/source/translator.go b/internal/source/translator.go new file mode 100644 index 000000000..4cc0b8ee8 --- /dev/null +++ b/internal/source/translator.go @@ -0,0 +1,72 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package source + +import ( + log "github.com/sirupsen/logrus" + + irtypes "github.com/konveyor/move2kube/internal/types" + plantypes "github.com/konveyor/move2kube/types/plan" +) + +// Translator interface defines loader that translates files and converts it to ir representation +type Translator interface { + GetTranslatorType() plantypes.TranslationTypeValue + GetServiceOptions(inputPath string, p plantypes.Plan) ([]plantypes.Service, error) + Translate(services []plantypes.Service, p plantypes.Plan) (irtypes.IR, error) + newService(serviceName string) plantypes.Service +} + +// GetSourceLoaders returns loader for given format +func GetSourceLoaders() []Translator { + var l = []Translator{new(DockerfileTranslator), new(ComposeTranslator), new(CfManifestTranslator), new(KnativeTranslator), new(KubeTranslator), new(Any2KubeTranslator)} //Any2Kube should be the last option + // new(ImagesTranslator)} + return l +} + +// Translate loads all sources +func Translate(p plantypes.Plan) (irtypes.IR, error) { + ts := GetSourceLoaders() + ir := irtypes.NewIR(p) + log.Infoln("Begin Translation") + for _, l := range ts { + log.Infof("[%T] Begin translation", l) + validservices := []plantypes.Service{} + for _, services := range p.Spec.Inputs.Services { + //Choose the first service even if there are multiple options + service := services[0] + if service.TranslationType == l.GetTranslatorType() { + validservices = append(validservices, service) + } + } + log.Debugf("Services to translate : %d", len(validservices)) + currir, err := l.Translate(validservices, p) + log.Debugf("Services translated : %d", len(currir.Services)) + log.Debugf("Containers translated : %d", len(currir.Containers)) + if err != nil { + log.Warnf("[%T] Failed : %s", l, err.Error()) + } else { + log.Infof("[%T] Done", l) + } + ir.Merge(currir) + log.Debugf("Total Services after translation : %d", len(ir.Services)) + log.Debugf("Total Containers after translation : %d", len(ir.Containers)) + } + log.Infoln("Translation done") + + return ir, nil +} diff --git a/internal/transformer/composetransformer.go b/internal/transformer/composetransformer.go new file mode 100644 index 000000000..537965930 --- /dev/null +++ b/internal/transformer/composetransformer.go @@ -0,0 +1,101 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package transform + +import ( + "os" + "path/filepath" + + log "github.com/sirupsen/logrus" + + composetypes "github.com/docker/cli/cli/compose/types" + + "github.com/konveyor/move2kube/internal/common" + irtypes "github.com/konveyor/move2kube/internal/types" +) + +// ComposeTransformer implements Transformer interface +type ComposeTransformer struct { + Compose composeConfig + Containers []irtypes.Container + Name string +} + +type composeConfig struct { + Version string + Services map[string]composetypes.ServiceConfig `yaml:",omitempty"` + Networks map[string]composetypes.NetworkConfig `yaml:",omitempty"` + Volumes map[string]composetypes.VolumeConfig `yaml:",omitempty"` + Secrets map[string]composetypes.SecretConfig `yaml:",omitempty"` + Configs map[string]composetypes.ConfigObjConfig `yaml:",omitempty"` +} + +// Transform translates intermediate representation to destination objects +func (kt *ComposeTransformer) Transform(ir irtypes.IR) error { + log.Debugf("Starting Compose transform") + log.Debugf("Total services to be transformed : %d", len(ir.Services)) + + kt.Name = ir.Name + kt.Containers = ir.Containers + kt.Compose = composeConfig{ + Version: "3.5", + Services: make(map[string]composetypes.ServiceConfig), + } + + var exposedPort uint32 = 8080 + for _, service := range ir.Services { + for _, container := range service.Containers { + ports := make([]composetypes.ServicePortConfig, 0) + for _, port := range container.Ports { + ports = append(ports, composetypes.ServicePortConfig{ + Target: uint32(port.ContainerPort), + Published: exposedPort, + }) + exposedPort++ + } + env := make(composetypes.MappingWithEquals) + for _, e := range container.Env { + env[e.Name] = &e.Value + } + serviceConfig := composetypes.ServiceConfig{ + ContainerName: container.Name, + Image: container.Image, + Ports: ports, + Environment: env, + } + kt.Compose.Services[service.Name] = serviceConfig + //TODO: Support more than one container + } + } + log.Debugf("Total transformed objects : %d", len(kt.Compose.Services)) + + return nil +} + +// WriteObjects writes Transformed objects to filesystem +func (kt *ComposeTransformer) WriteObjects(outpath string) error { + err := os.MkdirAll(outpath, common.DefaultDirectoryPermission) + if err != nil { + log.Errorf("Unable to create output directory %s : %s", outpath, err) + } + artifactspath := filepath.Join(outpath, "docker-compose.yaml") + err = common.WriteYaml(artifactspath, kt.Compose) + if err != nil { + log.Errorf("Unable to write docker compose file %s : %s", artifactspath, err) + } + return nil +} diff --git a/internal/transformer/k8stransformer.go b/internal/transformer/k8stransformer.go new file mode 100644 index 000000000..7cb961378 --- /dev/null +++ b/internal/transformer/k8stransformer.go @@ -0,0 +1,228 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package transform + +import ( + "io/ioutil" + "os" + "os/exec" + "path/filepath" + "strings" + + log "github.com/sirupsen/logrus" + + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + + knativev1 "knative.dev/serving/pkg/apis/serving/v1" + + "github.com/konveyor/move2kube/internal/apiresourceset" + common "github.com/konveyor/move2kube/internal/common" + "github.com/konveyor/move2kube/internal/transformer/templates" + irtypes "github.com/konveyor/move2kube/internal/types" + collecttypes "github.com/konveyor/move2kube/types/collection" + outputtypes "github.com/konveyor/move2kube/types/output" + plantypes "github.com/konveyor/move2kube/types/plan" +) + +// K8sTransformer implements Transformer interface +type K8sTransformer struct { + TransformedObjects []runtime.Object + Containers []irtypes.Container + Values outputtypes.HelmValues + TargetClusterSpec collecttypes.ClusterMetadataSpec + Helm bool + Name string + IgnoreUnsupportedKinds bool +} + +// Transform translates intermediate representation to destination objects +func (kt *K8sTransformer) Transform(ir irtypes.IR) error { + log.Debugf("Starting Kubernetes transform") + log.Debugf("Total services to be transformed : %d", len(ir.Services)) + + kt.Name = ir.Name + kt.Values = ir.Values + kt.Containers = ir.Containers + kt.TargetClusterSpec = ir.TargetClusterSpec + kt.Helm = (ir.Kubernetes.ArtifactType != plantypes.Yamls) + + kt.TransformedObjects = (&apiresourceset.K8sAPIResourceSet{}).CreateAPIResources(ir) + + log.Debugf("Total transformed objects : %d", len(kt.TransformedObjects)) + + return nil +} + +// WriteObjects writes Transformed objects to filesystem +func (kt *K8sTransformer) WriteObjects(outpath string) error { + areNewImagesCreated := writeContainers(outpath, kt.Containers, kt.Values.RegistryURL, kt.Values.RegistryNamespace) + + artifactspath := filepath.Join(outpath, kt.Name) + if kt.Helm { + _ = kt.generateHelmMetadata(artifactspath, kt.Values) + artifactspath = filepath.Join(artifactspath, "templates") + } + log.Debugf("Total services to be serialized : %d", len(kt.TransformedObjects)) + + scheme := (&apiresourceset.K8sAPIResourceSet{}).GetScheme() + objs := []runtime.Object{} + for _, obj := range kt.TransformedObjects { + kind := obj.GetObjectKind().GroupVersionKind().Kind + versions := kt.TargetClusterSpec.GetSupportedVersions(kind) + version := obj.GetObjectKind().GroupVersionKind().String() + if versions == nil { + if kt.IgnoreUnsupportedKinds { + log.Errorf("Kind %s unsupported in target cluster. Will ignore object. %+v", kind, obj.GetObjectKind()) + continue + } + } else { + if kind == "Service" { + for _, v := range versions { + if !strings.HasPrefix(v, knativev1.SchemeGroupVersion.Group) { + version = v + } + } + } else { + version = versions[0] + } + } + groupversion, err := schema.ParseGroupVersion(version) + if err != nil { + log.Errorf("Unable to parse group version %s : %s", version, err) + continue + } + //Change to supported version + newobj, err := scheme.ConvertToVersion(obj, schema.GroupVersion{Group: groupversion.Group, Version: groupversion.Version}) + if err != nil { + log.Errorf("Error while transforming version : %s. Writing in original version.", err) + //continue + } else { + obj = newobj + } + objs = append(objs, obj) + } + + _, err := writeTransformedObjects(artifactspath, objs) + if err != nil { + log.Errorf("Error occured while writing transformed objects %s", err) + } + if kt.Helm { + _ = kt.createOperator(kt.Name, outpath) + } else { + kt.writeDeployScript(kt.Name, outpath) + } + kt.writeReadMe(kt.Name, areNewImagesCreated, kt.Helm, outpath) + return nil +} + +func (kt *K8sTransformer) generateHelmMetadata(dirName string, values outputtypes.HelmValues) error { + err := os.MkdirAll(dirName, common.DefaultDirectoryPermission) + if err != nil { + log.Errorf("Unable to create Helm Metadata directory %s : %s", dirName, err) + return err + } + //README.md + readme := "This chart was created by Move2Kube\n" + err = ioutil.WriteFile(filepath.Join(dirName, "README.md"), []byte(readme), common.DefaultFilePermission) + if err != nil { + log.Errorf("Error while writing Readme : %s", err) + } + + //Chart.yaml + type ChartDetails struct { + Name string + } + err = common.WriteTemplateToFile(templates.Chart_tpl, ChartDetails{filepath.Base(dirName)}, filepath.Join(dirName, "Chart.yaml"), common.DefaultFilePermission) + if err != nil { + log.Errorf("Error while writing Chart.yaml : %s", err) + } + + //values.yaml + outputPath := filepath.Join(dirName, "values.yaml") + err = common.WriteYaml(outputPath, values) + if err != nil { + log.Warn("Error in writing Helm values", err) + } else { + log.Debugf("Wrote Helm values to file: %s", outputPath) + } + + err = common.WriteTemplateToFile(templates.Helminstall_sh, struct { + Project string + }{ + Project: filepath.Base(dirName), + }, filepath.Join(filepath.Dir(dirName), "helminstall.sh"), common.DefaultExecutablePermission) + return err +} + +func (kt *K8sTransformer) createOperator(projectname string, basepath string) error { + _, err := exec.LookPath("operator-sdk") + if err != nil { + log.Warnf("Unable to find operator-sdk. Skipping operator generation : %s", err) + return err + } + operatorname := projectname + "-operator" + operatorpath := filepath.Join(basepath, operatorname) + _, err = os.Stat(operatorpath) + if !os.IsNotExist(err) { + os.RemoveAll(operatorpath) + } + err = os.MkdirAll(operatorpath, common.DefaultDirectoryPermission) + if err != nil { + log.Errorf("Unable to create Operator directory %s : %s", operatorpath, err) + return err + } + helmchartpath, err := filepath.Abs(filepath.Join(basepath, projectname)) + if err != nil { + log.Warnf("Could not resolve helm chart path : %s", err) + return err + } + cmd := exec.Command("operator-sdk", "init", "--plugins=helm", "--helm-chart="+helmchartpath, "--domain=io", "--group="+projectname, "--version=v1alpha1") + cmd.Dir = operatorpath + output, err := cmd.Output() + if err != nil { + log.Warnf("Error during operator creation : %s, %s", err, output) + return err + } + return nil +} + +func (kt *K8sTransformer) writeDeployScript(proj string, outpath string) { + err := common.WriteTemplateToFile(templates.Deploy_sh, struct { + Project string + }{ + Project: proj, + }, filepath.Join(outpath, "deploy.sh"), common.DefaultExecutablePermission) + if err != nil { + log.Errorf("Unable to write deploy script : %s", err) + } +} + +func (kt *K8sTransformer) writeReadMe(project string, areNewImages bool, isHelm bool, outpath string) { + err := common.WriteTemplateToFile(templates.K8sReadme_md, struct { + Project string + NewImages bool + Helm bool + }{ + Project: project, + NewImages: areNewImages, + Helm: isHelm, + }, filepath.Join(outpath, "Readme.md"), common.DefaultFilePermission) + if err != nil { + log.Errorf("Unable to write readme : %s", err) + } +} diff --git a/internal/transformer/knativetransformer.go b/internal/transformer/knativetransformer.go new file mode 100644 index 000000000..1576a99cf --- /dev/null +++ b/internal/transformer/knativetransformer.go @@ -0,0 +1,99 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package transform + +import ( + "path/filepath" + + log "github.com/sirupsen/logrus" + + "k8s.io/apimachinery/pkg/runtime" + + "github.com/konveyor/move2kube/internal/apiresourceset" + common "github.com/konveyor/move2kube/internal/common" + "github.com/konveyor/move2kube/internal/transformer/templates" + irtypes "github.com/konveyor/move2kube/internal/types" + collecttypes "github.com/konveyor/move2kube/types/collection" + outputtypes "github.com/konveyor/move2kube/types/output" +) + +// KnativeTransformer implements Transformer interface +type KnativeTransformer struct { + TransformedObjects []runtime.Object + Containers []irtypes.Container + Values outputtypes.HelmValues + TargetClusterSpec collecttypes.ClusterMetadataSpec + Name string + IgnoreUnsupportedKinds bool +} + +// Transform translates intermediate representation to destination objects +func (kt *KnativeTransformer) Transform(ir irtypes.IR) error { + log.Debugf("Starting Knative transform") + log.Debugf("Total services to be transformed : %d", len(ir.Services)) + + kt.Name = ir.Name + kt.Values = ir.Values + kt.Containers = ir.Containers + kt.TargetClusterSpec = ir.TargetClusterSpec + kt.IgnoreUnsupportedKinds = ir.Kubernetes.IgnoreUnsupportedKinds + kt.TransformedObjects = (&apiresourceset.KnativeAPIResourceSet{}).CreateAPIResources(ir) + + log.Debugf("Total transformed objects : %d", len(kt.TransformedObjects)) + + return nil +} + +// WriteObjects writes Transformed objects to filesystem +func (kt *KnativeTransformer) WriteObjects(outpath string) error { + areNewImagesCreated := writeContainers(outpath, kt.Containers, kt.Values.RegistryURL, kt.Values.RegistryNamespace) + + artifactspath := filepath.Join(outpath, kt.Name) + log.Debugf("Total services to be serialized : %d", len(kt.TransformedObjects)) + + _, err := writeTransformedObjects(artifactspath, kt.TransformedObjects) + if err != nil { + log.Errorf("Error occured while writing transformed objects %s", err) + } + kt.writeDeployScript(kt.Name, outpath) + kt.writeReadeMe(kt.Name, areNewImagesCreated, outpath) + return nil +} + +func (kt *KnativeTransformer) writeDeployScript(proj string, outpath string) { + err := common.WriteTemplateToFile(templates.Deploy_sh, struct { + Project string + }{ + Project: proj, + }, filepath.Join(outpath, "deploy.sh"), common.DefaultExecutablePermission) + if err != nil { + log.Errorf("Unable to write deploy script : %s", err) + } +} + +func (kt *KnativeTransformer) writeReadeMe(project string, areNewImages bool, outpath string) { + err := common.WriteTemplateToFile(templates.KnativeReadme_md, struct { + Project string + NewImages bool + }{ + Project: project, + NewImages: areNewImages, + }, filepath.Join(outpath, "Readme.md"), common.DefaultFilePermission) + if err != nil { + log.Errorf("Unable to write Readme : %s", err) + } +} diff --git a/internal/transformer/templates/Buildimages.sh b/internal/transformer/templates/Buildimages.sh new file mode 100644 index 000000000..1a306aaf8 --- /dev/null +++ b/internal/transformer/templates/Buildimages.sh @@ -0,0 +1,18 @@ +# Copyright IBM Corporation 2020 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +{{range $key, $val := .}} +cd {{$val}} +./{{$key}} +cd -{{end}} diff --git a/internal/transformer/templates/Chart.tpl b/internal/transformer/templates/Chart.tpl new file mode 100644 index 000000000..73a5e2b8e --- /dev/null +++ b/internal/transformer/templates/Chart.tpl @@ -0,0 +1,8 @@ +name: {{.Name}} +description: A generated Helm Chart for {{.Name}} +version: 0.1.0 +apiVersion: v1 +keywords: + - {{.Name}} +sources: +home: \ No newline at end of file diff --git a/internal/transformer/templates/CopySources.sh b/internal/transformer/templates/CopySources.sh new file mode 100644 index 000000000..7818cdaf6 --- /dev/null +++ b/internal/transformer/templates/CopySources.sh @@ -0,0 +1,14 @@ +# Copyright IBM Corporation 2020 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +cp -r {{.Src}}/* {{.Dst}}/ diff --git a/internal/transformer/templates/Deploy.sh b/internal/transformer/templates/Deploy.sh new file mode 100644 index 000000000..3d7a94633 --- /dev/null +++ b/internal/transformer/templates/Deploy.sh @@ -0,0 +1,15 @@ +# Copyright IBM Corporation 2020 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +kubectl apply -f {{ .Project }} \ No newline at end of file diff --git a/internal/transformer/templates/Helminstall.sh b/internal/transformer/templates/Helminstall.sh new file mode 100644 index 000000000..b74b19bfe --- /dev/null +++ b/internal/transformer/templates/Helminstall.sh @@ -0,0 +1,15 @@ +# Copyright IBM Corporation 2020 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +helm upgrade -i {{ .Project }} {{ .Project }} \ No newline at end of file diff --git a/internal/transformer/templates/K8sReadme.md b/internal/transformer/templates/K8sReadme.md new file mode 100644 index 000000000..cece702f0 --- /dev/null +++ b/internal/transformer/templates/K8sReadme.md @@ -0,0 +1,21 @@ +Move2Kube +--------- +Congratulations! Move2Kube has generated the necessary build artfiacts for moving all your application components to Kubernetes. Using the artifacts in this directory you can deploy your application in a kubernetes cluster. + +Prerequisites +------------- +* Docker +* Helm +* Kubectl +* Source-To-Image (S2I) https://github.com/openshift/source-to-image + +Next Steps +---------- +{{if .NewImages -}} +* Copy the source directory into the containers folder for packaging as containers using "copysource.sh " +* Build your images using "buildimages.sh" +* Push images to registry "pushimages.sh " +{{end -}} +{{- if .Helm -}}* Your helm chart is at {{ .Project }}, you can install it using "helminstall.sh" or you can use the operator.{{- else -}} +* Use "deploy.sh" to deploy your artifacts into a kubernetes cluster. +{{- end}} diff --git a/internal/transformer/templates/KnativeReadme.md b/internal/transformer/templates/KnativeReadme.md new file mode 100644 index 000000000..c2f22e2af --- /dev/null +++ b/internal/transformer/templates/KnativeReadme.md @@ -0,0 +1,17 @@ +Move2Kube +--------- +Congratulations! Move2Kube has generated the necessary build artfiacts for moving all your application components to Knative. Using the artifacts in this directory you can deploy your application in a Knative instance + +Prerequisites +------------- +* Docker +* Kubectl + +Next Steps +---------- +{{if .NewImages -}} +* Copy this directory into your base source directory, so that the scripts gets merged at the right contexts. +* Build your images using buildimages.sh +* Push images to registry pushimages.sh +{{end -}} +* Use deploy.sh to deploy your artifacts into a knative. \ No newline at end of file diff --git a/internal/transformer/templates/Manualimages.md b/internal/transformer/templates/Manualimages.md new file mode 100644 index 000000000..fc993a42f --- /dev/null +++ b/internal/transformer/templates/Manualimages.md @@ -0,0 +1,6 @@ +Manual containers +----------------- +There is no known automated containerization approach for the below container requirements. + +{{range $image := .Images}}{{$image}} +{{end}} \ No newline at end of file diff --git a/internal/transformer/templates/Pushimages.sh b/internal/transformer/templates/Pushimages.sh new file mode 100644 index 000000000..c9af5e26d --- /dev/null +++ b/internal/transformer/templates/Pushimages.sh @@ -0,0 +1,30 @@ +# Copyright IBM Corporation 2020 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Invoke as pushimages.sh + +if [ "$#" -ne 2 ]; then + REGISTRY_URL={{ .RegistryURL }} + REGISTRY_NAMESPACE={{ .RegistryNamespace }} +else + REGISTRY_URL=$1 + REGISTRY_NAMESPACE=$2 +fi + +# Uncomment the below line if you want to enable login before pushing +# docker login ${REGISTRY_URL} + +{{range $image := .Images}}docker tag {{$image}} ${REGISTRY_URL}/${REGISTRY_NAMESPACE}/{{$image}} +docker push ${REGISTRY_URL}/${REGISTRY_NAMESPACE}/{{$image}} +{{end}} \ No newline at end of file diff --git a/internal/transformer/templates/constants.go b/internal/transformer/templates/constants.go new file mode 100644 index 000000000..178a80097 --- /dev/null +++ b/internal/transformer/templates/constants.go @@ -0,0 +1,181 @@ +// Code generated by go generate; DO NOT EDIT. +// This file was generated by robots at +// 2020-09-14 15:52:49.237152 +0530 IST m=+0.001411422 + +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package templates + +const ( + + Buildimages_sh = `# Copyright IBM Corporation 2020 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +{{range $key, $val := .}} +cd {{$val}} +./{{$key}} +cd -{{end}} +` + + Chart_tpl = `name: {{.Name}} +description: A generated Helm Chart for {{.Name}} +version: 0.1.0 +apiVersion: v1 +keywords: + - {{.Name}} +sources: +home:` + + CopySources_sh = `# Copyright IBM Corporation 2020 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +cp -r {{.Src}}/* {{.Dst}}/ +` + + Deploy_sh = `# Copyright IBM Corporation 2020 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +kubectl apply -f {{ .Project }}` + + Helminstall_sh = `# Copyright IBM Corporation 2020 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +helm upgrade -i {{ .Project }} {{ .Project }}` + + K8sReadme_md = `Move2Kube +--------- +Congratulations! Move2Kube has generated the necessary build artfiacts for moving all your application components to Kubernetes. Using the artifacts in this directory you can deploy your application in a kubernetes cluster. + +Prerequisites +------------- +* Docker +* Helm +* Kubectl +* Source-To-Image (S2I) https://github.com/openshift/source-to-image + +Next Steps +---------- +{{if .NewImages -}} +* Copy the source directory into the containers folder for packaging as containers using "copysource.sh " +* Build your images using "buildimages.sh" +* Push images to registry "pushimages.sh " +{{end -}} +{{- if .Helm -}}* Your helm chart is at {{ .Project }}, you can install it using "helminstall.sh" or you can use the operator.{{- else -}} +* Use "deploy.sh" to deploy your artifacts into a kubernetes cluster. +{{- end}} +` + + KnativeReadme_md = `Move2Kube +--------- +Congratulations! Move2Kube has generated the necessary build artfiacts for moving all your application components to Knative. Using the artifacts in this directory you can deploy your application in a Knative instance + +Prerequisites +------------- +* Docker +* Kubectl + +Next Steps +---------- +{{if .NewImages -}} +* Copy this directory into your base source directory, so that the scripts gets merged at the right contexts. +* Build your images using buildimages.sh +* Push images to registry pushimages.sh +{{end -}} +* Use deploy.sh to deploy your artifacts into a knative.` + + Manualimages_md = `Manual containers +----------------- +There is no known automated containerization approach for the below container requirements. + +{{range $image := .Images}}{{$image}} +{{end}}` + + Pushimages_sh = `# Copyright IBM Corporation 2020 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Invoke as pushimages.sh + +if [ "$#" -ne 2 ]; then + REGISTRY_URL={{ .RegistryURL }} + REGISTRY_NAMESPACE={{ .RegistryNamespace }} +else + REGISTRY_URL=$1 + REGISTRY_NAMESPACE=$2 +fi + +# Uncomment the below line if you want to enable login before pushing +# docker login ${REGISTRY_URL} + +{{range $image := .Images}}docker tag {{$image}} ${REGISTRY_URL}/${REGISTRY_NAMESPACE}/{{$image}} +docker push ${REGISTRY_URL}/${REGISTRY_NAMESPACE}/{{$image}} +{{end}}` + +) \ No newline at end of file diff --git a/internal/transformer/transformer.go b/internal/transformer/transformer.go new file mode 100644 index 000000000..b157134ed --- /dev/null +++ b/internal/transformer/transformer.go @@ -0,0 +1,203 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package transform + +import ( + "bytes" + "encoding/json" + "fmt" + "io/ioutil" + "os" + "path" + "path/filepath" + "reflect" + "strings" + + log "github.com/sirupsen/logrus" + "gopkg.in/yaml.v3" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + + common "github.com/konveyor/move2kube/internal/common" + "github.com/konveyor/move2kube/internal/transformer/templates" + irtypes "github.com/konveyor/move2kube/internal/types" + "github.com/konveyor/move2kube/types/plan" +) + +//go:generate go run github.com/konveyor/move2kube/internal/common/generator templates + +// Transformer translates intermediate representation to destination artifacts +type Transformer interface { + // Transform translates intermediate representation to destination objects + Transform(ir irtypes.IR) error + // WriteObjects writes Transformed objects to filesystem + WriteObjects(outDirectory string) error +} + +// GetTransformer returns a transformer that is suitable for an IR +func GetTransformer(ir irtypes.IR) Transformer { + if ir.Kubernetes.ArtifactType == plan.Knative { + return &KnativeTransformer{} + } + return &K8sTransformer{} +} + +func writeContainers(outpath string, containers []irtypes.Container, registryURL string, registryNamespace string) bool { //Returns if any scripts were written + containersdirectory := "containers" + containerspath := path.Join(outpath, containersdirectory) + log.Debugf("containerspath %s", containerspath) + err := os.MkdirAll(containerspath, common.DefaultDirectoryPermission) + if err != nil { + log.Errorf("Unable to create directory %s : %s", containerspath, err) + } + log.Debugf("Total number of containers : %d", len(containers)) + buildscripts := []string{} + dockerimages := []string{} + manualimages := []string{} + for _, container := range containers { + log.Debugf("Container : %t", container.New) + if !container.New { + continue + } + if len(container.NewFiles) == 0 { + manualimages = append(manualimages, container.ImageNames...) + } + log.Debugf("New Container : %s", container.ImageNames[0]) + dockerimages = append(dockerimages, container.ImageNames...) + for path, filecontents := range container.NewFiles { + writepath := filepath.Join(containerspath, path) + directory := filepath.Dir(writepath) + err := os.MkdirAll(directory, common.DefaultDirectoryPermission) + if err != nil { + log.Errorf("Unable to create directory %s : %s", directory, err) + continue + } + var fileperm os.FileMode + if filepath.Ext(writepath) == ".sh" { + fileperm = common.DefaultExecutablePermission + buildscripts = append(buildscripts, filepath.Join(containersdirectory, path)) + } else { + fileperm = common.DefaultFilePermission + } + log.Debugf("Writing at %s", writepath) + err = ioutil.WriteFile(writepath, []byte(filecontents), fileperm) + if err != nil { + log.Warnf("Error writing file at %s : %s", writepath, err) + } + } + } + //Write build scripts + if len(manualimages) > 0 { + writepath := filepath.Join(outpath, "Manualimages.md") + err := common.WriteTemplateToFile(templates.Manualimages_md, struct { + Scripts []string + }{ + Scripts: manualimages, + }, writepath, common.DefaultFilePermission) + if err != nil { + log.Errorf("Unable to create manual image : %s", err) + } + } + if len(buildscripts) > 0 { + buildScriptMap := make(map[string]string) + for _, value := range buildscripts { + buildScriptDir, buildScriptFile := filepath.Split(value) + buildScriptMap[buildScriptFile] = buildScriptDir + } + log.Debugf("buildscripts %s", buildscripts) + log.Debugf("buildScriptMap %s", buildScriptMap) + writepath := filepath.Join(outpath, "buildimages.sh") + err := common.WriteTemplateToFile(templates.Buildimages_sh, buildScriptMap, writepath, common.DefaultExecutablePermission) + if err != nil { + log.Errorf("Unable to create script to build images : %s", err) + } + + writepath = filepath.Join(outpath, "copysources.sh") + err = common.WriteTemplateToFile(templates.CopySources_sh, struct { + Src string + Dst string + }{ + Src: "$1", //Parameterized source folder + Dst: containersdirectory, + }, writepath, common.DefaultExecutablePermission) + if err != nil { + log.Errorf("Unable to create script to build images : %s", err) + } + } + if len(dockerimages) > 0 { + writepath := filepath.Join(outpath, "pushimages.sh") + err := common.WriteTemplateToFile(templates.Pushimages_sh, struct { + Images []string + RegistryURL string + RegistryNamespace string + }{ + Images: dockerimages, + RegistryURL: registryURL, + RegistryNamespace: registryNamespace, + }, writepath, common.DefaultExecutablePermission) + if err != nil { + log.Errorf("Unable to create script to push images : %s", err) + } + return true + } + return false +} + +func writeTransformedObjects(path string, objs []runtime.Object) ([]string, error) { + fileswritten := []string{} + err := os.MkdirAll(path, common.DefaultDirectoryPermission) + if err != nil { + log.Errorf("Unable to create directory %s : %s", path, err) + return nil, err + } + for _, obj := range objs { + //Encode object + j, err := json.Marshal(obj) + if err != nil { + log.Errorf("Error while Marshalling object : %s", err) + continue + } + var jsonObj interface{} + err = yaml.Unmarshal(j, &jsonObj) + if err != nil { + log.Errorf("Unable to unmarshal json : %s", err) + continue + } + var b bytes.Buffer + encoder := yaml.NewEncoder(&b) + encoder.SetIndent(2) + if err := encoder.Encode(jsonObj); err != nil { + log.Errorf("Error while Encoding object : %s", err) + continue + } + //Write to file + data := b.Bytes() + val := reflect.ValueOf(obj).Elem() + typeMeta := val.FieldByName("TypeMeta").Interface().(metav1.TypeMeta) + objectMeta := val.FieldByName("ObjectMeta").Interface().(metav1.ObjectMeta) + file := fmt.Sprintf("%s-%s.yaml", objectMeta.Name, strings.ToLower(typeMeta.Kind)) + file = filepath.Join(path, file) + fileswritten = append(fileswritten, file) + if err := ioutil.WriteFile(file, []byte(data), common.DefaultFilePermission); err != nil { + log.Error("Failed to write %s: %s"+strings.ToLower(typeMeta.Kind), err) + continue + } + log.Debugf("%q created", file) + } + return fileswritten, nil +} diff --git a/internal/types/ir.go b/internal/types/ir.go new file mode 100644 index 000000000..b435e2078 --- /dev/null +++ b/internal/types/ir.go @@ -0,0 +1,298 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package types + +import ( + "strings" + + log "github.com/sirupsen/logrus" + + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/runtime" + + common "github.com/konveyor/move2kube/internal/common" + collecttypes "github.com/konveyor/move2kube/types/collection" + outputtypes "github.com/konveyor/move2kube/types/output" + "github.com/konveyor/move2kube/types/plan" +) + +// IR is the intermediate representation +type IR struct { + Name string + Services map[string]Service + Storages []Storage + Containers []Container + + Kubernetes plan.KubernetesOutput + + TargetClusterSpec collecttypes.ClusterMetadataSpec + CachedObjects []runtime.Object + + Values outputtypes.HelmValues +} + +// Service defines structure of an IR service +type Service struct { + corev1.PodSpec + + Name string + Annotations map[string]string + Labels map[string]string + Replicas int + Networks []string + ExposeService bool + Daemon bool //Gets converted to DaemonSet +} + +// AddVolume adds a volume to a service +func (service *Service) AddVolume(volume corev1.Volume) { + merged := false + for _, existingVolume := range service.Volumes { + if existingVolume.Name == volume.Name { + log.Debugf("Found an existing volume. Ignoring new volume : %+v", volume) + merged = true + break + } + } + if !merged { + service.Volumes = append(service.Volumes, volume) + } +} + +// Container defines structure of a container +type Container struct { + ImageNames []string + New bool + NewFiles map[string]string //[filename][filecontents] + ExposedPorts []int + UserID int + AccessedDirs []string +} + +// NewContainer creates a new container +func NewContainer(imagename string, new bool) Container { + return Container{ + ImageNames: []string{imagename}, + New: new, + NewFiles: make(map[string]string), + ExposedPorts: []int{}, + UserID: -1, + AccessedDirs: []string{}, + } +} + +// NewContainerFromImageInfo creates a new container from image info +func NewContainerFromImageInfo(i collecttypes.ImageInfo) Container { + imagename := "" + if len(i.Spec.Tags) > 0 { + imagename = i.Spec.Tags[0] + } else { + log.Errorf("The image info %v has no tags. Leaving the tag empty for the container.", i) + } + c := NewContainer(imagename, false) + c.ImageNames = i.Spec.Tags + c.ExposedPorts = i.Spec.PortsToExpose + c.UserID = i.Spec.UserID + c.AccessedDirs = i.Spec.AccessedDirs + return c +} + +// Merge merges containers +func (c *Container) Merge(newc Container) bool { + for _, imagename := range newc.ImageNames { + if common.IsStringPresent(c.ImageNames, imagename) { + if c.New != newc.New { + log.Errorf("Both old and new image seems to share the same tag for container %s.", imagename) + } else if c.New && newc.New { + for filepath, filecontents := range newc.NewFiles { + if contents, ok := c.NewFiles[filepath]; ok { + if contents != filecontents { + log.Errorf("Two build scripts found for image : %s in %s. Ignoring new script.", imagename, filepath) + } + } else { + c.NewFiles[filepath] = filecontents + } + } + if c.UserID != newc.UserID { + log.Errorf("Two different users found for image : %d in %d. Ignoring new users.", c.UserID, newc.UserID) + } + } + c.ImageNames = common.MergeStringSlices(c.ImageNames, newc.ImageNames) + c.ExposedPorts = common.MergeIntSlices(c.ExposedPorts, newc.ExposedPorts) + c.AccessedDirs = common.MergeStringSlices(c.AccessedDirs, newc.AccessedDirs) //Needs to be clarified + if !c.New { + c.NewFiles = newc.NewFiles + c.UserID = newc.UserID //Needs to be clarified + } + return true + } + log.Debugf("Mismatching during container merge [%s, %s]", c.ImageNames, imagename) + } + return false +} + +// AddFile adds a file to a container +func (c *Container) AddFile(path string, newcontents string) { + if contents, ok := c.NewFiles[path]; ok { + if contents != newcontents { + log.Errorf("Script already exists for image at %s. Ignoring new script.", path) + } + } else { + c.NewFiles[path] = newcontents + } +} + +// AddExposedPort adds an exposed port to a container +func (c *Container) AddExposedPort(port int) { + if !common.IsIntPresent(c.ExposedPorts, port) { + c.ExposedPorts = append(c.ExposedPorts, port) + } +} + +// AddImageName adds image name to a container +func (c *Container) AddImageName(imagename string) { + if !common.IsStringPresent(c.ImageNames, imagename) { + c.ImageNames = append(c.ImageNames, imagename) + } +} + +// AddAccessedDirs adds accessed directories to container +func (c *Container) AddAccessedDirs(dirname string) { + if !common.IsStringPresent(c.AccessedDirs, dirname) { + c.AccessedDirs = append(c.AccessedDirs, dirname) + } +} + +// NewIR creates a new IR +func NewIR(p plan.Plan) IR { + var ir IR + ir.Name = p.Name + ir.Kubernetes = p.Spec.Outputs.Kubernetes + ir.Containers = make([]Container, 0) + ir.Services = make(map[string]Service) + ir.Storages = make([]Storage, 0) + ir.TargetClusterSpec = collecttypes.ClusterMetadataSpec{ + StorageClasses: []string{}, + APIKindVersionMap: make(map[string][]string), + } + ir.Values.GlobalVariables = make(map[string]string) + return ir +} + +// Merge merges IRs +func (ir *IR) Merge(newir IR) { + if ir.Name != newir.Name { + if ir.Name == "" { + ir.Name = newir.Name + } + } + ir.Kubernetes.Merge(newir.Kubernetes) + for scname, sc := range newir.Services { + if _, ok := ir.Services[scname]; ok { + log.Warnf("Two services of same service name %s. Using the new object.", scname) + } + ir.Services[scname] = sc + } + for _, newcontainer := range newir.Containers { + ir.AddContainer(newcontainer) + } + for _, newst := range newir.Storages { + ir.AddStorage(newst) + } + ir.TargetClusterSpec.Merge(newir.TargetClusterSpec) + ir.CachedObjects = append(ir.CachedObjects, newir.CachedObjects...) + ir.Values.Merge(newir.Values) +} + +// StorageKindType defines storage type kind +type StorageKindType string + +const ( + // SecretKind defines storage type of Secret + SecretKind StorageKindType = "Secret" + // ConfigMapKind defines storage type of ConfigMap + ConfigMapKind StorageKindType = "ConfigMap" + // PVCKind defines storage type of PersistentVolumeClaim + PVCKind StorageKindType = "PersistentVolumeClaim" + // PullSecretKind defines storage type of pull secret + PullSecretKind StorageKindType = "PullSecret" +) + +// Storage defines structure of a storage +type Storage struct { + Name string + corev1.PersistentVolumeClaimSpec //This promotion contains the volumeName which is used by configmap, secrets and pvc. + StorageType StorageKindType //Type of storage cfgmap, secret, pvc + Content map[string][]byte //Optional field meant to store content for cfgmap or secret +} + +// Merge merges storage +func (s *Storage) Merge(newst Storage) bool { + if strings.Compare(s.Name, newst.Name) == 0 { + if s.Content != nil && newst.Content != nil { + s.Content = newst.Content + } + s.StorageType = newst.StorageType + s.PersistentVolumeClaimSpec = newst.PersistentVolumeClaimSpec + return true + } + log.Debugf("Mismatching storages [%s, %s]", s.Name, newst.Name) + return false +} + +// AddContainer adds a conatainer to IR +func (ir *IR) AddContainer(container Container) { + merged := false + for i := range ir.Containers { + if ir.Containers[i].Merge(container) { + merged = true + break + } + } + if !merged { + ir.Containers = append(ir.Containers, container) + } +} + +// AddStorage adds a storage to IR +func (ir *IR) AddStorage(st Storage) { + merged := false + for i := range ir.Storages { + if ir.Storages[i].Merge(st) { + merged = true + break + } + } + if !merged { + ir.Storages = append(ir.Storages, st) + } +} + +// GetContainer returns container which has the imagename +func (ir *IR) GetContainer(imagename string) (con Container, exists bool) { + for _, c := range ir.Containers { + if common.IsStringPresent(c.ImageNames, imagename) { + return c, true + } else if c.New { + parts := strings.Split(imagename, "/") + if len(parts) > 2 && parts[0] == ir.Kubernetes.RegistryURL && common.IsStringPresent(c.ImageNames, parts[len(parts)-1]) { + return c, true + } + } + } + return Container{}, false +} diff --git a/internal/types/ir_test.go b/internal/types/ir_test.go new file mode 100644 index 000000000..24a3b3cfb --- /dev/null +++ b/internal/types/ir_test.go @@ -0,0 +1,777 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package types_test + +import ( + "reflect" + "testing" + + log "github.com/sirupsen/logrus" + + "github.com/konveyor/move2kube/internal/types" + collecttypes "github.com/konveyor/move2kube/types/collection" + plantypes "github.com/konveyor/move2kube/types/plan" + corev1 "k8s.io/api/core/v1" +) + +func TestAddVolume(t *testing.T) { + log.SetLevel(log.DebugLevel) + + t.Run("add a volume to an empty service", func(t *testing.T) { + // Setup + name1 := "name1" + v := corev1.Volume{Name: name1} + s := types.Service{} + want := types.Service{} + want.Volumes = []corev1.Volume{v} + + // Test + s.AddVolume(v) + if !reflect.DeepEqual(s, want) { + t.Fatal("Failed to add volume to an empty service properly. Expected:", want, "Actual:", s) + } + }) + + t.Run("add a new volume with same name to a filled service", func(t *testing.T) { + // Setup + name1 := "name1" + v := corev1.Volume{Name: name1} + s := types.Service{} + s.Volumes = []corev1.Volume{v} + want := types.Service{} + want.Volumes = []corev1.Volume{v} + + // Test + s.AddVolume(v) + if !reflect.DeepEqual(s, want) { + t.Fatal("Failed to add a volume with the same name to a filled service properly. Expected:", want, "Actual:", s) + } + }) +} + +func TestNewContainer(t *testing.T) { + log.SetLevel(log.DebugLevel) + + name1 := "name1" + new1 := true + c := types.NewContainer(name1, new1) + if len(c.ImageNames) != 1 || c.ImageNames[0] != name1 { + t.Fatal("Failed to initialize the container properly. Expected image names to be: [", name1, "] Actual:", c.ImageNames) + } + if c.New != new1 { + t.Fatal("Failed to initialize the container properly. Expected New to be:", new1, "Actual:", c.New) + } + if c.NewFiles == nil { + t.Fatal("Failed to initialize the container properly. The map NewFiles is not initialized. Actual:", c.NewFiles) + } +} + +func TestNewContainerFromImageInfo(t *testing.T) { + log.SetLevel(log.DebugLevel) + + t.Run("get container from image with tags", func(t *testing.T) { + imginfo1 := collecttypes.NewImageInfo() + imginfo1.Spec.Tags = []string{"tag1"} + c := types.NewContainerFromImageInfo(imginfo1) + if !reflect.DeepEqual(c.ImageNames, imginfo1.Spec.Tags) { + t.Fatal("Failed to initialze the image names from the tags properly. Expected image names:", imginfo1.Spec.Tags, "Actual:", c.ImageNames) + } + if !reflect.DeepEqual(c.ExposedPorts, imginfo1.Spec.PortsToExpose) { + t.Fatal("Failed to initialze the ports from the image info properly. Expected ports:", imginfo1.Spec.PortsToExpose, "Actual:", c.ExposedPorts) + } + if c.UserID != imginfo1.Spec.UserID { + t.Fatal("The user ids are not the same. Expected:", imginfo1.Spec.UserID, "Actual:", c.UserID) + } + if !reflect.DeepEqual(c.AccessedDirs, imginfo1.Spec.AccessedDirs) { + t.Fatal("Failed to initialze the directories from the image info properly. Expected ports:", imginfo1.Spec.AccessedDirs, "Actual:", c.AccessedDirs) + } + }) + + t.Run("get container from image without tags", func(t *testing.T) { + imginfo1 := collecttypes.NewImageInfo() + c := types.NewContainerFromImageInfo(imginfo1) + if !reflect.DeepEqual(c.ImageNames, imginfo1.Spec.Tags) { + t.Fatal("Failed to initialze the image names from the tags properly. Expected image names:", imginfo1.Spec.Tags, "Actual:", c.ImageNames) + } + if !reflect.DeepEqual(c.ExposedPorts, imginfo1.Spec.PortsToExpose) { + t.Fatal("Failed to initialze the ports from the image info properly. Expected ports:", imginfo1.Spec.PortsToExpose, "Actual:", c.ExposedPorts) + } + if c.UserID != imginfo1.Spec.UserID { + t.Fatal("The user ids are not the same. Expected:", imginfo1.Spec.UserID, "Actual:", c.UserID) + } + if !reflect.DeepEqual(c.AccessedDirs, imginfo1.Spec.AccessedDirs) { + t.Fatal("Failed to initialze the directories from the image info properly. Expected ports:", imginfo1.Spec.AccessedDirs, "Actual:", c.AccessedDirs) + } + }) +} + +func TestContainerMerge(t *testing.T) { + log.SetLevel(log.DebugLevel) + + t.Run("merge 2 empty containers", func(t *testing.T) { + // Setup + name1 := "name1" + new1 := true + c1 := types.NewContainer(name1, new1) + name2 := "name2" + new2 := true + c2 := types.NewContainer(name2, new2) + want := types.NewContainer(name1, new1) + + // Test + if c1.Merge(c2) || !reflect.DeepEqual(c1, want) { // TODO: If neither container has image name should it return true? + t.Fatal("Failed to merge 2 empty containers properly. Expected:", want, "Actual:", c1) + } + }) + + t.Run("merge containers that share no image names", func(t *testing.T) { + // Setup + name1 := "name1" + new1 := true + c1 := types.NewContainer(name1, new1) + c1.ImageNames = []string{"imgname1", "imgname2", "imgname3"} + name2 := "name2" + new2 := true + c2 := types.NewContainer(name2, new2) + c2.ImageNames = []string{"imgname4", "imgname5", "imgname6"} + want := types.NewContainer(name1, new1) + want.ImageNames = []string{"imgname1", "imgname2", "imgname3"} + + // Test + if c1.Merge(c2) || !reflect.DeepEqual(c1, want) { + t.Fatal("Should not merge 2 containers having no image names in common. Expected:", want, "Actual:", c1) + } + }) + + t.Run("merge containers that share some image names", func(t *testing.T) { + // Setup + name1 := "name1" + new1 := true + c1 := types.NewContainer(name1, new1) + c1.ImageNames = []string{"imgname1", "imgname2", "imgname3"} + name2 := "name2" + new2 := false + c2 := types.NewContainer(name2, new2) + c2.ImageNames = []string{"imgname3", "imgname4", "imgname5"} + want := types.NewContainer(name1, new1) + want.ImageNames = []string{"imgname1", "imgname2", "imgname3", "imgname4", "imgname5"} + + // Test + if !c1.Merge(c2) || !reflect.DeepEqual(c1, want) { + t.Fatal("Failed to merge 2 containers having common image names properly. Expected:", want, "Actual:", c1) + } + }) + + t.Run("merge 2 new containers that share some image names and have the same build scripts", func(t *testing.T) { + // Setup + name1 := "name1" + new1 := true + path1 := "path1" + contents1 := "contents1" + c1 := types.NewContainer(name1, new1) + c1.ImageNames = []string{"imgname1", "imgname2", "imgname3"} + c1.NewFiles[path1] = contents1 + name2 := "name2" + new2 := true + c2 := types.NewContainer(name2, new2) + c2.ImageNames = []string{"imgname3", "imgname4", "imgname5"} + c2.NewFiles[path1] = contents1 + want := types.NewContainer(name1, new1) + want.ImageNames = []string{"imgname1", "imgname2", "imgname3", "imgname4", "imgname5"} + want.NewFiles[path1] = contents1 + + // Test + if !c1.Merge(c2) || !reflect.DeepEqual(c1, want) { + t.Fatal("Failed to merge the 2 containers properly. Expected:", want, "Actual:", c1) + } + }) + + t.Run("merge 2 new containers that share some image names and having different build scripts", func(t *testing.T) { + // Setup + name1 := "name1" + new1 := true + path1 := "path1" + path2 := "path2" + contents1 := "contents1" + contents2 := "contents2" + c1 := types.NewContainer(name1, new1) + c1.ImageNames = []string{"imgname1", "imgname2", "imgname3"} + c1.NewFiles[path1] = contents1 + name2 := "name2" + new2 := true + c2 := types.NewContainer(name2, new2) + c2.ImageNames = []string{"imgname3", "imgname4", "imgname5"} + c2.NewFiles[path2] = contents2 + want := types.NewContainer(name1, new1) + want.ImageNames = []string{"imgname1", "imgname2", "imgname3", "imgname4", "imgname5"} + want.NewFiles[path1] = contents1 + want.NewFiles[path2] = contents2 + + // Test + if !c1.Merge(c2) || !reflect.DeepEqual(c1, want) { + t.Fatal("Failed to merge the 2 containers properly. Expected:", want, "Actual:", c1) + } + }) + + t.Run("merge 2 new containers that share some image names and having different build scripts for the same key", func(t *testing.T) { + // Setup + name1 := "name1" + new1 := true + path1 := "path1" + contents1 := "contents1" + contents2 := "contents2" + c1 := types.NewContainer(name1, new1) + c1.ImageNames = []string{"imgname1", "imgname2", "imgname3"} + c1.NewFiles[path1] = contents1 + name2 := "name2" + new2 := true + c2 := types.NewContainer(name2, new2) + c2.ImageNames = []string{"imgname3", "imgname4", "imgname5"} + c2.NewFiles[path1] = contents2 + want := types.NewContainer(name1, new1) + want.ImageNames = []string{"imgname1", "imgname2", "imgname3", "imgname4", "imgname5"} + want.NewFiles[path1] = contents1 + + // Test + if !c1.Merge(c2) || !reflect.DeepEqual(c1, want) { + t.Fatal("Failed to merge the 2 containers properly. Expected:", want, "Actual:", c1) + } + }) + + t.Run("merge 2 new containers that share some image names but have different user ids", func(t *testing.T) { + // Setup + name1 := "name1" + new1 := true + c1 := types.NewContainer(name1, new1) + c1.ImageNames = []string{"imgname1", "imgname2", "imgname3"} + c1.UserID = 1 + name2 := "name2" + new2 := true + c2 := types.NewContainer(name2, new2) + c2.ImageNames = []string{"imgname3", "imgname4", "imgname5"} + c2.UserID = 2 + want := types.NewContainer(name1, new1) + want.ImageNames = []string{"imgname1", "imgname2", "imgname3", "imgname4", "imgname5"} + want.UserID = 1 + + // Test + if !c1.Merge(c2) || !reflect.DeepEqual(c1, want) { + t.Fatal("Failed to merge the 2 containers properly. Expected:", want, "Actual:", c1) + } + }) + + t.Run("merge a new container into an old container that share some image names but have different user ids and build scripts", func(t *testing.T) { + // Setup + path1 := "path1" + path2 := "path2" + contents1 := "contents1" + contents2 := "contents2" + + name1 := "name1" + new1 := false + c1 := types.NewContainer(name1, new1) + c1.ImageNames = []string{"imgname1", "imgname2", "imgname3"} + c1.UserID = 1 + c1.NewFiles[path1] = contents1 + + name2 := "name2" + new2 := true + c2 := types.NewContainer(name2, new2) + c2.ImageNames = []string{"imgname3", "imgname4", "imgname5"} + c2.UserID = 2 + c2.NewFiles[path2] = contents2 + + want := types.NewContainer(name1, new1) + want.ImageNames = []string{"imgname1", "imgname2", "imgname3", "imgname4", "imgname5"} + want.UserID = 2 + want.NewFiles[path2] = contents2 + + // Test + if !c1.Merge(c2) || !reflect.DeepEqual(c1, want) { + t.Fatal("Failed to merge the 2 containers properly. Expected:", want, "Actual:", c1) + } + }) +} + +func TestAddFile(t *testing.T) { + log.SetLevel(log.DebugLevel) + + t.Run("add a new script to an empty container", func(t *testing.T) { + // Setup + name1 := "name1" + new1 := true + path1 := "path1/foo/bar" + contents1 := "contents1" + c := types.NewContainer(name1, new1) + want := types.NewContainer(name1, new1) + want.NewFiles[path1] = contents1 + + // Test + c.AddFile(path1, contents1) + if !reflect.DeepEqual(c, want) { + t.Fatal("Failed to add the new script to the empty container properly. Expected:", want, "Actual:", c) + } + }) + + t.Run("add the same script at the same path to a filled container", func(t *testing.T) { + // Setup + name1 := "name1" + new1 := true + path1 := "path1/foo/bar" + contents1 := "contents1" + c := types.NewContainer(name1, new1) + c.NewFiles[path1] = contents1 + want := types.NewContainer(name1, new1) + want.NewFiles[path1] = contents1 + + // Test + c.AddFile(path1, contents1) + if !reflect.DeepEqual(c, want) { + t.Fatal("Adding the same script to the same path should not change the container. Expected:", want, "Actual:", c) + } + }) + + t.Run("add a different script at the same path to a filled container", func(t *testing.T) { + // Setup + name1 := "name1" + new1 := true + path1 := "path1/foo/bar" + contents1 := "contents1" + contents2 := "contents2" + c := types.NewContainer(name1, new1) + c.NewFiles[path1] = contents1 + want := types.NewContainer(name1, new1) + want.NewFiles[path1] = contents1 + + // Test + c.AddFile(path1, contents2) + if !reflect.DeepEqual(c, want) { + t.Fatal("Adding a different script to the same path should not change the container. Expected:", want, "Actual:", c) + } + }) +} + +func TestAddExposedPort(t *testing.T) { + log.SetLevel(log.DebugLevel) + + t.Run("add a new port to expose to an empty container", func(t *testing.T) { + // Setup + name1 := "name1" + new1 := true + port1 := 8080 + c := types.NewContainer(name1, new1) + want := types.NewContainer(name1, new1) + want.ExposedPorts = append(want.ExposedPorts, port1) + + // Test + c.AddExposedPort(port1) + if !reflect.DeepEqual(c, want) { + t.Fatal("Failed to add the new port to the list of exposed ports properly. Expected:", want, "Actual:", c) + } + }) + + t.Run("add an already exposed port to a filled container", func(t *testing.T) { + // Setup + name1 := "name1" + new1 := true + port1 := 8080 + c := types.NewContainer(name1, new1) + c.ExposedPorts = append(c.ExposedPorts, port1) + want := types.NewContainer(name1, new1) + want.ExposedPorts = append(want.ExposedPorts, port1) + + // Test + c.AddExposedPort(port1) + if !reflect.DeepEqual(c, want) { + t.Fatal("Adding an already exposed port should not change the container. Expected:", want, "Actual:", c) + } + }) +} + +func TestAddImageName(t *testing.T) { + log.SetLevel(log.DebugLevel) + + t.Run("add a new image name to an empty container", func(t *testing.T) { + // Setup + name1 := "name1" + new1 := true + img1 := "img1" + c := types.NewContainer(name1, new1) + want := types.NewContainer(name1, new1) + want.ImageNames = append(want.ImageNames, img1) + + // Test + c.AddImageName(img1) + if !reflect.DeepEqual(c, want) { + t.Fatal("Failed to add an image name to an empty container properly. Expected:", want, "Actual:", c) + } + }) + + t.Run("add an existing image name to a filled container", func(t *testing.T) { + // Setup + name1 := "name1" + new1 := true + img1 := "img1" + c := types.NewContainer(name1, new1) + c.ImageNames = append(c.ImageNames, img1) + want := types.NewContainer(name1, new1) + want.ImageNames = append(want.ImageNames, img1) + + // Test + c.AddImageName(img1) + if !reflect.DeepEqual(c, want) { + t.Fatal("Adding an existing image name should not change the container. Expected:", want, "Actual:", c) + } + }) +} + +func TestAddAccessedDirs(t *testing.T) { + log.SetLevel(log.DebugLevel) + + t.Run("add a new directory to an empty container", func(t *testing.T) { + // Setup + name1 := "name1" + new1 := true + dir1 := "dir1" + c := types.NewContainer(name1, new1) + want := types.NewContainer(name1, new1) + want.AccessedDirs = append(want.AccessedDirs, dir1) + + // Test + c.AddAccessedDirs(dir1) + if !reflect.DeepEqual(c, want) { + t.Fatal("Failed to add a new directory to an empty container properly. Expected:", want, "Actual:", c) + } + }) + + t.Run("add an existing directory to a filled container", func(t *testing.T) { + // Setup + name1 := "name1" + new1 := true + dir1 := "dir1" + c := types.NewContainer(name1, new1) + c.AccessedDirs = append(c.AccessedDirs, dir1) + want := types.NewContainer(name1, new1) + want.AccessedDirs = append(want.AccessedDirs, dir1) + + // Test + c.AddAccessedDirs(dir1) + if !reflect.DeepEqual(c, want) { + t.Fatal("Adding an existing directory should not change the container. Expected:", want, "Actual:", c) + } + }) +} + +func TestNewIR(t *testing.T) { + log.SetLevel(log.DebugLevel) + + p := plantypes.NewPlan() + ir := types.NewIR(p) + if ir.Containers == nil || + ir.Services == nil || + ir.Storages == nil || + ir.Values.GlobalVariables == nil { + t.Fatal("Failed to initialize the maps inside IR properly. The IR returned by NewIR:", ir) + } +} + +func TestIRMerge(t *testing.T) { + log.SetLevel(log.DebugLevel) + + t.Run("merge 2 empty irs", func(t *testing.T) { + // Setup + p1 := plantypes.NewPlan() + ir1 := types.NewIR(p1) + p2 := plantypes.NewPlan() + ir2 := types.NewIR(p2) + p3 := plantypes.NewPlan() + want := types.NewIR(p3) + // Test + ir1.Merge(ir2) + if !reflect.DeepEqual(ir1, want) { + t.Fatal("Failed to merge the 2 irs properly. Expected:", want, "Actual:", ir1) + } + }) + + t.Run("merge 2 irs with different names", func(t *testing.T) { + // Setup + name1 := "name1" + name2 := "name2" + p1 := plantypes.NewPlan() + ir1 := types.NewIR(p1) + ir1.Name = name1 + p2 := plantypes.NewPlan() + ir2 := types.NewIR(p2) + ir2.Name = name2 + p3 := plantypes.NewPlan() + want := types.NewIR(p3) + want.Name = name1 + // Test + ir1.Merge(ir2) + if !reflect.DeepEqual(ir1, want) { + t.Fatal("Failed to merge the 2 irs properly. Expected:", want, "Actual:", ir1) + } + }) + + t.Run("merge an ir with a name into an ir with an empty name", func(t *testing.T) { + // Setup + name1 := "name1" + p1 := plantypes.NewPlan() + ir1 := types.NewIR(p1) + ir1.Name = "" + + p2 := plantypes.NewPlan() + ir2 := types.NewIR(p2) + ir2.Name = name1 + + p3 := plantypes.NewPlan() + want := types.NewIR(p3) + want.Name = name1 + + // Test + ir1.Merge(ir2) + if !reflect.DeepEqual(ir1, want) { + t.Fatal("Failed to merge the 2 irs properly. Expected:", want, "Actual:", ir1) + } + }) + + t.Run("merge 2 filled irs", func(t *testing.T) { + // Setup + contname1 := "contname1" + new1 := true + c1 := types.NewContainer(contname1, new1) + c1.ImageNames = []string{"imgname1", "imgname2", "imgname3"} + + s1 := types.Storage{Name: "storage1"} + + svcname1 := "svcname1" + svc1 := types.Service{Name: svcname1, Replicas: 2} + svc2 := types.Service{Name: svcname1, Replicas: 4} + + p1 := plantypes.NewPlan() + ir1 := types.NewIR(p1) + ir1.Services[svcname1] = svc1 + + p2 := plantypes.NewPlan() + ir2 := types.NewIR(p2) + ir2.Services[svcname1] = svc2 + ir2.Containers = append(ir2.Containers, c1) + ir2.Storages = append(ir2.Storages, s1) + + p3 := plantypes.NewPlan() + want := types.NewIR(p3) + want.Services[svcname1] = svc2 + want.Containers = append(want.Containers, c1) + want.Storages = append(want.Storages, s1) + + // Test + ir1.Merge(ir2) + if !reflect.DeepEqual(ir1, want) { + t.Fatal("Failed to merge the 2 irs properly. Expected:", want, "Actual:", ir1) + } + }) +} + +func TestStorageMerge(t *testing.T) { + log.SetLevel(log.DebugLevel) + + t.Run("merge empty storage into empty storage", func(t *testing.T) { + s1 := types.Storage{} + s2 := types.Storage{} + want := types.Storage{} + if !s1.Merge(s2) || !reflect.DeepEqual(s1, want) { + t.Fatal("Failed to merge 2 empty storages properly. Expected:", want, "Actual:", s1) + } + }) + + t.Run("merge storages with different names", func(t *testing.T) { + s1 := types.Storage{} + s1.Name = "name1" + s2 := types.Storage{} + s2.Name = "name2" + want := types.Storage{} + want.Name = "name1" + if s1.Merge(s2) || !reflect.DeepEqual(s1, want) { + t.Fatal("Should not merge 2 storages with different names. Merge should return false. Expected:", want, "Actual:", s1) + } + }) + + t.Run("merge filled storage into filled storage", func(t *testing.T) { + // Setup + s1 := types.Storage{} + s1.Content = map[string][]byte{"key1": []byte("val1")} + s2 := types.Storage{} + s2.Content = map[string][]byte{"key2": []byte("val2")} + want := types.Storage{} + want.Content = map[string][]byte{"key2": []byte("val2")} + // Test + if !s1.Merge(s2) || !reflect.DeepEqual(s1, want) { + t.Fatal("Failed to merge 2 filled storages properly. Expected:", want, "Actual:", s1) + } + }) +} + +func TestAddContainer(t *testing.T) { + log.SetLevel(log.DebugLevel) + + t.Run("add a new container to an empty IR", func(t *testing.T) { + // Setup + name1 := "name1" + new1 := true + c := types.NewContainer(name1, new1) + p1 := plantypes.NewPlan() + ir := types.NewIR(p1) + p2 := plantypes.NewPlan() + want := types.NewIR(p2) + want.Containers = append(want.Containers, c) + // Test + ir.AddContainer(c) + if !reflect.DeepEqual(ir, want) { + t.Fatal("Failed to add the container properly. Expected:", want, "Actual:", ir) + } + }) + + t.Run("add an existing container to a filled IR", func(t *testing.T) { + // Setup + name1 := "name1" + new1 := true + c1 := types.NewContainer(name1, new1) + p1 := plantypes.NewPlan() + ir := types.NewIR(p1) + ir.Containers = append(ir.Containers, c1) + + p2 := plantypes.NewPlan() + want := types.NewIR(p2) + c2 := types.NewContainer(name1, new1) + want.Containers = append(want.Containers, c2) + + // Test + ir.AddContainer(c1) + if !reflect.DeepEqual(ir, want) { + t.Fatal("Failed to add the container properly. Expected:", want, "Actual:", ir) + } + }) +} + +func TestAddStorage(t *testing.T) { + log.SetLevel(log.DebugLevel) + + t.Run("add a new storage to an empty IR", func(t *testing.T) { + // Setup + s := types.Storage{} + + p1 := plantypes.NewPlan() + ir := types.NewIR(p1) + + p2 := plantypes.NewPlan() + want := types.NewIR(p2) + want.Storages = append(want.Storages, s) + + // Test + ir.AddStorage(s) + if !reflect.DeepEqual(ir, want) { + t.Fatal("Failed to add the storage properly. Expected:", want, "Actual:", ir) + } + }) + + t.Run("add a existing storage to an filled IR", func(t *testing.T) { + // Setup + s := types.Storage{} + + p1 := plantypes.NewPlan() + ir := types.NewIR(p1) + ir.Storages = append(ir.Storages, s) + + p2 := plantypes.NewPlan() + want := types.NewIR(p2) + want.Storages = append(want.Storages, s) + + // Test + ir.AddStorage(s) + if !reflect.DeepEqual(ir, want) { + t.Fatal("Failed to add the storage properly. Expected:", want, "Actual:", ir) + } + }) +} + +func TestGetContainer(t *testing.T) { + log.SetLevel(log.DebugLevel) + + t.Run("get container for non existent image name from empty ir", func(t *testing.T) { + imgname1 := "imgname1" + p1 := plantypes.NewPlan() + ir := types.NewIR(p1) + if _, ok := ir.GetContainer(imgname1); ok { + t.Fatal("Should not have found the image name", imgname1, "in an empty ir.") + } + }) + + t.Run("get container for non existent image name from filled ir", func(t *testing.T) { + // Setup + name1 := "contname1" + new1 := true + c1 := types.NewContainer(name1, new1) + imgname1 := "imgname1" + p1 := plantypes.NewPlan() + ir := types.NewIR(p1) + ir.Containers = append(ir.Containers, c1) + + // Test + if _, ok := ir.GetContainer(imgname1); ok { + t.Fatal("Should not have found the non existent image name", imgname1, "in the ir.") + } + }) + + t.Run("get container for image name from filled ir", func(t *testing.T) { + // Setup + name1 := "contname1" + new1 := true + imgname1 := "imgname1" + + c1 := types.NewContainer(name1, new1) + c1.ImageNames = append(c1.ImageNames, imgname1) + p1 := plantypes.NewPlan() + ir := types.NewIR(p1) + ir.Containers = append(ir.Containers, c1) + + // Test + if _, ok := ir.GetContainer(imgname1); !ok { + t.Fatal("Failed to get the container for the image name", imgname1, "in the ir.") + } + }) + + t.Run("get container for image url from filled ir", func(t *testing.T) { + // Setup + name1 := "contname1" + new1 := true + registry1 := "registry1.com" + imgname1 := "imgname1" + imgurl1 := registry1 + "/namespace/" + imgname1 + + c1 := types.NewContainer(name1, new1) + c1.ImageNames = append(c1.ImageNames, imgname1) + p1 := plantypes.NewPlan() + ir := types.NewIR(p1) + ir.Containers = append(ir.Containers, c1) + ir.Kubernetes.RegistryURL = registry1 + + // Test + if _, ok := ir.GetContainer(imgurl1); !ok { + t.Fatal("Failed to get the container for the image url", imgurl1, "in the ir.") + } + }) +} diff --git a/misc/centos.repo b/misc/centos.repo new file mode 100644 index 000000000..8ab4f172e --- /dev/null +++ b/misc/centos.repo @@ -0,0 +1,13 @@ +[centos-8-baseos] +name = CentOS 8 (RPMs) - BaseOS +baseurl = http://mirror.centos.org/centos-8/8/BaseOS/x86_64/os/ +enabled = 1 +gpgkey = https://www.centos.org/keys/RPM-GPG-KEY-CentOS-Official +gpgcheck = 1 + +[centos-8-AppStream] +name = CentOS 8 (RPMs) - AppStream +baseurl = http://mirror.centos.org/centos-8/8/AppStream/x86_64/os/ +enabled = 1 +gpgkey = https://www.centos.org/keys/RPM-GPG-KEY-CentOS-Official +gpgcheck = 1 \ No newline at end of file diff --git a/samples/.m2kignore b/samples/.m2kignore new file mode 100644 index 000000000..9c558e357 --- /dev/null +++ b/samples/.m2kignore @@ -0,0 +1 @@ +. diff --git a/samples/docker-compose/api/Dockerfile b/samples/docker-compose/api/Dockerfile new file mode 100644 index 000000000..b585c7d64 --- /dev/null +++ b/samples/docker-compose/api/Dockerfile @@ -0,0 +1,6 @@ +FROM node:14 +WORKDIR /app +COPY . . +RUN npm install +EXPOSE 1234 +CMD ["npm", "run", "start"] diff --git a/samples/docker-compose/api/index.js b/samples/docker-compose/api/index.js new file mode 100644 index 000000000..2553a75a3 --- /dev/null +++ b/samples/docker-compose/api/index.js @@ -0,0 +1,51 @@ +import url from 'url'; +import http from 'http'; +import redis from "redis" + +const api_endpoint = '/fib'; +const usage_instructions = `usage: ${api_endpoint}?n=\n`; +const client = 'REDIS_URL' in process.env ? redis.createClient(process.env.REDIS_URL) : redis.createClient(); +client.on("error", err => console.error(err)); + +function requestHandler(req, res) { + const urlobj = url.parse(req.url, true); + + if (urlobj.pathname !== api_endpoint || !('n' in urlobj.query)) { + res.writeHead(400, { "Content-Type": "application/json" }); + return res.end(JSON.stringify({error:"invalid url",usage_instructions})); + } + + const n = parseInt(urlobj.query.n, 10); + if (isNaN(n)) { + res.writeHead(400, { "Content-Type": "application/json" }); + return res.end(JSON.stringify({error:"n is not a valid number"})); + } + + client.get(n, (err, ans) => { + if (err || ans === null) { + console.log(`CACHE MISS on n = ${n}`); + ans = fibonacci(n); + client.set(n, ans, err => { + if (err === null) console.log("cached", n); + else console.error("failed to cache the answer for n. error:", err) + }); + } else { + console.log(`CACHE HIT for n = ${n} ans is ${ans}`); + } + res.writeHead(200, { "Content-Type": "application/json" }); + res.end(JSON.stringify({ans})); + }); +} + +function fibonacci(n) { + let a = 0, b = 1, c = 1; + for(let i = 0; i < n; i++) { + c = a + b; + a = b; + b = c; + } + return a; +} + +// Main +http.createServer(requestHandler).listen(1234); diff --git a/samples/docker-compose/api/package-lock.json b/samples/docker-compose/api/package-lock.json new file mode 100644 index 000000000..d60e9b5a0 --- /dev/null +++ b/samples/docker-compose/api/package-lock.json @@ -0,0 +1,42 @@ +{ + "name": "api", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "denque": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/denque/-/denque-1.4.1.tgz", + "integrity": "sha512-OfzPuSZKGcgr96rf1oODnfjqBFmr1DVoc/TrItj3Ohe0Ah1C5WX5Baquw/9U9KovnQ88EqmJbD66rKYUQYN1tQ==" + }, + "redis": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/redis/-/redis-3.0.2.tgz", + "integrity": "sha512-PNhLCrjU6vKVuMOyFu7oSP296mwBkcE6lrAjruBYG5LgdSqtRBoVQIylrMyVZD/lkF24RSNNatzvYag6HRBHjQ==", + "requires": { + "denque": "^1.4.1", + "redis-commands": "^1.5.0", + "redis-errors": "^1.2.0", + "redis-parser": "^3.0.0" + } + }, + "redis-commands": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/redis-commands/-/redis-commands-1.6.0.tgz", + "integrity": "sha512-2jnZ0IkjZxvguITjFTrGiLyzQZcTvaw8DAaCXxZq/dsHXz7KfMQ3OUJy7Tz9vnRtZRVz6VRCPDvruvU8Ts44wQ==" + }, + "redis-errors": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz", + "integrity": "sha1-62LSrbFeTq9GEMBK/hUpOEJQq60=" + }, + "redis-parser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz", + "integrity": "sha1-tm2CjNyv5rS4pCin3vTGvKwxyLQ=", + "requires": { + "redis-errors": "^1.0.0" + } + } + } +} diff --git a/samples/docker-compose/api/package.json b/samples/docker-compose/api/package.json new file mode 100644 index 000000000..24f38483a --- /dev/null +++ b/samples/docker-compose/api/package.json @@ -0,0 +1,13 @@ +{ + "type": "module", + "name": "api", + "version": "0.1.0", + "description": "API that calculate the nth fibonacci number", + "main": "index.js", + "scripts": { + "start": "node index.js" + }, + "dependencies": { + "redis": "^3.0.2" + } +} diff --git a/samples/docker-compose/docker-compose.yaml b/samples/docker-compose/docker-compose.yaml new file mode 100644 index 000000000..f000bbced --- /dev/null +++ b/samples/docker-compose/docker-compose.yaml @@ -0,0 +1,19 @@ +version: '3' + +services: + api: + image: fibonacci-api:latest + build: ./api + ports: + - "1234:1234" + environment: + - REDIS_URL=redis://redis:6379 + redis: + image: redis + web: + image: fibonacci-web:latest + build: ./web + ports: + - "8080:80" + environment: + - API_URL=http://api:1234/fib diff --git a/samples/docker-compose/web/Dockerfile b/samples/docker-compose/web/Dockerfile new file mode 100644 index 000000000..6bfa46945 --- /dev/null +++ b/samples/docker-compose/web/Dockerfile @@ -0,0 +1,2 @@ +FROM php:7-apache +COPY . /var/www/html/ diff --git a/samples/docker-compose/web/fib.php b/samples/docker-compose/web/fib.php new file mode 100644 index 000000000..6149b6f92 --- /dev/null +++ b/samples/docker-compose/web/fib.php @@ -0,0 +1,31 @@ + + + + + + Fibonacci + + +

Answer

+

ans; + } else { + echo "Something went wrong. Please try again."; + echo "Error:" . $reply->error; + } + } else { + echo "You entered an invalid integer."; + } + ?>

+
Go back + + diff --git a/samples/docker-compose/web/index.php b/samples/docker-compose/web/index.php new file mode 100644 index 000000000..59d00524b --- /dev/null +++ b/samples/docker-compose/web/index.php @@ -0,0 +1,15 @@ + + + + + + Fibonacci + + +
+ + +
+

Enter an integer N to calculate the Nth fibonacci number.

+ + \ No newline at end of file diff --git a/samples/dockerfile/Dockerfile b/samples/dockerfile/Dockerfile new file mode 100644 index 000000000..fefaa47e1 --- /dev/null +++ b/samples/dockerfile/Dockerfile @@ -0,0 +1,6 @@ +FROM node:14 +WORKDIR /app +COPY . . +RUN npm install +EXPOSE 8080 +CMD ["npm", "run", "start"] diff --git a/samples/dockerfile/index.js b/samples/dockerfile/index.js new file mode 100644 index 000000000..93291d42a --- /dev/null +++ b/samples/dockerfile/index.js @@ -0,0 +1,7 @@ +import express from 'express' + +const port = 8080; + +const server = express(); +server.use(express.static("public")) +server.listen(port, () => console.log("Listening on port", port)); diff --git a/samples/dockerfile/package-lock.json b/samples/dockerfile/package-lock.json new file mode 100644 index 000000000..a3beb2cdd --- /dev/null +++ b/samples/dockerfile/package-lock.json @@ -0,0 +1,374 @@ +{ + "name": "dockerfile", + "version": "0.1.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "accepts": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", + "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "requires": { + "mime-types": "~2.1.24", + "negotiator": "0.6.2" + } + }, + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + }, + "body-parser": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", + "requires": { + "bytes": "3.1.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "on-finished": "~2.3.0", + "qs": "6.7.0", + "raw-body": "2.4.0", + "type-is": "~1.6.17" + } + }, + "bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" + }, + "content-disposition": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", + "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", + "requires": { + "safe-buffer": "5.1.2" + } + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" + }, + "cookie": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", + "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==" + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" + }, + "express": { + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", + "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", + "requires": { + "accepts": "~1.3.7", + "array-flatten": "1.1.1", + "body-parser": "1.19.0", + "content-disposition": "0.5.3", + "content-type": "~1.0.4", + "cookie": "0.4.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.1.2", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.5", + "qs": "6.7.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.1.2", + "send": "0.17.1", + "serve-static": "1.14.1", + "setprototypeof": "1.1.1", + "statuses": "~1.5.0", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + } + }, + "finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + } + }, + "forwarded": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" + }, + "http-errors": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", + "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + } + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" + }, + "mime-db": { + "version": "1.44.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz", + "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==" + }, + "mime-types": { + "version": "2.1.27", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz", + "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==", + "requires": { + "mime-db": "1.44.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "negotiator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "requires": { + "ee-first": "1.1.1" + } + }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + }, + "proxy-addr": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz", + "integrity": "sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==", + "requires": { + "forwarded": "~0.1.2", + "ipaddr.js": "1.9.1" + } + }, + "qs": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" + }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" + }, + "raw-body": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", + "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", + "requires": { + "bytes": "3.1.0", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "send": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", + "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", + "requires": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.7.2", + "mime": "1.6.0", + "ms": "2.1.1", + "on-finished": "~2.3.0", + "range-parser": "~1.2.1", + "statuses": "~1.5.0" + }, + "dependencies": { + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + } + } + }, + "serve-static": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", + "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.17.1" + } + }, + "setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" + }, + "toidentifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" + }, + "type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + } + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" + } + } +} diff --git a/samples/dockerfile/package.json b/samples/dockerfile/package.json new file mode 100644 index 000000000..b2a6c5692 --- /dev/null +++ b/samples/dockerfile/package.json @@ -0,0 +1,13 @@ +{ + "type": "module", + "name": "dockerfile", + "version": "0.1.0", + "description": "sample nodejs app that uses dockerfile", + "main": "index.js", + "scripts": { + "start": "node index.js" + }, + "dependencies": { + "express": "^4.17.1" + } +} diff --git a/samples/dockerfile/public/about.html b/samples/dockerfile/public/about.html new file mode 100644 index 000000000..83458c7f6 --- /dev/null +++ b/samples/dockerfile/public/about.html @@ -0,0 +1,23 @@ + + + + + + About + + + +

About

+

This app uses dockerfile to maintain a consistent development environment.

+ + + \ No newline at end of file diff --git a/samples/dockerfile/public/index.html b/samples/dockerfile/public/index.html new file mode 100644 index 000000000..f0ae66143 --- /dev/null +++ b/samples/dockerfile/public/index.html @@ -0,0 +1,23 @@ + + + + + + Sample Dockerfile Nodejs App + + + +

Home

+

This is a sample nodejs app that uses dockerfile.

+ + + \ No newline at end of file diff --git a/samples/golang/main.go b/samples/golang/main.go new file mode 100644 index 000000000..1406bee7e --- /dev/null +++ b/samples/golang/main.go @@ -0,0 +1,33 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +import ( + "fmt" + "log" + "net/http" +) + +func main() { + http.HandleFunc("/", func(writerObj http.ResponseWriter, requestObj *http.Request) { + fmt.Fprintf(writerObj, "This is a GOLANG web server app") + }) + + if err := http.ListenAndServe(":8080", nil); err != nil { + log.Fatal("Web server error") + } +} diff --git a/samples/java-gradle/build.gradle b/samples/java-gradle/build.gradle new file mode 100644 index 000000000..1535b0789 --- /dev/null +++ b/samples/java-gradle/build.gradle @@ -0,0 +1,29 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +apply plugin: 'java' +apply plugin: 'war' +apply from: 'https://raw.github.com/gretty-gradle-plugin/gretty/master/pluginScripts/gretty.plugin' +apply plugin: 'eclipse-wtp' + +repositories { + mavenCentral() +} + +dependencies { + providedCompile 'javax.servlet:servlet-api:2.5' + runtime 'javax.servlet:jstl:1.1.2' +} \ No newline at end of file diff --git a/samples/java-gradle/src/main/java/simplewebapp/MainServlet.java b/samples/java-gradle/src/main/java/simplewebapp/MainServlet.java new file mode 100644 index 000000000..c045d7cbb --- /dev/null +++ b/samples/java-gradle/src/main/java/simplewebapp/MainServlet.java @@ -0,0 +1,28 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package simplewebapp; + +import javax.servlet.*; +import javax.servlet.http.*; +import java.io.IOException; + +public class MainServlet extends HttpServlet { + @Override + protected void doGet(HttpServletRequest requestObj, HttpServletResponse responseObj) throws ServletException, IOException { + responseObj.getOutputStream().println("

This is a gradle web app!

Its running on a web server

"); + } +} \ No newline at end of file diff --git a/samples/java-gradle/src/main/webapp/WEB-INF/web.xml b/samples/java-gradle/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 000000000..cf43d2162 --- /dev/null +++ b/samples/java-gradle/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,34 @@ + + + + + + + MainServlet + MainServlet + simplewebapp.MainServlet + + + + MainServlet + / + + + \ No newline at end of file diff --git a/samples/java-maven/pom.xml b/samples/java-maven/pom.xml new file mode 100644 index 000000000..ec00416c6 --- /dev/null +++ b/samples/java-maven/pom.xml @@ -0,0 +1,29 @@ + + + + 4.0.0 + com.simplewebapp + simplewebapp + war + 1.0 + simplewebapp Maven Webapp + + simplewebapp + + diff --git a/samples/java-maven/src/main/webapp/WEB-INF/web.xml b/samples/java-maven/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 000000000..9259e3a4c --- /dev/null +++ b/samples/java-maven/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,24 @@ + + + + + + Maven Web App For Move2Kube + diff --git a/samples/java-maven/src/main/webapp/index.jsp b/samples/java-maven/src/main/webapp/index.jsp new file mode 100644 index 000000000..6e7d8b44a --- /dev/null +++ b/samples/java-maven/src/main/webapp/index.jsp @@ -0,0 +1,22 @@ + + + + +

This is a java-maven web app

+ + diff --git a/samples/nodejs/main.js b/samples/nodejs/main.js new file mode 100644 index 000000000..b4559eaed --- /dev/null +++ b/samples/nodejs/main.js @@ -0,0 +1,23 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +var serverObj = require('http'); +var PORT = 8080; + +serverObj.createServer(function (requestObj, responseObj) { + responseObj.write('

This is a node server

'); + responseObj.end(); +}).listen(PORT); diff --git a/samples/nodejs/package.json b/samples/nodejs/package.json new file mode 100644 index 000000000..20471ca81 --- /dev/null +++ b/samples/nodejs/package.json @@ -0,0 +1,9 @@ +{ + "name" : "main", + "version" : "0.1.0", + "description": "This is a test web server", + "keywords": ["test", "webserver"], + "scripts": { + "start": "node main.js" + } +} diff --git a/samples/php/src/simplewebapp.php b/samples/php/src/simplewebapp.php new file mode 100644 index 000000000..15fe874fb --- /dev/null +++ b/samples/php/src/simplewebapp.php @@ -0,0 +1,20 @@ + + +This is a PHP App"; +?> diff --git a/samples/python/main.py b/samples/python/main.py new file mode 100644 index 000000000..ebe800d62 --- /dev/null +++ b/samples/python/main.py @@ -0,0 +1,25 @@ +# Copyright IBM Corporation 2020 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from flask import Flask + +simpleRestApiApp = Flask (__name__) + + +@simpleRestApiApp.route("/") +def api(): + return "This is a PYTHON web app" + +if __name__ == "__main__": + simpleRestApiApp.run(host='0.0.0.0', port=8080) \ No newline at end of file diff --git a/samples/python/requirements.txt b/samples/python/requirements.txt new file mode 100644 index 000000000..3422e07f4 --- /dev/null +++ b/samples/python/requirements.txt @@ -0,0 +1,15 @@ +# Copyright IBM Corporation 2020 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +Flask==1.0.2 diff --git a/samples/ruby/Gemfile b/samples/ruby/Gemfile new file mode 100644 index 000000000..1d70bd234 --- /dev/null +++ b/samples/ruby/Gemfile @@ -0,0 +1,18 @@ +# Copyright 2020 Move2Kube authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +source "https://rubygems.org" +gem 'sinatra' +gem "puma" +gem "rails" diff --git a/samples/ruby/app.rb b/samples/ruby/app.rb new file mode 100644 index 000000000..efb136ffe --- /dev/null +++ b/samples/ruby/app.rb @@ -0,0 +1,22 @@ +# Copyright 2020 Move2Kube authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +require 'sinatra' + +set :bind, '0.0.0.0' +set :port, 8080 + +get '/' do + erb :main +end \ No newline at end of file diff --git a/samples/ruby/config.ru b/samples/ruby/config.ru new file mode 100644 index 000000000..f7f503c44 --- /dev/null +++ b/samples/ruby/config.ru @@ -0,0 +1,16 @@ +# Copyright 2020 Move2Kube authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +require './app' +run Sinatra::Application \ No newline at end of file diff --git a/samples/ruby/views/main.erb b/samples/ruby/views/main.erb new file mode 100644 index 000000000..602c83320 --- /dev/null +++ b/samples/ruby/views/main.erb @@ -0,0 +1,24 @@ +<% +=begin + +Copyright 2020 Move2Kube authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +=end +%> + + + +This is a RUBY App View + \ No newline at end of file diff --git a/scripts/installdeps.sh b/scripts/installdeps.sh new file mode 100644 index 000000000..693c1c320 --- /dev/null +++ b/scripts/installdeps.sh @@ -0,0 +1,41 @@ +#!/usr/bin/env bash + +# Copyright IBM Corporation 2020 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +if [ "$(uname)" == "Darwin" ]; then + PACKPLATFORM="macos" + KUBECTLPLATFORM="darwin" + OPERATORSDKPLATFORM="apple-darwin" + echo "Once this installation finishes, please do install docker from https://docs.docker.com/docker-for-mac/install/" +elif [ "$(expr substr $(uname -s) 1 5)" == "Linux" ]; then + PACKPLATFORM="linux" + KUBECTLPLATFORM="linux" + OPERATORSDKPLATFORM="linux-gnu" + if ! grep -q container_t "/proc/1/attr/current"; then + curl -fsSL get.docker.com -o get-docker.sh && sudo sh get-docker.sh && rm get-docker.sh + fi +else + echo "Unsupported platform." + exit 1 +fi + +mkdir -p bin +curl -o pack.tgz -LJO https://github.com/buildpacks/pack/releases/download/v0.12.0/pack-v0.12.0-$PACKPLATFORM.tgz && tar -xzf pack.tgz && mv pack bin/ && rm pack.tgz +curl -o kubectl -LJO https://storage.googleapis.com/kubernetes-release/release/`curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt`/bin/$KUBECTLPLATFORM/amd64/kubectl && mv kubectl bin/ +chmod +x bin/kubectl +curl -o operator-sdk -LJO https://github.com/operator-framework/operator-sdk/releases/download/v1.0.0/operator-sdk-v1.0.0-x86_64-$OPERATORSDKPLATFORM && mv operator-sdk bin/ +chmod +x bin/operator-sdk +echo "PATH=$PATH:$PWD/bin" >> ~/.bash_profile +source ~/.bash_profile diff --git a/scripts/licensecheck.sh b/scripts/licensecheck.sh new file mode 100755 index 000000000..3c00a1f95 --- /dev/null +++ b/scripts/licensecheck.sh @@ -0,0 +1,39 @@ +#!/usr/bin/env bash + +# Copyright IBM Corporation 2020 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +find_files_without_string() { + find . -type f \( -name '*.go' -o -name '*.sh' \) ! -exec grep -q -e "$1" \{\} \; -print +} + +didfail=0 + +filepaths=$(find_files_without_string 'Licensed under the Apache License, Version 2.0 (the "License")') + +if [[ $filepaths ]]; then + echo "The following files are missing the license:" + echo "$filepaths" + didfail=1 +fi + +filepaths=$(find_files_without_string 'IBM Corporation') + +if [[ $filepaths ]]; then + echo "The following files are missing the copyright:" + echo "$filepaths" + didfail=1 +fi + +exit "$didfail" diff --git a/types/collection/cfcontainerizers.go b/types/collection/cfcontainerizers.go new file mode 100644 index 000000000..ccf650d6f --- /dev/null +++ b/types/collection/cfcontainerizers.go @@ -0,0 +1,55 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package collection + +import ( + "github.com/konveyor/move2kube/types" + plantypes "github.com/konveyor/move2kube/types/plan" +) + +// CfContainerizersMetadataKind defines kind of cfcontainerizers +const CfContainerizersMetadataKind types.Kind = "CfContainerizers" + +// CfContainerizers is the file structure of cfcontainerizers +type CfContainerizers struct { + types.TypeMeta `yaml:",inline"` + types.ObjectMeta `yaml:"metadata,omitempty"` + Spec CfContainerizersSpec `yaml:"spec,omitempty"` +} + +// CfContainerizersSpec stores the data +type CfContainerizersSpec struct { + BuildpackContainerizers []BuildpackContainerizer `yaml:"buildpackContainerizers"` +} + +// BuildpackContainerizer defines the structure of Buildpack and the containerization strategy to be used for it +type BuildpackContainerizer struct { + BuildpackName string `yaml:"buildpackName"` + ContainerBuildType plantypes.ContainerBuildTypeValue `yaml:"containerBuildType"` + ContainerizationTargetOptions []string `yaml:"targetOptions,omitempty"` +} + +// NewCfContainerizers creates new CfContainerizers instance +func NewCfContainerizers() CfContainerizers { + var cfcontainerizers = CfContainerizers{ + TypeMeta: types.TypeMeta{ + Kind: string(CfContainerizersMetadataKind), + APIVersion: types.SchemeGroupVersion.String(), + }, + } + return cfcontainerizers +} diff --git a/types/collection/cfcontainerizers_test.go b/types/collection/cfcontainerizers_test.go new file mode 100644 index 000000000..ba1cadd1e --- /dev/null +++ b/types/collection/cfcontainerizers_test.go @@ -0,0 +1,31 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package collection_test + +import ( + "testing" + + "github.com/konveyor/move2kube/types" + "github.com/konveyor/move2kube/types/collection" +) + +func TestNewCfContainerizers(t *testing.T) { + cfs := collection.NewCfContainerizers() + if cfs.Kind != string(collection.CfContainerizersMetadataKind) || cfs.APIVersion != types.SchemeGroupVersion.String() { + t.Fatal("Failed to initialize CfContainerizers properly.") + } +} diff --git a/types/collection/cfinstanceapps.go b/types/collection/cfinstanceapps.go new file mode 100644 index 000000000..b82e8e45a --- /dev/null +++ b/types/collection/cfinstanceapps.go @@ -0,0 +1,59 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package collection + +import ( + "github.com/konveyor/move2kube/types" +) + +// CfInstanceAppsMetadataKind defines kind of cf runtime instance apps file +const CfInstanceAppsMetadataKind types.Kind = "CfInstanceApps" + +// CfInstanceApps defines definition of cf runtime instance apps file +type CfInstanceApps struct { + types.TypeMeta `yaml:",inline"` + types.ObjectMeta `yaml:"metadata,omitempty"` + Spec CfInstanceAppsSpec `yaml:"spec,omitempty"` +} + +// CfInstanceAppsSpec stores the data +type CfInstanceAppsSpec struct { + CfApplications []CfApplication `yaml:"applications"` +} + +// CfApplication defines the structure of a cf runtime application +type CfApplication struct { + Name string `yaml:"name"` + Buildpack string `yaml:"buildpack,omitempty"` + DetectedBuildpack string `yaml:"detectedBuildpack,omitempty"` + Memory int64 `yaml:"memory"` + Instances int `yaml:"instances"` + DockerImage string `yaml:"dockerImage,omitempty"` + Ports []int32 `yaml:"ports"` + Env map[string]string `yaml:"env,omitempty"` +} + +// NewCfInstanceApps creates a new instance of CfInstanceApps +func NewCfInstanceApps() CfInstanceApps { + var cfInstanceApps = CfInstanceApps{ + TypeMeta: types.TypeMeta{ + Kind: string(CfInstanceAppsMetadataKind), + APIVersion: types.SchemeGroupVersion.String(), + }, + } + return cfInstanceApps +} diff --git a/types/collection/cfinstanceapps_test.go b/types/collection/cfinstanceapps_test.go new file mode 100644 index 000000000..826f171f2 --- /dev/null +++ b/types/collection/cfinstanceapps_test.go @@ -0,0 +1,31 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package collection_test + +import ( + "testing" + + "github.com/konveyor/move2kube/types" + "github.com/konveyor/move2kube/types/collection" +) + +func TestNewCfInstanceApps(t *testing.T) { + cfapps := collection.NewCfInstanceApps() + if cfapps.Kind != string(collection.CfInstanceAppsMetadataKind) || cfapps.APIVersion != types.SchemeGroupVersion.String() { + t.Fatal("Failed to initialize CfInstanceApps properly.") + } +} diff --git a/types/collection/cluster.go b/types/collection/cluster.go new file mode 100644 index 000000000..0411256c6 --- /dev/null +++ b/types/collection/cluster.go @@ -0,0 +1,129 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package collection + +import ( + common "github.com/konveyor/move2kube/internal/common" + "github.com/konveyor/move2kube/types" +) + +// ClusterMetadataKind defines the kind of cluster metadata file +const ClusterMetadataKind types.Kind = "ClusterMetadata" + +// ClusterMetadata for collect output +type ClusterMetadata struct { + types.TypeMeta `yaml:",inline"` + types.ObjectMeta `yaml:"metadata,omitempty"` + Spec ClusterMetadataSpec `yaml:"spec,omitempty"` +} + +// ClusterMetadataSpec stores the data +type ClusterMetadataSpec struct { + StorageClasses []string `yaml:"storageClasses"` + APIKindVersionMap map[string][]string `yaml:"apiKindVersionMap"` //[kubernetes kind]["gv1", "gv2",...,"gvn"] prioritized group-version +} + +// Merge helps merge clustermetadata +func (c *ClusterMetadata) Merge(newc ClusterMetadata) bool { + if newc.isEmpty() { + return true + } + if c.isEmpty() { + c.Kind = newc.Kind + c.Name = newc.Name + } else if c.Kind != newc.Kind { + // If neither metadata is empty then their kinds should match + return false + } + if newc.Name != "" { + c.Name = newc.Name + } + + // Allow only intersection of storage classes + newslice := []string{} + for _, sc := range c.Spec.StorageClasses { + if common.IsStringPresent(newc.Spec.StorageClasses, sc) { + newslice = append(newslice, sc) + } + } + c.Spec.StorageClasses = newslice + if len(c.Spec.StorageClasses) == 0 { + c.Spec.StorageClasses = []string{"default"} + } + //TODO: Do Intelligent merge of version + apiversionkindmap := make(map[string][]string) + for kindname, gvList := range newc.Spec.APIKindVersionMap { + if _, ok := c.Spec.APIKindVersionMap[kindname]; ok { + apiversionkindmap[kindname] = gvList + } + } + c.Spec.APIKindVersionMap = apiversionkindmap + return true +} + +// Merge helps merge clustermetadata +func (c *ClusterMetadataSpec) Merge(newc ClusterMetadataSpec) bool { + // Allow only intersection of storage classes + newslice := []string{} + for _, sc := range c.StorageClasses { + if common.IsStringPresent(newc.StorageClasses, sc) { + newslice = append(newslice, sc) + } + } + c.StorageClasses = newslice + //TODO: Do Intelligent merge of version + apiversionkindmap := make(map[string][]string) + for kindname, gvList := range newc.APIKindVersionMap { + if _, ok := c.APIKindVersionMap[kindname]; ok { + apiversionkindmap[kindname] = gvList + } + } + c.APIKindVersionMap = apiversionkindmap + return true +} + +func (c *ClusterMetadata) isEmpty() bool { + return c.Kind == "" +} + +// GetSupportedVersions returns all the group version supported for the kind in this cluster +func (c *ClusterMetadataSpec) GetSupportedVersions(kind string) []string { + if gvList, ok := c.APIKindVersionMap[kind]; ok { + if len(gvList) > 0 { + return gvList + } + } + return nil +} + +// NewClusterMetadata creates a new cluster metadata instance +func NewClusterMetadata(contextName string) ClusterMetadata { + var clusterMetadata = ClusterMetadata{ + TypeMeta: types.TypeMeta{ + Kind: string(ClusterMetadataKind), + APIVersion: types.SchemeGroupVersion.String(), + }, + ObjectMeta: types.ObjectMeta{ + Name: contextName, + }, + Spec: ClusterMetadataSpec{ + StorageClasses: []string{}, + APIKindVersionMap: make(map[string][]string), + }, + } + return clusterMetadata +} diff --git a/types/collection/cluster_test.go b/types/collection/cluster_test.go new file mode 100644 index 000000000..dbb4a064d --- /dev/null +++ b/types/collection/cluster_test.go @@ -0,0 +1,138 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package collection_test + +import ( + "reflect" + "testing" + + "github.com/konveyor/move2kube/types" + "github.com/konveyor/move2kube/types/collection" +) + +func TestMerge(t *testing.T) { + t.Run("merging 2 empty metadatas", func(t *testing.T) { + cmeta1 := collection.NewClusterMetadata("") + cmeta1.Kind = "" + cmeta2 := collection.NewClusterMetadata("") + cmeta2.Kind = "" + want := collection.NewClusterMetadata("") + want.Kind = "" + if merged := cmeta1.Merge(cmeta2); !merged || !reflect.DeepEqual(cmeta1, want) { + t.Fatal("Failed to merge ClusterMetadata properly. Expected:", want, "Actual:", cmeta1) + } + }) + + t.Run("merging a non empty metadata into an empty metadata", func(t *testing.T) { + cmeta1 := collection.NewClusterMetadata("") + cmeta1.Kind = "" + + cmeta2 := collection.NewClusterMetadata("ctxname1") + + want := collection.NewClusterMetadata("") + want.Name = "ctxname1" + want.Spec.StorageClasses = []string{"default"} + + if merged := cmeta1.Merge(cmeta2); !merged || !reflect.DeepEqual(cmeta1, want) { + t.Fatal("Failed to merge ClusterMetadata properly. Expected:", want, "Actual:", cmeta1) + } + }) + + t.Run("merging metadata with different kinds", func(t *testing.T) { + cmeta1 := collection.NewClusterMetadata("") + cmeta1.Kind = "kind1" + + cmeta2 := collection.NewClusterMetadata("") + cmeta2.Kind = "kind2" + + if merged := cmeta1.Merge(cmeta2); merged { + t.Fatal("Should not have merged metadata with different kinds. The kinds are", cmeta1.Kind, "and", cmeta2.Kind) + } + }) + + t.Run("merging version maps from filled metadata into filled metadata", func(t *testing.T) { + key1 := "key1" + val1 := []string{"1.0.0", "1.1.0", "1.1.1"} + key2 := "key2" + val2 := []string{"2.0.0", "2.2.0", "2.2.2"} + + cmeta1 := collection.NewClusterMetadata("") + cmeta1.Spec.APIKindVersionMap = map[string][]string{key1: val1} + + cmeta2 := collection.NewClusterMetadata("") + cmeta2.Spec.APIKindVersionMap = map[string][]string{key1: val2, key2: val2} + + want := collection.NewClusterMetadata("") + want.Spec.StorageClasses = []string{"default"} + want.Spec.APIKindVersionMap = map[string][]string{key1: val2} + + if merged := cmeta1.Merge(cmeta2); !merged || !reflect.DeepEqual(cmeta1, want) { + t.Fatal("Failed to merge ClusterMetadata properly. Expected:", want, "Actual:", cmeta1) + } + }) + + t.Run("merging storage classes from filled metadata into filled metadata", func(t *testing.T) { + cmeta1 := collection.NewClusterMetadata("") + cmeta1.Spec.StorageClasses = []string{"111", "222", "333"} + + cmeta2 := collection.NewClusterMetadata("") + cmeta2.Spec.StorageClasses = []string{"222", "333", "444"} + + want := collection.NewClusterMetadata("") + want.Spec.StorageClasses = []string{"222", "333"} + + if merged := cmeta1.Merge(cmeta2); !merged || !reflect.DeepEqual(cmeta1, want) { + t.Fatal("Failed to merge ClusterMetadata properly. Expected:", want, "Actual:", cmeta1) + } + }) +} + +func TestGetSupportedVersions(t *testing.T) { + t.Run("get nil for non existent key", func(t *testing.T) { + key1 := "foobar_non_existent_key" + cmeta := collection.NewClusterMetadata("") + if arr := cmeta.Spec.GetSupportedVersions(key1); arr != nil { + t.Fatal("The method should have returned nil since the key", key1, "is not present in the APIKindVersionMap.") + } + }) + + t.Run("get nil for key with empty list of supported versions", func(t *testing.T) { + key1 := "key1" + cmeta := collection.NewClusterMetadata("") + cmeta.Spec.APIKindVersionMap = map[string][]string{key1: {}} + if arr := cmeta.Spec.GetSupportedVersions(key1); arr != nil { + t.Fatal("The method should have returned nil since the supported versions for the", key1, "is an empty list.") + } + }) + + t.Run("get a list of versions for a valid key", func(t *testing.T) { + key1 := "key1" + val1 := []string{"0.1.0", "0.1.1", "1.2.3"} + cmeta := collection.NewClusterMetadata("") + cmeta.Spec.APIKindVersionMap = map[string][]string{key1: val1} + if arr := cmeta.Spec.GetSupportedVersions(key1); arr == nil { + t.Fatal("The method did not return the correct list of supported versions for the", key1, "Expected:", val1, "Actual:", arr) + } + }) +} + +func TestNewClusterMetadata(t *testing.T) { + cmeta := collection.NewClusterMetadata("") + if cmeta.Kind != string(collection.ClusterMetadataKind) || cmeta.APIVersion != types.SchemeGroupVersion.String() { + t.Fatal("Failed to initialize ClusterMetadata properly.") + } +} diff --git a/types/collection/image.go b/types/collection/image.go new file mode 100644 index 000000000..419f1bfad --- /dev/null +++ b/types/collection/image.go @@ -0,0 +1,50 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package collection + +import ( + "github.com/konveyor/move2kube/types" +) + +// ImageMetadataKind defines kind for imagemetadata file +const ImageMetadataKind types.Kind = "ImageMetadata" + +// ImageInfo stores data about different images +type ImageInfo struct { + types.TypeMeta `yaml:",inline"` + types.ObjectMeta `yaml:"metadata,omitempty"` + Spec ImageInfoSpec `yaml:"spec,omitempty"` +} + +// ImageInfoSpec defines the data stored about ImageInfo +type ImageInfoSpec struct { + Tags []string `yaml:"tags"` + PortsToExpose []int `yaml:"ports"` + AccessedDirs []string `yaml:"accessedDirs"` + UserID int `yaml:"userID"` +} + +// NewImageInfo creates a new imageinfo instance +func NewImageInfo() ImageInfo { + var imageInfo = ImageInfo{ + TypeMeta: types.TypeMeta{ + Kind: string(ImageMetadataKind), + APIVersion: types.SchemeGroupVersion.String(), + }, + } + return imageInfo +} diff --git a/types/collection/image_test.go b/types/collection/image_test.go new file mode 100644 index 000000000..a172fd3c6 --- /dev/null +++ b/types/collection/image_test.go @@ -0,0 +1,31 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package collection_test + +import ( + "testing" + + "github.com/konveyor/move2kube/types" + "github.com/konveyor/move2kube/types/collection" +) + +func TestNewImageInfo(t *testing.T) { + img := collection.NewImageInfo() + if img.Kind != string(collection.ImageMetadataKind) || img.APIVersion != types.SchemeGroupVersion.String() { + t.Fatal("Failed to initialize ImageInfo properly.") + } +} diff --git a/types/info/versioninfo.go b/types/info/versioninfo.go new file mode 100644 index 000000000..fb0775ba9 --- /dev/null +++ b/types/info/versioninfo.go @@ -0,0 +1,100 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package info + +import ( + "runtime" + + semver "github.com/Masterminds/semver/v3" + log "github.com/sirupsen/logrus" +) + +var ( + // Update this whenever making a new release. + // The version is of the format Major.Minor.Patch[-Prerelease][+BuildMetadata] + // Given a version number MAJOR.MINOR.PATCH, increment the: + // MAJOR version when you make incompatible API changes, + // MINOR version when you add functionality in a backwards compatible manner, and + // PATCH version when you make backwards compatible bug fixes. + // Additional labels for pre-release and build metadata are available as extensions to the MAJOR.MINOR.PATCH format. + // For more details about semver 2 see https://semver.org/ + version = "v0.1.0" + + // metadata is extra build time data + buildmetadata = "" + // gitCommit is the git sha1 + gitCommit = "" + // gitTreeState is the state of the git tree + gitTreeState = "" +) + +// GetVersion returns the semver string of the version +func GetVersion() string { + if buildmetadata == "" { + return version + } + return version + "+" + buildmetadata +} + +// GetVersionInfo returns version info +func GetVersionInfo() VersionInfo { + v := VersionInfo{ + Version: GetVersion(), + GitCommit: gitCommit, + GitTreeState: gitTreeState, + GoVersion: runtime.Version(), + } + return v +} + +// VersionInfo describes the compile time information. +type VersionInfo struct { + // Version is the current semver. + Version string `yaml:"version,omitempty"` + // GitCommit is the git sha1. + GitCommit string `yaml:"gitCommit,omitempty"` + // GitTreeState is the state of the git tree. + GitTreeState string `yaml:"gitTreeState,omitempty"` + // GoVersion is the version of the Go compiler used. + GoVersion string `yaml:"goVersion,omitempty"` +} + +// IsSameVersion checks if two versions are same and logs a message if the version is newer or older +func (v *VersionInfo) IsSameVersion() bool { + binaryversion, err := semver.NewVersion(GetVersion()) + if err != nil { + log.Warnf("Unable to load current version of binary : %s", err) + return false + } + objversion, err := semver.NewVersion(v.Version) + if err != nil { + log.Warnf("Unable to load current version : %s", err) + return false + } + + compare := binaryversion.Compare(objversion) + + if compare == 0 { + return true + } + if compare < 0 { + log.Warnf("The file version (%s) is newer than the binary version (%s).", objversion, binaryversion) + } else { + log.Warnf("The file version (%s) is older than the binary version (%s).", objversion, binaryversion) + } + return false +} diff --git a/types/info/versioninfo_test.go b/types/info/versioninfo_test.go new file mode 100644 index 000000000..0cef91e86 --- /dev/null +++ b/types/info/versioninfo_test.go @@ -0,0 +1,63 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package info_test + +import ( + "testing" + + "github.com/konveyor/move2kube/types/info" +) + +func TestGetVersionInfo(t *testing.T) { + vinfo := info.GetVersionInfo() + if !vinfo.IsSameVersion() { + t.Fatal("Versions don't match. Expected:", info.GetVersion(), "Actual:", vinfo.Version) + } +} + +func TestIsSameVersion(t *testing.T) { + t.Run("same version", func(t *testing.T) { + vinfo := info.GetVersionInfo() + if !vinfo.IsSameVersion() { + t.Fatal("The versions are same but the method says they are different. Binary version:", info.GetVersion(), "Object version:", vinfo.Version) + } + }) + + t.Run("older version", func(t *testing.T) { + vinfo := info.GetVersionInfo() + vinfo.Version = "0.0.0" + if vinfo.IsSameVersion() { + t.Fatal("The versions are different but the method says they are equal. Binary version:", info.GetVersion(), "Object version:", vinfo.Version) + } + }) + + t.Run("newer version", func(t *testing.T) { + vinfo := info.GetVersionInfo() + vinfo.Version = "100.0.0" + if vinfo.IsSameVersion() { + t.Fatal("The versions are different but the method says they are equal. Binary version:", info.GetVersion(), "Object version:", vinfo.Version) + } + }) + + t.Run("invalid version", func(t *testing.T) { + vinfo := info.GetVersionInfo() + vinfo.Version = "foobar" + if vinfo.IsSameVersion() { + t.Fatal("The versions are different but the method says they are equal. Binary version:", info.GetVersion(), "Object version:", vinfo.Version) + } + }) +} diff --git a/types/output/helmvaluesoutput.go b/types/output/helmvaluesoutput.go new file mode 100644 index 000000000..00ef457df --- /dev/null +++ b/types/output/helmvaluesoutput.go @@ -0,0 +1,77 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package output + +const ( + // ParameterRegistryPrefix defines the parameter registry + ParameterRegistryPrefix string = "{{.Values.registryurl}}/{{.Values.registrynamespace}}/" + // ServicesTag is the tag name for services + ServicesTag string = "services" + // ImageTagTag is the tag name for images + ImageTagTag string = "imagetag" + // ContainersTag is the tag name for conatiners + ContainersTag string = "containers" +) + +// HelmValues defines the format of values.yaml +type HelmValues struct { + RegistryURL string `yaml:"registryurl"` + RegistryNamespace string `yaml:"registrynamespace"` + Services map[string]Service `yaml:"services"` + StorageClass string `yaml:"storageclass,omitempty"` + GlobalVariables map[string]string `yaml:"globalvariables,omitempty"` +} + +// Merge helps merge helmvalues +func (h *HelmValues) Merge(newh HelmValues) { + if newh.RegistryNamespace != "" { + h.RegistryNamespace = newh.RegistryNamespace + } + if newh.RegistryURL != "" { + h.RegistryURL = newh.RegistryURL + } + if newh.StorageClass != "" { + h.StorageClass = newh.StorageClass + } + for gvkey, gvval := range newh.GlobalVariables { + h.GlobalVariables[gvkey] = gvval + } + for serviceName, service := range newh.Services { + if _, ok := h.Services[serviceName]; !ok { + h.Services[serviceName] = service + } else { + for ncn, nc := range service.Containers { + if c, ok := h.Services[serviceName].Containers[ncn]; !ok { + h.Services[serviceName].Containers[ncn] = nc + } else { + c.TagName = nc.TagName + h.Services[serviceName].Containers[ncn] = c + } + } + } + } +} + +// Service stores the metadata about the services and its containers +type Service struct { + Containers map[string]Container `yaml:"containers"` +} + +// Container stores the metadata the container +type Container struct { + TagName string `yaml:"imagetag"` +} diff --git a/types/output/helmvaluesoutput_test.go b/types/output/helmvaluesoutput_test.go new file mode 100644 index 000000000..abd81edff --- /dev/null +++ b/types/output/helmvaluesoutput_test.go @@ -0,0 +1,105 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package output_test + +import ( + "reflect" + "testing" + + "github.com/konveyor/move2kube/types/output" +) + +func TestMerge(t *testing.T) { + t.Run("merge 2 empty helm values", func(t *testing.T) { + h1 := output.HelmValues{} + h2 := output.HelmValues{} + want := output.HelmValues{} + if h1.Merge(h2); !reflect.DeepEqual(h1, want) { + t.Fatal("The value should not have changed after merge. Expected:", want, "Actual:", h1) + } + }) + + t.Run("merge filled helm value into filled helm value", func(t *testing.T) { + h1 := output.HelmValues{} + h1.RegistryNamespace = "namespace1" + h1.RegistryURL = "url1" + h1.StorageClass = "storagecls1" + h2 := output.HelmValues{} + h2.RegistryNamespace = "namespace2" + h2.RegistryURL = "url2" + h2.StorageClass = "storagecls2" + want := output.HelmValues{} + want.RegistryNamespace = "namespace2" + want.RegistryURL = "url2" + want.StorageClass = "storagecls2" + if h1.Merge(h2); !reflect.DeepEqual(h1, want) { + t.Fatal("Failed to merge the helm values properly. Expected:", want, "Actual:", h1) + } + }) + + t.Run("merge global and service variables into filled helm value", func(t *testing.T) { + makeH := func() output.HelmValues { + h := output.HelmValues{} + h.GlobalVariables = make(map[string]string) + return h + } + key1 := "key1" + val1 := "val1" + val2 := "val2" + + h1 := makeH() + h1.GlobalVariables[key1] = val1 + + h2 := makeH() + h2.GlobalVariables[key1] = val2 + + want := makeH() + want.GlobalVariables[key1] = val2 + + if h1.Merge(h2); !reflect.DeepEqual(h1, want) { + t.Fatal("Failed to merge the helm values properly. Expected:", want, "Actual:", h1) + } + }) + + t.Run("merge ImageTagTree properly into filled helm value", func(t *testing.T) { + makeH := func() output.HelmValues { + h := output.HelmValues{} + h.Services = make(map[string]output.Service) + return h + } + key1 := "key1" + key2 := "key2" + con1 := "name1" + val1 := output.Container{"tag1"} + val2 := output.Container{"tag2"} + + h1 := makeH() + h1.Services[key1] = output.Service{map[string]output.Container{con1: val1}} + + h2 := makeH() + h2.Services[key1] = output.Service{map[string]output.Container{con1: val2}} + h2.Services[key2] = output.Service{map[string]output.Container{con1: val1}} + + want := makeH() + want.Services[key1] = output.Service{map[string]output.Container{con1: val2}} + want.Services[key2] = output.Service{map[string]output.Container{con1: val1}} + + if h1.Merge(h2); !reflect.DeepEqual(h1, want) { + t.Fatal("Failed to merge the helm values properly. Expected:", want, "Actual:", h1) + } + }) +} diff --git a/types/plan/plan.go b/types/plan/plan.go new file mode 100644 index 000000000..d1365d73b --- /dev/null +++ b/types/plan/plan.go @@ -0,0 +1,393 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package plan + +import ( + "path/filepath" + "strings" + + log "github.com/sirupsen/logrus" + + "github.com/konveyor/move2kube/internal/common" + "github.com/konveyor/move2kube/types" +) + +// SourceTypeValue defines the type of source +type SourceTypeValue string + +// ContainerBuildTypeValue defines the containerization type +type ContainerBuildTypeValue string + +// TranslationTypeValue defines the translation type +type TranslationTypeValue string + +// TargetInfoArtifactTypeValue defines the target info type +type TargetInfoArtifactTypeValue string + +// BuildArtifactTypeValue defines the build artifact type +type BuildArtifactTypeValue string + +// SourceArtifactTypeValue defines the source artifact type +type SourceArtifactTypeValue string + +// TargetArtifactTypeValue defines the target artifact type +type TargetArtifactTypeValue string + +// PlanKind is kind of plan file +const PlanKind types.Kind = "Plan" + +const ( + // Compose2KubeTranslation translation type is used when source is docker compose + Compose2KubeTranslation TranslationTypeValue = "Compose2Kube" + // CfManifest2KubeTranslation translation type is used when source is cloud foundry manifest + CfManifest2KubeTranslation TranslationTypeValue = "Cfmanifest2Kube" + // Any2KubeTranslation translation type is used when source is of an unknown platform + Any2KubeTranslation TranslationTypeValue = "Any2Kube" + // Kube2KubeTranslation translation type is used when source is Kubernetes + Kube2KubeTranslation TranslationTypeValue = "Kube2Kube" + // Knative2KubeTranslation translation type is used when source is Knative + Knative2KubeTranslation TranslationTypeValue = "Knative2Kube" + // Dockerfile2KubeTranslation translation type is used when source is Knative + Dockerfile2KubeTranslation TranslationTypeValue = "Dockerfile2Kube" +) + +const ( + // ComposeSourceTypeValue defines the source as docker compose + ComposeSourceTypeValue SourceTypeValue = "DockerCompose" + // DirectorySourceTypeValue defines the source as a simple directory + DirectorySourceTypeValue SourceTypeValue = "Directory" + // CfManifestSourceTypeValue defines the source as cf manifest + CfManifestSourceTypeValue SourceTypeValue = "CfManifest" + // KNativeSourceTypeValue defines the source as KNative + KNativeSourceTypeValue SourceTypeValue = "Knative" + // K8sSourceTypeValue defines the source as Kubernetes + K8sSourceTypeValue SourceTypeValue = "Kubernetes" +) + +const ( + // DockerFileContainerBuildTypeValue defines the containerization type as docker file + DockerFileContainerBuildTypeValue ContainerBuildTypeValue = "NewDockerfile" + // ReuseDockerFileContainerBuildTypeValue defines the containerization type as reuse of dockerfile + ReuseDockerFileContainerBuildTypeValue ContainerBuildTypeValue = "ReuseDockerfile" + // ReuseContainerBuildTypeValue defines the containerization type as reuse of an existing container + ReuseContainerBuildTypeValue ContainerBuildTypeValue = "Reuse" + // CNBContainerBuildTypeValue defines the containerization type of cloud native buildpack + CNBContainerBuildTypeValue ContainerBuildTypeValue = "CNB" + // ManualContainerBuildTypeValue defines that the tool assumes that the image will be created manually + ManualContainerBuildTypeValue ContainerBuildTypeValue = "Manual" + // S2IContainerBuildTypeValue defines the containerization type of S2I + S2IContainerBuildTypeValue ContainerBuildTypeValue = "S2I" +) + +const ( + // K8sFileArtifactType defines the source artifact type of K8s + K8sFileArtifactType SourceArtifactTypeValue = "Kubernetes" + // KnativeFileArtifactType defines the source artifact type of KNative + KnativeFileArtifactType SourceArtifactTypeValue = "Knative" + // ComposeFileArtifactType defines the source artifact type of Docker compose + ComposeFileArtifactType SourceArtifactTypeValue = "DockerCompose" + // ImageInfoArtifactType defines the source artifact type of image info + ImageInfoArtifactType SourceArtifactTypeValue = "ImageInfo" + // CfManifestArtifactType defines the source artifact type of cf manifest + CfManifestArtifactType SourceArtifactTypeValue = "CfManifest" + // CfRunningManifestArtifactType defines the source artifact type of a manifest of a running instance + CfRunningManifestArtifactType SourceArtifactTypeValue = "CfRunningManifest" + // SourceDirectoryArtifactType defines the source artifact type of normal source code directory + SourceDirectoryArtifactType SourceArtifactTypeValue = "SourceCode" + // DockerfileArtifactType defines the source artifact type of dockerfile + DockerfileArtifactType SourceArtifactTypeValue = "Dockerfile" +) + +const ( + // SourceDirectoryBuildArtifactType defines source data artifact type + SourceDirectoryBuildArtifactType BuildArtifactTypeValue = "SourceCode" +) + +const ( + // K8sClusterArtifactType defines target info + K8sClusterArtifactType TargetInfoArtifactTypeValue = "KubernetesCluster" +) + +const ( + // Helm defines helm artifact type + Helm TargetArtifactTypeValue = "Helm" + // Yamls defines K8s artifact type + Yamls TargetArtifactTypeValue = "Yamls" + // Knative defines Knative artifact type + Knative TargetArtifactTypeValue = "Knative" +) + +// Plan defines the format of plan +type Plan struct { + types.TypeMeta `yaml:",inline"` + types.ObjectMeta `yaml:"metadata,omitempty"` + Spec PlanSpec `yaml:"spec,omitempty"` +} + +// PlanSpec stores the data about the plan +type PlanSpec struct { + Inputs Inputs `yaml:"inputs"` + Outputs Outputs `yaml:"outputs"` +} + +// Outputs defines the output section of plan +type Outputs struct { + Kubernetes KubernetesOutput `yaml:"kubernetes"` +} + +// KubernetesOutput defines the output format for kubernetes deployable artifacts +type KubernetesOutput struct { + RegistryURL string `yaml:"registryURL,omitempty"` + RegistryNamespace string `yaml:"registryNamespace,omitempty"` + ArtifactType TargetArtifactTypeValue `yaml:"artifactType"` + ClusterType string `yaml:"clusterType,omitempty"` + IgnoreUnsupportedKinds bool `yaml:"ignoreUnsupportedKinds,omitempty"` +} + +// Merge allows merge of two Kubernetes Outputs +func (output *KubernetesOutput) Merge(newoutput KubernetesOutput) { + if newoutput != (KubernetesOutput{}) { + if newoutput.RegistryURL != "" { + output.RegistryURL = newoutput.RegistryURL + } + if newoutput.RegistryNamespace != "" { + output.RegistryNamespace = newoutput.RegistryNamespace + } + output.ArtifactType = newoutput.ArtifactType + output.IgnoreUnsupportedKinds = newoutput.IgnoreUnsupportedKinds + if newoutput.ClusterType != "" { + output.ClusterType = newoutput.ClusterType + } + } +} + +// Inputs defines the input section of plan +type Inputs struct { + RootDir string `yaml:"rootDir"` + K8sFiles []string `yaml:"kubernetesYamls,omitempty"` + QACaches []string `yaml:"qaCaches,omitempty"` + Services map[string][]Service `yaml:"services"` // [serviceName][Services] + TargetInfoArtifacts map[TargetInfoArtifactTypeValue][]string `yaml:"targetInfoArtifacts,omitempty"` //[targetinfoartifacttype][List of artifacts] +} + +// Service defines a plan service +type Service struct { + ServiceName string `yaml:"serviceName"` + Image string `yaml:"image"` + TranslationType TranslationTypeValue `yaml:"translationType"` + ContainerBuildType ContainerBuildTypeValue `yaml:"containerBuildType"` + SourceTypes []SourceTypeValue `yaml:"sourceType"` + ContainerizationTargetOptions []string `yaml:"targetOptions,omitempty"` + SourceArtifacts map[SourceArtifactTypeValue][]string `yaml:"sourceArtifacts"` //[translationartifacttype][List of artifacts] + BuildArtifacts map[BuildArtifactTypeValue][]string `yaml:"buildArtifacts,omitempty"` //[buildartifacttype][List of artifacts] + UpdateContainerBuildPipeline bool `yaml:"updateContainerBuildPipeline"` + UpdateDeployPipeline bool `yaml:"updateDeployPipeline"` +} + +func (service *Service) merge(newservice Service) bool { + if service.ServiceName != newservice.ServiceName || service.Image != newservice.Image || service.TranslationType != newservice.TranslationType || service.ContainerBuildType != newservice.ContainerBuildType { + return false + } + if len(service.BuildArtifacts[SourceDirectoryBuildArtifactType]) > 0 && len(newservice.BuildArtifacts[SourceDirectoryBuildArtifactType]) > 0 && service.BuildArtifacts[SourceDirectoryBuildArtifactType][0] != newservice.BuildArtifacts[SourceDirectoryBuildArtifactType][0] { + return false + } + service.UpdateContainerBuildPipeline = service.UpdateContainerBuildPipeline || newservice.UpdateContainerBuildPipeline + service.UpdateDeployPipeline = service.UpdateDeployPipeline || newservice.UpdateDeployPipeline + service.addSourceTypes(newservice.SourceTypes) + service.addTargetOptions(newservice.ContainerizationTargetOptions) + service.addSourceArtifacts(newservice.SourceArtifacts) + service.addBuildArtifacts(newservice.BuildArtifacts) + return true +} + +// AddSourceArtifact adds a source artifact to a plan service +func (service *Service) AddSourceArtifact(sat SourceArtifactTypeValue, value string) { + if val, ok := service.SourceArtifacts[sat]; ok { + service.SourceArtifacts[sat] = append(val, value) + } else { + service.SourceArtifacts[sat] = []string{value} + } +} + +func (service *Service) addSourceArtifactArray(sat SourceArtifactTypeValue, values []string) { + if val, ok := service.SourceArtifacts[sat]; ok { + service.SourceArtifacts[sat] = common.MergeStringSlices(val, values) + } else { + service.SourceArtifacts[sat] = values + } +} + +func (service *Service) addSourceArtifacts(sats map[SourceArtifactTypeValue][]string) { + for key2, value2 := range sats { + service.addSourceArtifactArray(key2, value2) + } +} + +// AddBuildArtifact adds a build artifact to a plan service +func (service *Service) AddBuildArtifact(sat BuildArtifactTypeValue, value string) { + if val, ok := service.BuildArtifacts[sat]; ok { + service.BuildArtifacts[sat] = append(val, value) + } else { + service.BuildArtifacts[sat] = []string{value} + } +} + +func (service *Service) addBuildArtifactArray(sat BuildArtifactTypeValue, values []string) { + if val, ok := service.BuildArtifacts[sat]; ok { + service.BuildArtifacts[sat] = common.MergeStringSlices(val, values) + } else { + service.BuildArtifacts[sat] = values + } +} + +func (service *Service) addBuildArtifacts(sats map[BuildArtifactTypeValue][]string) { + for key2, value2 := range sats { + service.addBuildArtifactArray(key2, value2) + } +} + +// AddSourceType adds source type to a plan service +func (service *Service) AddSourceType(st SourceTypeValue) bool { + found := false + for _, est := range service.SourceTypes { + if est == st { + found = true + break + } + } + if !found { + service.SourceTypes = append(service.SourceTypes, st) + } + return true +} + +// addSourceTypes adds source types to a plan service +func (service *Service) addSourceTypes(sts []SourceTypeValue) { + for _, st := range sts { + service.AddSourceType(st) + } +} + +// addTargetOption adds target option to a plan service +func (service *Service) addTargetOption(st string) bool { + found := false + for _, est := range service.ContainerizationTargetOptions { + if est == st { + found = true + break + } + } + if !found { + service.ContainerizationTargetOptions = append(service.ContainerizationTargetOptions, st) + } + return true +} + +// addTargetOptions adds target options to a plan service +func (service *Service) addTargetOptions(sts []string) { + for _, st := range sts { + service.addTargetOption(st) + } +} + +// GetFullPath returns the full path with rootdir, unless the directory is in assets path +func (p Plan) GetFullPath(path string) string { + if strings.HasPrefix(path, common.AssetsDir) { + return filepath.Join(common.TempPath, path) + } + return filepath.Join(p.Spec.Inputs.RootDir, path) +} + +// GetRelativePath returns the relative path with respect to the rootdir, unless the directory is in assets path +func (p Plan) GetRelativePath(path string) (string, error) { + if strings.HasPrefix(path, common.TempPath) { + rel, err := filepath.Rel(common.TempPath, path) + if err != nil { + return "", err + } + return rel, nil + } + rel, err := filepath.Rel(p.Spec.Inputs.RootDir, path) + if err != nil { + return "", err + } + return rel, nil +} + +// AddServicesToPlan adds a list of services to a plan +func (p *Plan) AddServicesToPlan(services []Service) { + for _, service := range services { + if _, ok := p.Spec.Inputs.Services[service.ServiceName]; !ok { + p.Spec.Inputs.Services[service.ServiceName] = []Service{} + log.Debugf("Added new service to plan : %s", service.ServiceName) + } + merged := false + existingServices := p.Spec.Inputs.Services[service.ServiceName] + for i := range existingServices { + if existingServices[i].merge(service) { + merged = true + } + } + if !merged { + p.Spec.Inputs.Services[service.ServiceName] = append(p.Spec.Inputs.Services[service.ServiceName], service) + } + } +} + +// NewPlan creates a new plan +// Sets the version and optionally fills in some default values +func NewPlan() Plan { + plan := Plan{ + TypeMeta: types.TypeMeta{ + Kind: string(PlanKind), + APIVersion: types.SchemeGroupVersion.String(), + }, + ObjectMeta: types.ObjectMeta{ + Name: common.DefaultProjectName, + }, + Spec: PlanSpec{ + Inputs: Inputs{ + Services: make(map[string][]Service), + TargetInfoArtifacts: make(map[TargetInfoArtifactTypeValue][]string), + }, + Outputs: Outputs{ + Kubernetes: KubernetesOutput{ + ArtifactType: Yamls, + ClusterType: common.DefaultClusterType, + IgnoreUnsupportedKinds: false, + }, + }, + }, + } + return plan +} + +// NewService creates a new service +func NewService(servicename string, translationtype TranslationTypeValue) Service { + var service Service + service.ServiceName = servicename + service.Image = servicename + ":latest" + service.TranslationType = translationtype + service.SourceTypes = make([]SourceTypeValue, 0) + service.ContainerBuildType = ReuseContainerBuildTypeValue + service.BuildArtifacts = make(map[BuildArtifactTypeValue][]string) + service.SourceArtifacts = make(map[SourceArtifactTypeValue][]string) + service.UpdateDeployPipeline = false + service.UpdateContainerBuildPipeline = false + + return service +} diff --git a/types/plan/plan_test.go b/types/plan/plan_test.go new file mode 100644 index 000000000..3b5ee02b5 --- /dev/null +++ b/types/plan/plan_test.go @@ -0,0 +1,444 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package plan_test + +import ( + "path/filepath" + "reflect" + "testing" + + "github.com/konveyor/move2kube/internal/common" + "github.com/konveyor/move2kube/types/plan" +) + +func TestMerge(t *testing.T) { + t.Run("merge new empty k8s output into empty k8s output", func(t *testing.T) { + out1 := plan.KubernetesOutput{} + out2 := plan.KubernetesOutput{} + want := plan.KubernetesOutput{} + out1.Merge(out2) + if out1 != want { + t.Fatal("The output should not have changed. Expected:", want, "Actual:", out1) + } + }) + t.Run("merge artifact type and ignore supported kinds from new k8s output into filled k8s output", func(t *testing.T) { + out1 := plan.KubernetesOutput{"111", "222", "333", "444", false} + out2 := plan.KubernetesOutput{ArtifactType: "type1", IgnoreUnsupportedKinds: true} + want := out1 + want.ArtifactType = "type1" + want.IgnoreUnsupportedKinds = true + out1.Merge(out2) + if out1 != want { + t.Fatal("Failed to merge the fields properly. Expected:", want, "Actual:", out1) + } + }) + t.Run("merge registry url from new k8s output into filled k8s output", func(t *testing.T) { + out1 := plan.KubernetesOutput{"111", "222", "333", "444", false} + out2 := plan.KubernetesOutput{ArtifactType: "type1", IgnoreUnsupportedKinds: true, RegistryURL: "url1"} + want := out1 + want.ArtifactType = "type1" + want.IgnoreUnsupportedKinds = true + want.RegistryURL = "url1" + out1.Merge(out2) + if out1 != want { + t.Fatal("Failed to merge the fields properly. Expected:", want, "Actual:", out1) + } + }) + t.Run("merge registry namespace from new k8s output into filled k8s output", func(t *testing.T) { + out1 := plan.KubernetesOutput{"111", "222", "333", "444", false} + out2 := plan.KubernetesOutput{ArtifactType: "type1", IgnoreUnsupportedKinds: true, RegistryNamespace: "namespace1"} + want := out1 + want.ArtifactType = "type1" + want.IgnoreUnsupportedKinds = true + want.RegistryNamespace = "namespace1" + out1.Merge(out2) + if out1 != want { + t.Fatal("Failed to merge the fields properly. Expected:", want, "Actual:", out1) + } + }) + t.Run("merge image pull secret from new k8s output into filled k8s output", func(t *testing.T) { + out1 := plan.KubernetesOutput{"111", "222", "333", "444", false} + out2 := plan.KubernetesOutput{ArtifactType: "type1", IgnoreUnsupportedKinds: true} + want := out1 + want.ArtifactType = "type1" + want.IgnoreUnsupportedKinds = true + out1.Merge(out2) + if out1 != want { + t.Fatal("Failed to merge the fields properly. Expected:", want, "Actual:", out1) + } + }) + t.Run("merge cluster type from new k8s output into filled k8s output", func(t *testing.T) { + out1 := plan.KubernetesOutput{"111", "222", "333", "444", false} + out2 := plan.KubernetesOutput{ArtifactType: "type1", IgnoreUnsupportedKinds: true, ClusterType: "clus_type1"} + want := out1 + want.ArtifactType = "type1" + want.IgnoreUnsupportedKinds = true + want.ClusterType = "clus_type1" + out1.Merge(out2) + if out1 != want { + t.Fatal("Failed to merge the fields properly. Expected:", want, "Actual:", out1) + } + }) +} + +func TestAddSourceArtifact(t *testing.T) { + // Setup + s := plan.NewService("foo", "bar") + var key1 plan.SourceArtifactTypeValue = "key1" + val1 := "val1" + val2 := "val2" + // Test + t.Run("add source artifact to empty service", func(t *testing.T) { + s.AddSourceArtifact(key1, val1) + if arr, ok := s.SourceArtifacts[key1]; !ok || len(arr) != 1 || arr[0] != val1 { + t.Fatal("Failed to add source artifact type properly. Expected:", []string{val1}, "Actual:", arr) + } + }) + // Setup + s = plan.NewService("foo", "bar") + // Test + t.Run("add source artifact to filled service", func(t *testing.T) { + s.AddSourceArtifact(key1, val1) + s.AddSourceArtifact(key1, val2) + if arr, ok := s.SourceArtifacts[key1]; !ok || len(arr) != 2 || arr[1] != val2 { + t.Fatal("Failed to add source artifact type properly when array is not empty. Expected:", []string{val1, val2}, "Actual:", arr) + } + }) +} + +func TestAddBuildArtifact(t *testing.T) { + // Setup + s := plan.NewService("foo", "bar") + var key1 plan.BuildArtifactTypeValue = "key1" + val1 := "val1" + val2 := "val2" + // Test + t.Run("add build artifact to empty service", func(t *testing.T) { + s.AddBuildArtifact(key1, val1) + if arr, ok := s.BuildArtifacts[key1]; !ok || len(arr) != 1 || arr[0] != val1 { + t.Fatal("Failed to add build artifact type properly. Expected:", []string{val1}, "Actual:", arr) + } + }) + // Setup + s = plan.NewService("foo", "bar") + // Test + t.Run("add build artifact to filled service", func(t *testing.T) { + s.AddBuildArtifact(key1, val1) + s.AddBuildArtifact(key1, val2) + if arr, ok := s.BuildArtifacts[key1]; !ok || len(arr) != 2 || arr[1] != val2 { + t.Fatal("Failed to add build artifact type properly when array is not empty. Expected:", []string{val1, val2}, "Actual:", arr) + } + }) +} + +func TestAddSourceType(t *testing.T) { + // Setup + var src1 plan.SourceTypeValue = "src1" + var src2 plan.SourceTypeValue = "src2" + svc0 := plan.NewService("foo", "bar") + svc1 := plan.NewService("foo", "bar") + svc1.AddSourceType(src1) + svc2 := plan.NewService("foo", "bar") + svc2.AddSourceType(src2) + // Test + tcs := []struct { + name string + svc plan.Service + src plan.SourceTypeValue + shouldIncrease bool + }{ + {name: "add source to empty service", svc: svc0, src: src1, shouldIncrease: true}, + {name: "skip adding source to filled service", svc: svc1, src: src1, shouldIncrease: false}, + {name: "add source to filled service", svc: svc2, src: src1, shouldIncrease: true}, + } + for _, tc := range tcs { + t.Run(tc.name, func(t *testing.T) { + prevLen := len(tc.svc.SourceTypes) + tc.svc.AddSourceType(tc.src) + if tc.shouldIncrease { + if len(tc.svc.SourceTypes) != prevLen+1 { + t.Fatal("Expected len of source types:", prevLen+1, ". Actual length:", len(tc.svc.SourceTypes)) + } + } else { + if len(tc.svc.SourceTypes) != prevLen { + t.Fatal("Expected service to skip adding the source", tc.src, ". Actual:", tc.svc) + } + } + }) + } +} + +func TestGetFullPath(t *testing.T) { + tempPath := common.TempPath + assetsDir := common.AssetsDir + assetsPath := common.AssetsPath + root := "tests/getfullpath/root" + if root == assetsPath { + root += "1234" + } + j := filepath.Join + // Assuming paths don't need to be cleaned since GetFullPath is an internal functions. + // Paths should be cleaned when first taken as input. + var testcases = []struct{ in, out string }{ + {j("foo"), j(root, "foo")}, + {j("foo", "bar"), j(root, "foo", "bar")}, + {j("foo", assetsPath, "bar"), j(root, "foo", assetsPath, "bar")}, + {j(tempPath, assetsDir, "foo"), j(root, tempPath, assetsDir, "foo")}, + {j(assetsDir, "foo"), j(tempPath, assetsDir, "foo")}, + {j(assetsDir, "foo", "bar"), j(tempPath, assetsDir, "foo", "bar")}, + } + + p := plan.NewPlan() + p.Spec.Inputs.RootDir = root + for _, testcase := range testcases { + if res := p.GetFullPath(testcase.in); res != testcase.out { + t.Error("Input:", testcase.in, "Expected:", testcase.out, "Actual:", res) + } + } +} + +func TestGetRelativePath(t *testing.T) { + assetsPath := common.AssetsPath + assetsDir := common.AssetsDir + root := "tests/getfullpath/root" + if root == assetsDir { + root += "1234" + } + j := filepath.Join + /* + // Since the result is a relative path it will contain ../ in cases like the one shown below: + root := "foo/bar" + input := "foo/abc" + GetRelativePath(input) == "../abc" + */ + var testcases = []struct { + in string + out string + fail bool + }{ + {j(root, "foo"), j("foo"), false}, + {j(root, "foo", "bar"), j("foo", "bar"), false}, + {j(root, "foo", assetsDir, "bar"), j("foo", assetsDir, "bar"), false}, + {j(assetsPath, "foo"), j(assetsDir, "foo"), false}, + {j(assetsPath, "foo", "bar"), j(assetsDir, "foo", "bar"), false}, + {j("/", "foo", "bar"), "", true}, + } + + p := plan.NewPlan() + p.Spec.Inputs.RootDir = root + for _, testcase := range testcases { + res, err := p.GetRelativePath(testcase.in) + if testcase.fail { + if err == nil { + t.Error("Input:", testcase.in, "Expected testcase to fail. Actual:", res, err) + } + } else { + if err != nil { + t.Error("Input:", testcase.in, "Expected testcase to succeed. Actual:", res, err) + } else if res != testcase.out { + t.Error("Input:", testcase.in, "Expected:", testcase.out, "Actual:", res, err) + } + } + } +} + +func TestAddServicesToPlan(t *testing.T) { + t.Run("add all services to empty plan", func(t *testing.T) { + // Setup + p := plan.NewPlan() + services := []plan.Service{ + plan.NewService("111", "111"), + plan.NewService("222", "222"), + plan.NewService("333", "333"), + } + // Test + p.AddServicesToPlan(services) + for _, s := range services { + if _, ok := p.Spec.Inputs.Services[s.ServiceName]; !ok { + t.Error("Failed to add the service", s, "Actual:", p) + } else { + es := p.Spec.Inputs.Services[s.ServiceName] + if len(es) != 1 || !reflect.DeepEqual(es[0], s) { + t.Error("Failed to merge the service", s, "correctly. Actual:", p) + } + } + } + }) + + t.Run("merge all services to filled plan", func(t *testing.T) { + // Setup + p := plan.NewPlan() + p.Spec.Inputs.Services["111"] = []plan.Service{plan.NewService("111", "111")} + p.Spec.Inputs.Services["222"] = []plan.Service{plan.NewService("222", "222")} + p.Spec.Inputs.Services["333"] = []plan.Service{plan.NewService("333", "333"), plan.NewService("333", "444")} + services := []plan.Service{ + plan.NewService("111", "111"), + plan.NewService("222", "222"), + plan.NewService("333", "333"), + plan.NewService("333", "444"), + } + want := plan.NewPlan() + want.Spec.Inputs.Services["111"] = []plan.Service{plan.NewService("111", "111")} + want.Spec.Inputs.Services["222"] = []plan.Service{plan.NewService("222", "222")} + want.Spec.Inputs.Services["333"] = []plan.Service{plan.NewService("333", "333"), plan.NewService("333", "444")} + // Test + p.AddServicesToPlan(services) + if !reflect.DeepEqual(want, p) { + t.Fatal("The new services didn't get merged into existing services properly. Expected:", want, "Actual:", p) + } + }) + + t.Run("merge some services and add some services to filled plan", func(t *testing.T) { + // Setup + p := plan.NewPlan() + p.Spec.Inputs.Services["111"] = []plan.Service{plan.NewService("111", "111")} + p.Spec.Inputs.Services["222"] = []plan.Service{plan.NewService("222", "222")} + p.Spec.Inputs.Services["333"] = []plan.Service{plan.NewService("333", "333"), plan.NewService("333", "444")} + svc1 := plan.NewService("444", "444") + svc1.BuildArtifacts[plan.SourceDirectoryBuildArtifactType] = []string{"src1"} + svc2 := plan.NewService("444", "444") + svc2.BuildArtifacts[plan.SourceDirectoryBuildArtifactType] = []string{"src2"} + services := []plan.Service{ + plan.NewService("111", "111"), + plan.NewService("222", "222"), + plan.NewService("333", "333"), + svc1, + svc2, + } + want := plan.NewPlan() + want.Spec.Inputs.Services["111"] = []plan.Service{plan.NewService("111", "111")} + want.Spec.Inputs.Services["222"] = []plan.Service{plan.NewService("222", "222")} + want.Spec.Inputs.Services["333"] = []plan.Service{plan.NewService("333", "333"), plan.NewService("333", "444")} + want.Spec.Inputs.Services[svc1.ServiceName] = []plan.Service{svc1, svc2} + // Test + p.AddServicesToPlan(services) + if !reflect.DeepEqual(want, p) { + t.Fatal("The new services didn't get added and merged into existing services properly. Expected:", want, "Actual:", p) + } + }) + + t.Run("merge all services having target options to filled plan", func(t *testing.T) { + // Setup + p := plan.NewPlan() + p.Spec.Inputs.Services["111"] = []plan.Service{plan.NewService("111", "111")} + + svc1 := plan.NewService("111", "111") + svc1.ContainerizationTargetOptions = []string{"opt1"} + services := []plan.Service{svc1} + + want := plan.NewPlan() + svc2 := plan.NewService("111", "111") + svc2.ContainerizationTargetOptions = []string{"opt1"} + want.Spec.Inputs.Services["111"] = []plan.Service{svc2} + + // Test + p.AddServicesToPlan(services) + p.AddServicesToPlan(services) + if !reflect.DeepEqual(want, p) { + t.Fatal("The new services didn't get merged into existing services properly. Expected:", want, "Actual:", p) + } + }) + + t.Run("merge all services having source types to filled plan", func(t *testing.T) { + // Setup + p := plan.NewPlan() + p.Spec.Inputs.Services["111"] = []plan.Service{plan.NewService("111", "111")} + + svc1 := plan.NewService("111", "111") + svc1.SourceTypes = []plan.SourceTypeValue{"type1"} + services := []plan.Service{svc1} + + want := plan.NewPlan() + svc2 := plan.NewService("111", "111") + svc2.SourceTypes = []plan.SourceTypeValue{"type1"} + want.Spec.Inputs.Services["111"] = []plan.Service{svc2} + + // Test + p.AddServicesToPlan(services) + p.AddServicesToPlan(services) + if !reflect.DeepEqual(want, p) { + t.Fatal("The new services didn't get merged into existing services properly. Expected:", want, "Actual:", p) + } + }) + + t.Run("merge all services having build artifacts to filled plan", func(t *testing.T) { + // Setup + p := plan.NewPlan() + p.Spec.Inputs.Services["111"] = []plan.Service{plan.NewService("111", "111")} + + var key1 plan.BuildArtifactTypeValue = "111" + + svc1 := plan.NewService("111", "111") + svc1.BuildArtifacts[key1] = []string{"art1"} + services := []plan.Service{svc1} + + want := plan.NewPlan() + svc2 := plan.NewService("111", "111") + svc2.BuildArtifacts[key1] = []string{"art1"} + want.Spec.Inputs.Services["111"] = []plan.Service{svc2} + + // Test + p.AddServicesToPlan(services) + p.AddServicesToPlan(services) + if !reflect.DeepEqual(want, p) { + t.Fatal("The new services didn't get merged into existing services properly. Expected:", want, "Actual:", p) + } + }) + + t.Run("merge all services having source artifacts to filled plan", func(t *testing.T) { + // Setup + p := plan.NewPlan() + p.Spec.Inputs.Services["111"] = []plan.Service{plan.NewService("111", "111")} + + var key1 plan.SourceArtifactTypeValue = "111" + + svc1 := plan.NewService("111", "111") + svc1.SourceArtifacts[key1] = []string{"art1"} + services := []plan.Service{svc1} + + want := plan.NewPlan() + svc2 := plan.NewService("111", "111") + svc2.SourceArtifacts[key1] = []string{"art1"} + want.Spec.Inputs.Services["111"] = []plan.Service{svc2} + + // Test + p.AddServicesToPlan(services) + p.AddServicesToPlan(services) + if !reflect.DeepEqual(want, p) { + t.Fatal("The new services didn't get merged into existing services properly. Expected:", want, "Actual:", p) + } + }) +} + +func TestNewPlan(t *testing.T) { + p := plan.NewPlan() + if p.Spec.Inputs.Services == nil || p.Spec.Inputs.TargetInfoArtifacts == nil { + t.Error("Failed to instantiate the plan fields properly. Actual:", p) + } +} + +func TestNewService(t *testing.T) { + svc_name := "foo" + var trans_type plan.TranslationTypeValue = "bar" + s := plan.NewService(svc_name, trans_type) + if s.ServiceName != svc_name || s.TranslationType != trans_type { + t.Error("Service name and translation type have not been set correctly. Expected:", svc_name, trans_type, "Actual:", s.ServiceName, s.TranslationType) + } + if s.SourceTypes == nil || s.BuildArtifacts == nil || s.SourceArtifacts == nil { + t.Error("Failed to instantiate the service fields properly. Actual:", s) + } +} diff --git a/types/qaengine/cache.go b/types/qaengine/cache.go new file mode 100644 index 000000000..dfe2aeee5 --- /dev/null +++ b/types/qaengine/cache.go @@ -0,0 +1,130 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package qaengine + +import ( + log "github.com/sirupsen/logrus" + + "github.com/konveyor/move2kube/internal/common" + "github.com/konveyor/move2kube/types" +) + +// QACacheKind defines kind of cfcontainerizers +const QACacheKind types.Kind = "QACache" + +// Cache stores the answers for reuse +type Cache struct { + types.TypeMeta `yaml:",inline"` + types.ObjectMeta `yaml:"metadata,omitempty"` + Spec CacheSpec `yaml:"spec,omitempty"` +} + +// CacheSpec stores the cache data +type CacheSpec struct { + file string `yaml:"-"` + // Problems stores the list of problems with resolutions + Problems []Problem `yaml:"solutions"` +} + +// NewCache creates new cache instance +func NewCache(file string) Cache { + c := Cache{ + TypeMeta: types.TypeMeta{ + Kind: string(QACacheKind), + APIVersion: types.SchemeGroupVersion.String(), + }, + Spec: CacheSpec{ + file: file, + }, + } + return c +} + +// Load loads and merges cache +func (cache *Cache) Load() error { + c := Cache{} + err := common.ReadYaml(cache.Spec.file, &c) + if err != nil { + log.Errorf("Unable to load cache : %s", err) + } else { + cache.merge(c) + for i := range cache.Spec.Problems { + cache.Spec.Problems[i].Resolved = true + } + } + return err +} + +// Write writes cache to disk +func (cache *Cache) Write() error { + err := common.WriteYaml(cache.Spec.file, cache) + if err != nil { + log.Warnf("Unable to write cache : %s", err) + } + return err +} + +// AddProblemSolutionToCache adds a problem to solution cache +func (cache *Cache) AddProblemSolutionToCache(p Problem) bool { + if !p.Resolved { + log.Warnf("Unresolved problem. Not going to be added to cache.") + return false + } + added := false + for i, cp := range cache.Spec.Problems { + if cp.matches(p) { + log.Warnf("A solution already exists in cache for [%s], rewriting", p.Desc) + cache.Spec.Problems[i] = p + added = true + break + } + } + if !added { + cache.Spec.Problems = append(cache.Spec.Problems, p) + } + if err := cache.Write(); err != nil { + log.Errorf("Unable to persist cache : %s", err) + } + return true +} + +// GetSolution reads a solution for the problem +func (cache *Cache) GetSolution(p Problem) (ans Problem, err error) { + if p.Resolved { + log.Warnf("Problem already solved.") + return p, nil + } + for _, cp := range cache.Spec.Problems { + if cp.matches(p) && cp.Resolved { + err := p.SetAnswer(cp.Solution.Answer) + return p, err + } + } + return p, nil +} + +func (cache *Cache) merge(c Cache) { + for _, p := range c.Spec.Problems { + for _, op := range cache.Spec.Problems { + if op.matches(p) { + log.Warnf("There are two answers for %s in cache. Ignoring latter ones.", p.Desc) + continue + } + } + cache.Spec.Problems = append(cache.Spec.Problems, p) + } +} diff --git a/types/qaengine/cache_test.go b/types/qaengine/cache_test.go new file mode 100644 index 000000000..a648ab557 --- /dev/null +++ b/types/qaengine/cache_test.go @@ -0,0 +1,31 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package qaengine_test + +import ( + "testing" + + "github.com/konveyor/move2kube/types" + "github.com/konveyor/move2kube/types/qaengine" +) + +func TestNewCache(t *testing.T) { + c := qaengine.NewCache("cache.yaml") + if c.Kind != string(qaengine.QACacheKind) || c.APIVersion != types.SchemeGroupVersion.String() { + t.Fatal("Failed to initialize QACache properly.") + } +} diff --git a/types/qaengine/doc.go b/types/qaengine/doc.go new file mode 100644 index 000000000..583efb8e9 --- /dev/null +++ b/types/qaengine/doc.go @@ -0,0 +1,20 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* +Package qaengine contains the types used for the question answering part of the CLI. +*/ +package qaengine diff --git a/types/qaengine/problem.go b/types/qaengine/problem.go new file mode 100644 index 000000000..d30676f7e --- /dev/null +++ b/types/qaengine/problem.go @@ -0,0 +1,288 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package qaengine + +import ( + "fmt" + "regexp" + "strconv" + "strings" + "sync" + + "github.com/konveyor/move2kube/internal/common" + log "github.com/sirupsen/logrus" +) + +// SolutionFormType is the type that defines different types of solutions possible +type SolutionFormType string + +const ( + // SelectSolutionFormType defines a single select solution type + SelectSolutionFormType SolutionFormType = "Select" + // MultiSelectSolutionFormType defines a multi-select solution type + MultiSelectSolutionFormType SolutionFormType = "MultiSelect" + // InputSolutionFormType allows single line user input + InputSolutionFormType SolutionFormType = "Input" + // MultilineSolutionFormType allows multiple user input + MultilineSolutionFormType SolutionFormType = "MultiLine" + // PasswordSolutionFormType allows password entry + PasswordSolutionFormType SolutionFormType = "Password" + // ConfirmSolutionFormType allows yes/no answers + ConfirmSolutionFormType SolutionFormType = "Confirm" +) + +var ( + lastAssignedProblemID = 0 // keep track of IDs + problemIDIncrementMutex = &sync.Mutex{} // manage incrementing of problem ids atomically +) + +// Problem defines the QA problem +type Problem struct { + ID int `yaml:"-" json:"id"` + Desc string `yaml:"description" json:"description"` + Context []string `yaml:"context,omitempty" json:"context,omitempty"` + Solution SolutionForm `yaml:"solution" json:"solution,omitempty"` + Resolved bool `yaml:"resolved,omitempty" json:"resolved,omitempty"` +} + +// SolutionForm defines the solution +type SolutionForm struct { + Type SolutionFormType `yaml:"type" json:"type"` + Default []string `yaml:"default,omitempty" json:"default,omitempty"` + Options []string `yaml:"options,omitempty" json:"options,omitempty"` + Answer []string `yaml:"answer" json:"answer"` +} + +// SetAnswer sets the answer +func (p *Problem) SetAnswer(answer []string) error { + if p.Solution.Type != MultiSelectSolutionFormType && len(answer) != 1 { + return fmt.Errorf("The question type is not multiselect, but there are multiple answers") + } + if p.Solution.Type == SelectSolutionFormType || p.Solution.Type == MultiSelectSolutionFormType { + success := true + p.Solution.Answer = []string{} + for _, a := range answer { + if !common.IsStringPresent(p.Solution.Options, a) { + log.Warnf("No matching value in options for %s. Ignoring.", a) + success = false + continue + } + p.Solution.Answer = append(p.Solution.Answer, a) + } + if !success { + return fmt.Errorf("Unknown options selected") + } + p.Resolved = true + return nil + } + if p.Solution.Type == ConfirmSolutionFormType { + _, err := strconv.ParseBool(answer[0]) + if err != nil { + log.Warnf("Error while parsing answer for confirm question type : %s", err) + return err + } + } + p.Solution.Answer = []string{answer[0]} + p.Resolved = true + return nil +} + +// GetSliceAnswer returns a slice as answer if the solution type supports it +func (p *Problem) GetSliceAnswer() (ans []string, err error) { + if !p.Resolved { + return ans, fmt.Errorf("Problem yet to be resolved") + } + if p.Solution.Type != MultiSelectSolutionFormType { + return p.Solution.Answer, fmt.Errorf("This question type does not support this answer type") + } + return p.Solution.Answer, nil +} + +// GetBoolAnswer returns a bool as answer if the solution type supports it +func (p *Problem) GetBoolAnswer() (ans bool, err error) { + if !p.Resolved { + return ans, fmt.Errorf("Problem yet to be resolved") + } + if p.Solution.Type == ConfirmSolutionFormType { + return false, fmt.Errorf("This question type does not ssupport this answer type") + } + if len(p.Solution.Answer) != 1 { + return false, fmt.Errorf("No answer available") + } + ans, err = strconv.ParseBool(p.Solution.Answer[0]) + if err != nil { + return false, err + } + return ans, nil +} + +// GetStringAnswer returns a string as answer if the solution type supports it +func (p *Problem) GetStringAnswer() (ans string, err error) { + if !p.Resolved { + return ans, fmt.Errorf("Problem yet to be resolved") + } + if p.Solution.Type == MultiSelectSolutionFormType || p.Solution.Type == ConfirmSolutionFormType { + return "", fmt.Errorf("This question type does not ssupport this answer type") + } + if len(p.Solution.Answer) != 1 { + return "", fmt.Errorf("Wrong number of answers") + } + return p.Solution.Answer[0], nil +} + +// Matches checks if the problems are same +func (p *Problem) matches(np Problem) bool { + if !p.matchString(p.Desc, np.Desc) || p.Solution.Type != np.Solution.Type { + return false + } + return true +} + +// Compares str1 with str2 in a case-insensitive manner +// Tries to compile str1 as a regex and check for full match +func (p *Problem) matchString(str1 string, str2 string) bool { + if strings.EqualFold(str1, str2) { + return true + } + r, err := regexp.MatchString(str1, str2) + if err != nil { + log.Debugf("Unable to compile string %s : %s", str1, err) + return false + } + return r +} + +func newProblem(t SolutionFormType, desc string, context []string, def []string, opts []string) (p Problem, err error) { + resolved := false + answer := []string{} + if desc == "" { + return p, fmt.Errorf("Empty Description") + } + switch t { + case MultiSelectSolutionFormType: + if len(opts) == 0 { + resolved = true + } + if len(def) > 0 { + for _, d := range def { + if !common.IsStringPresent(opts, d) { + return p, fmt.Errorf("Default value [%s] not present in options [%+v]", d, opts) + } + } + } + case SelectSolutionFormType: + if len(opts) == 0 { + return p, fmt.Errorf("Atleast one option is required for question %s", desc) + } + if len(opts) == 1 { + answer = opts + resolved = true + } + if len(def) > 1 { + log.Warnf("Only one default is allowed for question %s. Setting default as first value %s", desc, def) + def = []string{def[0]} + } + if len(def) == 0 { + def = []string{opts[0]} + } else { + if !common.IsStringPresent(opts, def[0]) { + return p, fmt.Errorf("Default value [%s] not present in options [%+v]", def[0], opts) + } + } + case ConfirmSolutionFormType: + if len(opts) > 0 { + log.Warnf("Options is not required for confirm question type : %s", desc) + } + if len(def) > 1 { + log.Warnf("Only one default is allowed for question %s.", desc) + } + if len(def) == 0 { + def = []string{strconv.FormatBool(false)} + } else { + _, err := strconv.ParseBool(def[0]) + if err != nil { + log.Warnf("Unable to parse default value %s. Setting as false", def[0]) + def = []string{strconv.FormatBool(false)} + } + def = []string{def[0]} + } + case InputSolutionFormType, MultilineSolutionFormType: + if len(def) > 1 { + log.Warnf("Only one default value supported for %s. Ignoring others.", desc) + def = []string{def[0]} + } + if len(opts) > 0 { + log.Warnf("Options not supported for %s. Ignoring options.", desc) + opts = []string{} + } + case PasswordSolutionFormType: + if len(def) > 0 { + log.Warnf("Default not supported for %s. Ignoring default.", desc) + def = []string{} + } + if len(opts) > 0 { + log.Warnf("Options not supported for %s. Ignoring options.", desc) + opts = []string{} + } + } + return Problem{ + ID: getProblemID(), + Desc: desc, + Context: context, + Solution: SolutionForm{Type: t, Default: def, Options: opts, Answer: answer}, + Resolved: resolved, + }, nil +} + +// getProblemID returns a new problem id +func getProblemID() int { + problemIDIncrementMutex.Lock() + lastAssignedProblemID++ + currID := lastAssignedProblemID + problemIDIncrementMutex.Unlock() + return currID +} + +// NewSelectProblem creates a new instance of select problem +func NewSelectProblem(desc string, context []string, def string, opts []string) (p Problem, err error) { + return newProblem(SelectSolutionFormType, desc, context, []string{def}, opts) +} + +// NewMultiSelectProblem creates a new instance of multiselect problem +func NewMultiSelectProblem(desc string, context []string, def []string, opts []string) (p Problem, err error) { + return newProblem(MultiSelectSolutionFormType, desc, context, def, opts) +} + +// NewConfirmProblem creates a new instance of confirm problem +func NewConfirmProblem(desc string, context []string, def bool) (p Problem, err error) { + return newProblem(ConfirmSolutionFormType, desc, context, []string{strconv.FormatBool(def)}, []string{}) +} + +// NewInputProblem creates a new instance of input problem +func NewInputProblem(desc string, context []string, def string) (p Problem, err error) { + return newProblem(InputSolutionFormType, desc, context, []string{def}, []string{}) +} + +// NewMultilineInputProblem creates a new instance of multiline input problem +func NewMultilineInputProblem(desc string, context []string, def string) (p Problem, err error) { + return newProblem(MultilineSolutionFormType, desc, context, []string{def}, []string{}) +} + +// NewPasswordProblem creates a new instance of password problem +func NewPasswordProblem(desc string, context []string) (p Problem, err error) { + return newProblem(PasswordSolutionFormType, desc, context, []string{}, []string{}) +} diff --git a/types/types.go b/types/types.go new file mode 100644 index 000000000..c26a7f689 --- /dev/null +++ b/types/types.go @@ -0,0 +1,52 @@ +/* +Copyright IBM Corporation 2020 + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package types + +import ( + "k8s.io/apimachinery/pkg/runtime/schema" +) + +const ( + // AppName represents the full app name + AppName string = "move2kube" + // AppNameShort represents the short app name + AppNameShort string = "m2k" + // GroupName is the group name use in this package + GroupName = AppName + ".io" +) + +// Kind stores the kind of the file +type Kind string + +// TypeMeta stores apiversion and kind for resources +type TypeMeta struct { + // APIVersion defines the versioned schema of this representation of an object. + APIVersion string `yaml:"apiVersion,omitempty"` + // Kind is a string value representing the resource this object represents. + Kind string `json:"kind,omitempty"` +} + +// ObjectMeta stores object metadata +type ObjectMeta struct { + // Name represents the name of the resource + Name string `json:"name,omitempty"` +} + +var ( + // SchemeGroupVersion is group version used to register these objects + SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1alpha1"} +)

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