├── .python-version ├── pkg ├── addons │ ├── testdata │ │ └── testfile │ ├── assets │ │ ├── doc.go │ │ ├── assets_dev.go │ │ ├── assets.go │ │ └── generator │ │ │ └── assets_generate.go │ ├── addon_test.go │ ├── vfs_importer.go │ ├── transform_test.go │ └── transform.go ├── apis │ └── wksprovider │ │ ├── machine │ │ ├── crds │ │ │ ├── doc.go │ │ │ ├── crds_dev.go │ │ │ └── assets_generate.go │ │ └── scripts │ │ │ ├── doc.go │ │ │ ├── scripts_dev.go │ │ │ ├── all │ │ │ └── dummy.sh │ │ │ ├── assets_generate.go │ │ │ └── README.md │ │ └── controller │ │ └── manifests │ │ ├── doc.go │ │ ├── yaml │ │ ├── 01_namespace.yaml │ │ ├── 03_secrets.yaml │ │ ├── 05_sealed_secret_crd.yaml │ │ ├── 04_capi_controller.yaml │ │ └── 04_controller.yaml │ │ ├── manifests_dev.go │ │ └── assets_generate.go ├── utilities │ ├── manifest │ │ └── manifest.go │ ├── indent.go │ ├── print.go │ ├── path │ │ ├── path_test.go │ │ └── path.go │ ├── indent_test.go │ ├── version │ │ ├── version.go │ │ └── version_test.go │ ├── tarball │ │ └── tarball.go │ └── file.go ├── kubernetes │ └── version.go ├── cluster │ ├── node │ │ ├── node.go │ │ └── node_test.go │ └── nodes │ │ ├── nodes.go │ │ └── nodes_test.go ├── version │ └── version.go ├── plan │ ├── resource │ │ ├── common.go │ │ └── kubectl_annotate.go │ ├── runners │ │ └── ssh │ │ │ └── ssh.go │ └── recipe │ │ └── install_plans.go ├── security │ └── key.go ├── specs │ └── parse_test.go ├── git │ └── git.go └── manifests │ └── manifests_test.go ├── test ├── container │ ├── .gitignore │ ├── images │ │ └── names.go │ ├── resource │ │ ├── testdata │ │ │ └── daemon.json │ │ ├── common_test.go │ │ ├── run_test.go │ │ ├── os_test.go │ │ ├── rpm_test.go │ │ ├── file_test.go │ │ ├── deb_test.go │ │ ├── service_test.go │ │ └── dir_test.go │ └── ssh │ │ ├── common_test.go │ │ ├── exitcode_test.go │ │ └── loginshell_test.go └── integration │ ├── bin │ ├── down.sh │ ├── test.sh │ ├── up.sh │ └── internal │ │ ├── colourise.sh │ │ └── provisioning │ │ ├── gcp │ │ ├── outputs.tf │ │ └── variables.tf │ │ └── README.md │ ├── test │ ├── assets │ │ ├── kubernetes.keytab │ │ ├── rootCA.pem │ │ ├── server.crt │ │ ├── server.key │ │ └── ss.cert │ ├── help_test.go │ ├── download.go │ ├── terraform.go │ ├── terraform_test.go │ └── main_test.go │ └── spawn │ ├── run.go │ └── executor_test.go ├── examples ├── footloose │ ├── user.sudoers │ ├── docker-config.yaml │ ├── centos7 │ │ ├── ignite │ │ │ ├── multimaster.yaml │ │ │ └── singlemaster.yaml │ │ └── docker │ │ │ ├── multimaster.yaml │ │ │ └── singlemaster.yaml │ ├── ubuntu18.04 │ │ ├── ignite │ │ │ ├── multimaster.yaml │ │ │ └── singlemaster.yaml │ │ └── docker │ │ │ ├── multimaster.yaml │ │ │ └── singlemaster.yaml │ ├── upload-controller-image.sh │ ├── machines.yaml │ ├── upload-image.sh │ └── machines-multimaster.yaml ├── vagrant │ ├── .gitignore │ ├── docker-config.yaml │ ├── Vagrantfile │ ├── Vagrantfile-ubuntu │ └── machines.yaml └── gce │ ├── .gitignore │ ├── delete-instances.sh │ ├── generate-machines-manifest.sh │ ├── delete-network.sh │ ├── create-instances.sh │ ├── cluster.yaml │ ├── create-network.sh │ └── generate-machines-manifest.js ├── DEPENDENCIES ├── tools ├── config_management │ ├── roles │ │ ├── setup-apt │ │ │ ├── files │ │ │ │ └── apt-daily.timer.conf │ │ │ └── tasks │ │ │ │ └── main.yml │ │ ├── docker-prerequisites │ │ │ └── tasks │ │ │ │ ├── main.yml │ │ │ │ └── debian.yml │ │ ├── docker-configuration │ │ │ ├── files │ │ │ │ └── docker.conf │ │ │ └── tasks │ │ │ │ └── main.yml │ │ ├── docker-from-get.docker.com │ │ │ └── tasks │ │ │ │ ├── main.yml │ │ │ │ ├── debian.yml │ │ │ │ └── redhat.yml │ │ ├── docker-from-tarball │ │ │ ├── vars │ │ │ │ └── main.yml │ │ │ └── tasks │ │ │ │ └── main.yml │ │ ├── docker-from-docker-ce-repo │ │ │ └── tasks │ │ │ │ ├── main.yml │ │ │ │ ├── redhat.yml │ │ │ │ └── debian.yml │ │ ├── docker-from-docker-repo │ │ │ └── tasks │ │ │ │ ├── main.yml │ │ │ │ ├── redhat.yml │ │ │ │ └── debian.yml │ │ ├── kubernetes-install │ │ │ └── tasks │ │ │ │ ├── main.yml │ │ │ │ ├── redhat.yml │ │ │ │ └── debian.yml │ │ ├── kubelet-stop │ │ │ └── tasks │ │ │ │ └── main.yml │ │ ├── weave-net │ │ │ └── tasks │ │ │ │ └── main.yml │ │ ├── kubernetes-docker-images │ │ │ └── tasks │ │ │ │ └── main.yml │ │ ├── weave-net-sources │ │ │ └── tasks │ │ │ │ └── main.yml │ │ ├── weave-kube │ │ │ └── tasks │ │ │ │ └── main.yml │ │ ├── docker-install │ │ │ └── tasks │ │ │ │ └── main.yml │ │ ├── dev-tools │ │ │ └── tasks │ │ │ │ └── main.yml │ │ ├── golang-from-tarball │ │ │ └── tasks │ │ │ │ └── main.yml │ │ ├── sock-shop │ │ │ └── tasks │ │ │ │ └── tasks.yml │ │ ├── setup-ansible │ │ │ └── pre_tasks │ │ │ │ └── main.yml │ │ ├── weave-net-utilities │ │ │ └── tasks │ │ │ │ └── main.yml │ │ └── kubernetes-start │ │ │ └── tasks │ │ │ └── main.yml │ ├── group_vars │ │ └── all │ ├── setup_bare_docker.yml │ ├── setup_weave-net_debug.yml │ ├── setup_weave-net_test.yml │ ├── setup_weave-net_dev.yml │ ├── setup_weave-kube.yml │ └── library │ │ └── setup_ansible_dependencies.yml ├── embedmd.sh ├── check-embedmd.sh ├── .gitignore ├── files-with-type ├── go-lint ├── LICENSE ├── image-tag └── build │ ├── golang │ ├── build.sh │ └── Dockerfile │ └── Makefile ├── addons ├── vendor │ ├── kubernetes-mixin │ │ ├── .gitignore │ │ ├── lib │ │ │ ├── alerts.jsonnet │ │ │ ├── rules.jsonnet │ │ │ ├── dashboards.jsonnet │ │ │ ├── promgrafonnet │ │ │ │ ├── promgrafonnet.libsonnet │ │ │ │ ├── numbersinglestat.libsonnet │ │ │ │ └── gauge.libsonnet │ │ │ └── utils.libsonnet │ │ ├── mixin.libsonnet │ │ ├── dashboards │ │ │ ├── dashboards.libsonnet │ │ │ └── defaults.libsonnet │ │ ├── alerts │ │ │ ├── alerts.libsonnet │ │ │ ├── absent_alerts.libsonnet │ │ │ ├── add-runbook-links.libsonnet │ │ │ └── storage_alerts.libsonnet │ │ ├── .circleci │ │ │ └── config.yml │ │ ├── jsonnetfile.json │ │ └── Makefile │ ├── etcd-mixin │ │ ├── README.md │ │ └── test.yaml │ └── ksonnet │ │ └── ksonnet.beta.3 │ │ └── k.libsonnet ├── weave-net │ └── addon.json ├── flux-helm-op │ └── addon.json ├── make-vendor.sh ├── flux │ └── addon.json └── mixin.libsonnet ├── docs ├── requirements.txt ├── index.md └── _static │ ├── custom.css │ └── logo.svg ├── environments ├── local-rpm-repo │ ├── docker-ce.repo │ ├── kubernetes.repo │ ├── nginx.conf │ ├── Dockerfile │ └── README.md └── local-docker-registry │ ├── README.md │ └── retag_push.sh ├── cmd ├── wksctl │ ├── profile │ │ ├── constants │ │ │ └── constants.go │ │ ├── profile.go │ │ └── enable │ │ │ └── enable_test.go │ ├── plan │ │ └── plan.go │ ├── version │ │ └── version.go │ ├── addon │ │ ├── addon.go │ │ ├── list │ │ │ └── list.go │ │ ├── build │ │ │ ├── build_test.go │ │ │ └── build.go │ │ └── show │ │ │ └── show.go │ ├── zshcompletions │ │ └── zshcompletions.go │ ├── bashcompletions │ │ └── bashcompletions.go │ ├── main.go │ └── registrysynccommands │ │ └── registrysynccommands.go ├── mock-authz-server │ ├── Dockerfile │ └── main.go └── mock-https-authz-server │ └── main.go ├── CODE_OF_CONDUCT.md ├── .github └── workflows │ ├── golangci-lint.yaml │ └── check-links.yaml ├── MAINTAINERS ├── .readthedocs.yaml ├── .goreleaser.yml ├── .gitignore └── mkdocs.yml /.python-version: -------------------------------------------------------------------------------- 1 | 3.10.10 2 | -------------------------------------------------------------------------------- /pkg/addons/testdata/testfile: -------------------------------------------------------------------------------- 1 | content 2 | -------------------------------------------------------------------------------- /test/container/.gitignore: -------------------------------------------------------------------------------- 1 | .tmp-key-* 2 | -------------------------------------------------------------------------------- /examples/footloose/user.sudoers: -------------------------------------------------------------------------------- 1 | user ALL=(ALL) NOPASSWD:ALL 2 | -------------------------------------------------------------------------------- /examples/vagrant/.gitignore: -------------------------------------------------------------------------------- 1 | .vagrant 2 | wks_controller.tar.gz 3 | -------------------------------------------------------------------------------- /DEPENDENCIES: -------------------------------------------------------------------------------- 1 | DOCKER_VERSION=17.06 2 | KUBERNETES_VERSION=1.10.4 3 | KUBERNETES_CNI_VERSION=0.6.0 4 | -------------------------------------------------------------------------------- /tools/config_management/roles/setup-apt/files/apt-daily.timer.conf: -------------------------------------------------------------------------------- 1 | [Timer] 2 | Persistent=false 3 | -------------------------------------------------------------------------------- /addons/vendor/kubernetes-mixin/.gitignore: -------------------------------------------------------------------------------- 1 | *.yaml 2 | dashboards_out 3 | vendor 4 | jsonnetfile.lock.json 5 | -------------------------------------------------------------------------------- /addons/vendor/kubernetes-mixin/lib/alerts.jsonnet: -------------------------------------------------------------------------------- 1 | std.manifestYamlDoc((import '../mixin.libsonnet').prometheusAlerts) 2 | -------------------------------------------------------------------------------- /addons/vendor/kubernetes-mixin/lib/rules.jsonnet: -------------------------------------------------------------------------------- 1 | std.manifestYamlDoc((import '../mixin.libsonnet').prometheusRules) 2 | -------------------------------------------------------------------------------- /test/integration/bin/down.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | $SRCDIR/test/integration/bin/internal/run-integration-tests.sh destroy 4 | -------------------------------------------------------------------------------- /tools/embedmd.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | 3 | for f in "$@"; do 4 | echo "embedmd: generating $f" 5 | embedmd -w "$f" 6 | done 7 | -------------------------------------------------------------------------------- /tools/check-embedmd.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | 3 | for f in "$@"; do 4 | echo "embedmd: checking $f" 5 | embedmd -d "$f" 6 | done 7 | -------------------------------------------------------------------------------- /test/integration/test/assets/kubernetes.keytab: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weaveworks/wksctl/HEAD/test/integration/test/assets/kubernetes.keytab -------------------------------------------------------------------------------- /pkg/apis/wksprovider/machine/crds/doc.go: -------------------------------------------------------------------------------- 1 | //go:generate go run -tags=dev assets_generate.go 2 | 3 | // Package crds contains wksctl's crds. 4 | package crds 5 | -------------------------------------------------------------------------------- /docs/requirements.txt: -------------------------------------------------------------------------------- 1 | mkdocs == 1.4.2 2 | mkdocs-material == 9.1.5 3 | pymdown-extensions == 9.10 4 | mkdocs-redirects == 1.2.0 5 | -------------------------------------------------------------------------------- /examples/gce/.gitignore: -------------------------------------------------------------------------------- 1 | /instances.json 2 | /machines.yaml 3 | cluster-key 4 | cluster-key.pub 5 | ssh_key.list 6 | .envrc 7 | git_deploy_key 8 | git_deploy_key.pub 9 | -------------------------------------------------------------------------------- /test/container/images/names.go: -------------------------------------------------------------------------------- 1 | package images 2 | 3 | const ( 4 | CentOS7 = "quay.io/wksctl/centos7" 5 | Ubuntu1804 = "quay.io/footloose/ubuntu18.04:0.4.0" 6 | ) 7 | -------------------------------------------------------------------------------- /pkg/apis/wksprovider/controller/manifests/doc.go: -------------------------------------------------------------------------------- 1 | //go:generate go run -tags=dev assets_generate.go 2 | 3 | // Package manifests contains wksctl's manifests. 4 | package manifests 5 | -------------------------------------------------------------------------------- /tools/config_management/roles/docker-prerequisites/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | # Distribution-specific tasks: 4 | - include: debian.yml 5 | when: ansible_os_family == "Debian" 6 | -------------------------------------------------------------------------------- /pkg/addons/assets/doc.go: -------------------------------------------------------------------------------- 1 | //go:generate go run -tags=dev generator/assets_generate.go 2 | 3 | // Package addons defines components to be installed on Kubernetes clusters. 4 | package assets 5 | -------------------------------------------------------------------------------- /addons/weave-net/addon.json: -------------------------------------------------------------------------------- 1 | { 2 | "kind": "yaml", 3 | "category": "CNI", 4 | "name": "Weave Net", 5 | "description": "Weaveworks CNI plugin", 6 | "entryPoint": "weave-net.yaml" 7 | } 8 | -------------------------------------------------------------------------------- /pkg/apis/wksprovider/controller/manifests/yaml/01_namespace.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Namespace 4 | metadata: 5 | labels: 6 | controller-tools.k8s.io: "1.0" 7 | name: system 8 | -------------------------------------------------------------------------------- /pkg/utilities/manifest/manifest.go: -------------------------------------------------------------------------------- 1 | package manifest 2 | 3 | const ( 4 | DefaultNamespace = `weavek8sops` 5 | ) 6 | 7 | var DefaultAddonNamespaces = map[string]string{"weave-net": "kube-system"} 8 | -------------------------------------------------------------------------------- /tools/.gitignore: -------------------------------------------------------------------------------- 1 | cover/cover 2 | socks/proxy 3 | socks/image.tar 4 | runner/runner 5 | *.pyc 6 | *~ 7 | terraform.tfstate 8 | terraform.tfstate.backup 9 | *.retry 10 | build/**/.uptodate 11 | -------------------------------------------------------------------------------- /addons/vendor/kubernetes-mixin/mixin.libsonnet: -------------------------------------------------------------------------------- 1 | (import 'config.libsonnet') + 2 | (import 'alerts/alerts.libsonnet') + 3 | (import 'dashboards/dashboards.libsonnet') + 4 | (import 'rules/rules.libsonnet') 5 | -------------------------------------------------------------------------------- /addons/vendor/kubernetes-mixin/lib/dashboards.jsonnet: -------------------------------------------------------------------------------- 1 | local dashboards = (import '../mixin.libsonnet').grafanaDashboards; 2 | 3 | { 4 | [name]: dashboards[name] 5 | for name in std.objectFields(dashboards) 6 | } 7 | -------------------------------------------------------------------------------- /pkg/apis/wksprovider/machine/scripts/doc.go: -------------------------------------------------------------------------------- 1 | //go:generate go run -tags=dev assets_generate.go 2 | 3 | // Package scripts contains all the scripts to be used to setup Kubernetes on 4 | // machines. 5 | package scripts 6 | -------------------------------------------------------------------------------- /pkg/kubernetes/version.go: -------------------------------------------------------------------------------- 1 | package kubernetes 2 | 3 | // DefaultVersionsRange is the default Kubernetes versions' range used by WKS to validate Kubernetes versions. 4 | const DefaultVersionsRange = ">=1.16.1 <=1.20.x" 5 | -------------------------------------------------------------------------------- /pkg/apis/wksprovider/controller/manifests/yaml/03_secrets.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Secret 4 | metadata: 5 | name: wks-controller-secrets 6 | namespace: system 7 | type: Opaque 8 | data: 9 | sshKey: "" 10 | -------------------------------------------------------------------------------- /addons/flux-helm-op/addon.json: -------------------------------------------------------------------------------- 1 | { 2 | "kind": "yaml", 3 | "category": "Helm", 4 | "name": "Flux Helm Operator", 5 | "description": "Operator for deploying Helm Charts via Flux", 6 | "entryPoint": "flux-helm-op.yaml" 7 | } 8 | -------------------------------------------------------------------------------- /pkg/utilities/indent.go: -------------------------------------------------------------------------------- 1 | package utilities 2 | 3 | import "strings" 4 | 5 | func Indent(s, prefix string) string { 6 | trimmed := strings.TrimRight(s, "\n") 7 | return prefix + strings.Replace(trimmed, "\n", "\n"+prefix, -1) 8 | } 9 | -------------------------------------------------------------------------------- /addons/vendor/kubernetes-mixin/lib/promgrafonnet/promgrafonnet.libsonnet: -------------------------------------------------------------------------------- 1 | { 2 | numbersinglestat:: import 'numbersinglestat.libsonnet', 3 | gauge:: import 'gauge.libsonnet', 4 | percentlinegraph:: import 'percentlinegraph.libsonnet', 5 | } 6 | -------------------------------------------------------------------------------- /examples/gce/delete-instances.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -o errexit 4 | set -o pipefail 5 | set -o nounset 6 | 7 | gcloud compute --project="${project}" instances delete ${user}-wks-{1,2,3} \ 8 | --zone="${zone}" \ 9 | --quiet 10 | -------------------------------------------------------------------------------- /tools/config_management/roles/docker-configuration/files/docker.conf: -------------------------------------------------------------------------------- 1 | [Service] 2 | ExecStart= 3 | ExecStart=/usr/bin/dockerd -H fd:// -H unix:///var/run/alt-docker.sock -H tcp://0.0.0.0:2375 -s overlay --insecure-registry "weave-ci-registry:5000" 4 | -------------------------------------------------------------------------------- /environments/local-rpm-repo/docker-ce.repo: -------------------------------------------------------------------------------- 1 | [docker-ce-stable] 2 | name=Docker CE Stable - $basearch 3 | baseurl=https://download.docker.com/linux/centos/7/$basearch/stable 4 | enabled=1 5 | gpgcheck=1 6 | gpgkey=https://download.docker.com/linux/centos/gpg 7 | -------------------------------------------------------------------------------- /addons/vendor/kubernetes-mixin/dashboards/dashboards.libsonnet: -------------------------------------------------------------------------------- 1 | (import 'node.libsonnet') + 2 | (import 'pods.libsonnet') + 3 | (import 'resources.libsonnet') + 4 | (import 'statefulset.libsonnet') + 5 | (import 'use.libsonnet') + 6 | (import 'defaults.libsonnet') 7 | -------------------------------------------------------------------------------- /pkg/utilities/print.go: -------------------------------------------------------------------------------- 1 | package utilities 2 | 3 | import ( 4 | log "github.com/sirupsen/logrus" 5 | "k8s.io/apimachinery/pkg/util/validation/field" 6 | ) 7 | 8 | func PrintErrors(errors field.ErrorList) { 9 | for _, e := range errors { 10 | log.Errorf("%v\n", e) 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /addons/vendor/kubernetes-mixin/alerts/alerts.libsonnet: -------------------------------------------------------------------------------- 1 | (import 'absent_alerts.libsonnet') + 2 | (import 'apps_alerts.libsonnet') + 3 | (import 'resource_alerts.libsonnet') + 4 | (import 'storage_alerts.libsonnet') + 5 | (import 'system_alerts.libsonnet') + 6 | (import 'add-runbook-links.libsonnet') 7 | -------------------------------------------------------------------------------- /addons/vendor/kubernetes-mixin/lib/utils.libsonnet: -------------------------------------------------------------------------------- 1 | { 2 | mapRuleGroups(f): { 3 | groups: [ 4 | group { 5 | rules: [ 6 | f(rule) 7 | for rule in super.rules 8 | ], 9 | } 10 | for group in super.groups 11 | ], 12 | }, 13 | } 14 | -------------------------------------------------------------------------------- /cmd/wksctl/profile/constants/constants.go: -------------------------------------------------------------------------------- 1 | package constants 2 | 3 | const ( 4 | AppDevAlias = "app-dev" 5 | AppDevRepoURL = "git@github.com:weaveworks/eks-quickstart-app-dev" 6 | 7 | // WKSctlIgnoreFilename is the ignore file recognized by wksctl 8 | WKSctlIgnoreFilename = ".wksctlignore" 9 | ) 10 | -------------------------------------------------------------------------------- /test/container/resource/testdata/daemon.json: -------------------------------------------------------------------------------- 1 | { 2 | "exec-opts": ["native.cgroupdriver=systemd"], 3 | "log-driver": "json-file", 4 | "log-opts": { 5 | "max-size": "100m" 6 | }, 7 | "storage-driver": "overlay2", 8 | "storage-opts": [ 9 | "overlay2.override_kernel_check=true" 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /examples/gce/generate-machines-manifest.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -o errexit 4 | set -o pipefail 5 | set -o nounset 6 | 7 | gcloud compute --project="${project}" instances list --filter="zone:(${zone}) AND name~'^${user}-wks-\d+$'" --format=json > instances.json 8 | jk run -p user=$user generate-machines-manifest.js 9 | -------------------------------------------------------------------------------- /tools/config_management/roles/docker-from-get.docker.com/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Set up Docker 3 | # See also: legacy gce.sh script 4 | 5 | # Distribution-specific tasks: 6 | - include: debian.yml 7 | when: ansible_os_family == "Debian" 8 | 9 | - include: redhat.yml 10 | when: ansible_os_family == "RedHat" 11 | -------------------------------------------------------------------------------- /tools/files-with-type: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # Find all files with a given MIME type. 4 | # 5 | # e.g. 6 | # $ files-with-type text/x-shellscript k8s infra 7 | 8 | mime_type=$1 9 | shift 10 | 11 | git ls-files "$@" | grep -vE '^vendor/' | xargs file --mime-type | grep "${mime_type}" | sed -e 's/:.*$//' 12 | -------------------------------------------------------------------------------- /tools/config_management/roles/docker-from-tarball/vars/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | docker_dir: '/opt/docker' 3 | docker_url: '{{ "rc" in {{ docker_version }} | ternary( > 4 | "https://test.docker.com/builds/Linux/x86_64/docker-{{ docker_version }}.tgz", > 5 | "https://get.docker.com/builds/Linux/x86_64/docker-{{ docker_version }}.tgz") }}' 6 | -------------------------------------------------------------------------------- /pkg/addons/assets/assets_dev.go: -------------------------------------------------------------------------------- 1 | // +build dev 2 | 3 | package assets 4 | 5 | import ( 6 | "net/http" 7 | 8 | "github.com/weaveworks/cluster-api-provider-existinginfra/pkg/utilities/fixeddate" 9 | ) 10 | 11 | // Assets is the content of the addons directory. 12 | var Assets http.FileSystem = fixeddate.Dir("../../../addons") 13 | -------------------------------------------------------------------------------- /pkg/apis/wksprovider/machine/crds/crds_dev.go: -------------------------------------------------------------------------------- 1 | // +build dev 2 | 3 | package crds 4 | 5 | import ( 6 | "net/http" 7 | 8 | "github.com/weaveworks/cluster-api-provider-existinginfra/pkg/utilities/fixeddate" 9 | ) 10 | 11 | // CRDs contains wksctl's crds. 12 | var CRDs http.FileSystem = fixeddate.Dir("../../../../../config/crd") 13 | -------------------------------------------------------------------------------- /environments/local-rpm-repo/kubernetes.repo: -------------------------------------------------------------------------------- 1 | [kubernetes] 2 | name=Kubernetes 3 | baseurl=https://packages.cloud.google.com/yum/repos/kubernetes-el7-x86_64 4 | enabled=1 5 | gpgcheck=1 6 | repo_gpgcheck=1 7 | gpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg 8 | exclude=kube* 9 | -------------------------------------------------------------------------------- /pkg/apis/wksprovider/controller/manifests/manifests_dev.go: -------------------------------------------------------------------------------- 1 | // +build dev 2 | 3 | package manifests 4 | 5 | import ( 6 | "net/http" 7 | 8 | "github.com/weaveworks/cluster-api-provider-existinginfra/pkg/utilities/fixeddate" 9 | ) 10 | 11 | // Manifests contains wksctl's manifests. 12 | var Manifests http.FileSystem = fixeddate.Dir("yaml") 13 | -------------------------------------------------------------------------------- /pkg/apis/wksprovider/machine/scripts/scripts_dev.go: -------------------------------------------------------------------------------- 1 | // +build dev 2 | 3 | package scripts 4 | 5 | import ( 6 | "net/http" 7 | 8 | "github.com/weaveworks/cluster-api-provider-existinginfra/pkg/utilities/fixeddate" 9 | ) 10 | 11 | // Scripts contains all operating systems' scripts. 12 | var Scripts http.FileSystem = fixeddate.Dir("all") 13 | -------------------------------------------------------------------------------- /pkg/apis/wksprovider/machine/scripts/all/dummy.sh: -------------------------------------------------------------------------------- 1 | # This file exists so that the Makefile will find at least one .sh file for machine scripts. 2 | # It's possible we will want to add new scripts later so the script gathering infrastructure is being left in place. 3 | 4 | echo 'A stand-in for builds. If we add any new scripts, this will be unnecessary' 5 | 6 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | ## Community Code of Conduct 2 | 3 | Weaveworks follows the [CNCF Code of Conduct](https://github.com/cncf/foundation/blob/master/code-of-conduct.md). 4 | 5 | Instances of abusive, harassing, or otherwise unacceptable behavior 6 | may be reported by contacting a Weaveworks project maintainer, or 7 | Alexis Richardson (alexis@weave.works). 8 | -------------------------------------------------------------------------------- /tools/config_management/roles/docker-from-docker-ce-repo/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Set up Docker 3 | # See also: https://docs.docker.com/engine/installation/linux/ubuntulinux/#install 4 | 5 | # Distribution-specific tasks: 6 | - include: debian.yml 7 | when: ansible_os_family == "Debian" 8 | 9 | - include: redhat.yml 10 | when: ansible_os_family == "RedHat" 11 | -------------------------------------------------------------------------------- /tools/config_management/roles/docker-from-docker-repo/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Set up Docker 3 | # See also: https://docs.docker.com/engine/installation/linux/ubuntulinux/#install 4 | 5 | # Distribution-specific tasks: 6 | - include: debian.yml 7 | when: ansible_os_family == "Debian" 8 | 9 | - include: redhat.yml 10 | when: ansible_os_family == "RedHat" 11 | -------------------------------------------------------------------------------- /examples/footloose/docker-config.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: docker 5 | namespace: system 6 | data: 7 | daemon.json: | 8 | { 9 | "log-driver": "json-file", 10 | "log-opts": { 11 | "max-size": "100m" 12 | }, 13 | "exec-opts": [ 14 | "native.cgroupdriver=cgroupfs" 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /examples/vagrant/docker-config.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: docker 5 | namespace: system 6 | data: 7 | daemon.json: | 8 | { 9 | "log-driver": "json-file", 10 | "log-opts": { 11 | "max-size": "100m" 12 | }, 13 | "exec-opts": [ 14 | "native.cgroupdriver=cgroupfs" 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /examples/footloose/centos7/ignite/multimaster.yaml: -------------------------------------------------------------------------------- 1 | cluster: 2 | name: centos-multimaster 3 | privateKey: cluster-key 4 | machines: 5 | - count: 4 6 | spec: 7 | image: weaveworks/ignite-centos:latest 8 | backend: ignite 9 | name: node%d 10 | portMappings: 11 | - containerPort: 22 12 | hostPort: 2222 13 | - containerPort: 6443 14 | hostPort: 6443 15 | -------------------------------------------------------------------------------- /pkg/addons/assets/assets.go: -------------------------------------------------------------------------------- 1 | package assets 2 | 3 | import ( 4 | "io/ioutil" 5 | ) 6 | 7 | // ReadAll reads all content from path. 8 | func ReadAll(path string) (string, error) { 9 | f, err := Assets.Open(path) 10 | if err != nil { 11 | return "", err 12 | } 13 | d, err := ioutil.ReadAll(f) 14 | if err != nil { 15 | return "", err 16 | } 17 | return string(d), nil 18 | } 19 | -------------------------------------------------------------------------------- /test/container/ssh/common_test.go: -------------------------------------------------------------------------------- 1 | package ssh 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/weaveworks/wksctl/test/container/testutils" 7 | ) 8 | 9 | var sshPort = testutils.PortAllocator{Next: 2322} 10 | 11 | func NewRunnerForTest(t *testing.T, image string) (*testutils.TestRunner, func()) { 12 | return testutils.MakeFootlooseTestRunner(t, image, sshPort.Allocate()) 13 | } 14 | -------------------------------------------------------------------------------- /cmd/wksctl/plan/plan.go: -------------------------------------------------------------------------------- 1 | package plan 2 | 3 | import ( 4 | "github.com/spf13/cobra" 5 | "github.com/weaveworks/wksctl/cmd/wksctl/plan/view" 6 | ) 7 | 8 | // Cmd represents the plan command 9 | var Cmd = &cobra.Command{ 10 | Use: "plan", 11 | Hidden: true, 12 | Short: "Debugging commands for the cluster plan.", 13 | } 14 | 15 | func init() { 16 | Cmd.AddCommand(view.Cmd) 17 | } 18 | -------------------------------------------------------------------------------- /examples/footloose/ubuntu18.04/ignite/multimaster.yaml: -------------------------------------------------------------------------------- 1 | cluster: 2 | name: ubuntu-multimaster 3 | privateKey: cluster-key 4 | machines: 5 | - count: 4 6 | spec: 7 | image: weaveworks/ignite-ubuntu:latest 8 | backend: ignite 9 | name: node%d 10 | portMappings: 11 | - containerPort: 22 12 | hostPort: 2222 13 | - containerPort: 6443 14 | hostPort: 6443 15 | -------------------------------------------------------------------------------- /examples/footloose/ubuntu18.04/ignite/singlemaster.yaml: -------------------------------------------------------------------------------- 1 | cluster: 2 | name: ubuntu-singlemaster 3 | privateKey: cluster-key 4 | machines: 5 | - count: 2 6 | spec: 7 | image: weaveworks/ignite-ubuntu:latest 8 | backend: ignite 9 | name: node%d 10 | portMappings: 11 | - containerPort: 22 12 | hostPort: 2222 13 | - containerPort: 6443 14 | hostPort: 6443 15 | -------------------------------------------------------------------------------- /test/container/resource/common_test.go: -------------------------------------------------------------------------------- 1 | package resource 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/weaveworks/wksctl/test/container/testutils" 7 | ) 8 | 9 | var sshPort = testutils.PortAllocator{Next: 2222} 10 | 11 | func NewRunnerForTest(t *testing.T, image string) (*testutils.TestRunner, func()) { 12 | return testutils.MakeFootlooseTestRunner(t, image, sshPort.Allocate()) 13 | } 14 | -------------------------------------------------------------------------------- /tools/config_management/group_vars/all: -------------------------------------------------------------------------------- 1 | --- 2 | go_version: 1.8.1 3 | terraform_version: 0.8.5 4 | docker_version: 17.06 5 | docker_install_role: 'docker-from-docker-ce-repo' 6 | kubernetes_version: 1.6.1 7 | kubernetes_cni_version: 0.5.1 8 | kubernetes_token: '123456.0123456789123456' 9 | etcd_container_version: 2.2.5 10 | kube_discovery_container_version: 1.0 11 | pause_container_version: 3.0 12 | -------------------------------------------------------------------------------- /cmd/mock-authz-server/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:3.11 2 | 3 | RUN apk --no-cache --update add ca-certificates 4 | 5 | COPY server /bin/ 6 | 7 | ENTRYPOINT [ "/bin/server" ] 8 | 9 | ARG revision 10 | LABEL org.opencontainers.image.title="mock-authz-server" \ 11 | org.opencontainers.image.source="https://github.com/weaveworks/wksctl" \ 12 | org.opencontainers.image.revision="${revision}" 13 | -------------------------------------------------------------------------------- /cmd/wksctl/version/version.go: -------------------------------------------------------------------------------- 1 | package version 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/spf13/cobra" 7 | "github.com/weaveworks/wksctl/pkg/version" 8 | ) 9 | 10 | var Cmd = &cobra.Command{ 11 | Use: "version", 12 | Short: "Display wksctl version", 13 | Run: versionRun, 14 | } 15 | 16 | func versionRun(cmd *cobra.Command, args []string) { 17 | fmt.Println(version.Version) 18 | } 19 | -------------------------------------------------------------------------------- /examples/footloose/upload-controller-image.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | scriptdir="$(cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd)" 4 | toolsdir=$scriptdir/../../tools 5 | 6 | $scriptdir/upload-image.sh centos-multimaster-node0 docker.io/weaveworks/wksctl-controller:$($toolsdir/image-tag) $@ 7 | $scriptdir/upload-image.sh ubuntu-multimaster-node0 docker.io/weaveworks/wksctl-controller:$($toolsdir/image-tag) $@ 8 | -------------------------------------------------------------------------------- /tools/config_management/roles/docker-prerequisites/tasks/debian.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Install Docker's dependencies 3 | # See also: https://docs.docker.com/engine/installation/linux/ubuntulinux/#install 4 | 5 | - name: install linux-image-extra-*/virtual 6 | package: 7 | name: "{{ item }}" 8 | state: present 9 | with_items: 10 | - linux-image-extra-{{ ansible_kernel }} 11 | - linux-image-extra-virtual 12 | -------------------------------------------------------------------------------- /tools/config_management/roles/kubernetes-install/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Install Kubernetes 3 | 4 | # Distribution-specific tasks: 5 | - include: debian.yml 6 | when: ansible_os_family == "Debian" 7 | 8 | - include: redhat.yml 9 | when: ansible_os_family == "RedHat" 10 | 11 | - name: install ebtables 12 | package: 13 | name: "{{ item }}" 14 | state: present 15 | with_items: 16 | - ebtables 17 | -------------------------------------------------------------------------------- /addons/make-vendor.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | 3 | rm -rf vendor 4 | 5 | jb install 6 | 7 | # cleanup the ksonnet repo to just keep the beta.3 jsonnet library 8 | find vendor/ksonnet/ | grep -v -e ksonnet.beta.3 -e ^vendor/ksonnet/$ | xargs rm -rf 9 | 10 | # https://github.com/kubernetes-monitoring/kubernetes-mixin/issues/129 11 | rm vendor/kubernetes-mixin/.circleci/jsonnet 12 | 13 | # left behind by jb 14 | rmdir vendor/.tmp 15 | -------------------------------------------------------------------------------- /pkg/apis/wksprovider/controller/manifests/yaml/05_sealed_secret_crd.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: apiextensions.k8s.io/v1beta1 3 | kind: CustomResourceDefinition 4 | metadata: 5 | name: sealedsecrets.bitnami.com 6 | spec: 7 | group: bitnami.com 8 | names: 9 | kind: SealedSecret 10 | listKind: SealedSecretList 11 | plural: sealedsecrets 12 | singular: sealedsecret 13 | scope: Namespaced 14 | version: v1alpha1 -------------------------------------------------------------------------------- /tools/config_management/roles/docker-from-get.docker.com/tasks/debian.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Debian / Ubuntu specific: 3 | 4 | - name: apt-import gpg key for the docker repository 5 | shell: curl -sSL https://get.docker.com/gpg | sudo apt-key add - 6 | 7 | - name: install docker 8 | shell: 'curl -sSL https://get.docker.com/ | sed -e s/docker-engine/docker-engine={{ docker_version }}*/ -e s/docker-ce/docker-ce={{ docker_version }}*/ | sh' 9 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | # wksctl Documentation 2 | 3 | !!! important "Deprecation notice" 4 | [Weave Kubernetes System has been retired](https://eol.weave.works/). 5 | Please see the previous versions if you still need documentation for the 6 | legacy `wksctl`. 7 | 8 | Please see [Weave GitOps](https://www.weave.works/product/gitops/) and [ Weave GitOps Enterprise ](https://www.weave.works/product/gitops-enterprise/) for alternatives. 9 | -------------------------------------------------------------------------------- /pkg/addons/assets/generator/assets_generate.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | 6 | "github.com/shurcooL/vfsgen" 7 | "github.com/weaveworks/wksctl/pkg/addons/assets" 8 | ) 9 | 10 | func main() { 11 | err := vfsgen.Generate(assets.Assets, vfsgen.Options{ 12 | PackageName: "assets", 13 | BuildTags: "!dev", 14 | VariableName: "Assets", 15 | }) 16 | if err != nil { 17 | log.Fatalln(err) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /tools/config_management/roles/kubelet-stop/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: check if kubelet service exists 4 | stat: 5 | path: /etc/init.d/kubelet 6 | register: kubelet 7 | 8 | # avoids having weave-net and weave-kube conflict in some test cases (e.g. 130_expose_test.sh) 9 | - name: stop kubelet service 10 | systemd: 11 | name: kubelet 12 | state: stopped 13 | enabled: no 14 | when: kubelet.stat.exists 15 | -------------------------------------------------------------------------------- /tools/go-lint: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | if [ ! -x "$(command -v golangci-lint)" ] 6 | then 7 | go get github.com/golangci/golangci-lint/cmd/golangci-lint@v1.27.0 8 | fi 9 | 10 | 11 | golangci-lint run --tests --disable-all --deadline=600s \ 12 | --enable=misspell \ 13 | --enable=ineffassign \ 14 | --enable=gofmt \ 15 | --skip-dirs=pkg/guide \ 16 | --skip-dirs=pkg/addons/assets \ 17 | ./... 18 | -------------------------------------------------------------------------------- /.github/workflows/golangci-lint.yaml: -------------------------------------------------------------------------------- 1 | # https://github.com/marketplace/actions/run-golangci-lint 2 | name: golangci-lint 3 | on: [push, pull_request] 4 | jobs: 5 | golangci: 6 | name: linter 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: actions/checkout@v2 10 | - name: golangci-lint 11 | uses: golangci/golangci-lint-action@v2.3.0 12 | with: 13 | version: v1.30 14 | args: --timeout 5m -------------------------------------------------------------------------------- /test/integration/bin/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | # Run integration tests 6 | IMGTAG=$(./tools/image-tag) 7 | 8 | export PATH=$GOROOT/bin:$PATH 9 | # Work around for broken docker package in RHEL 10 | export DOCKER_VERSION='1.13.1-75*' 11 | go test -failfast -v -timeout 1h ./test/integration/test -args -run.interactive -cmd /tmp/workspace/cmd/wksctl/wksctl -tags.wks-k8s-krb5-server=$IMGTAG -tags.wks-mock-authz-server=$IMGTAG 12 | -------------------------------------------------------------------------------- /cmd/wksctl/profile/profile.go: -------------------------------------------------------------------------------- 1 | package profile 2 | 3 | import ( 4 | "github.com/spf13/cobra" 5 | "github.com/weaveworks/wksctl/cmd/wksctl/profile/disable" 6 | "github.com/weaveworks/wksctl/cmd/wksctl/profile/enable" 7 | ) 8 | 9 | var Cmd = &cobra.Command{ 10 | Use: "profile", 11 | Aliases: []string{"profile"}, 12 | Short: "Profile management", 13 | } 14 | 15 | func init() { 16 | Cmd.AddCommand(enable.Cmd) 17 | Cmd.AddCommand(disable.Cmd) 18 | } 19 | -------------------------------------------------------------------------------- /environments/local-rpm-repo/nginx.conf: -------------------------------------------------------------------------------- 1 | worker_processes 1; 2 | daemon off; 3 | 4 | events { 5 | worker_connections 1024; 6 | } 7 | 8 | http { 9 | server { 10 | listen 80; 11 | server_name localhost; 12 | root /var/www/html/repos; 13 | location / { 14 | index index.php index.html index.htm; 15 | autoindex on; #enable listing of directory index 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /pkg/cluster/node/node.go: -------------------------------------------------------------------------------- 1 | package node 2 | 3 | import ( 4 | corev1 "k8s.io/api/core/v1" 5 | ) 6 | 7 | // IsMaster returns true if the provided node is a master or false otherwise. 8 | func IsMaster(n corev1.Node) bool { 9 | _, ok := n.Labels["node-role.kubernetes.io/master"] 10 | return ok 11 | } 12 | 13 | // IsWorker returns true if the provided node is a worker or false otherwise. 14 | func IsWorker(n corev1.Node) bool { 15 | return !IsMaster(n) 16 | } 17 | -------------------------------------------------------------------------------- /pkg/apis/wksprovider/machine/crds/assets_generate.go: -------------------------------------------------------------------------------- 1 | // +build ignore 2 | 3 | package main 4 | 5 | import ( 6 | "log" 7 | 8 | "github.com/shurcooL/vfsgen" 9 | "github.com/weaveworks/wksctl/pkg/apis/wksprovider/machine/crds" 10 | ) 11 | 12 | func main() { 13 | err := vfsgen.Generate(crds.CRDs, vfsgen.Options{ 14 | PackageName: "crds", 15 | BuildTags: "!dev", 16 | VariableName: "CRDs", 17 | }) 18 | if err != nil { 19 | log.Fatalln(err) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /addons/vendor/kubernetes-mixin/dashboards/defaults.libsonnet: -------------------------------------------------------------------------------- 1 | { 2 | local grafanaDashboards = super.grafanaDashboards, 3 | 4 | // Automatically add a uid to each dashboard based on the base64 encoding 5 | // of the file name and set the timezone to be 'default'. 6 | grafanaDashboards:: { 7 | [filename]: grafanaDashboards[filename] { 8 | uid: std.md5(filename), 9 | timezone: '', 10 | } 11 | for filename in std.objectFields(grafanaDashboards) 12 | }, 13 | } 14 | -------------------------------------------------------------------------------- /pkg/apis/wksprovider/machine/scripts/assets_generate.go: -------------------------------------------------------------------------------- 1 | // +build ignore 2 | 3 | package main 4 | 5 | import ( 6 | "log" 7 | 8 | "github.com/shurcooL/vfsgen" 9 | "github.com/weaveworks/wksctl/pkg/apis/wksprovider/machine/scripts" 10 | ) 11 | 12 | func main() { 13 | err := vfsgen.Generate(scripts.Scripts, vfsgen.Options{ 14 | PackageName: "scripts", 15 | BuildTags: "!dev", 16 | VariableName: "Scripts", 17 | }) 18 | if err != nil { 19 | log.Fatalln(err) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /MAINTAINERS: -------------------------------------------------------------------------------- 1 | In alphabetical order: 2 | 3 | Bryan Boreham (@bboreham) 4 | Chanwit Kaewkasi (@chanwit) 5 | Dennis Marttinen (@twelho) 6 | Dimitri Mitropoulos (@dimitropoulos) 7 | Filip Barl (@fbarl) 8 | Jerry R. Jackson (@jrryjcksn) 9 | Lucas Käldström (@luxas) 10 | Mark Emeis (@palemtnrider) 11 | Simon Howe (@foot) 12 | -------------------------------------------------------------------------------- /examples/footloose/centos7/ignite/singlemaster.yaml: -------------------------------------------------------------------------------- 1 | cluster: 2 | name: centos-singlemaster 3 | privateKey: cluster-key 4 | machines: 5 | - count: 2 6 | spec: 7 | image: weaveworks/ignite-centos:latest 8 | backend: ignite 9 | name: node%d 10 | portMappings: 11 | - containerPort: 22 12 | hostPort: 2222 13 | - containerPort: 6443 14 | hostPort: 6443 15 | - containerPort: 30443 16 | hostPort: 30443 17 | - containerPort: 30080 18 | hostPort: 30080 19 | -------------------------------------------------------------------------------- /pkg/apis/wksprovider/controller/manifests/assets_generate.go: -------------------------------------------------------------------------------- 1 | // +build ignore 2 | 3 | package main 4 | 5 | import ( 6 | "log" 7 | 8 | "github.com/shurcooL/vfsgen" 9 | "github.com/weaveworks/wksctl/pkg/apis/wksprovider/controller/manifests" 10 | ) 11 | 12 | func main() { 13 | err := vfsgen.Generate(manifests.Manifests, vfsgen.Options{ 14 | PackageName: "manifests", 15 | BuildTags: "!dev", 16 | VariableName: "Manifests", 17 | }) 18 | if err != nil { 19 | log.Fatalln(err) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /test/integration/bin/up.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | [ -n "$SECRET_KEY" ] || { 6 | echo "Cannot run smoke tests: no secret key" 7 | exit 1 8 | } 9 | 10 | # Ensure .ssh directory exists so we can unpack things into it 11 | mkdir -p $HOME/.ssh 12 | 13 | # Base name of VMs for integration tests: 14 | export NAME=test-$CIRCLE_BUILD_NUM-$CIRCLE_NODE_INDEX 15 | 16 | $SRCDIR/test/integration/bin/internal/run-integration-tests.sh configure 17 | echo "Test VMs now provisioned and configured. $(date)." 18 | -------------------------------------------------------------------------------- /examples/gce/delete-network.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -o errexit 4 | set -o pipefail 5 | set -o nounset 6 | 7 | firewall_rules=( 8 | "${network}-external-fw-allow-ping-and-ssh" 9 | "${network}-external-fw-allow-kubernetes-api" 10 | "${network}-external-fw-allow-node-ports" 11 | "${network}-internal-fw" 12 | ) 13 | 14 | gcloud compute --project="${project}" firewall-rules delete "${firewall_rules[@]}" \ 15 | --quiet 16 | 17 | gcloud compute --project="${project}" networks delete "${network}" \ 18 | --quiet 19 | -------------------------------------------------------------------------------- /pkg/version/version.go: -------------------------------------------------------------------------------- 1 | package version 2 | 3 | var ( 4 | // The constants below are to be overridden by linker flags passed to `go build`. 5 | // Examples: -X github.com/weaveworks/wksctl/pkg/version.Version=xxxxx -X github.com/weaveworks/wksctl/pkg/version.ImageTag=yyyyy 6 | // If wksctl is used as an imported module, the importing program shall override these values using the linker flags above. If not done, the defaults below will be used instead. 7 | 8 | Version = "undefined" 9 | ImageTag = "0.8.0-beta.1" 10 | ) 11 | -------------------------------------------------------------------------------- /cmd/wksctl/addon/addon.go: -------------------------------------------------------------------------------- 1 | package addon 2 | 3 | import ( 4 | "github.com/spf13/cobra" 5 | "github.com/weaveworks/wksctl/cmd/wksctl/addon/build" 6 | "github.com/weaveworks/wksctl/cmd/wksctl/addon/list" 7 | "github.com/weaveworks/wksctl/cmd/wksctl/addon/show" 8 | ) 9 | 10 | var Cmd = &cobra.Command{ 11 | Use: "addon", 12 | Aliases: []string{"addons"}, 13 | Short: "Manipulate addons", 14 | } 15 | 16 | func init() { 17 | Cmd.AddCommand(build.Cmd) 18 | Cmd.AddCommand(list.Cmd) 19 | Cmd.AddCommand(show.Cmd) 20 | } 21 | -------------------------------------------------------------------------------- /pkg/utilities/path/path_test.go: -------------------------------------------------------------------------------- 1 | package path 2 | 3 | import ( 4 | "os" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | func TestWKSHome(t *testing.T) { 11 | // explicit path unchanged 12 | assert.Equal(t, WKSHome("/aPath"), "/aPath") 13 | 14 | // '~' path expanded 15 | homeDir, err := os.UserHomeDir() 16 | assert.NoError(t, err) 17 | assert.Equal(t, WKSHome("~/aPath"), homeDir+"/aPath") 18 | 19 | // empty path replaced with homedir/.wks 20 | assert.Equal(t, WKSHome(""), homeDir+"/.wks") 21 | } 22 | -------------------------------------------------------------------------------- /tools/config_management/roles/docker-from-get.docker.com/tasks/redhat.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # RedHat / CentOS specific: 3 | 4 | - name: rpm-import gpg key for the docker repository 5 | shell: curl -sSLo /tmp/docker.gpg https://get.docker.com/gpg && sudo rpm --import /tmp/docker.gpg 6 | 7 | - name: install docker 8 | shell: 'curl -sSL https://get.docker.com/ | sed -e s/docker-engine/docker-engine-{{ docker_version }}*/ | sh' 9 | 10 | - name: wait for docker installation to complete 11 | shell: yum install -y yum-utils && yum-complete-transaction 12 | -------------------------------------------------------------------------------- /.readthedocs.yaml: -------------------------------------------------------------------------------- 1 | # .readthedocs.yml 2 | # Read the Docs configuration file 3 | # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details 4 | 5 | # Required 6 | version: 2 7 | 8 | # Build documentation with MkDocs 9 | mkdocs: 10 | configuration: mkdocs.yml 11 | 12 | # Optionally build your docs in additional formats such as PDF and ePub 13 | formats: all 14 | 15 | # Optionally set the version of Python and requirements required to build your docs 16 | python: 17 | version: 3.7 18 | install: 19 | - requirements: docs/requirements.txt 20 | -------------------------------------------------------------------------------- /tools/config_management/setup_bare_docker.yml: -------------------------------------------------------------------------------- 1 | --- 2 | ################################################################################ 3 | # Install Docker from Docker's official repository 4 | ################################################################################ 5 | 6 | - name: install docker 7 | hosts: all 8 | gather_facts: false # required in case Python is not available on the host 9 | become: true 10 | become_user: root 11 | 12 | pre_tasks: 13 | - include: library/setup_ansible_dependencies.yml 14 | 15 | roles: 16 | - docker-install 17 | -------------------------------------------------------------------------------- /test/integration/bin/internal/colourise.sh: -------------------------------------------------------------------------------- 1 | # NB only to be sourced 2 | 3 | colourise() { 4 | [ -t 0 ] && echo -ne $'\e['$1'm' || true 5 | shift 6 | # It's important that we don't do this in a subshell, as some 7 | # commands we execute need to modify global state 8 | "$@" 9 | [ -t 0 ] && echo -ne $'\e[0m' || true 10 | } 11 | 12 | whitely() { 13 | colourise '1;37' "$@" 14 | } 15 | 16 | greyly () { 17 | colourise '0;37' "$@" 18 | } 19 | 20 | redly() { 21 | colourise '1;31' "$@" 22 | } 23 | 24 | greenly() { 25 | colourise '1;32' "$@" 26 | } 27 | 28 | -------------------------------------------------------------------------------- /examples/footloose/centos7/docker/multimaster.yaml: -------------------------------------------------------------------------------- 1 | cluster: 2 | name: centos-multimaster 3 | privateKey: cluster-key 4 | machines: 5 | - count: 4 6 | spec: 7 | image: quay.io/footloose/centos7:0.6.0 8 | name: node%d 9 | portMappings: 10 | - containerPort: 22 11 | hostPort: 2222 12 | - containerPort: 6443 13 | hostPort: 6443 14 | # The below is required for dockerd to run smoothly. 15 | # See also: https://github.com/weaveworks/footloose#running-dockerd-in-container-machines 16 | privileged: true 17 | volumes: 18 | - type: volume 19 | destination: /var/lib/docker 20 | -------------------------------------------------------------------------------- /tools/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2018 Weaveworks. All rights reserved. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /test/integration/test/help_test.go: -------------------------------------------------------------------------------- 1 | package test 2 | 3 | import ( 4 | "os/exec" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | "github.com/stretchr/testify/require" 9 | ) 10 | 11 | // Check "help" has some help blurb about the the "apply", "help", "version" 12 | // commands. 13 | func TestHelp(t *testing.T) { 14 | exe := run.NewExecutor() 15 | 16 | run, err := exe.RunCmd(exec.Command(cmd, "help")) 17 | require.NoError(t, err) 18 | assert.Equal(t, 0, run.ExitCode()) 19 | assert.True(t, run.Contains("apply")) 20 | assert.True(t, run.Contains("help")) 21 | assert.True(t, run.Contains("version")) 22 | } 23 | -------------------------------------------------------------------------------- /cmd/wksctl/addon/list/list.go: -------------------------------------------------------------------------------- 1 | package list 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "text/tabwriter" 7 | 8 | "github.com/spf13/cobra" 9 | "github.com/weaveworks/wksctl/pkg/addons" 10 | ) 11 | 12 | var Cmd = &cobra.Command{ 13 | Use: "list", 14 | Short: "List addons", 15 | Run: addonListRun, 16 | } 17 | 18 | func addonListRun(cmd *cobra.Command, args []string) { 19 | const tabWidth = 4 20 | w := tabwriter.NewWriter(os.Stdout, 0, 0, tabWidth, ' ', 0) 21 | 22 | addons := addons.List() 23 | for _, addon := range addons { 24 | fmt.Fprintf(w, "%s\t%s\n", addon.ShortName, addon.Name) 25 | } 26 | 27 | w.Flush() 28 | } 29 | -------------------------------------------------------------------------------- /examples/footloose/ubuntu18.04/docker/multimaster.yaml: -------------------------------------------------------------------------------- 1 | cluster: 2 | name: ubuntu-multimaster 3 | privateKey: cluster-key 4 | machines: 5 | - count: 4 6 | spec: 7 | image: quay.io/footloose/ubuntu18.04:0.4.0 8 | name: node%d 9 | portMappings: 10 | - containerPort: 22 11 | hostPort: 2222 12 | - containerPort: 6443 13 | hostPort: 6443 14 | # The below is required for dockerd to run smoothly. 15 | # See also: https://github.com/weaveworks/footloose#running-dockerd-in-container-machines 16 | privileged: true 17 | volumes: 18 | - type: volume 19 | destination: /var/lib/docker 20 | -------------------------------------------------------------------------------- /examples/footloose/ubuntu18.04/docker/singlemaster.yaml: -------------------------------------------------------------------------------- 1 | cluster: 2 | name: ubuntu-singlemaster 3 | privateKey: cluster-key 4 | machines: 5 | - count: 2 6 | spec: 7 | image: quay.io/footloose/ubuntu18.04:0.4.0 8 | name: node%d 9 | portMappings: 10 | - containerPort: 22 11 | hostPort: 2222 12 | - containerPort: 6443 13 | hostPort: 6443 14 | # The below is required for dockerd to run smoothly. 15 | # See also: https://github.com/weaveworks/footloose#running-dockerd-in-container-machines 16 | privileged: true 17 | volumes: 18 | - type: volume 19 | destination: /var/lib/docker 20 | -------------------------------------------------------------------------------- /pkg/plan/resource/common.go: -------------------------------------------------------------------------------- 1 | package resource 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | 7 | "github.com/pkg/errors" 8 | log "github.com/sirupsen/logrus" 9 | "github.com/weaveworks/cluster-api-provider-existinginfra/pkg/plan" 10 | ) 11 | 12 | func removeFile(ctx context.Context, remotePath string, runner plan.Runner) error { 13 | if stdouterr, err := runner.RunCommand(ctx, fmt.Sprintf("rm -f %q", remotePath), nil); err != nil { 14 | log.WithField("stdouterr", stdouterr).WithField("path", remotePath).Debugf("failed to delete file") 15 | return errors.Wrapf(err, "failed to delete %q", remotePath) 16 | } 17 | return nil 18 | } 19 | -------------------------------------------------------------------------------- /docs/_static/custom.css: -------------------------------------------------------------------------------- 1 | @import url("https://fonts.googleapis.com/css?family=Montserrat&display=swap"); 2 | 3 | body { 4 | font-family: "Montserrat", sans-serif; 5 | } 6 | 7 | .md-logo { 8 | width: 40px; 9 | height: 40px; 10 | padding-bottom: 2px; 11 | padding-top: 2px; 12 | } 13 | .md-logo img { 14 | width: 40px; 15 | height: 40px; 16 | } 17 | 18 | .md-header, .md-footer-nav { 19 | background-image: linear-gradient(45deg, rgb(0, 150, 225) 0%, rgb(27, 141, 226) 24%, rgb(42, 125, 227) 53%, rgb(53, 112, 227) 78%, rgb(53, 112, 227) 100%); 20 | } 21 | 22 | .md-header-nav__title { 23 | font-size: .85rem; 24 | } 25 | -------------------------------------------------------------------------------- /pkg/plan/runners/ssh/ssh.go: -------------------------------------------------------------------------------- 1 | package ssh 2 | 3 | import ( 4 | "github.com/weaveworks/cluster-api-provider-existinginfra/apis/cluster.weave.works/v1alpha3" 5 | capeissh "github.com/weaveworks/cluster-api-provider-existinginfra/pkg/plan/runners/ssh" 6 | ) 7 | 8 | func NewClientForMachine(m *v1alpha3.MachineSpec, user, keyPath string, printOutputs bool) (*capeissh.Client, error) { 9 | ip := m.Public.Address 10 | port := m.Public.Port 11 | return capeissh.NewClient(capeissh.ClientParams{ 12 | User: user, 13 | Host: ip, 14 | Port: port, 15 | PrivateKeyPath: keyPath, 16 | PrintOutputs: printOutputs, 17 | }) 18 | } 19 | -------------------------------------------------------------------------------- /tools/config_management/setup_weave-net_debug.yml: -------------------------------------------------------------------------------- 1 | --- 2 | ################################################################################ 3 | # Install Docker from Docker's official repository and Weave Net. 4 | ################################################################################ 5 | 6 | - name: install docker and weave net for development 7 | hosts: all 8 | gather_facts: false # required in case Python is not available on the host 9 | become: true 10 | become_user: root 11 | 12 | pre_tasks: 13 | - include: library/setup_ansible_dependencies.yml 14 | 15 | roles: 16 | - docker-install 17 | - weave-net-utilities 18 | - weave-net 19 | -------------------------------------------------------------------------------- /tools/config_management/roles/weave-net/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Set up Weave Net. 3 | 4 | - name: install weave net 5 | get_url: 6 | url: https://git.io/weave 7 | dest: /usr/local/bin/weave 8 | mode: 0555 9 | 10 | - name: stop weave net 11 | command: /usr/local/bin/weave stop 12 | 13 | - name: start weave net 14 | command: /usr/local/bin/weave launch 15 | 16 | - name: get weave net's status 17 | command: /usr/local/bin/weave status 18 | changed_when: false 19 | register: weave_status 20 | tags: 21 | - output 22 | 23 | - name: print outpout of `weave status` 24 | debug: msg="{{ weave_status.stdout_lines }}" 25 | tags: 26 | - output 27 | -------------------------------------------------------------------------------- /tools/config_management/roles/setup-apt/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Set up apt 3 | 4 | # Ubuntu runs an apt update process that will run on first boot from image. 5 | # This is of questionable value when the machines are only going to live for a few minutes. 6 | # If you leave them on they will run the process daily. 7 | # Also we have seen the update process create a 'defunct' process which then throws off Weave Net smoke-test checks. 8 | # So, we override the 'persistent' setting so it will still run at the scheduled time but will not try to catch up on first boot. 9 | - name: copy apt daily override 10 | copy: src=apt-daily.timer.conf dest=/etc/systemd/system/apt-daily.timer.d/ 11 | -------------------------------------------------------------------------------- /addons/vendor/kubernetes-mixin/alerts/absent_alerts.libsonnet: -------------------------------------------------------------------------------- 1 | { 2 | prometheusAlerts+:: { 3 | groups+: [ 4 | { 5 | name: 'kubernetes-absent', 6 | rules: [ 7 | { 8 | alert: '%sDown' % name, 9 | expr: ||| 10 | absent(up{%s} == 1) 11 | ||| % $._config.jobs[name], 12 | 'for': '15m', 13 | labels: { 14 | severity: 'critical', 15 | }, 16 | annotations: { 17 | message: '%s has disappeared from Prometheus target discovery.' % name, 18 | }, 19 | } 20 | for name in std.objectFields($._config.jobs) 21 | ], 22 | }, 23 | ], 24 | }, 25 | } 26 | -------------------------------------------------------------------------------- /.goreleaser.yml: -------------------------------------------------------------------------------- 1 | before: 2 | hooks: 3 | - go mod download 4 | builds: 5 | - id: wksctl 6 | main: ./cmd/wksctl 7 | binary: wksctl 8 | ldflags: 9 | - -X github.com/weaveworks/wksctl/pkg/version.Version={{.Version}} 10 | - -X github.com/weaveworks/wksctl/pkg/version.ImageTag={{.Env.IMAGE_TAG}} 11 | env: 12 | - CGO_ENABLED=0 13 | - GO111MODULE=on 14 | goarch: 15 | - amd64 16 | hooks: 17 | pre: make generated 18 | archives: 19 | - name_template: "wksctl-{{ .Version }}-{{ .Os }}-{{ .Arch }}" 20 | replacements: 21 | 386: i386 22 | amd64: x86_64 23 | files: 24 | - examples/**/* 25 | changelog: 26 | sort: asc 27 | filters: 28 | exclude: 29 | - '^docs:' 30 | - '^test:' 31 | -------------------------------------------------------------------------------- /addons/vendor/kubernetes-mixin/.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | jobs: 3 | build: 4 | docker: 5 | - image: circleci/golang:1.10.3-stretch 6 | 7 | working_directory: /go/src/github.com/kubernetes-monitoring/kubernetes-mixin 8 | steps: 9 | - checkout 10 | - run: 11 | name: Install tools 12 | command: | 13 | go get github.com/jsonnet-bundler/jsonnet-bundler/cmd/jb 14 | go get github.com/prometheus/prometheus/cmd/promtool 15 | sudo curl -o /usr/bin/jsonnet https://raw.githubusercontent.com/kubernetes-monitoring/kubernetes-mixin/${CIRCLE_SHA1}/.circleci/jsonnet 16 | sudo chmod +x /usr/bin/jsonnet 17 | - run: jb install 18 | - run: make 19 | -------------------------------------------------------------------------------- /addons/vendor/kubernetes-mixin/jsonnetfile.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": [ 3 | { 4 | "name": "grafonnet", 5 | "source": { 6 | "git": { 7 | "remote": "https://github.com/grafana/grafonnet-lib", 8 | "subdir": "grafonnet" 9 | } 10 | }, 11 | "version": "master" 12 | }, 13 | { 14 | "name": "grafana-builder", 15 | "source": { 16 | "git": { 17 | "remote": "https://github.com/kausalco/public", 18 | "subdir": "grafana-builder" 19 | } 20 | }, 21 | "version": "master" 22 | } 23 | ] 24 | } -------------------------------------------------------------------------------- /examples/footloose/centos7/docker/singlemaster.yaml: -------------------------------------------------------------------------------- 1 | cluster: 2 | name: centos-singlemaster 3 | privateKey: cluster-key 4 | machines: 5 | - count: 2 6 | spec: 7 | image: quay.io/footloose/centos7:0.3.0 8 | name: node%d 9 | portMappings: 10 | - containerPort: 22 11 | hostPort: 2222 12 | - containerPort: 6443 13 | hostPort: 6443 14 | - containerPort: 30443 15 | hostPort: 30443 16 | - containerPort: 30080 17 | hostPort: 30080 18 | # The below is required for dockerd to run smoothly. 19 | # See also: https://github.com/weaveworks/footloose#running-dockerd-in-container-machines 20 | privileged: true 21 | volumes: 22 | - type: volume 23 | destination: /var/lib/docker 24 | -------------------------------------------------------------------------------- /pkg/cluster/nodes/nodes.go: -------------------------------------------------------------------------------- 1 | package nodes 2 | 3 | import ( 4 | "github.com/weaveworks/wksctl/pkg/cluster/node" 5 | corev1 "k8s.io/api/core/v1" 6 | ) 7 | 8 | // Masters selects master nodes among the provided nodes. 9 | func Masters(nodes corev1.NodeList) corev1.NodeList { 10 | out := corev1.NodeList{} 11 | for _, n := range nodes.Items { 12 | if node.IsMaster(n) { 13 | out.Items = append(out.Items, n) 14 | } 15 | } 16 | return out 17 | } 18 | 19 | // Workers selects master nodes among the provided nodes. 20 | func Workers(nodes corev1.NodeList) corev1.NodeList { 21 | out := corev1.NodeList{} 22 | for _, n := range nodes.Items { 23 | if node.IsWorker(n) { 24 | out.Items = append(out.Items, n) 25 | } 26 | } 27 | return out 28 | } 29 | -------------------------------------------------------------------------------- /tools/config_management/setup_weave-net_test.yml: -------------------------------------------------------------------------------- 1 | --- 2 | ################################################################################ 3 | # Install Docker from Docker's official repository and Weave Net. 4 | ################################################################################ 5 | 6 | - name: install docker and weave net for testing 7 | hosts: all 8 | gather_facts: false # required in case Python is not available on the host 9 | become: true 10 | become_user: root 11 | 12 | pre_tasks: 13 | - include: library/setup_ansible_dependencies.yml 14 | 15 | roles: 16 | - setup-apt 17 | - docker-install 18 | - weave-net-utilities 19 | - kubernetes-install 20 | - kubernetes-docker-images 21 | - kubelet-stop 22 | -------------------------------------------------------------------------------- /environments/local-docker-registry/README.md: -------------------------------------------------------------------------------- 1 | # Local Docker Registry 2 | 3 | This directory contains the resources required to run your own Docker registry. 4 | This can be useful when working offline, when setting up air-gapped cluster, or 5 | just to speed up integration tests, among other scenarii. 6 | 7 | ## Instructions 8 | 9 | 1. Install Docker. 10 | 2. Start the [Docker registry](https://hub.docker.com/_/registry): 11 | 12 | ```console 13 | $ docker run -d \ 14 | -p 5000:5000 \ 15 | --restart always \ 16 | -v /tmp/registry:/var/lib/registry \ 17 | --name registry \ 18 | registry:2 19 | ``` 20 | 21 | 3. Push the container images used by WKS to it: 22 | 23 | ```console 24 | ./retag_push.sh 25 | ``` 26 | -------------------------------------------------------------------------------- /tools/config_management/roles/docker-from-docker-repo/tasks/redhat.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # RedHat / CentOS specific: 3 | 4 | - name: add docker' yum repository (centos/{{ ansible_lsb.major_release }}) 5 | yum_repository: 6 | name: docker 7 | description: Docker YUM repo 8 | file: external_repos 9 | baseurl: https://yum.dockerproject.org/repo/main/centos/{{ ansible_lsb.major_release }} 10 | enabled: yes 11 | gpgkey: https://yum.dockerproject.org/gpg 12 | gpgcheck: yes 13 | state: present 14 | 15 | - name: update yum's cache 16 | yum: 17 | name: "*" 18 | update_cache: yes 19 | 20 | - name: install docker-engine 21 | package: 22 | name: "{{ item }}" 23 | state: present 24 | with_items: 25 | - docker-engine-{{ docker_version }} 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .uptodate 2 | /examples/.vagrant 3 | /rpm/output 4 | /test/resource/tests 5 | /test/integration/test/kubectl 6 | /.idea 7 | 8 | # Ignore generated binaries: 9 | /cmd/controller/controller 10 | /cmd/mock-authz-server/server 11 | /cmd/mock-https-authz-server/server 12 | /cmd/wksctl/wksctl 13 | 14 | # Ignore files generated by footlose: 15 | cluster-key 16 | cluster-key.pub 17 | footloose.yaml 18 | 19 | # OS-specific files: 20 | .DS_Store 21 | 22 | # Ignore direnv's .envrc files, as they should not be shared and may contain 23 | # sensitive information: 24 | .envrc 25 | 26 | # Ignore Terraform state files & working directories: 27 | .terraform/ 28 | terraform.tfstate 29 | terraform.tfstate.backup 30 | .terraform.tfstate.lock.info 31 | tf.json 32 | 33 | # Docs: 34 | site 35 | -------------------------------------------------------------------------------- /tools/config_management/roles/kubernetes-docker-images/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: docker pull images used by k8s tests 4 | docker_image: 5 | name: '{{ item }}' 6 | state: present 7 | with_items: 8 | - gcr.io/google_containers/etcd-amd64:{{ etcd_container_version }} 9 | - gcr.io/google_containers/kube-apiserver-amd64:v{{ kubernetes_version }} 10 | - gcr.io/google_containers/kube-controller-manager-amd64:v{{ kubernetes_version }} 11 | - gcr.io/google_containers/kube-proxy-amd64:v{{ kubernetes_version }} 12 | - gcr.io/google_containers/kube-scheduler-amd64:v{{ kubernetes_version }} 13 | - gcr.io/google_containers/kube-discovery-amd64:{{ kube_discovery_container_version }} 14 | - gcr.io/google_containers/pause-amd64:{{ pause_container_version }} 15 | -------------------------------------------------------------------------------- /tools/image-tag: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -o errexit 4 | set -o nounset 5 | set -o pipefail 6 | 7 | WORKING_SUFFIX=$(if git status --porcelain | grep -qE '^(?:[^?][^ ]|[^ ][^?])\s'; then echo "-WIP"; else echo ""; fi) 8 | CURRENT_TAG=$(if TAG=$(git describe --tags --exact-match 2>/dev/null); then echo $TAG; else echo ""; fi) 9 | if test -z "$WORKING_SUFFIX" && test ! -z "$CURRENT_TAG" 10 | then 11 | echo $CURRENT_TAG 12 | else 13 | BRANCH_PREFIX=$(git rev-parse --abbrev-ref HEAD) 14 | 15 | # Fix the object name prefix length to 8 characters to have it consistent across the system. 16 | # See https://git-scm.com/docs/git-rev-parse#Documentation/git-rev-parse.txt---shortlength 17 | echo "${BRANCH_PREFIX//\//-}-$(git rev-parse --short=8 HEAD)$WORKING_SUFFIX" 18 | fi 19 | -------------------------------------------------------------------------------- /addons/vendor/kubernetes-mixin/alerts/add-runbook-links.libsonnet: -------------------------------------------------------------------------------- 1 | local utils = import '../lib/utils.libsonnet'; 2 | 3 | local lower(x) = 4 | local cp(c) = std.codepoint(c); 5 | local lowerLetter(c) = 6 | if cp(c) >= 65 && cp(c) < 91 7 | then std.char(cp(c) + 32) 8 | else c; 9 | std.join('', std.map(lowerLetter, std.stringChars(x))); 10 | 11 | { 12 | _config+:: { 13 | runbookURLPattern: 'https://github.com/kubernetes-monitoring/kubernetes-mixin/tree/master/runbook.md#alert-name-%s', 14 | }, 15 | 16 | prometheusAlerts+:: 17 | local addRunbookURL(rule) = rule { 18 | [if 'alert' in rule then 'annotations']+: { 19 | runbook_url: $._config.runbookURLPattern % lower(rule.alert), 20 | }, 21 | }; 22 | utils.mapRuleGroups(addRunbookURL), 23 | } 24 | -------------------------------------------------------------------------------- /environments/local-rpm-repo/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM centos:7 2 | RUN yum install -y epel-release && \ 3 | yum install -y \ 4 | createrepo \ 5 | nginx \ 6 | && \ 7 | yum clean all 8 | 9 | RUN mkdir -p /var/www/html/repos/{base,centosplus,extras,updates} 10 | COPY docker-ce.repo /etc/yum.repos.d/docker-ce.repo 11 | COPY kubernetes.repo /etc/yum.repos.d/kubernetes.repo 12 | RUN yum --downloadonly --downloaddir /var/www/html/repos install -y --disableexcludes=kubernetes \ 13 | device-mapper-persistent-data \ 14 | docker-ce-19.03.8 \ 15 | kubeadm-1.16.11 \ 16 | kubectl-1.16.11 \ 17 | kubelet-1.16.11 \ 18 | lvm2 \ 19 | yum-utils \ 20 | yum-versionlock 21 | RUN createrepo /var/www/html/repos 22 | 23 | COPY nginx.conf /etc/nginx/nginx.conf 24 | EXPOSE 80 25 | CMD ["nginx"] 26 | -------------------------------------------------------------------------------- /tools/config_management/roles/weave-net-sources/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Set up Development Environment for Weave Net. 3 | 4 | - name: check if weave net has been checked out 5 | become: false # Run as SSH-user 6 | stat: 7 | path: $HOME/src/github.com/weaveworks/weave 8 | register: weave 9 | failed_when: false 10 | changed_when: false 11 | 12 | - name: git clone weave net 13 | become: false # Run as SSH-user 14 | git: 15 | repo: https://github.com/weaveworks/weave.git 16 | dest: $HOME/src/github.com/weaveworks/weave 17 | when: not weave.stat.exists 18 | 19 | - name: create a convenience symlink to $HOME/src/github.com/weaveworks/weave 20 | become: false # Run as SSH-user 21 | file: 22 | src: $HOME/src/github.com/weaveworks/weave 23 | dest: $HOME/weave 24 | state: link 25 | -------------------------------------------------------------------------------- /pkg/cluster/node/node_test.go: -------------------------------------------------------------------------------- 1 | package node_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | "github.com/weaveworks/wksctl/pkg/cluster/node" 8 | corev1 "k8s.io/api/core/v1" 9 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 10 | ) 11 | 12 | var master = corev1.Node{ 13 | ObjectMeta: metav1.ObjectMeta{ 14 | Labels: map[string]string{ 15 | "node-role.kubernetes.io/master": "", 16 | }, 17 | }, 18 | } 19 | 20 | var worker = corev1.Node{ 21 | ObjectMeta: metav1.ObjectMeta{ 22 | Labels: map[string]string{}, 23 | }, 24 | } 25 | 26 | func TestIsMaster(t *testing.T) { 27 | assert.True(t, node.IsMaster(master)) 28 | assert.False(t, node.IsMaster(worker)) 29 | } 30 | 31 | func TestIsWorker(t *testing.T) { 32 | assert.True(t, node.IsWorker(worker)) 33 | assert.False(t, node.IsWorker(master)) 34 | } 35 | -------------------------------------------------------------------------------- /tools/config_management/setup_weave-net_dev.yml: -------------------------------------------------------------------------------- 1 | --- 2 | ################################################################################ 3 | # Install Docker from Docker's official repository and Weave Net. 4 | ################################################################################ 5 | 6 | - name: install docker and weave net for development 7 | hosts: all 8 | gather_facts: false # required in case Python is not available on the host 9 | become: true 10 | become_user: root 11 | 12 | pre_tasks: 13 | - include: library/setup_ansible_dependencies.yml 14 | 15 | roles: 16 | - setup-apt 17 | - dev-tools 18 | - golang-from-tarball 19 | - docker-install 20 | # Do not run this role when building with Vagrant, as sources have been already checked out: 21 | - { role: weave-net-sources, when: "ansible_user != 'vagrant'" } 22 | -------------------------------------------------------------------------------- /cmd/wksctl/addon/build/build_test.go: -------------------------------------------------------------------------------- 1 | package build 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestParseParam(t *testing.T) { 10 | tests := []struct { 11 | intput string 12 | valid bool 13 | expected []string 14 | }{ 15 | {"key", false, nil}, 16 | {"key=value=bar", true, []string{"key", "value=bar"}}, 17 | {"key=value", true, []string{"key", "value"}}, 18 | {"key=value=bar", true, []string{"key", "value=bar"}}, 19 | } 20 | 21 | for _, test := range tests { 22 | key, value, err := parseParam(test.intput) 23 | if !test.valid { 24 | assert.Error(t, err) 25 | assert.Equal(t, "", key) 26 | assert.Equal(t, "", value) 27 | continue 28 | } 29 | assert.NoError(t, err) 30 | assert.Equal(t, test.expected[0], key) 31 | assert.Equal(t, test.expected[1], value) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /tools/build/golang/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -eu 4 | 5 | if [ -n "${SRC_NAME:-}" ]; then 6 | SRC_PATH=${SRC_PATH:-$GOPATH/src/$SRC_NAME} 7 | elif [ -z "${SRC_PATH:-}" ]; then 8 | echo "Must set either \$SRC_NAME or \$SRC_PATH." 9 | exit 1 10 | fi 11 | 12 | # If we run make directly, any files created on the bind mount 13 | # will have awkward ownership. So we switch to a user with the 14 | # same user and group IDs as source directory. We have to set a 15 | # few things up so that sudo works without complaining later on. 16 | uid=$(stat --format="%u" "$SRC_PATH") 17 | gid=$(stat --format="%g" "$SRC_PATH") 18 | echo "weave:x:$uid:$gid::$SRC_PATH:/bin/sh" >>/etc/passwd 19 | echo "weave:*:::::::" >>/etc/shadow 20 | echo "weave ALL=(ALL) NOPASSWD: ALL" >>/etc/sudoers 21 | 22 | su weave -c "PATH=$PATH make -C $SRC_PATH BUILD_IN_CONTAINER=false $*" 23 | -------------------------------------------------------------------------------- /test/integration/spawn/run.go: -------------------------------------------------------------------------------- 1 | package run 2 | 3 | // Options holds configuration options for the Executor object. 4 | type Options struct { 5 | // Verbose controls if Executor should print command output to stdout and stderr. 6 | Verbose bool 7 | } 8 | 9 | // Run is the top level API objects. It can be used to create executor, 10 | // responsible for running a series of commands. 11 | type Run struct { 12 | options Options 13 | } 14 | 15 | // New creates a new run context that can be used to run successive commands. 16 | func New(options Options) *Run { 17 | return &Run{ 18 | options: options, 19 | } 20 | } 21 | 22 | // NewExecutor creates an executor for a specific test. 23 | func (r *Run) NewExecutor() *Executor { 24 | return &Executor{ 25 | run: r, 26 | showOutput: r.options.Verbose, 27 | showBreadcrumbs: r.options.Verbose, 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /test/integration/test/download.go: -------------------------------------------------------------------------------- 1 | package test 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "net/http" 7 | "os" 8 | ) 9 | 10 | func downloadFile(filepath, url string) error { 11 | out, err := os.Create(filepath) 12 | if err != nil { 13 | return err 14 | } 15 | defer out.Close() 16 | 17 | resp, err := http.Get(url) 18 | if err != nil { 19 | return err 20 | } 21 | defer resp.Body.Close() 22 | 23 | if resp.StatusCode != http.StatusOK { 24 | return fmt.Errorf("bad status: %s", resp.Status) 25 | } 26 | 27 | _, err = io.Copy(out, resp.Body) 28 | if err != nil { 29 | return err 30 | } 31 | 32 | return nil 33 | } 34 | 35 | func downloadFileWithRetries(filepath, url string, retries int) error { 36 | var err error 37 | for i := 0; i < retries; i++ { 38 | err = downloadFile(filepath, url) 39 | if err == nil { 40 | return nil 41 | } 42 | } 43 | 44 | return err 45 | } 46 | -------------------------------------------------------------------------------- /pkg/security/key.go: -------------------------------------------------------------------------------- 1 | package security 2 | 3 | import ( 4 | "crypto/rsa" 5 | "crypto/x509" 6 | "encoding/pem" 7 | "fmt" 8 | "io/ioutil" 9 | ) 10 | 11 | func parsePublicKey(data []byte) (*rsa.PublicKey, error) { 12 | block, _ := pem.Decode(data) 13 | if block.Type != "PUBLIC KEY" { 14 | return nil, fmt.Errorf("unexpected block %s, wanted PUBLIC KEY", block.Type) 15 | } 16 | 17 | return x509.ParsePKCS1PublicKey(block.Bytes) 18 | } 19 | 20 | // ParsePublicKeyFromString loads a public key from a string. 21 | func ParsePublicKeyFromString(s string) (*rsa.PublicKey, error) { 22 | return parsePublicKey([]byte(s)) 23 | } 24 | 25 | // ParsePublicKeyFromFile loads a public key from a file. 26 | func ParsePublicKeyFromFile(filename string) (*rsa.PublicKey, error) { 27 | data, err := ioutil.ReadFile(filename) 28 | if err != nil { 29 | return nil, err 30 | } 31 | return parsePublicKey(data) 32 | } 33 | -------------------------------------------------------------------------------- /pkg/utilities/indent_test.go: -------------------------------------------------------------------------------- 1 | package utilities 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestIndent(t *testing.T) { 10 | for _, tt := range []struct { 11 | name string 12 | s, indent string 13 | want string 14 | }{ 15 | { 16 | name: "empty", 17 | }, 18 | { 19 | name: "one line", 20 | s: "hello world", 21 | indent: " ", 22 | want: " hello world", 23 | }, 24 | { 25 | name: "one line, trimmed", 26 | s: "hello world\n", 27 | indent: " ", 28 | want: " hello world", 29 | }, 30 | { 31 | name: "many lines", 32 | s: "hello world\npotato\ncarrot\n", 33 | indent: " ", 34 | want: " hello world\n potato\n carrot", 35 | }, 36 | } { 37 | t.Run(tt.name, func(t *testing.T) { 38 | got := Indent(tt.s, tt.indent) 39 | assert.Equal(t, got, tt.want) 40 | }) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /tools/config_management/roles/weave-kube/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Set up Weave Kube on top of Kubernetes. 3 | 4 | - name: set url for weave-kube daemonset 5 | set_fact: 6 | weave_kube_url: '{{ (kubernetes_version < "1.6") | ternary("https://git.io/weave-kube", "https://git.io/weave-kube-1.6") }}' 7 | 8 | - name: configure weave net's cni plugin 9 | command: 'kubectl {{ kubeconfig }} apply -f {{ weave_kube_url }}' 10 | when: '{{ play_hosts[0] == inventory_hostname }}' 11 | 12 | - name: list kubernetes' pods 13 | command: 'kubectl {{ kubeconfig }} get pods --all-namespaces' 14 | when: '{{ play_hosts[0] == inventory_hostname }}' 15 | changed_when: false 16 | register: kubectl_get_pods 17 | tags: 18 | - output 19 | 20 | - name: print outpout of `kubectl get pods --all-namespaces` 21 | debug: msg="{{ kubectl_get_pods.stdout_lines }}" 22 | when: '{{ play_hosts[0] == inventory_hostname }}' 23 | tags: 24 | - output 25 | -------------------------------------------------------------------------------- /test/integration/spawn/executor_test.go: -------------------------------------------------------------------------------- 1 | package run 2 | 3 | import ( 4 | "os/exec" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | func TestRunCmd(t *testing.T) { 11 | e := New(Options{}).NewExecutor() 12 | 13 | cmd, err := e.RunCmd(exec.Command("ls", "/")) 14 | assert.NoError(t, err) 15 | assert.True(t, cmd.Contains("etc")) 16 | assert.Equal(t, 0, cmd.ExitCode()) 17 | } 18 | 19 | func TestRunNonExistentCmd(t *testing.T) { 20 | e := New(Options{}).NewExecutor() 21 | _, err := e.RunCmd(exec.Command("foofoobar", "--help")) 22 | assert.Error(t, err) 23 | } 24 | 25 | func TestExitStatus(t *testing.T) { 26 | e := New(Options{}).NewExecutor() 27 | 28 | cmd, err := e.RunCmd(exec.Command("ls", "/")) 29 | assert.NoError(t, err) 30 | assert.Equal(t, 0, cmd.ExitCode()) 31 | 32 | cmd, err = e.RunCmd(exec.Command("ls", "/foofoobar")) 33 | assert.NoError(t, err) 34 | assert.NotEqual(t, 0, cmd.ExitCode()) 35 | } 36 | -------------------------------------------------------------------------------- /test/container/ssh/exitcode_test.go: -------------------------------------------------------------------------------- 1 | package ssh 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | "github.com/weaveworks/cluster-api-provider-existinginfra/pkg/plan" 9 | "github.com/weaveworks/wksctl/test/container/images" 10 | ) 11 | 12 | func TestExitCode(t *testing.T) { 13 | r, closer := NewRunnerForTest(t, images.CentOS7) 14 | defer closer() 15 | 16 | for _, tt := range []struct { 17 | command string 18 | wantExitCode int 19 | }{ 20 | {"/bin/true", 0}, 21 | {"/bin/false", 1}, 22 | {"(exit 2)", 2}, 23 | {"(exit 58)", 58}, 24 | } { 25 | wantError := (tt.wantExitCode != 0) 26 | 27 | t.Run(tt.command, func(t *testing.T) { 28 | _, gotErr := r.RunCommand(context.Background(), tt.command, nil) 29 | 30 | assert.Equal(t, wantError, gotErr != nil) 31 | 32 | if wantError { 33 | assert.Equal(t, tt.wantExitCode, gotErr.(*plan.RunError).ExitCode) 34 | } 35 | }) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /tools/config_management/roles/docker-from-docker-ce-repo/tasks/redhat.yml: -------------------------------------------------------------------------------- 1 | # Docker installation from Docker's CentOS Community Edition 2 | # See also: https://docs.docker.com/engine/installation/linux/centos/ 3 | 4 | - name: remove all potentially pre existing packages 5 | yum: 6 | name: '{{ item }}' 7 | state: absent 8 | with_items: 9 | - docker 10 | - docker-common 11 | - container-selinux 12 | - docker-selinux 13 | - docker-engine 14 | 15 | - name: install yum-utils 16 | yum: 17 | name: yum-utils 18 | state: present 19 | 20 | - name: add docker ce repo 21 | command: yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo 22 | 23 | # Note that Docker CE versions do not follow regular Docker versions, but look 24 | # like, for example: "17.03.0.el7" 25 | - name: install docker 26 | yum: 27 | name: 'docker-ce-{{ docker_version }}' 28 | update_cache: yes 29 | state: present 30 | -------------------------------------------------------------------------------- /tools/config_management/setup_weave-kube.yml: -------------------------------------------------------------------------------- 1 | --- 2 | ################################################################################ 3 | # Install Docker and Kubernetes, and configure Kubernetes to 4 | # use Weave Net's CNI plugin (a.k.a. Weave Kube). 5 | # 6 | # See also: 7 | # - http://kubernetes.io/docs/getting-started-guides/kubeadm/ 8 | # - https://github.com/weaveworks/weave-kube 9 | ################################################################################ 10 | 11 | - name: install docker, kubernetes and weave-kube 12 | hosts: all 13 | gather_facts: false # required in case Python is not available on the host 14 | become: true 15 | become_user: root 16 | 17 | pre_tasks: 18 | - include: library/setup_ansible_dependencies.yml 19 | 20 | roles: 21 | - docker-install 22 | - weave-net-utilities 23 | - kubernetes-install 24 | - kubernetes-docker-images 25 | - kubelet-stop 26 | - kubernetes-start 27 | - weave-kube 28 | -------------------------------------------------------------------------------- /test/container/ssh/loginshell_test.go: -------------------------------------------------------------------------------- 1 | package ssh 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | "github.com/weaveworks/wksctl/test/container/images" 9 | "github.com/weaveworks/wksctl/test/container/testutils" 10 | ) 11 | 12 | // Expect /etc/nologin content not to pollute SSH RunCommand() output. 13 | // This is a regression test for bug #431. 14 | func TestNotLoginShell(t *testing.T) { 15 | r, closer := NewRunnerForTest(t, images.CentOS7) 16 | defer closer() 17 | 18 | gotOutSetup, err := r.RunCommand(context.Background(), "echo 'this text should not appear in the output' > /etc/nologin", nil) 19 | assert.NoError(t, err) 20 | assert.Equal(t, "", gotOutSetup) 21 | 22 | client := testutils.ConnectSSH(t, r.Runner.(*testutils.FootlooseRunner)) 23 | 24 | gotOutHello, err := client.RunCommand(context.Background(), "echo hello", nil) 25 | assert.NoError(t, err) 26 | assert.Equal(t, "hello\n", gotOutHello) 27 | } 28 | -------------------------------------------------------------------------------- /pkg/apis/wksprovider/controller/manifests/yaml/04_capi_controller.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: apps/v1 3 | kind: Deployment 4 | metadata: 5 | name: capi-controller 6 | namespace: system 7 | labels: 8 | name: capi-controller 9 | spec: 10 | replicas: 1 11 | selector: 12 | matchLabels: 13 | name: capi-controller 14 | template: 15 | metadata: 16 | labels: 17 | name: capi-controller 18 | spec: 19 | tolerations: 20 | # Allow scheduling on master nodes; required during bootstrapping. 21 | - effect: NoSchedule 22 | key: node-role.kubernetes.io/master 23 | operator: Exists 24 | # Mark this as a critical addon: 25 | - key: CriticalAddonsOnly 26 | operator: Exists 27 | containers: 28 | - name: controller 29 | image: us.gcr.io/k8s-artifacts-prod/cluster-api/cluster-api-controller:v0.3.5 30 | resources: 31 | requests: 32 | cpu: 100m 33 | memory: 20Mi 34 | -------------------------------------------------------------------------------- /test/container/resource/run_test.go: -------------------------------------------------------------------------------- 1 | package resource 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | "github.com/weaveworks/cluster-api-provider-existinginfra/pkg/plan" 9 | "github.com/weaveworks/cluster-api-provider-existinginfra/pkg/plan/resource" 10 | "github.com/weaveworks/cluster-api-provider-existinginfra/pkg/utilities/object" 11 | "github.com/weaveworks/wksctl/test/container/images" 12 | ) 13 | 14 | const runScript = ` 15 | for i in s u c c e s s; do 16 | echo -n $i 17 | done 18 | echo 19 | ` 20 | 21 | func TestRun(t *testing.T) { 22 | r, closer := NewRunnerForTest(t, images.CentOS7) 23 | defer closer() 24 | 25 | run := &resource.Run{ 26 | Script: object.String(runScript), 27 | } 28 | 29 | emptyDiff := plan.EmptyDiff() 30 | _, err := run.Apply(context.Background(), r, emptyDiff) 31 | assert.NoError(t, err) 32 | assert.Equal(t, 1, len(r.Operations())) 33 | assert.Equal(t, "success\n", r.Operation(-1).Output) 34 | } 35 | -------------------------------------------------------------------------------- /tools/config_management/roles/docker-install/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Set up Docker 3 | 4 | - include_role: 5 | name: docker-prerequisites 6 | 7 | # Dynamically include docker installation role using 'when' as Ansible does not 8 | # allow for include_role's name to be set to a variable. Indeed: 9 | # - include_role: 10 | # name: '{{ docker_install_role }}' 11 | # fails with: 12 | # ERROR! 'docker_install_role' is undefined 13 | - include_role: 14 | name: docker-from-docker-repo 15 | when: docker_install_role == 'docker-from-docker-repo' 16 | 17 | - include_role: 18 | name: docker-from-docker-ce-repo 19 | when: docker_install_role == 'docker-from-docker-ce-repo' 20 | 21 | - include_role: 22 | name: docker-from-get.docker.com 23 | when: docker_install_role == 'docker-from-get.docker.com' 24 | 25 | - include_role: 26 | name: docker-from-tarball 27 | when: docker_install_role == 'docker-from-tarball' 28 | 29 | - include_role: 30 | name: docker-configuration 31 | -------------------------------------------------------------------------------- /addons/vendor/etcd-mixin/README.md: -------------------------------------------------------------------------------- 1 | # Prometheus Monitoring Mixin for etcd 2 | 3 | > NOTE: This project is *alpha* stage. Flags, configuration, behaviour and design may change significantly in following releases. 4 | 5 | A set of customisable Prometheus alerts for etcd. 6 | 7 | Instructions for use are the same as the [kubernetes-mixin](https://github.com/kubernetes-monitoring/kubernetes-mixin). 8 | 9 | ## Background 10 | 11 | * For more information about monitoring mixins, see this [design doc](https://docs.google.com/document/d/1A9xvzwqnFVSOZ5fD3blKODXfsat5fg6ZhnKu9LK3lB4/edit#). 12 | 13 | ## Testing alerts 14 | 15 | Make sure to have [jsonnet](https://jsonnet.org/) and [gojsontoyaml](https://github.com/brancz/gojsontoyaml) installed. 16 | 17 | First compile the mixin to a YAML file, which the promtool will read: 18 | ``` 19 | jsonnet -e '(import "mixin.libsonnet").prometheusAlerts' | gojsontoyaml > mixin.yaml 20 | ``` 21 | 22 | Then run the unit test: 23 | ``` 24 | promtool test rules test.yaml 25 | ``` 26 | -------------------------------------------------------------------------------- /pkg/utilities/version/version.go: -------------------------------------------------------------------------------- 1 | package version 2 | 3 | import ( 4 | "github.com/blang/semver" 5 | "github.com/pkg/errors" 6 | ) 7 | 8 | const ( 9 | // AnyRange represents any versions range. 10 | AnyRange = "*" 11 | emptyRange = "" 12 | ) 13 | 14 | // MatchesRange parses the provided version and versions range, and checks if 15 | // the provided version matches the provided range. 16 | func MatchesRange(version, versionsRange string) (bool, error) { 17 | if versionsRange == AnyRange || versionsRange == emptyRange { 18 | // Check specifically for the above special cases, as otherwise semver 19 | // fails with "Last element in range is '||'". 20 | return true, nil 21 | } 22 | v, err := semver.ParseTolerant(version) 23 | if err != nil { 24 | return false, errors.Wrapf(err, "invalid version \"%s\"", version) 25 | } 26 | r, err := semver.ParseRange(versionsRange) 27 | if err != nil { 28 | return false, errors.Wrapf(err, "invalid versions range \"%s\"", versionsRange) 29 | } 30 | return r(v), nil 31 | } 32 | -------------------------------------------------------------------------------- /.github/workflows/check-links.yaml: -------------------------------------------------------------------------------- 1 | # https://github.com/marketplace/actions/link-checker 2 | on: [push, pull_request] 3 | name: Check links in docs 4 | jobs: 5 | linkChecker: 6 | runs-on: ubuntu-latest 7 | strategy: 8 | matrix: 9 | python-version: [3.8] 10 | steps: 11 | - uses: actions/checkout@v2 12 | - name: Set up Python ${{ matrix.python-version }} 13 | uses: actions/setup-python@v1 14 | with: 15 | python-version: ${{ matrix.python-version }} 16 | - name: Install dependencies 17 | run: | 18 | python -m pip install --upgrade pip 19 | pip install -r docs/requirements.txt 20 | - name: Build docs for link check 21 | run: mkdocs build 22 | - name: Link Checker 23 | id: lc 24 | uses: peter-evans/link-checker@v1 25 | with: 26 | args: -r ./site *.md -x https://wksctl.readthedocs.io 27 | - name: Fail if there were link errors 28 | run: exit ${{ steps.lc.outputs.exit_code }} 29 | -------------------------------------------------------------------------------- /examples/gce/create-instances.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -o errexit 4 | set -o pipefail 5 | set -o nounset 6 | 7 | ensure_ssh_key() { 8 | name=$1 9 | [ -f $name ] && return 10 | ssh-keygen -q -t rsa -b 4096 -C "wks-dev@weave.works" -f $name -N "" 11 | } 12 | 13 | ensure_ssh_key cluster-key 14 | echo "wks:$(cat ./cluster-key.pub | awk '{print $1" "$2" wks"}')" > ssh_key.list 15 | 16 | gcloud compute --project="${project}" instances create ${user}-wks-{1,2,3} \ 17 | --network="${network}" \ 18 | --zone="${zone}" \ 19 | --metadata-from-file="ssh-keys=ssh_key.list" \ 20 | --machine-type=n1-standard-2 \ 21 | --image-project=${image_project} \ 22 | --image-family=${image_family} 23 | 24 | for i in ${user}-wks-1 ; do 25 | gcloud compute --project="${project}" instances add-tags "${i}" \ 26 | --zone="${zone}" \ 27 | --tags=master 28 | done 29 | 30 | for i in ${user}-wks-{2,3} ; do 31 | gcloud compute --project="${project}" instances add-tags "${i}" \ 32 | --zone="${zone}" \ 33 | --tags=node 34 | done 35 | -------------------------------------------------------------------------------- /pkg/cluster/nodes/nodes_test.go: -------------------------------------------------------------------------------- 1 | package nodes_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | "github.com/weaveworks/wksctl/pkg/cluster/nodes" 8 | corev1 "k8s.io/api/core/v1" 9 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 10 | ) 11 | 12 | var master = corev1.Node{ 13 | ObjectMeta: metav1.ObjectMeta{ 14 | Labels: map[string]string{ 15 | "node-role.kubernetes.io/master": "unused-value", 16 | }, 17 | }, 18 | } 19 | 20 | var worker = corev1.Node{ 21 | ObjectMeta: metav1.ObjectMeta{ 22 | Labels: map[string]string{}, 23 | }, 24 | } 25 | 26 | var nodeList = corev1.NodeList{ 27 | Items: []corev1.Node{ 28 | master, 29 | worker, 30 | }, 31 | } 32 | 33 | func TestMasters(t *testing.T) { 34 | masters := nodes.Masters(nodeList) 35 | assert.Len(t, masters.Items, 1) 36 | assert.Equal(t, master, masters.Items[0]) 37 | } 38 | 39 | func TestWorkers(t *testing.T) { 40 | workers := nodes.Workers(nodeList) 41 | assert.Len(t, workers.Items, 1) 42 | assert.Equal(t, worker, workers.Items[0]) 43 | } 44 | -------------------------------------------------------------------------------- /pkg/utilities/version/version_test.go: -------------------------------------------------------------------------------- 1 | package version 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestMatchesRangeAnyVersionsRangeWildcard(t *testing.T) { 10 | matches, err := MatchesRange("1.anything", "*") 11 | assert.NoError(t, err) 12 | assert.True(t, matches) 13 | } 14 | 15 | func TestMatchesRangeAnyVersionsRangeBlank(t *testing.T) { 16 | matches, err := MatchesRange("1.anything", "") 17 | assert.NoError(t, err) 18 | assert.True(t, matches) 19 | } 20 | 21 | func TestMatchesInvalidVersionsRange(t *testing.T) { 22 | matches, err := MatchesRange("1.2.3", "bad range") 23 | assert.EqualError(t, err, "invalid versions range \"bad range\": Could not get version from string: \"bad\"") 24 | assert.False(t, matches) 25 | } 26 | 27 | func TestMatchesInvalidVersion(t *testing.T) { 28 | matches, err := MatchesRange("bad version", ">1.0.0 <=1.2.3") 29 | assert.EqualError(t, err, "invalid version \"bad version\": Invalid character(s) found in major number \"bad version\"") 30 | assert.False(t, matches) 31 | } 32 | -------------------------------------------------------------------------------- /tools/config_management/roles/dev-tools/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Set up Development Environment. 3 | 4 | - name: install development tools 5 | package: 6 | name: "{{ item }}" 7 | state: present 8 | with_items: 9 | # weave net dependencies 10 | - make 11 | - vagrant 12 | # ansible dependencies 13 | - python-pip 14 | - python-dev 15 | - libffi-dev 16 | - libssl-dev 17 | # terraform dependencies 18 | - unzip 19 | # other potentially useful tools: 20 | - aufs-tools 21 | - ethtool 22 | - iputils-arping 23 | - libpcap-dev 24 | - git 25 | - mercurial 26 | - bc 27 | - jq 28 | 29 | - name: install ansible 30 | pip: 31 | name: ansible 32 | state: present 33 | 34 | - name: install terraform 35 | unarchive: 36 | src: 'https://releases.hashicorp.com/terraform/{{ terraform_version }}/terraform_{{ terraform_version }}_linux_{{ {"x86_64": "amd64", "i386": "386"}[ansible_architecture] }}.zip' 37 | remote_src: yes 38 | dest: /usr/bin 39 | mode: 0555 40 | creates: /usr/bin/terraform 41 | -------------------------------------------------------------------------------- /tools/config_management/roles/golang-from-tarball/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Set up Go. 3 | 4 | - name: install go 5 | unarchive: 6 | src: 'https://storage.googleapis.com/golang/go{{ go_version }}.linux-{{ {"x86_64": "amd64", "i386": "386"}[ansible_architecture] }}.tar.gz' 7 | remote_src: yes 8 | dest: /usr/local 9 | mode: 0777 10 | creates: /usr/local/go/bin/go 11 | 12 | - name: set go env. vars. and add go to path 13 | blockinfile: 14 | dest: '$HOME/.bashrc' 15 | block: | 16 | export PATH=$PATH:/usr/local/go/bin 17 | export GOPATH=$HOME 18 | state: present 19 | create: yes 20 | mode: 0644 21 | become: '{{ item }}' 22 | with_items: 23 | - true # Run as root 24 | - false # Run as SSH user 25 | 26 | - name: source ~/.bashrc from ~/.bash_profile 27 | lineinfile: 28 | dest: '$HOME/.bash_profile' 29 | line: '[ -r $HOME/.bashrc ] && source $HOME/.bashrc' 30 | state: present 31 | create: yes 32 | mode: 0644 33 | become: '{{ item }}' 34 | with_items: 35 | - true # Run as root 36 | - false # Run as SSH user 37 | -------------------------------------------------------------------------------- /examples/gce/cluster.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: cluster.x-k8s.io/v1alpha3 2 | kind: Cluster 3 | metadata: 4 | name: example-gce 5 | spec: 6 | clusterNetwork: 7 | pods: 8 | cidrBlocks: 9 | - 192.168.0.0/16 10 | services: 11 | cidrBlocks: 12 | - 10.96.0.0/12 13 | infrastructureRef: 14 | apiVersion: cluster.weave.works/v1alpha3 15 | kind: ExistingInfraCluster 16 | name: example-gce-provider 17 | --- 18 | apiVersion: cluster.weave.works/v1alpha3 19 | kind: ExistingInfraCluster 20 | metadata: 21 | name: example-gce-provider 22 | spec: 23 | cri: 24 | kind: docker 25 | package: docker-ce 26 | version: 19.03.8 27 | os: 28 | files: 29 | - destination: /etc/yum.repos.d/kubernetes.repo 30 | source: 31 | configmap: repo 32 | key: kubernetes.repo 33 | - destination: /etc/yum.repos.d/docker-ce.repo 34 | source: 35 | configmap: repo 36 | key: docker-ce.repo 37 | - destination: /tmp/cloud-google-com.gpg.b64 38 | source: 39 | configmap: repo 40 | key: cloud-google-com.gpg.b64 41 | user: wks -------------------------------------------------------------------------------- /tools/config_management/roles/kubernetes-install/tasks/redhat.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # RedHat / CentOS specific: 3 | 4 | - name: add kubernetes' yum repository (kubernetes-el{{ ansible_lsb.major_release }}-x86-64) 5 | yum_repository: 6 | name: kubernetes 7 | description: Kubernetes YUM repo 8 | file: external_repos 9 | baseurl: https://packages.cloud.google.com/yum/repos/kubernetes-el{{ ansible_lsb.major_release }}-x86_64 10 | enabled: yes 11 | gpgkey: https://packages.cloud.google.com/yum/doc/yum-key.gpg https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg 12 | gpgcheck: yes 13 | state: present 14 | register: yum_k8s_repo 15 | 16 | - name: update yum's cache 17 | yum: 18 | name: "*" 19 | update_cache: yes 20 | when: yum_k8s_repo.changed 21 | 22 | - name: install kubelet and kubectl 23 | package: 24 | name: "{{ item }}" 25 | state: present 26 | with_items: 27 | - kubelet-{{ kubernetes_version }}* 28 | - kubectl-{{ kubernetes_version }}* 29 | - kubeadm-{{ kubernetes_version }}* 30 | - kubernetes-cni-{{ kubernetes_cni_version }}* 31 | -------------------------------------------------------------------------------- /examples/vagrant/Vagrantfile: -------------------------------------------------------------------------------- 1 | # -*- mode: ruby -*- 2 | # vi: set ft=ruby : 3 | 4 | Vagrant.configure("2") do |config| 5 | (1..2).each do |i| 6 | config.vm.define vm_name = "%s-%02d" % ["kube", i] do |config| 7 | config.vm.box = "centos/7" 8 | config.vm.hostname = vm_name 9 | 10 | config.ssh.insert_key = false 11 | config.vm.provision "file", source: "~/.vagrant.d/insecure_private_key", destination: "/home/vagrant/.ssh/id_rsa" 12 | config.vm.provision "shell", inline: "chmod 400 /home/vagrant/.ssh/id_rsa" 13 | 14 | config.vm.provider "virtualbox" do |vb| 15 | vb.memory = "2048" 16 | vb.cpus = 2 17 | end 18 | 19 | config.vm.network :private_network, ip: "172.17.8.#{i+100}" 20 | # The below line is required for Weave Net to reach the API server 21 | # in order to get the list of peers. Without it, worker nodes never 22 | # become "Ready". 23 | config.vm.provision "shell", inline: "ip route add 10.96.0.0/16 dev eth1" 24 | end 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /pkg/utilities/tarball/tarball.go: -------------------------------------------------------------------------------- 1 | package tarball 2 | 3 | import ( 4 | "fmt" 5 | "os/exec" 6 | 7 | "github.com/weaveworks/wksctl/pkg/utilities" 8 | ) 9 | 10 | type Tarball struct { 11 | // Path is the filesystem path of the tarball file. 12 | Path string 13 | // Compression should be "" for plain .tar files, "z" for gzipped files, "j" for bzip2'ed files. 14 | Compression string 15 | } 16 | 17 | // Check returns error if `tar t` fails, and no error otherwise. 18 | func (t *Tarball) Check() error { 19 | flags := fmt.Sprintf("-t%s", t.Compression) 20 | out, err := exec.Command("tar", flags, "-f", t.Path).CombinedOutput() 21 | if err != nil { 22 | return fmt.Errorf("tar failed: %v; combined output:\n%s", err, utilities.Indent(string(out), "\t")) 23 | } 24 | return nil 25 | } 26 | 27 | func (t *Tarball) Unpack(destDir string) error { 28 | flags := fmt.Sprintf("-x%s", t.Compression) 29 | out, err := exec.Command("tar", flags, "-f", t.Path, "-C", destDir).CombinedOutput() 30 | if err != nil { 31 | return fmt.Errorf("tar failed: %v; combined output:\n%s", err, utilities.Indent(string(out), "\t")) 32 | } 33 | return nil 34 | } 35 | -------------------------------------------------------------------------------- /tools/config_management/roles/docker-from-docker-ce-repo/tasks/debian.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Debian / Ubuntu specific: 3 | 4 | - name: install dependencies for docker repository 5 | package: 6 | name: "{{ item }}" 7 | state: present 8 | with_items: 9 | - apt-transport-https 10 | - ca-certificates 11 | 12 | - name: add apt key for the docker repository 13 | apt_key: 14 | keyserver: hkp://ha.pool.sks-keyservers.net:80 15 | id: 9DC858229FC7DD38854AE2D88D81803C0EBFCD88 16 | state: present 17 | register: apt_key_docker_repo 18 | 19 | - name: add docker's apt repository ({{ ansible_distribution | lower }}-{{ ansible_distribution_release }}) 20 | apt_repository: 21 | repo: deb https://download.docker.com/linux/ubuntu {{ ansible_lsb.codename|lower }} stable 22 | state: present 23 | register: apt_docker_repo 24 | 25 | - name: update apt's cache 26 | apt: 27 | update_cache: yes 28 | when: apt_key_docker_repo.changed or apt_docker_repo.changed 29 | 30 | - name: install docker-engine 31 | package: 32 | name: "{{ item }}" 33 | state: present 34 | with_items: 35 | - docker-ce={{ docker_version }}* 36 | -------------------------------------------------------------------------------- /addons/flux/addon.json: -------------------------------------------------------------------------------- 1 | { 2 | "category": "gitops", 3 | "name": "Weaveworks Flux", 4 | "description": "The GitOps Kubernetes operator", 5 | "entryPoint": "flux.jsonnet", 6 | "params": [ 7 | { 8 | "name": "gitURL", 9 | "defaultValue": "git@github.com/owner/repo", 10 | "required": true, 11 | "description": "URL of your Git repository" 12 | }, 13 | { 14 | "name": "gitBranch", 15 | "defaultValue": "master", 16 | "description": "Branch for Flux to use" 17 | }, 18 | { 19 | "name": "gitPath", 20 | "defaultValue": ".", 21 | "description": "Relative path to directory for Flux to search" 22 | }, 23 | { 24 | "name": "namespace", 25 | "defaultValue": "flux", 26 | "description": "Override the namespace for Flux's Kubernetes objects" 27 | }, 28 | { 29 | "name": "imageRepository", 30 | "defaultValue": "", 31 | "description": "Override the container image repository" 32 | }, 33 | { 34 | "name": "gitDeployKey", 35 | "defaultValue": "", 36 | "description": "base64 encoded deployment key" 37 | } 38 | ] 39 | } 40 | -------------------------------------------------------------------------------- /tools/config_management/roles/docker-configuration/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Configure Docker 3 | # See also: https://docs.docker.com/engine/installation/linux/ubuntulinux/#install 4 | 5 | - name: ensure docker group is present (or create it) 6 | group: 7 | name: docker 8 | state: present 9 | 10 | - name: add user to docker group (avoids sudo-ing) 11 | user: 12 | name: "{{ ansible_user }}" 13 | group: docker 14 | state: present 15 | 16 | - name: ensure docker's systemd directory exists 17 | file: 18 | path: /etc/systemd/system/docker.service.d 19 | state: directory 20 | recurse: yes 21 | when: ansible_os_family != "RedHat" 22 | 23 | - name: enable docker remote api over tcp 24 | copy: 25 | src: "{{ role_path }}/files/docker.conf" 26 | dest: /etc/systemd/system/docker.service.d/docker.conf 27 | register: docker_conf 28 | when: ansible_os_family != "RedHat" 29 | 30 | - name: restart docker service 31 | systemd: 32 | name: docker 33 | state: restarted 34 | daemon_reload: yes # ensure docker.conf is picked up. 35 | enabled: yes 36 | when: docker_conf.changed or ansible_os_family == "RedHat" 37 | -------------------------------------------------------------------------------- /tools/config_management/roles/docker-from-docker-repo/tasks/debian.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Debian / Ubuntu specific: 3 | 4 | - name: install dependencies for docker repository 5 | package: 6 | name: "{{ item }}" 7 | state: present 8 | with_items: 9 | - apt-transport-https 10 | - ca-certificates 11 | 12 | - name: add apt key for the docker repository 13 | apt_key: 14 | keyserver: hkp://ha.pool.sks-keyservers.net:80 15 | id: 58118E89F3A912897C070ADBF76221572C52609D 16 | state: present 17 | register: apt_key_docker_repo 18 | 19 | - name: add docker's apt repository ({{ ansible_distribution | lower }}-{{ ansible_distribution_release }}) 20 | apt_repository: 21 | repo: deb https://apt.dockerproject.org/repo {{ ansible_distribution | lower }}-{{ ansible_distribution_release }} main 22 | state: present 23 | register: apt_docker_repo 24 | 25 | - name: update apt's cache 26 | apt: 27 | update_cache: yes 28 | when: apt_key_docker_repo.changed or apt_docker_repo.changed 29 | 30 | - name: install docker-engine 31 | package: 32 | name: "{{ item }}" 33 | state: present 34 | with_items: 35 | - docker-engine={{ docker_version }}* 36 | -------------------------------------------------------------------------------- /examples/gce/create-network.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -o errexit 4 | set -o pipefail 5 | set -o nounset 6 | 7 | gcloud compute --project="${project}" networks create "${network}" 8 | 9 | # Allow ping and SSH for all instances 10 | gcloud compute --project="${project}" firewall-rules create "${network}-external-fw-allow-ping-and-ssh" \ 11 | --network="${network}" \ 12 | --allow="tcp:22,icmp" \ 13 | --target-tags=master,node 14 | 15 | # Allow Kubernetes API port 16 | gcloud compute --project="${project}" firewall-rules create "${network}-external-fw-allow-kubernetes-api" \ 17 | --network="${network}" \ 18 | --allow="tcp:6443" \ 19 | --target-tags=master 20 | 21 | # Allow node ports for all instances 22 | gcloud compute --project="${project}" firewall-rules create "${network}-external-fw-allow-node-ports" \ 23 | --network="${network}" \ 24 | --allow="tcp:30000-32767" \ 25 | --target-tags=node 26 | 27 | # Allow all high ports internally 28 | gcloud compute --project="${project}" firewall-rules create "${network}-internal-fw" \ 29 | --network="${network}" \ 30 | --allow="tcp:1024-65535,udp:1024-65535,icmp" \ 31 | --source-tags=master,node \ 32 | --target-tags=master,node 33 | -------------------------------------------------------------------------------- /test/container/resource/os_test.go: -------------------------------------------------------------------------------- 1 | package resource 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | "github.com/weaveworks/cluster-api-provider-existinginfra/pkg/apis/wksprovider/machine/os" 9 | "github.com/weaveworks/cluster-api-provider-existinginfra/pkg/plan" 10 | "github.com/weaveworks/cluster-api-provider-existinginfra/pkg/plan/resource" 11 | "github.com/weaveworks/wksctl/test/container/images" 12 | ) 13 | 14 | const ( 15 | uuidRegexp = `[a-fA-F0-9]{6}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}` 16 | machineidRegexp = `[a-f0-9]{32}` 17 | ) 18 | 19 | func TestOS(t *testing.T) { 20 | r, closer := NewRunnerForTest(t, images.CentOS7) 21 | defer closer() 22 | 23 | os, err := os.Identify(context.Background(), r.Runner) 24 | assert.NoError(t, err) 25 | 26 | resOs := &resource.OS{} 27 | // os.apply shoud force a query and update of state. 28 | emptyDiff := plan.EmptyDiff() 29 | _, err = resOs.Apply(context.Background(), r, emptyDiff) 30 | 31 | assert.NoError(t, err) 32 | assert.Equal(t, "centos", os.Name) 33 | assert.Regexp(t, machineidRegexp, resOs.MachineID) 34 | assert.Regexp(t, uuidRegexp, resOs.SystemUUID) 35 | } 36 | -------------------------------------------------------------------------------- /cmd/wksctl/zshcompletions/zshcompletions.go: -------------------------------------------------------------------------------- 1 | package zshcompletions 2 | 3 | import ( 4 | "log" 5 | "os" 6 | 7 | "github.com/spf13/cobra" 8 | "github.com/weaveworks/wksctl/pkg/utilities" 9 | ) 10 | 11 | var ( 12 | output string 13 | zshCompletionFileName = "wksctl_zsh_completions.sh" 14 | ) 15 | 16 | var Cmd = &cobra.Command{ 17 | Use: "zsh-completions", 18 | Short: "Generate zsh completion scripts", 19 | Long: `To load completion run 20 | 21 | wksctl zsh-completions [-o ] 22 | 23 | and follow instructions for your OS to configure/install the completion file. 24 | `, 25 | Run: func(cmd *cobra.Command, args []string) { 26 | if output != "" { 27 | outfile, err := utilities.CreateFile(output, zshCompletionFileName) 28 | if err != nil { 29 | log.Fatal(err) 30 | } 31 | if err = cmd.Root().GenZshCompletion(outfile); err != nil { 32 | log.Fatal(err) 33 | } 34 | } else { 35 | if err := cmd.Root().GenZshCompletion(os.Stdout); err != nil { 36 | log.Fatal(err) 37 | } 38 | } 39 | }} 40 | 41 | func init() { 42 | Cmd.Flags().StringVarP( 43 | &output, "output", "o", "", 44 | "completion filename or directory (default stdout)") 45 | } 46 | -------------------------------------------------------------------------------- /addons/vendor/kubernetes-mixin/lib/promgrafonnet/numbersinglestat.libsonnet: -------------------------------------------------------------------------------- 1 | local grafana = import 'grafonnet/grafana.libsonnet'; 2 | local singlestat = grafana.singlestat; 3 | local prometheus = grafana.prometheus; 4 | 5 | { 6 | new(title, query):: 7 | singlestat.new( 8 | title, 9 | datasource='$datasource', 10 | span=3, 11 | valueName='current', 12 | valueMaps=[ 13 | { 14 | op: '=', 15 | text: '0', 16 | value: 'null', 17 | }, 18 | ], 19 | ) 20 | .addTarget( 21 | prometheus.target( 22 | query 23 | ) 24 | ) + { 25 | withTextNullValue(text):: self { 26 | valueMaps: [ 27 | { 28 | op: '=', 29 | text: text, 30 | value: 'null', 31 | }, 32 | ], 33 | }, 34 | withSpanSize(size):: self { 35 | span: size, 36 | }, 37 | withPostfix(postfix):: self { 38 | postfix: postfix, 39 | }, 40 | withSparkline():: self { 41 | sparkline: { 42 | show: true, 43 | lineColor: 'rgb(31, 120, 193)', 44 | fillColor: 'rgba(31, 118, 189, 0.18)', 45 | }, 46 | }, 47 | }, 48 | } 49 | -------------------------------------------------------------------------------- /cmd/wksctl/bashcompletions/bashcompletions.go: -------------------------------------------------------------------------------- 1 | package bashcompletions 2 | 3 | import ( 4 | "log" 5 | "os" 6 | 7 | "github.com/spf13/cobra" 8 | "github.com/weaveworks/wksctl/pkg/utilities" 9 | ) 10 | 11 | var ( 12 | output string 13 | bashCompletionFilename = "wksctl_bash_completion.sh" 14 | ) 15 | 16 | var Cmd = &cobra.Command{ 17 | Use: "bash-completions", 18 | Short: "Generate bash completion scripts", 19 | Long: `To generate completion files, run 20 | 21 | wksctl bash-completions [-o ] 22 | 23 | and follow instructions for your OS to configure/install the completion file. 24 | `, 25 | Run: func(cmd *cobra.Command, args []string) { 26 | if output != "" { 27 | outfile, err := utilities.CreateFile(output, bashCompletionFilename) 28 | if err != nil { 29 | log.Fatal(err) 30 | } 31 | if err = cmd.Root().GenBashCompletion(outfile); err != nil { 32 | log.Fatal(err) 33 | } 34 | } else { 35 | if err := cmd.Root().GenBashCompletion(os.Stdout); err != nil { 36 | log.Fatal(err) 37 | } 38 | } 39 | }} 40 | 41 | func init() { 42 | Cmd.Flags().StringVarP( 43 | &output, "output", "o", "", 44 | "completion filename or directory (default stdout)") 45 | } 46 | -------------------------------------------------------------------------------- /examples/vagrant/Vagrantfile-ubuntu: -------------------------------------------------------------------------------- 1 | # -*- mode: ruby -*- 2 | # vi: set ft=ruby : 3 | 4 | Vagrant.configure("2") do |config| 5 | (1..2).each do |i| 6 | config.vm.define vm_name = "%s-%02d" % ["kube", i] do |config| 7 | config.vm.box = "ubuntu/bionic64" 8 | config.vm.hostname = vm_name 9 | 10 | config.ssh.insert_key = false 11 | config.vm.provision "file", source: "~/.vagrant.d/insecure_private_key", destination: "/home/vagrant/.ssh/id_rsa" 12 | config.vm.provision "shell", inline: "chmod 400 /home/vagrant/.ssh/id_rsa" 13 | 14 | config.vm.provider "virtualbox" do |vb| 15 | vb.memory = "4096" 16 | vb.cpus = 2 17 | end 18 | 19 | config.vm.network :private_network, ip: "172.17.8.#{i+100}" 20 | config.vm.network "forwarded_port", guest: 6443, host: 6443, auto_correct: true 21 | # The below line is required for Weave Net to reach the API server 22 | # in order to get the list of peers. Without it, worker nodes never 23 | # become "Ready". 24 | #config.vm.provision "shell", inline: "ip route add 10.96.0.0/16 dev eth1" 25 | end 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /cmd/mock-authz-server/main.go: -------------------------------------------------------------------------------- 1 | // A Kubernetes Webhook Authenticator for Kerboros 2 | 3 | package main 4 | 5 | import ( 6 | "encoding/json" 7 | "log" 8 | "net/http" 9 | 10 | flag "github.com/spf13/pflag" 11 | authzv1 "k8s.io/api/authorization/v1" 12 | ) 13 | 14 | func authHandler(w http.ResponseWriter, r *http.Request) { 15 | // Decode the incoming request 16 | var sar authzv1.SubjectAccessReview 17 | err := json.NewDecoder(r.Body).Decode(&sar) 18 | if err != nil { 19 | log.Println("[Error]", err.Error()) 20 | w.WriteHeader(http.StatusBadRequest) 21 | return 22 | } 23 | 24 | log.Println(sar) 25 | 26 | if sar.Spec.User == "admin/admin" { 27 | sar.Status.Allowed = true 28 | } 29 | 30 | err = json.NewEncoder(w).Encode(sar) 31 | if err != nil { 32 | log.Println("[Error]", err.Error()) 33 | w.WriteHeader(http.StatusBadRequest) 34 | return 35 | } 36 | 37 | w.WriteHeader(http.StatusOK) 38 | } 39 | 40 | func main() { 41 | listenAddress := flag.String("listen-address", "127.0.0.1:5001", "address to listen for webhook requests") 42 | flag.Parse() 43 | 44 | http.HandleFunc("/authorize", authHandler) 45 | log.Printf("Listening for requests on %s\n", *listenAddress) 46 | log.Fatal(http.ListenAndServe(*listenAddress, nil)) 47 | } 48 | -------------------------------------------------------------------------------- /mkdocs.yml: -------------------------------------------------------------------------------- 1 | site_name: wksctl 2 | site_description: Weave Kubernetes System Control 3 | site_author: wksctl developer community 4 | site_url: https://wksctl.readthedocs.io 5 | 6 | # Repository 7 | repo_name: weaveworks/wksctl 8 | repo_url: https://github.com/weaveworks/wksctl 9 | edit_uri: "" 10 | 11 | theme: 12 | name: material 13 | logo: _static/logo.svg 14 | language: en 15 | feature: 16 | tabs: false 17 | palette: 18 | primary: blue 19 | accent: indigo 20 | highlightjs: true 21 | 22 | docs_dir: docs 23 | 24 | extra_css: 25 | - _static/custom.css 26 | 27 | markdown_extensions: 28 | - admonition 29 | - codehilite: 30 | guess_lang: false 31 | - pymdownx.superfences 32 | - toc: 33 | permalink: true 34 | 35 | plugins: 36 | - redirects: 37 | redirect_maps: 38 | 'cluster.md': 'index.md' 39 | 'development.md': 'index.md' 40 | 'faq.md': 'index.md' 41 | 'get-started.md': 'index.md' 42 | 'releasing.md': 'index.md' 43 | 'requirements.md': 'index.md' 44 | 'wks-and-firekube.md': 'index.md' 45 | 'wks-and-footloose.md': 'index.md' 46 | 'wks-and-vagrant.md': 'index.md' 47 | 'wks-on-gce.md': 'index.md' 48 | -------------------------------------------------------------------------------- /addons/vendor/etcd-mixin/test.yaml: -------------------------------------------------------------------------------- 1 | rule_files: 2 | - mixin.yaml 3 | 4 | evaluation_interval: 1m 5 | 6 | tests: 7 | - interval: 1m 8 | input_series: 9 | - series: 'up{job="etcd",instance="10.10.10.0"}' 10 | values: '1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0' 11 | - series: 'up{job="etcd",instance="10.10.10.1"}' 12 | values: '1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0' 13 | - series: 'up{job="etcd",instance="10.10.10.2"}' 14 | values: '1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0' 15 | alert_rule_test: 16 | - eval_time: 3m 17 | alertname: EtcdInsufficientMembers 18 | - eval_time: 7m 19 | alertname: EtcdInsufficientMembers 20 | - eval_time: 11m 21 | alertname: EtcdInsufficientMembers 22 | exp_alerts: 23 | - exp_labels: 24 | job: etcd 25 | severity: critical 26 | exp_annotations: 27 | message: 'Etcd cluster "etcd": insufficient members (1).' 28 | - eval_time: 15m 29 | alertname: EtcdInsufficientMembers 30 | exp_alerts: 31 | - exp_labels: 32 | job: etcd 33 | severity: critical 34 | exp_annotations: 35 | message: 'Etcd cluster "etcd": insufficient members (0).' 36 | -------------------------------------------------------------------------------- /examples/vagrant/machines.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: cluster.x-k8s.io/v1alpha3 2 | kind: Machine 3 | metadata: 4 | labels: 5 | set: master 6 | name: master-v5n5l 7 | spec: 8 | clusterName: example 9 | bootstrap: {} 10 | version: 1.18.9 11 | infrastructureRef: 12 | apiVersion: cluster.weave.works/v1alpha3 13 | kind: ExistingInfraMachine 14 | name: master-v5n5l-provider 15 | --- 16 | apiVersion: cluster.weave.works/v1alpha3 17 | kind: ExistingInfraMachine 18 | metadata: 19 | name: master-v5n5l-provider 20 | spec: 21 | private: 22 | address: 172.17.8.101 23 | port: 22 24 | public: 25 | address: 127.0.0.1 26 | port: 2222 27 | --- 28 | apiVersion: cluster.x-k8s.io/v1alpha3 29 | kind: Machine 30 | metadata: 31 | labels: 32 | set: worker 33 | name: worker-tsb5q 34 | spec: 35 | clusterName: example 36 | bootstrap: {} 37 | version: 1.18.9 38 | infrastructureRef: 39 | apiVersion: cluster.weave.works/v1alpha3 40 | kind: ExistingInfraMachine 41 | name: worker-tsb5q-provider 42 | --- 43 | apiVersion: cluster.weave.works/v1alpha3 44 | kind: ExistingInfraMachine 45 | metadata: 46 | name: worker-tsb5q-provider 47 | spec: 48 | private: 49 | address: 172.17.8.102 50 | port: 22 51 | public: 52 | address: 127.0.0.1 53 | port: 2200 54 | -------------------------------------------------------------------------------- /addons/vendor/kubernetes-mixin/Makefile: -------------------------------------------------------------------------------- 1 | JSONNET_FMT := jsonnet fmt -n 2 --max-blank-lines 2 --string-style s --comment-style s 2 | 3 | all: fmt prometheus_alerts.yaml prometheus_rules.yaml dashboards_out lint test 4 | 5 | fmt: 6 | find . -name 'vendor' -prune -o -name '*.libsonnet' -print -o -name '*.jsonnet' -print | \ 7 | xargs -n 1 -- $(JSONNET_FMT) -i 8 | 9 | prometheus_alerts.yaml: mixin.libsonnet lib/alerts.jsonnet alerts/*.libsonnet 10 | jsonnet -S lib/alerts.jsonnet > $@ 11 | 12 | prometheus_rules.yaml: mixin.libsonnet lib/rules.jsonnet rules/*.libsonnet 13 | jsonnet -S lib/rules.jsonnet > $@ 14 | 15 | dashboards_out: mixin.libsonnet lib/dashboards.jsonnet dashboards/*.libsonnet 16 | @mkdir -p dashboards_out 17 | jsonnet -J vendor -m dashboards_out lib/dashboards.jsonnet 18 | 19 | lint: prometheus_alerts.yaml prometheus_rules.yaml 20 | find . -name 'vendor' -prune -o -name '*.libsonnet' -print -o -name '*.jsonnet' -print | \ 21 | while read f; do \ 22 | $(JSONNET_FMT) "$$f" | diff -u "$$f" -; \ 23 | done 24 | 25 | promtool check rules prometheus_rules.yaml 26 | promtool check rules prometheus_alerts.yaml 27 | 28 | clean: 29 | rm -rf dashboards_out prometheus_alerts.yaml prometheus_rules.yaml 30 | 31 | test: prometheus_alerts.yaml prometheus_rules.yaml 32 | promtool test rules tests.yaml 33 | -------------------------------------------------------------------------------- /cmd/wksctl/addon/show/show.go: -------------------------------------------------------------------------------- 1 | package show 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "os" 7 | "text/tabwriter" 8 | 9 | log "github.com/sirupsen/logrus" 10 | "github.com/spf13/cobra" 11 | "github.com/weaveworks/wksctl/pkg/addons" 12 | ) 13 | 14 | var Cmd = &cobra.Command{ 15 | Use: "show", 16 | Short: "Show details about an addon", 17 | Args: addonShowArgs, 18 | Run: addonShowRun, 19 | } 20 | 21 | func addonShowArgs(cmd *cobra.Command, args []string) error { 22 | if len(args) != 1 { 23 | return errors.New("show requires an addon name") 24 | } 25 | return nil 26 | } 27 | 28 | func addonShowRun(cmd *cobra.Command, args []string) { 29 | addon, err := addons.Get(args[0]) 30 | if err != nil { 31 | log.Fatal(err) 32 | } 33 | 34 | const tabWidth = 4 35 | w := tabwriter.NewWriter(os.Stdout, 0, 0, tabWidth, ' ', 0) 36 | 37 | fmt.Fprintf(w, "Name\t%s\n", addon.Name) 38 | fmt.Fprintf(w, "Category\t%s\n", addon.Category) 39 | fmt.Fprintf(w, "Description\t%s\n", addon.Description) 40 | fmt.Fprintf(w, "Params\n") 41 | for _, param := range addon.Params { 42 | var required string 43 | if param.Required { 44 | required = "required, " 45 | } 46 | fmt.Fprintf(w, "%s\t%s\t%s\t(%sdefault: '%s')\n", "", param.Name, param.Description, required, param.DefaultValue) 47 | } 48 | 49 | w.Flush() 50 | } 51 | -------------------------------------------------------------------------------- /cmd/wksctl/profile/enable/enable_test.go: -------------------------------------------------------------------------------- 1 | package enable 2 | 3 | import ( 4 | "strings" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | const ( 11 | ignoreFileFixture = `a 12 | b/ 13 | #c 14 | #d 15 | e 16 | f 17 | ../g 18 | h.. 19 | i # this is i 20 | j/# this is j 21 | ` 22 | ) 23 | 24 | func TestParseDotIgnoreFile(t *testing.T) { 25 | r := strings.NewReader(ignoreFileFixture) 26 | lines, err := parseDotIgnorefile("", r) 27 | assert.NoError(t, err, "parsing ignore file should not be error") 28 | assert.Equal(t, 8, len(lines), "ignore file entries should be 8") 29 | // Entry: 'b/' is resolved to 'b' by path.Join() 30 | assert.Equal(t, []string{"a", "b", "e", "f", "../g", "h..", "i", "j"}, lines) 31 | } 32 | 33 | func TestParseDotIgnoreFileWithPrefix(t *testing.T) { 34 | r := strings.NewReader(ignoreFileFixture) 35 | lines, err := parseDotIgnorefile("profiles", r) 36 | assert.NoError(t, err, "parsing ignore file should not be error") 37 | assert.Equal(t, 8, len(lines), "ignore file entries should be 8") 38 | // Note: 39 | // - 'profiles/b/' is resolved to 'profiles/b' 40 | // - 'profiles/../g' is resolved to 'g' 41 | assert.Equal(t, []string{ 42 | "profiles/a", "profiles/b", "profiles/e", 43 | "profiles/f", "g", "profiles/h..", 44 | "profiles/i", "profiles/j"}, lines) 45 | } 46 | -------------------------------------------------------------------------------- /pkg/apis/wksprovider/machine/scripts/README.md: -------------------------------------------------------------------------------- 1 | # Scripts 2 | 3 | ## Introduction 4 | 5 | This package is responsible for grouping scripts and other assets required to 6 | setup Kubernetes on machines running various operating systems. 7 | 8 | By default, these files aren't packaged inside our Go binaries, and therefore 9 | not callable by it, if sources aren't kept alongside it. 10 | 11 | We therefore create a "virtual file system" using: 12 | https://github.com/shurcooL/vfsgen 13 | to artificially package these, and be able to just ship the binary. 14 | 15 | ## How does it work 16 | 17 | Given: 18 | 19 | - `assets_generate.go` (naming convention imposed by `vfsgen`) 20 | - `doc.go` 21 | - `scripts_dev.go` 22 | - and the following `Makefile` configuration: 23 | 24 | ``` 25 | SCRIPTS=$(shell find pkg/apis/wksprovider/machine/scripts -name '*.sh' -print) 26 | pkg/apis/wksprovider/machine/scripts/scripts_vfsdata.go: $(SCRIPTS) 27 | go generate ./pkg/apis/wksprovider/machine/scripts 28 | 29 | ALL_ASSETS = ... pkg/apis/wksprovider/machine/scripts/scripts_vfsdata.go 30 | ``` 31 | 32 | running `make` will eventually call `vfsgen` to read all the scripts and copy 33 | their content to `pkg/apis/wksprovider/machine/scripts/scripts_vfsdata.go`, 34 | which can later be used by the binary, instead of calling the scripts directly. 35 | -------------------------------------------------------------------------------- /tools/config_management/roles/sock-shop/tasks/tasks.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Set up sock-shop on top of Kubernetes. 3 | # Dependencies on other roles: 4 | # - kubernetes 5 | 6 | - name: create sock-shop namespace in k8s 7 | command: kubectl --kubeconfig /etc/kubernetes/admin.conf create namespace sock-shop 8 | 9 | - name: create sock-shop in k8s 10 | command: kubectl --kubeconfig /etc/kubernetes/admin.conf apply -n sock-shop -f "https://github.com/microservices-demo/microservices-demo/blob/master/deploy/kubernetes/complete-demo.yaml?raw=true" 11 | 12 | - name: describe front-end service 13 | command: kubectl --kubeconfig /etc/kubernetes/admin.conf describe svc front-end -n sock-shop 14 | changed_when: false 15 | register: kubectl_describe_svc_frontend 16 | tags: 17 | - output 18 | 19 | - name: print outpout of `kubectl describe svc front-end -n sock-shop` 20 | debug: msg="{{ kubectl_describe_svc_frontend.stdout_lines }}" 21 | tags: 22 | - output 23 | 24 | - name: list sock-shop k8s' pods 25 | command: kubectl --kubeconfig /etc/kubernetes/admin.conf get pods -n sock-shop 26 | changed_when: false 27 | register: kubectl_get_pods 28 | tags: 29 | - output 30 | 31 | - name: print outpout of `kubectl get pods -n sock-shop` 32 | debug: msg="{{ kubectl_get_pods.stdout_lines }}" 33 | tags: 34 | - output 35 | -------------------------------------------------------------------------------- /tools/config_management/roles/setup-ansible/pre_tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Set machine up to be able to run ansible playbooks. 3 | 4 | - name: check if python is installed (as required by ansible modules) 5 | raw: test -e /usr/bin/python 6 | register: is_python_installed 7 | failed_when: is_python_installed.rc not in [0, 1] 8 | changed_when: false # never mutates state. 9 | 10 | - name: install python if missing (as required by ansible modules) 11 | when: is_python_installed|failed # skip otherwise 12 | raw: (test -e /usr/bin/apt-get && apt-get install -y python-minimal) || (test -e /usr/bin/yum && yum install -y python) 13 | changed_when: is_python_installed.rc == 1 14 | 15 | - name: check if lsb_release is installed (as required for ansible facts) 16 | raw: test -e /usr/bin/lsb_release 17 | register: is_lsb_release_installed 18 | failed_when: is_lsb_release_installed.rc not in [0, 1] 19 | changed_when: false # never mutates state. 20 | 21 | - name: install lsb_release if missing (as required for ansible facts) 22 | when: is_lsb_release_installed|failed # skip otherwise 23 | raw: (test -e /usr/bin/apt-get && apt-get install -y lsb_release) || (test -e /usr/bin/yum && yum install -y lsb_release) 24 | changed_when: is_lsb_release_installed.rc == 1 25 | 26 | - setup: # gather 'facts', i.e. compensates for the above 'gather_facts: false'. 27 | -------------------------------------------------------------------------------- /tools/config_management/roles/weave-net-utilities/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: install epel-release 4 | package: 5 | name: "{{ item }}" 6 | state: present 7 | with_items: 8 | - epel-release 9 | when: ansible_os_family == "RedHat" 10 | 11 | - name: install jq 12 | package: 13 | name: "{{ item }}" 14 | state: present 15 | with_items: 16 | - jq 17 | 18 | - name: install ethtool (used by the weave script) 19 | package: 20 | name: "{{ item }}" 21 | state: present 22 | with_items: 23 | - ethtool 24 | 25 | - name: install nsenter (used by the weave script) 26 | command: docker run --rm -v /usr/local/bin:/target jpetazzo/nsenter 27 | 28 | - name: install pip (for docker-py) 29 | package: 30 | name: "{{ item }}" 31 | state: present 32 | with_items: 33 | - python-pip 34 | 35 | - name: install docker-py (for docker_image) 36 | pip: 37 | name: docker-py 38 | state: present 39 | 40 | - name: docker pull images used by tests 41 | docker_image: 42 | name: '{{ item }}' 43 | state: present 44 | with_items: 45 | - alpine 46 | - aanand/docker-dnsutils 47 | - weaveworks/hello-world 48 | 49 | - name: docker pull docker-py which is used by tests 50 | docker_image: 51 | name: joffrey/docker-py 52 | tag: '{{ item }}' 53 | state: present 54 | with_items: 55 | - '1.8.1' 56 | - '1.9.0-rc2' 57 | -------------------------------------------------------------------------------- /test/integration/test/assets/rootCA.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDqjCCApICCQDzkXC8qiB/tzANBgkqhkiG9w0BAQsFADCBljELMAkGA1UEBhMC 3 | VVMxETAPBgNVBAgMCENvbG9yYWRvMRkwFwYDVQQHDBBDb2xvcmFkbyBTcHJpbmdz 4 | MRMwEQYDVQQKDApXZWF2ZXdvcmtzMQwwCgYDVQQLDANXS1AxEjAQBgNVBAMMCWpy 5 | cnlqY2tzbjEiMCAGCSqGSIb3DQEJARYTanJyeWpja3NuQGdtYWlsLmNvbTAeFw0x 6 | OTA1MjEyMTAxMDRaFw0yMjAzMTAyMTAxMDRaMIGWMQswCQYDVQQGEwJVUzERMA8G 7 | A1UECAwIQ29sb3JhZG8xGTAXBgNVBAcMEENvbG9yYWRvIFNwcmluZ3MxEzARBgNV 8 | BAoMCldlYXZld29ya3MxDDAKBgNVBAsMA1dLUDESMBAGA1UEAwwJanJyeWpja3Nu 9 | MSIwIAYJKoZIhvcNAQkBFhNqcnJ5amNrc25AZ21haWwuY29tMIIBIjANBgkqhkiG 10 | 9w0BAQEFAAOCAQ8AMIIBCgKCAQEAptYTa44NPBXLlc+cjsPxdI52vBTm+9nLK8Ns 11 | xg+T9r2n+dlj7nS4wmZBZRJEoSTbhqUXpK9HHQcl21y2QaXbMWIZlz9JQpX/0urZ 12 | WCSBlT0KvRIbbRyb8sJMQfZ6rySrFvd/DxMkENgTo6JlEf2wr89xd0CYDW6dgT0n 13 | KpYYfmzaELlZVu9sLfmJaQPbtU/syEygHuKhu4h6wrPHHssColb43+zID5HK6pjW 14 | Sv4Lhme3mqKzShEUmSmgCTle33ORKEtSh6LzQRr+OEqLuCG4FqopKsqo/+Xye3hH 15 | soBYWsaM8czw6QdLT7K/mEoDhelbrDGrFSuUxKIcdjbu3OXMIwIDAQABMA0GCSqG 16 | SIb3DQEBCwUAA4IBAQAACd3WJOXB49vEMZvIQDuSrYtiaYHuySckMyFUYB6rJc+g 17 | Tdwdf1irNfgUgREC/E0rhYuNUxcIAexConakfW3AH22OPrivhRnGiH3ZJxVpWbs2 18 | AjQTh1Fi9AnRyrHeCC8qOhPhH4KOvOFDEfg+Re8rE07aJWIG4ukIEKom4qbkDEy/ 19 | PWM5RLfFGQihvEO7mzglUmDKxr1CV4b6fzlfEwKxmDTfX3Zlwmb+2SSNXsTpBRN4 20 | p20eXJDZHf85t1/3YixcTxRfzbB6GNS9QGmqAvX3WNOiS833VdsVLG6uguOk3FxF 21 | KTq75NsY22Bnk6I9NBjTvwcftF2IdzFH9cHUX7zm 22 | -----END CERTIFICATE----- 23 | -------------------------------------------------------------------------------- /tools/config_management/roles/kubernetes-install/tasks/debian.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Debian / Ubuntu specific: 3 | 4 | - name: add apt key for the kubernetes repository 5 | apt_key: 6 | url: https://packages.cloud.google.com/apt/doc/apt-key.gpg 7 | state: present 8 | register: apt_key_k8s_repo 9 | 10 | - name: add kubernetes' apt repository (kubernetes-{{ ansible_distribution_release }}) 11 | apt_repository: 12 | repo: deb http://apt.kubernetes.io/ kubernetes-{{ ansible_distribution_release }} main 13 | state: present 14 | register: apt_k8s_repo 15 | when: '"alpha" not in kubernetes_version and "beta" not in kubernetes_version' 16 | 17 | - name: add kubernetes' apt repository (kubernetes-{{ ansible_distribution_release }}-unstable) 18 | apt_repository: 19 | repo: deb http://apt.kubernetes.io/ kubernetes-{{ ansible_distribution_release }}-unstable main 20 | state: present 21 | register: apt_k8s_repo 22 | when: '"alpha" in kubernetes_version or "beta" in kubernetes_version' 23 | 24 | - name: update apt's cache 25 | apt: 26 | update_cache: yes 27 | when: apt_key_k8s_repo.changed or apt_k8s_repo.changed 28 | 29 | - name: install kubelet and kubectl 30 | package: 31 | name: "{{ item }}" 32 | state: present 33 | with_items: 34 | - kubelet={{ kubernetes_version }}* 35 | - kubectl={{ kubernetes_version }}* 36 | - kubeadm={{ kubernetes_version }}* 37 | - kubernetes-cni={{ kubernetes_cni_version }}* 38 | -------------------------------------------------------------------------------- /test/integration/test/assets/server.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDvjCCAqagAwIBAgIJALk+SYBJpliCMA0GCSqGSIb3DQEBCwUAMIGWMQswCQYD 3 | VQQGEwJVUzERMA8GA1UECAwIQ29sb3JhZG8xGTAXBgNVBAcMEENvbG9yYWRvIFNw 4 | cmluZ3MxEzARBgNVBAoMCldlYXZld29ya3MxDDAKBgNVBAsMA1dLUDESMBAGA1UE 5 | AwwJanJyeWpja3NuMSIwIAYJKoZIhvcNAQkBFhNqcnJ5amNrc25AZ21haWwuY29t 6 | MB4XDTE5MDYxNDEwNDQyMVoXDTI5MDYxMTEwNDQyMVoweTELMAkGA1UEBhMCVVMx 7 | ETAPBgNVBAgMCENvbG9yYWRvMRUwEwYDVQQHDAxCbGFjayBGb3Jlc3QxEzARBgNV 8 | BAoMCldlYXZld29ya3MxDDAKBgNVBAsMA1dLUDEdMBsGA1UEAwwUaG9zdC5kb2Nr 9 | ZXIuaW50ZXJuYWwwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDiJI1q 10 | 1/yF3oCzGYbOqQjyfx73OvLWbsUhKMKDNpKVjI1xV8f5AQLR4WvX7b5GH5tXP2H7 11 | zT55tF72RsL5qA1ZTtzQ3OEmNbztUSsL5ogMMLIWSsTDen9WDbzQaEKT+qa6r4G5 12 | Hhqg1sb7p8nDh+HMNpoNiyernYjgI+GNeZddhKXT7ecl+3weJxPCBOzo7mo1525T 13 | nRNt69fD4zYYHatlsNcjacJdco7aSx9crbwnIKAV79g7N8N2RMmWpwR0UU0+S5xP 14 | evI8TlKCOnBELHHBUQVuCmRVs2QoHVYTXLr4Ztp/mJDI+n88+ng5+3R1XUL12laX 15 | mDqXxxT0I88azM55AgMBAAGjKzApMAkGA1UdEwQCMAAwCwYDVR0PBAQDAgXgMA8G 16 | A1UdEQQIMAaHBH8AAAEwDQYJKoZIhvcNAQELBQADggEBAGgUTPb0SAvbRFS0RPra 17 | vvEr2wdlkswdzjOPY7L9ZrjaA0KKvSPz6BuvwNHg7RxLwngPhPHPxKHaXU83FBcJ 18 | sIqgH0Y5zmMWI2KQh8WefhhCe9UGJMuKUPTYD6+h17XPMJz9lZtJvTGrqVYdUbGE 19 | 2i90ztSvxUUgxIhP2s11MsFyY5CV1y7ru6QyxhDrcGaZQnaVXXdE8QFyMAOKdZuw 20 | y1AhfwPSq0ZRSjVi8znFNkQuarlxbL7UmiD4FxIFJKI/ywbrVU3Y8OH5MEqIdAHl 21 | M7LEj/t4E/6wnqrA7quPZLiGI1DT8qNFVNgaHrRodri3oLVQR2IZbDR1Qyqe47vQ 22 | 2xk= 23 | -----END CERTIFICATE----- 24 | -------------------------------------------------------------------------------- /docs/_static/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /pkg/utilities/file.go: -------------------------------------------------------------------------------- 1 | package utilities 2 | 3 | import ( 4 | "log" 5 | "os" 6 | "path/filepath" 7 | "strings" 8 | ) 9 | 10 | //CreateFile creates the file named in fname or a file named defaultName in the directory named in fname 11 | func CreateFile(fname, defaultName string) (*os.File, error) { 12 | if isDir(fname) { 13 | // Create the default completion file in the directory 14 | f, err := CreateFile(filepath.Join(fname, defaultName), "") 15 | if err != nil { 16 | log.Fatal(err) 17 | } 18 | return f, nil 19 | } 20 | f, err := os.Create(fname) 21 | if err != nil { 22 | log.Fatal(err) 23 | } 24 | return f, nil 25 | 26 | } 27 | 28 | /* 29 | Heuristically determines if the passed in filename is a directory 30 | 31 | A filename is determined to be a directory if 32 | - the filename ends in "/" 33 | - the filename matches an existing directory 34 | */ 35 | func isDir(fname string) bool { 36 | if strings.HasSuffix(fname, "/") { 37 | // create the directory if it doesn't exist 38 | if err := os.MkdirAll(fname, 0755); err != nil { 39 | log.Fatal(err) 40 | } 41 | return true 42 | } 43 | finfo, err := os.Stat(fname) 44 | if err == nil { 45 | return finfo.IsDir() 46 | } 47 | return false 48 | } 49 | 50 | // FileExists returns whether or not a filename corresponds to an actual file 51 | func FileExists(filename string) bool { 52 | info, err := os.Stat(filename) 53 | if os.IsNotExist(err) { 54 | return false 55 | } 56 | return !info.IsDir() 57 | } 58 | -------------------------------------------------------------------------------- /addons/vendor/kubernetes-mixin/lib/promgrafonnet/gauge.libsonnet: -------------------------------------------------------------------------------- 1 | local grafana = import 'grafonnet/grafana.libsonnet'; 2 | local singlestat = grafana.singlestat; 3 | local prometheus = grafana.prometheus; 4 | 5 | { 6 | new(title, query):: 7 | singlestat.new( 8 | title, 9 | datasource='$datasource', 10 | span=3, 11 | format='percent', 12 | valueName='current', 13 | colors=[ 14 | 'rgba(245, 54, 54, 0.9)', 15 | 'rgba(237, 129, 40, 0.89)', 16 | 'rgba(50, 172, 45, 0.97)', 17 | ], 18 | thresholds='50, 80', 19 | valueMaps=[ 20 | { 21 | op: '=', 22 | text: 'N/A', 23 | value: 'null', 24 | }, 25 | ], 26 | ) 27 | .addTarget( 28 | prometheus.target( 29 | query 30 | ) 31 | ) + { 32 | gauge: { 33 | maxValue: 100, 34 | minValue: 0, 35 | show: true, 36 | thresholdLabels: false, 37 | thresholdMarkers: true, 38 | }, 39 | withTextNullValue(text):: self { 40 | valueMaps: [ 41 | { 42 | op: '=', 43 | text: text, 44 | value: 'null', 45 | }, 46 | ], 47 | }, 48 | withSpanSize(size):: self { 49 | span: size, 50 | }, 51 | withLowerBeingBetter():: self { 52 | colors: [ 53 | 'rgba(50, 172, 45, 0.97)', 54 | 'rgba(237, 129, 40, 0.89)', 55 | 'rgba(245, 54, 54, 0.9)', 56 | ], 57 | thresholds: '80, 90', 58 | }, 59 | }, 60 | } 61 | -------------------------------------------------------------------------------- /pkg/addons/addon_test.go: -------------------------------------------------------------------------------- 1 | package addons 2 | 3 | import ( 4 | "io/ioutil" 5 | "os" 6 | "testing" 7 | 8 | "github.com/stretchr/testify/assert" 9 | "github.com/weaveworks/wksctl/pkg/registry" 10 | ) 11 | 12 | func TestListImages(t *testing.T) { 13 | addon, err := Get("flux") 14 | assert.NoError(t, err, "missing 'flux' addon") 15 | 16 | images, err := addon.ListImages() 17 | 18 | assert.NoError(t, err) 19 | assert.NotEmpty(t, images) 20 | assert.Equal(t, 2, len(images)) 21 | matchCount := 0 22 | image1 := registry.Image{ 23 | Registry: "", 24 | User: "fluxcd", 25 | Name: "flux", 26 | Tag: "1.13.3", 27 | } 28 | image2 := registry.Image{ 29 | Registry: "", 30 | User: "", 31 | Name: "memcached", 32 | Tag: "1.4.25", 33 | } 34 | for _, image := range images { 35 | if image == image1 || image == image2 { 36 | matchCount++ 37 | } 38 | } 39 | assert.Equal(t, 2, matchCount) 40 | } 41 | 42 | func TestBuildAllAddons(t *testing.T) { 43 | dir, err := ioutil.TempDir("", t.Name()) 44 | assert.NoError(t, err) 45 | defer os.RemoveAll(dir) 46 | 47 | for _, addon := range List() { 48 | t.Run(addon.ShortName, func(t *testing.T) { 49 | _, err = addon.autoBuild(BuildOptions{ 50 | OutputDirectory: dir, 51 | }) 52 | assert.NoError(t, err) 53 | }) 54 | } 55 | } 56 | 57 | func TestListImagesAllAddons(t *testing.T) { 58 | for _, addon := range List() { 59 | t.Run(addon.ShortName, func(t *testing.T) { 60 | images, err := addon.ListImages() 61 | assert.NoError(t, err) 62 | assert.True(t, len(images) >= 1) 63 | }) 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /test/integration/test/terraform.go: -------------------------------------------------------------------------------- 1 | package test 2 | 3 | import ( 4 | "encoding/json" 5 | "io" 6 | "os" 7 | ) 8 | 9 | const ( 10 | keyPublicIPs = "public_ips" 11 | keyPrivateIPs = "private_ips" 12 | ) 13 | 14 | type terraformVariable struct { 15 | Sensitive bool 16 | Type string 17 | Value interface{} 18 | } 19 | 20 | func (v *terraformVariable) asString() string { 21 | return v.Value.(string) 22 | } 23 | 24 | func (v *terraformVariable) asStringArray() []string { 25 | a := v.Value.([]interface{}) 26 | r := make([]string, len(a)) 27 | for i, v := range a { 28 | r[i] = v.(string) 29 | } 30 | return r 31 | } 32 | 33 | type terraformOutput struct { 34 | data map[string]*terraformVariable 35 | } 36 | 37 | func newTerraformOutput(r io.Reader) (*terraformOutput, error) { 38 | output := &terraformOutput{ 39 | data: make(map[string]*terraformVariable), 40 | } 41 | decoder := json.NewDecoder(r) 42 | 43 | if err := decoder.Decode(&output.data); err != nil { 44 | return nil, err 45 | } 46 | 47 | return output, nil 48 | } 49 | 50 | func newTerraformOutputFromFile(path string) (*terraformOutput, error) { 51 | r, err := os.Open(path) 52 | if err != nil { 53 | return nil, err 54 | } 55 | return newTerraformOutput(r) 56 | } 57 | 58 | func (o *terraformOutput) numMachines() int { 59 | return len(o.stringArrayVar(keyPublicIPs)) 60 | } 61 | 62 | func (o *terraformOutput) stringVar(name string) string { 63 | return o.data[name].asString() 64 | } 65 | 66 | func (o *terraformOutput) stringArrayVar(name string) []string { 67 | return o.data[name].asStringArray() 68 | } 69 | -------------------------------------------------------------------------------- /test/container/resource/rpm_test.go: -------------------------------------------------------------------------------- 1 | package resource 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | "github.com/weaveworks/cluster-api-provider-existinginfra/pkg/plan" 9 | "github.com/weaveworks/cluster-api-provider-existinginfra/pkg/plan/resource" 10 | "github.com/weaveworks/wksctl/test/container/images" 11 | "github.com/weaveworks/wksctl/test/container/testutils" 12 | ) 13 | 14 | func TestRPM(t *testing.T) { 15 | r, closer := NewRunnerForTest(t, images.CentOS7) 16 | defer closer() 17 | emptyDiff := plan.EmptyDiff() 18 | 19 | // First, make isn't installed. 20 | p := &resource.RPM{ 21 | Name: "make", 22 | } 23 | 24 | testutils.AssertEmptyState(t, p, r) 25 | 26 | // Install make. 27 | _, err := p.Apply(context.Background(), r, emptyDiff) 28 | assert.NoError(t, err) 29 | 30 | // Verify make is installed. 31 | installedState, err := p.QueryState(context.Background(), r) 32 | assert.NoError(t, err) 33 | assert.Equal(t, "make", installedState["name"]) 34 | assert.NotZero(t, installedState["version"]) 35 | assert.NotZero(t, installedState["release"]) 36 | 37 | // Verify that, if we apply again, no command will actually be issued. 38 | r.ResetOperations() 39 | installedDiff := plan.Diff{ 40 | CurrentState: installedState, 41 | InvalidatedDeps: []plan.Resource{}} 42 | _, err = p.Apply(context.Background(), r, installedDiff) 43 | assert.NoError(t, err) 44 | assert.Equal(t, 0, len(r.Operations())) 45 | 46 | // Undo the install. 47 | err = p.Undo(context.Background(), r, installedState) 48 | assert.NoError(t, err) 49 | testutils.AssertEmptyState(t, p, r) 50 | } 51 | -------------------------------------------------------------------------------- /pkg/specs/parse_test.go: -------------------------------------------------------------------------------- 1 | package specs 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "os" 7 | "testing" 8 | 9 | "github.com/stretchr/testify/assert" 10 | ) 11 | 12 | const clusterMissingClusterDefinition = ` 13 | apiVersion: "cluster.weave.works/v1alpha3" 14 | kind: "ExistingInfraCluster" 15 | metadata: 16 | name: example 17 | spec: 18 | user: "vagrant" 19 | ` 20 | 21 | const clusterMissingExistingInfraClusterDefinition = ` 22 | apiVersion: "cluster.x-k8s.io/v1alpha3" 23 | kind: Cluster 24 | metadata: 25 | name: example 26 | spec: 27 | clusterNetwork: 28 | services: 29 | cidrBlocks: ["10.96.0.0/12"] 30 | pods: 31 | cidrBlocks: ["192.168.0.0/16"] 32 | infrastructureRef: 33 | kind: ExistingInfraCluster 34 | name: example 35 | ` 36 | 37 | func mergeObjects(a string, b string) string { 38 | return fmt.Sprintf("%s---%s", a, b) 39 | } 40 | 41 | func parseConfig(s string) (err error) { 42 | f, err := ioutil.TempFile("", "") 43 | if err != nil { 44 | return err 45 | } 46 | defer os.Remove(f.Name()) 47 | _, err = f.WriteString(s) 48 | if err != nil { 49 | return err 50 | } 51 | if err = f.Close(); err != nil { 52 | return err 53 | } 54 | 55 | _, _, err = ParseClusterManifest(f.Name()) 56 | return err 57 | } 58 | 59 | func TestParseCluster(t *testing.T) { 60 | assert.NoError(t, parseConfig(mergeObjects(clusterMissingExistingInfraClusterDefinition, clusterMissingClusterDefinition))) 61 | 62 | // Verify that the objects individually don't result in a successful parse 63 | assert.Error(t, parseConfig(clusterMissingClusterDefinition)) 64 | assert.Error(t, parseConfig(clusterMissingExistingInfraClusterDefinition)) 65 | } 66 | -------------------------------------------------------------------------------- /addons/mixin.libsonnet: -------------------------------------------------------------------------------- 1 | // imageName extracts the image name from a fully qualified image string. eg. 2 | // quay.io/coreos/addon-resizer -> addon-resizer 3 | // grafana/grafana -> grafana 4 | local imageName(image) = 5 | local parts = std.split(image, '/'); 6 | local len = std.length(parts); 7 | if len == 3 then 8 | # registry.com/org/image 9 | parts[2] 10 | else if len == 2 then 11 | # org/image 12 | parts[1] 13 | else if len == 1 then 14 | # image, ie. busybox 15 | parts[0] 16 | else 17 | error 'unknown image format: ' + image; 18 | 19 | // withImageRepository is a mixin that replaces all images prefixes by repository. eg. 20 | // quay.io/coreos/addon-resizer -> $repository/addon-resizer 21 | // grafana/grafana -> grafana $repository/grafana 22 | local withImageRepository(repository) = { 23 | local images = super.images, 24 | local substituteRepository(image, repository) = 25 | if repository == null then image else repository + '/' + imageName(image), 26 | images+:: { 27 | [image]+: { 28 | repo: substituteRepository(images[image].repo, repository), 29 | } 30 | for image in std.objectFields(images) 31 | }, 32 | }; 33 | 34 | { 35 | withImageRepository:: withImageRepository, 36 | runOnMasterNodes:: { 37 | spec+: { 38 | template+: { 39 | spec+: { 40 | nodeSelector+: { 41 | 'node-role.kubernetes.io/master': '', 42 | }, 43 | tolerations+: [ 44 | { 45 | key: 'node-role.kubernetes.io/master', 46 | effect: 'NoSchedule' 47 | }, 48 | ], 49 | }, 50 | }, 51 | }, 52 | }, 53 | } 54 | -------------------------------------------------------------------------------- /test/container/resource/file_test.go: -------------------------------------------------------------------------------- 1 | package resource 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "io/ioutil" 7 | "testing" 8 | 9 | "github.com/weaveworks/cluster-api-provider-existinginfra/pkg/plan" 10 | "github.com/weaveworks/cluster-api-provider-existinginfra/pkg/plan/resource" 11 | "github.com/weaveworks/wksctl/test/container/images" 12 | "github.com/weaveworks/wksctl/test/container/testutils" 13 | 14 | "github.com/stretchr/testify/assert" 15 | ) 16 | 17 | func TestFile(t *testing.T) { 18 | r, closer := NewRunnerForTest(t, images.CentOS7) 19 | defer closer() 20 | 21 | srcPath := "testdata/daemon.json" 22 | file := &resource.File{ 23 | Source: srcPath, 24 | Destination: "/this/dir/does/not/exist/daemon.json", 25 | } 26 | 27 | emptyDiff := plan.EmptyDiff() 28 | 29 | // File shouldn't exist just yet. 30 | testutils.AssertEmptyState(t, file, r) 31 | 32 | // Go create that file and check that it exists and has the right content. 33 | _, err := file.Apply(context.Background(), r, emptyDiff) 34 | assert.NoError(t, err) 35 | 36 | remoteContent, err := r.RunCommand(context.Background(), fmt.Sprintf("cat %q", file.Destination), nil) 37 | assert.NoError(t, err) 38 | 39 | localContent, err := ioutil.ReadFile(srcPath) 40 | if err != nil { 41 | t.Fatalf("ReadFile %q failed: %v", srcPath, err) 42 | } 43 | 44 | assert.Equal(t, string(localContent), remoteContent) 45 | 46 | // Query the state and ensures it's consistent. 47 | realizedState, err := file.QueryState(context.Background(), r) 48 | assert.NoError(t, err) 49 | assert.Equal(t, realizedState, file.State()) 50 | 51 | // Undo and check the file isn't there. 52 | err = file.Undo(context.Background(), r, realizedState) 53 | assert.NoError(t, err) 54 | 55 | } 56 | -------------------------------------------------------------------------------- /pkg/plan/recipe/install_plans.go: -------------------------------------------------------------------------------- 1 | package recipe 2 | 3 | import ( 4 | "fmt" 5 | 6 | log "github.com/sirupsen/logrus" 7 | "github.com/weaveworks/cluster-api-provider-existinginfra/pkg/plan" 8 | "github.com/weaveworks/cluster-api-provider-existinginfra/pkg/plan/resource" 9 | "github.com/weaveworks/cluster-api-provider-existinginfra/pkg/utilities/object" 10 | ) 11 | 12 | // BuildConfigMapPlan creates a plan to handle config maps 13 | func BuildConfigMapPlan(manifests map[string][]byte, namespace string) plan.Resource { 14 | b := plan.NewBuilder() 15 | for name, manifest := range manifests { 16 | remoteName := fmt.Sprintf("config-map-%s", name) 17 | b.AddResource("install:"+remoteName, &resource.KubectlApply{Filename: object.String(remoteName), Manifest: manifest, Namespace: object.String(namespace)}) 18 | } 19 | p, err := b.Plan() 20 | if err != nil { 21 | log.Fatalf("%v", err) 22 | } 23 | return &p 24 | } 25 | 26 | // BuildAddonPlan creates a plan containing all the addons from the cluster manifest 27 | func BuildAddonPlan(clusterManifestPath string, addons map[string][][]byte) plan.Resource { 28 | b := plan.NewBuilder() 29 | for name, manifests := range addons { 30 | var previous *string 31 | for i, m := range manifests { 32 | resFile := fmt.Sprintf("%s-%02d", name, i) 33 | resName := "install:addon:" + resFile 34 | manRsc := &resource.KubectlApply{Manifest: m, Filename: object.String(resFile + ".yaml"), Namespace: object.String("addons")} 35 | 36 | if previous != nil { 37 | b.AddResource(resName, manRsc, plan.DependOn(*previous)) 38 | } else { 39 | b.AddResource(resName, manRsc) 40 | } 41 | previous = &resName 42 | } 43 | } 44 | p, err := b.Plan() 45 | if err != nil { 46 | log.Fatalf("%v", err) 47 | } 48 | return &p 49 | } 50 | -------------------------------------------------------------------------------- /tools/config_management/roles/kubernetes-start/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Start Kubernetes 3 | 4 | - name: kubeadm reset 5 | command: kubeadm reset 6 | 7 | - name: restart kubelet service 8 | systemd: 9 | name: kubelet 10 | state: restarted 11 | enabled: yes 12 | 13 | - name: optionally set kubeconfig option 14 | set_fact: 15 | kubeconfig: '{{ (kubernetes_version >= "1.5.4") | ternary("--kubeconfig /etc/kubernetes/admin.conf", "") }}' 16 | kubernetes_version_option: '{{ (kubernetes_version >= "1.6") | ternary("kubernetes_version", "use-kubernetes-version") }}' 17 | 18 | - name: kubeadm init on the master 19 | command: 'kubeadm init --{{ kubernetes_version_option }}=v{{ kubernetes_version }} --token={{ kubernetes_token }}' 20 | when: ' {{ play_hosts[0] == inventory_hostname }}' 21 | 22 | - name: allow pods to be run on the master (if only node) 23 | command: 'kubectl {{ kubeconfig }} taint nodes --all {{ (kubernetes_version < "1.6") | ternary("dedicated-", "node-role.kubernetes.io/master:NoSchedule-") }}' 24 | when: '{{ play_hosts | length }} == 1' 25 | 26 | - name: kubeadm join on workers 27 | command: 'kubeadm join --token={{ kubernetes_token }} {{ hostvars[play_hosts[0]].private_ip }}{{ (kubernetes_version > "1.6") | ternary(":6443", "") }}' 28 | when: ' {{ play_hosts[0] != inventory_hostname }}' 29 | 30 | - name: list kubernetes' pods 31 | command: kubectl {{ kubeconfig }} get pods --all-namespaces 32 | when: ' {{ play_hosts[0] == inventory_hostname }}' 33 | changed_when: false 34 | register: kubectl_get_pods 35 | tags: 36 | - output 37 | 38 | - name: print outpout of `kubectl get pods --all-namespaces` 39 | debug: msg="{{ kubectl_get_pods.stdout_lines }}" 40 | when: ' {{ play_hosts[0] == inventory_hostname }}' 41 | tags: 42 | - output 43 | -------------------------------------------------------------------------------- /test/integration/test/assets/server.key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEpQIBAAKCAQEA4iSNatf8hd6AsxmGzqkI8n8e9zry1m7FISjCgzaSlYyNcVfH 3 | +QEC0eFr1+2+Rh+bVz9h+80+ebRe9kbC+agNWU7c0NzhJjW87VErC+aIDDCyFkrE 4 | w3p/Vg280GhCk/qmuq+BuR4aoNbG+6fJw4fhzDaaDYsnq52I4CPhjXmXXYSl0+3n 5 | Jft8HicTwgTs6O5qNeduU50TbevXw+M2GB2rZbDXI2nCXXKO2ksfXK28JyCgFe/Y 6 | OzfDdkTJlqcEdFFNPkucT3ryPE5SgjpwRCxxwVEFbgpkVbNkKB1WE1y6+Gbaf5iQ 7 | yPp/PPp4Oft0dV1C9dpWl5g6l8cU9CPPGszOeQIDAQABAoIBAQCipCNJOnmVVgc9 8 | yBgaPZv/u8lrievoqNYCGSx77h3SjLmVUMqznTSH+hXzwDreeBDi2OUBkgVixoSd 9 | nxrPLzwahQtu88zCDFgKXhwVfQFPsx4BxlhpNoqqO0sWoEVx5A1RqrQjjTEdiBqo 10 | F26Wv/13P7XgE7q+RJiSi3vGojJowIlXpOin8Y1xDIjRiYto55pwOQW/F4dG4bFD 11 | Ofy+0Vd3DtJREhdNawRYyaMgiHMTnF6xXxW96H5OsD+Spyi0dHf8TD9jlEO4Elg3 12 | Jkvcm32oaQT9noghPMh+NSHRwSHhC0CDQIzXcwyCKL8z6pViTP1fJa9CxBFpbDFK 13 | Vtd4MIKZAoGBAP56cMEE49C4H/6GtQB6iTU9obYEvTPsO/E3Z1Txs7ACiAVki7ny 14 | acwAPusgTbJvNadCmkv+v7UHx31fvF3k6E9Ez1F1BFa5wwucwk38D+jPhTbUwLZw 15 | CP8qB4TA6PxRGFBrUi633241esAK6hd5dnpPZaQ2WANjKXtWx+so0YgnAoGBAON+ 16 | vEq4jJkwge3olI86LxfAD6KPeoXHZff3q3J6Hv7fQLWtVTGwHnG7Bidth+q3Usum 17 | MLIWTqWUM5feMohBaPI9HXaTk1fNHaOA0C5YXZFzVFqPfgcaOZkmSjgLmcxv8dF3 18 | PR3hyePjcF+/WL7XPO/txjU30EDdfQ072uiLn3hfAoGBAJibyN6YFh7nLJixI/7j 19 | fUEmcsH7WZO3ycLAnQE96apV+khxobGjhHrIcvMCblXhh2WE9Y85eLIRtjqjnQ0Z 20 | 548SDtokuLNht2xRV9z4mnndaWAWenNuAJc1F0kvfwlBgLlJgwFtV1p6S+C7KuNk 21 | /f4fey7dQC7X2tqSklWeJvnlAoGBAJPACAJvgcEsY/ZkC7hKDbPbJUxq6yRfsLYv 22 | wMYE0oSt8pUMEjzHKb6rvP92f8PNdJSXRyEio8meSzPjN+aOtN4/GxecGSH5Mbqz 23 | OoIfGgYRZUO71ho+yhHRcHqd7jF8sw1b5/G0Zy7+1EkbOUQY/pbFUunVagf20fT6 24 | Xt6Rb+z5AoGAIMNO0ewU7Gf6i+Po9BjbKsfWbudmo0EES9hRX7uch3QsVsx3ZY6U 25 | 5Tlu6KKaqB4Dpc0sQVhCG3lIidIoFe16PaxGKfKyQ95GAdgW5g8trXz10usO3UzX 26 | xuKZ7GVTsmxqctZqX1mbMV3djzNPOONK7FVMwawhexnl6KRrUyjN7og= 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /test/container/resource/deb_test.go: -------------------------------------------------------------------------------- 1 | package resource 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | "github.com/weaveworks/cluster-api-provider-existinginfra/pkg/plan" 9 | "github.com/weaveworks/cluster-api-provider-existinginfra/pkg/plan/resource" 10 | "github.com/weaveworks/wksctl/test/container/images" 11 | "github.com/weaveworks/wksctl/test/container/testutils" 12 | ) 13 | 14 | func TestDeb(t *testing.T) { 15 | r, closer := NewRunnerForTest(t, images.Ubuntu1804) 16 | defer closer() 17 | 18 | AssertNotInstalled(t, "nonexistent", r) 19 | 20 | AssertInstalled(t, "libc6", r) 21 | 22 | AssertNotInstalled(t, "busybox", r) 23 | InstallAndAssertSuccess(t, "busybox", "", r) 24 | AssertInstalled(t, "busybox", r) 25 | PurgeAndAssertSuccess(t, "busybox", r) 26 | AssertNotInstalled(t, "busybox", r) 27 | } 28 | 29 | func AssertNotInstalled(t *testing.T, name string, r plan.Runner) { 30 | testutils.AssertEmptyState(t, &resource.Deb{Name: name}, r) 31 | } 32 | 33 | func AssertInstalled(t *testing.T, name string, r plan.Runner) { 34 | res := resource.Deb{Name: name} 35 | installedState, err := res.QueryState(context.Background(), r) 36 | assert.NoError(t, err) 37 | assert.Equal(t, name, installedState["name"]) 38 | assert.NotZero(t, installedState["suffix"]) 39 | } 40 | 41 | func InstallAndAssertSuccess(t *testing.T, name, suffix string, r plan.Runner) { 42 | res := resource.Deb{Name: name, Suffix: suffix} 43 | prop, err := res.Apply(context.Background(), r, plan.EmptyDiff()) 44 | assert.NoError(t, err) 45 | assert.True(t, prop) 46 | } 47 | 48 | func PurgeAndAssertSuccess(t *testing.T, name string, r plan.Runner) { 49 | res := resource.Deb{Name: name} 50 | err := res.Undo(context.Background(), r, res.State()) 51 | assert.NoError(t, err) 52 | } 53 | -------------------------------------------------------------------------------- /tools/config_management/roles/docker-from-tarball/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Set up Docker 3 | # See also: 4 | # - https://docs.docker.com/engine/installation/linux/ubuntulinux/#install 5 | # - https://github.com/docker/docker/releases 6 | 7 | - include_role: 8 | name: docker-prerequisites 9 | 10 | - name: install daemon 11 | package: 12 | name: daemon 13 | state: present 14 | 15 | - name: 'create directory {{ docker_dir }}/{{ docker_version }}' 16 | file: 17 | path: '{{ docker_dir }}/{{ docker_version }}' 18 | state: directory 19 | mode: 0755 20 | 21 | - name: download and extract docker 22 | unarchive: 23 | src: 'https://get.docker.com/builds/Linux/x86_64/docker-{{ docker_version }}.tgz' 24 | remote_src: yes 25 | dest: '{{ docker_dir }}/{{ docker_version }}' 26 | extra_opts: '--strip-components=1' 27 | mode: 0555 28 | creates: '{{ docker_dir }}/{{ docker_version }}/docker' 29 | 30 | - name: create symlink to current version 31 | file: 32 | src: '{{ docker_dir }}/{{ docker_version }}' 33 | dest: '{{ docker_dir }}/current' 34 | state: link 35 | mode: 0555 36 | 37 | - name: list all files to symlink 38 | find: 39 | paths: '{{ docker_dir }}/current' 40 | file_type: file 41 | register: binaries 42 | changed_when: false 43 | 44 | - name: create symlinks to all binaries 45 | file: 46 | src: '{{ item }}' 47 | dest: /usr/bin/{{ item | basename }} 48 | state: link 49 | with_items: "{{ binaries.files | map(attribute='path') | list }}" 50 | 51 | - name: killall docker 52 | command: killall docker 53 | register: killall 54 | failed_when: false 55 | changed_when: killall.rc == 0 56 | 57 | - name: start dockerd 58 | command: daemon -- /usr/bin/dockerd 59 | 60 | - include_role: 61 | name: docker-configuration 62 | -------------------------------------------------------------------------------- /pkg/utilities/path/path.go: -------------------------------------------------------------------------------- 1 | package path 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "path/filepath" 7 | 8 | capeipath "github.com/weaveworks/cluster-api-provider-existinginfra/pkg/utilities/path" 9 | ) 10 | 11 | // WKSHome sanitises the provided (optional) artifact directory or defaults it. 12 | func WKSHome(artifactDirectory string) string { 13 | // Command line option overrides the default home directory. 14 | if artifactDirectory != "" { 15 | return capeipath.ExpandHome(artifactDirectory) 16 | } 17 | if userHome, err := os.UserHomeDir(); err == nil { 18 | return filepath.Join(userHome, ".wks") 19 | } 20 | wd, _ := os.Getwd() 21 | return wd 22 | } 23 | 24 | // WKSResourcePath joins the provided (optional) artifact directory and the 25 | // provided path components into a well-formed path. 26 | func WKSResourcePath(artifactDirectory string, paths ...string) string { 27 | args := []string{WKSHome(artifactDirectory)} 28 | args = append(args, paths...) 29 | return filepath.Join(args...) 30 | } 31 | 32 | // CreateDirectory creates directories corresponding to the provided path. 33 | func CreateDirectory(path string) (string, error) { 34 | // Create wksHome if it doesn't exist, or ensure it's a directory if it does 35 | if wksHomeStat, err := os.Stat(path); err != nil { 36 | if !os.IsNotExist(err) { 37 | return "", fmt.Errorf("Error stating: %v", err) 38 | } 39 | if err := os.MkdirAll(path, 0755); err != nil { 40 | return "", fmt.Errorf("Error creating: %v", err) 41 | } 42 | } else { 43 | if !wksHomeStat.IsDir() { 44 | return "", fmt.Errorf("Not a directory: %v", path) 45 | } 46 | } 47 | return path, nil 48 | } 49 | 50 | func Kubeconfig(artifactDirectory, ns, clusterName string) string { 51 | return filepath.Join(WKSResourcePath(artifactDirectory, ns, clusterName), "kubeconfig") 52 | } 53 | -------------------------------------------------------------------------------- /tools/config_management/library/setup_ansible_dependencies.yml: -------------------------------------------------------------------------------- 1 | --- 2 | ################################################################################ 3 | # Install Ansible's dependencies: python and lsb_release, required respectively 4 | # to run Ansible modules and gather Ansible facts. 5 | # 6 | # See also: 7 | # - http://docs.ansible.com/ansible/intro_installation.html#managed-node-requirements 8 | # - http://docs.ansible.com/ansible/setup_module.html 9 | ################################################################################ 10 | 11 | - name: check if python is installed (as required by ansible modules) 12 | raw: test -e /usr/bin/python 13 | register: is_python_installed 14 | failed_when: is_python_installed.rc not in [0, 1] 15 | changed_when: false # never mutates state. 16 | 17 | - name: install python if missing (as required by ansible modules) 18 | when: is_python_installed|failed # skip otherwise 19 | raw: (test -e /usr/bin/apt-get && apt-get update && apt-get install -y python-minimal) || (test -e /usr/bin/yum && yum update && yum install -y python) 20 | changed_when: is_python_installed.rc == 1 21 | 22 | - name: check if lsb_release is installed (as required for ansible facts) 23 | raw: test -e /usr/bin/lsb_release 24 | register: is_lsb_release_installed 25 | failed_when: is_lsb_release_installed.rc not in [0, 1] 26 | changed_when: false # never mutates state. 27 | 28 | - name: install lsb_release if missing (as required for ansible facts) 29 | when: is_lsb_release_installed|failed # skip otherwise 30 | raw: (test -e /usr/bin/apt-get && apt-get install -y lsb_release) || (test -e /usr/bin/yum && yum install -y redhat-lsb-core) 31 | changed_when: is_lsb_release_installed.rc == 1 32 | 33 | - setup: # gather 'facts', i.e. compensates for 'gather_facts: false' in calling playbook. 34 | -------------------------------------------------------------------------------- /examples/footloose/machines.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: cluster.x-k8s.io/v1alpha3 2 | kind: Machine 3 | metadata: 4 | labels: 5 | set: master 6 | name: master-1 7 | spec: 8 | clusterName: example 9 | bootstrap: {} 10 | version: 1.18.15 11 | infrastructureRef: 12 | apiVersion: cluster.weave.works/v1alpha3 13 | kind: ExistingInfraMachine 14 | name: master-1 15 | --- 16 | apiVersion: cluster.weave.works/v1alpha3 17 | kind: ExistingInfraMachine 18 | metadata: 19 | name: master-1 20 | spec: 21 | private: 22 | address: 172.17.0.2 23 | port: 22 24 | public: 25 | address: 127.0.0.1 26 | port: 2222 27 | --- 28 | apiVersion: cluster.x-k8s.io/v1alpha3 29 | kind: Machine 30 | metadata: 31 | labels: 32 | set: worker 33 | name: worker-1 34 | spec: 35 | clusterName: example 36 | bootstrap: {} 37 | version: 1.18.15 38 | infrastructureRef: 39 | apiVersion: cluster.weave.works/v1alpha3 40 | kind: ExistingInfraMachine 41 | name: worker-1 42 | --- 43 | apiVersion: cluster.weave.works/v1alpha3 44 | kind: ExistingInfraMachine 45 | metadata: 46 | name: worker-1 47 | spec: 48 | private: 49 | address: 172.17.0.3 50 | port: 22 51 | public: 52 | address: 127.0.0.1 53 | port: 2223 54 | --- 55 | apiVersion: cluster.x-k8s.io/v1alpha3 56 | kind: Machine 57 | metadata: 58 | labels: 59 | set: master 60 | name: master-2 61 | spec: 62 | clusterName: example 63 | bootstrap: {} 64 | version: 1.18.15 65 | infrastructureRef: 66 | apiVersion: cluster.weave.works/v1alpha3 67 | kind: ExistingInfraMachine 68 | name: master-2 69 | --- 70 | apiVersion: cluster.weave.works/v1alpha3 71 | kind: ExistingInfraMachine 72 | metadata: 73 | name: master-2 74 | spec: 75 | private: 76 | address: 172.17.0.4 77 | port: 22 78 | public: 79 | address: 127.0.0.1 80 | port: 2224 81 | -------------------------------------------------------------------------------- /pkg/apis/wksprovider/controller/manifests/yaml/04_controller.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: apps/v1 3 | kind: Deployment 4 | metadata: 5 | name: wks-controller 6 | namespace: system 7 | labels: 8 | name: wks-controller 9 | control-plane: wks-controller 10 | controller-tools.k8s.io: "1.0" 11 | spec: 12 | replicas: 1 13 | selector: 14 | matchLabels: 15 | name: wks-controller 16 | template: 17 | metadata: 18 | labels: 19 | name: wks-controller 20 | control-plane: wks-controller 21 | controller-tools.k8s.io: "1.0" 22 | spec: 23 | nodeSelector: 24 | node-role.kubernetes.io/master: "" 25 | tolerations: 26 | # Allow scheduling on master nodes. This is required because during 27 | # bootstrapping of the cluster, we may initially have just one master, 28 | # and would then need to deploy this controller there to set the entire 29 | # cluster up. 30 | - effect: NoSchedule 31 | key: node-role.kubernetes.io/master 32 | operator: Exists 33 | # Mark this as a critical addon: 34 | - key: CriticalAddonsOnly 35 | operator: Exists 36 | # Only schedule on nodes which are ready and reachable: 37 | - effect: NoExecute 38 | key: node.alpha.kubernetes.io/notReady 39 | operator: Exists 40 | - effect: NoExecute 41 | key: node.alpha.kubernetes.io/unreachable 42 | operator: Exists 43 | containers: 44 | - name: controller 45 | image: weaveworks/cluster-api-existinginfra-controller:v0.2.5 46 | args: 47 | - --verbose 48 | resources: 49 | limits: 50 | cpu: 100m 51 | memory: 30Mi 52 | requests: 53 | cpu: 100m 54 | memory: 20Mi 55 | -------------------------------------------------------------------------------- /environments/local-rpm-repo/README.md: -------------------------------------------------------------------------------- 1 | # local-docker-registry 2 | 3 | ## Instructions 4 | 5 | 1. Create the Docker image for the local YUM repository: 6 | 7 | ```console 8 | $ export IMAGE_TAG="$(cd ../.. ; ./tools/image-tag)" 9 | $ docker build -t "docker.io/weaveworks/local-yum-repo:${IMAGE_TAG}" . 10 | [...] 11 | Successfully tagged docker.io/weaveworks/local-yum-repo:${IMAGE_TAG} 12 | ``` 13 | 14 | 2. Run it: 15 | 16 | ```console 17 | docker run -d -p 8080:80 --restart always --name yumrepo docker.io/weaveworks/local-yum-repo:${IMAGE_TAG} 18 | ``` 19 | 20 | 3. Use it: 21 | 22 | ```console 23 | $ curl localhost:8080 24 | 25 | Index of / 26 | 27 |

Index of /


../
28 |     base/                                              13-May-2019 10:04                   -
29 |     [...]
30 |     yum-plugin-versionlock-1.1.31-50.el7.noarch.rpm        12-Nov-2018 15:27               36584
31 |     

32 | 33 | ``` 34 | 35 | 4. Create a repository configuration file pointing to your local YUM repository: 36 | 37 | ```ini 38 | [local] 39 | name=Local 40 | baseurl=http://localhost:8080 41 | enabled=1 42 | gpgcheck=0 43 | ``` 44 | 45 | 5. Configure it in your `cluster.yaml`: 46 | 47 | ```yaml 48 | apiVersion: cluster.weave.works/v1alpha3 49 | kind: ExistingInfraCluster 50 | spec: 51 | os: 52 | files: 53 | - source: 54 | configmap: repo 55 | key: local.repo 56 | destination: /etc/yum.repos.d/local.repo 57 | ``` 58 | 59 | ## Future work 60 | 61 | The exact list of packages to install should be driven by the "plan" for nodes. 62 | Currently, it is hardcoded in the `Dockerfile` file. 63 | -------------------------------------------------------------------------------- /pkg/plan/resource/kubectl_annotate.go: -------------------------------------------------------------------------------- 1 | package resource 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "strings" 7 | 8 | "github.com/pkg/errors" 9 | "github.com/weaveworks/cluster-api-provider-existinginfra/pkg/plan" 10 | "github.com/weaveworks/cluster-api-provider-existinginfra/pkg/plan/resource" 11 | ) 12 | 13 | // KubectlAnnotateSingleNode is a resource to apply an annotation to the only node in a cluster 14 | type KubectlAnnotateSingleNode struct { 15 | resource.Base 16 | 17 | Key string // Which annotation to apply 18 | Value string // Value of annotation 19 | } 20 | 21 | var _ plan.Resource = plan.RegisterResource(&KubectlAnnotateSingleNode{}) 22 | 23 | // State implements plan.Resource. 24 | func (ka *KubectlAnnotateSingleNode) State() plan.State { 25 | return resource.ToState(ka) 26 | } 27 | 28 | // Apply fetches the node name and performs a "kubectl annotate". 29 | func (ka *KubectlAnnotateSingleNode) Apply(ctx context.Context, runner plan.Runner, diff plan.Diff) (bool, error) { 30 | output, err := runner.RunCommand(ctx, resource.WithoutProxy("kubectl get nodes -o name"), nil) 31 | if err != nil { 32 | return false, errors.Wrapf(err, "could not fetch node name to annotate") 33 | } 34 | 35 | nodeName := strings.Trim(output, " \n") 36 | if strings.Contains(nodeName, "\n") { 37 | return false, fmt.Errorf("unexpected output in node name: %q", output) 38 | } 39 | 40 | path, err := writeTempFile(ctx, runner, []byte(ka.Value), "node_annotation") 41 | if err != nil { 42 | return false, errors.Wrap(err, "writeTempFile") 43 | } 44 | //nolint:errcheck 45 | defer runner.RunCommand(ctx, fmt.Sprintf("rm -vf %q", path), nil) 46 | 47 | cmd := fmt.Sprintf("kubectl annotate %q %s=\"$(cat %s)\"", nodeName, ka.Key, path) 48 | 49 | if stdouterr, err := runner.RunCommand(ctx, resource.WithoutProxy(cmd), nil); err != nil { 50 | return false, errors.Wrapf(err, "failed to apply annotation %s on %s; output %s", ka.Key, nodeName, stdouterr) 51 | } 52 | 53 | return true, nil 54 | } 55 | -------------------------------------------------------------------------------- /tools/build/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all clean images 2 | .DEFAULT_GOAL := all 3 | 4 | # Boiler plate for bulding Docker containers. 5 | # All this must go at top of file I'm afraid. 6 | IMAGE_PREFIX := weaveworks/build- 7 | IMAGE_TAG := $(shell ../image-tag) 8 | GIT_REVISION := $(shell git rev-parse HEAD) 9 | UPTODATE := .uptodate 10 | 11 | # Every directory with a Dockerfile in it builds an image called 12 | # $(IMAGE_PREFIX). Dependencies (i.e. things that go in the image) 13 | # still need to be explicitly declared. 14 | %/$(UPTODATE): %/Dockerfile %/* 15 | $(SUDO) docker build --build-arg=revision=$(GIT_REVISION) -t $(IMAGE_PREFIX)$(shell basename $(@D)) $(@D)/ 16 | $(SUDO) docker tag $(IMAGE_PREFIX)$(shell basename $(@D)) $(IMAGE_PREFIX)$(shell basename $(@D)):$(IMAGE_TAG) 17 | touch $@ 18 | 19 | # Get a list of directories containing Dockerfiles 20 | DOCKERFILES := $(shell find . -name tools -prune -o -name vendor -prune -o -type f -name 'Dockerfile' -print) 21 | UPTODATE_FILES := $(patsubst %/Dockerfile,%/$(UPTODATE),$(DOCKERFILES)) 22 | DOCKER_IMAGE_DIRS := $(patsubst %/Dockerfile,%,$(DOCKERFILES)) 23 | IMAGE_NAMES := $(foreach dir,$(DOCKER_IMAGE_DIRS),$(patsubst %,$(IMAGE_PREFIX)%,$(shell basename $(dir)))) 24 | images: 25 | $(info $(IMAGE_NAMES)) 26 | @echo > /dev/null 27 | 28 | # Define imagetag-golang, etc, for each image, which parses the dockerfile and 29 | # prints an image tag. For example: 30 | # FROM golang:1.8.1-stretch 31 | # in the "foo/Dockerfile" becomes: 32 | # $ make imagetag-foo 33 | # 1.8.1-stretch 34 | define imagetag_dep 35 | .PHONY: imagetag-$(1) 36 | $(patsubst $(IMAGE_PREFIX)%,imagetag-%,$(1)): $(patsubst $(IMAGE_PREFIX)%,%,$(1))/Dockerfile 37 | @cat $$< | grep "^FROM " | head -n1 | sed 's/FROM \(.*\):\(.*\)/\2/' 38 | endef 39 | $(foreach image, $(IMAGE_NAMES), $(eval $(call imagetag_dep, $(image)))) 40 | 41 | all: $(UPTODATE_FILES) 42 | 43 | clean: 44 | $(SUDO) docker rmi $(IMAGE_NAMES) >/dev/null 2>&1 || true 45 | rm -rf $(UPTODATE_FILES) 46 | 47 | 48 | -------------------------------------------------------------------------------- /test/integration/test/assets/ss.cert: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIFSjCCAzICCQDpyaNy+Lx8vjANBgkqhkiG9w0BAQsFADBnMQswCQYDVQQGEwJV 3 | UzERMA8GA1UECAwIQ29sb3JhZG8xFjAUBgNVBAcMDUJsYWNrIEZvcmVzdCAxEzAR 4 | BgNVBAoMCldlYXZld29ya3MxDDAKBgNVBAsMA1dLUDEKMAgGA1UEAwwBKjAeFw0x 5 | OTA2MTIxNjQxMDVaFw0yOTA2MDkxNjQxMDVaMGcxCzAJBgNVBAYTAlVTMREwDwYD 6 | VQQIDAhDb2xvcmFkbzEWMBQGA1UEBwwNQmxhY2sgRm9yZXN0IDETMBEGA1UECgwK 7 | V2VhdmV3b3JrczEMMAoGA1UECwwDV0tQMQowCAYDVQQDDAEqMIICIjANBgkqhkiG 8 | 9w0BAQEFAAOCAg8AMIICCgKCAgEAzkfigCZsEVvAU1wIF2bSqoJylzztRqJ41apO 9 | fK3IQbvSvdCES9uBloTFDPp4oWYtNH+0j5HwxDLyvnwa3OmaFiOqmaH6FlYsi/YR 10 | AJOOP8R4HpOUSLB2ADdOvZaeezDBYV8d8M/CSuWQt6qoZF2iw6Hpx8GSxYvJKDiD 11 | rzCMzBJKKuh3w7e8jtSUKgLKY8g1J+Lp0Z1BGVTrDWFYkO5PNWjhVTC5Q74jZv7E 12 | IOWJf1WXudW2bb3ZWTVuOhLzbOGO23o+OxlETWqXxtvPwizYb5Aa7rLFizjIFlqS 13 | cx+CLqGjyiUHeoRz5m/7wVKmB9NXjzwnko+9J49zyPfIvC3QYtu9KJYkEzBXVfhJ 14 | aHMXedVMueUWNgNYly9D+QCPg5TH5wrKvYjba7wAkYaOmIGDBvbPu0Eq0XqVqDL+ 15 | NLynbp+MW4TCOchdWuMF/qWjjGsuPl3y78ciq3ks8oQyOThTeZf1tG+GZO8nWH+D 16 | Sq+zEp8bAA4Ko+BfLFc7/ZtI4NApqXKhDrIMTWAgZ7ryNiCq7dH83ZAwjzVSH1C/ 17 | 6lC87f+ujUGWrEoPZJQoLPuSzRp5c1pCvHSQm51NmALeHedGTFDNG7op3zD/D6eC 18 | RARiWMVNF/Wmn/M5plvaSYGKndMlRL/7q436yTNQe/5nxU25DaaG5lWMRsciF7eU 19 | 1+HudI0CAwEAATANBgkqhkiG9w0BAQsFAAOCAgEAFhxpKJRfNNrherfhjXHZ99Yw 20 | /24bX63sjDnMYpwmKagk4VYSnF3MOWkdTKh7+qAX90JVyod0iD+XtQVtEy/MG/dY 21 | l7LJIj8B4DIMbkPc5Kc2s2K8PiBrW/YYLn8+frLuDe9xRLFBWdjx6o4gswtG2wBZ 22 | pEqLmVgHPQfZhTb9RkI6bbYH4D8CE6qFyYxpwhx9PG+1v/Ug5ZWxuOR24Gb9TFTq 23 | 7biWW9x7kPww21i6psMApwN7KG3emOVFlEHLIuJNDUOy0x2S3JgjspifCEuTqD+H 24 | E8ULv8H8fR9dtRid7u9cN0l4j+z1JkVcb8P8doubFm3i8pkB6OT6kPrkJQ3UqeDk 25 | fGl9xCNA3hogNFp4oTXF4PdAUe0wSlyjU9ck/hFINeFE5mBWVHDDdPifXwYIcjyo 26 | HNJ4vg8/gxDOMOlt+eNUKs1eO4BePGnvZ7tMIt+XKQJqJ0FCeFZHMu1nyze7ylyk 27 | OvTIpftI1JLVPV8r9yHNqTF6/wGUFJj1526or5OhIC2DjWrQXsgNnZYfs0MO7G41 28 | 3QWGzCgzn5DWWVytiqUvidKUy2mYDjUezO1RmOS3xHVJ5xWKigl54IdvMwOjalAV 29 | fZdkc8S6NccZDPmFPTXBK+FHutBKr98kGKuV3g4TR8F3B0cGLfsOKqApLjNmJvjG 30 | 5qw/uRDIMiFpN3t09ik= 31 | -----END CERTIFICATE----- 32 | -------------------------------------------------------------------------------- /pkg/git/git.go: -------------------------------------------------------------------------------- 1 | package git 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "os/exec" 7 | "strings" 8 | 9 | "github.com/pkg/errors" 10 | log "github.com/sirupsen/logrus" 11 | giturls "github.com/whilp/git-urls" 12 | ) 13 | 14 | func gitExec(args ...string) error { 15 | cmd := exec.Command("git", args...) 16 | cmd.Stdout = os.Stdout 17 | cmd.Stderr = os.Stderr 18 | return cmd.Run() 19 | } 20 | 21 | func HasNoStagedChanges() error { 22 | return errors.Wrap(gitExec("diff", "--quiet", "--staged", "--exit-code"), "repository contains staged changes") 23 | } 24 | 25 | func RmRecursive(paths ...string) error { 26 | return gitExec(append([]string{"rm", "-r", "--"}, paths...)...) 27 | } 28 | 29 | func AddAll(path string) error { 30 | return gitExec("add", "-A", path) 31 | } 32 | 33 | func SubtreeAdd(path, repository, revision string) error { 34 | return gitExec("subtree", "add", "--squash", "--prefix", path, repository, revision) 35 | } 36 | 37 | func Commit(message string) error { 38 | log.Infof("Committing the changes...") 39 | err := gitExec("commit", "-m", message) 40 | if err == nil { 41 | log.Info("Committed the changes.") 42 | } 43 | return err 44 | } 45 | 46 | func Push() error { 47 | log.Info("Pushing to the remote...") 48 | err := gitExec("push", "-v", "origin", "HEAD") 49 | if err == nil { 50 | log.Info("Pushed successfully.") 51 | } 52 | return err 53 | } 54 | 55 | func HostAndRepoPath(repoURL string) (string, string, error) { 56 | url, err := giturls.Parse(repoURL) 57 | if err != nil { 58 | return "", "", errors.Wrapf(err, "unable to parse git URL '%s'", repoURL) 59 | } 60 | 61 | return url.Hostname(), strings.TrimRight(url.Path, ".git"), nil 62 | } 63 | 64 | func IsGitURL(rawURL string) error { 65 | parsedURL, err := giturls.Parse(rawURL) 66 | if err != nil { 67 | return err 68 | } 69 | if !parsedURL.IsAbs() { 70 | return fmt.Errorf("URL %q does not have a scheme", parsedURL) 71 | } 72 | if parsedURL.Hostname() == "" { 73 | return fmt.Errorf("URL %q has an empty hostname", parsedURL) 74 | } 75 | return nil 76 | } 77 | -------------------------------------------------------------------------------- /examples/footloose/upload-image.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | # XXX: This assumes wksctl is going to install a specific upstream version of 6 | # docker. It may not be true in the future. The best way to solve this 7 | # generically would be able to query wksctl what is its plan and install the 8 | # same docker we want to install anyway. 9 | 10 | # XXX: This also will not work with other CRI runtimes. 11 | 12 | if [ $# -ne 2 ] && [ $# -ne 4 ]; then 13 | echo "Usage: $(basename $0) NODE IMAGE [-c footlooseconfig]" 14 | exit 1 15 | fi 16 | 17 | # Holds the footloose command. If an alternate footloose.yaml is passed via the command line, 18 | # override the footloose command to use it 19 | footlooseCmd=footloose 20 | if [ $# -eq 4 ]; then 21 | echo "Using config $@" 22 | footlooseCmd="footloose $3 $4" 23 | fi 24 | 25 | ensure_docker_centos() { 26 | node=$1 27 | $footlooseCmd ssh root@$node -- sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo 28 | $footlooseCmd ssh root@$node -- sudo yum install -y docker-ce-19.03.8 29 | $footlooseCmd ssh root@$node -- sudo systemctl start docker 30 | } 31 | 32 | ensure_docker_ubuntu() { 33 | node=$1 34 | $footlooseCmd ssh root@$node -- apt-get update 35 | $footlooseCmd ssh root@$node -- apt-get install docker.io 36 | } 37 | 38 | ensure_docker() { 39 | node=$1 40 | os=$2 41 | case $os in 42 | centos) 43 | ensure_docker_centos $node 44 | ;; 45 | ubuntu) 46 | ensure_docker_ubuntu $node 47 | ;; 48 | *) 49 | echo "error: unknown os: '$os'" 50 | exit 0 51 | esac 52 | } 53 | 54 | os() { 55 | node=$1 56 | os=$($footlooseCmd ssh root@$node cat /etc/os-release | grep ^ID= | cut -d= -f2 | tr -d '"') 57 | echo $os 58 | } 59 | 60 | upload() { 61 | node=$1 62 | image=$2 63 | docker save $image | $footlooseCmd ssh root@$node docker load 64 | } 65 | 66 | node=$1 67 | image=$2 68 | os=$(os $node) 69 | 70 | ensure_docker $node $os 71 | upload $node $image 72 | -------------------------------------------------------------------------------- /test/integration/bin/internal/provisioning/gcp/outputs.tf: -------------------------------------------------------------------------------- 1 | output "username" { 2 | value = "${var.gcp_username}" 3 | } 4 | 5 | output "public_ips" { 6 | value = ["${google_compute_instance.tf_test_vm.*.network_interface.0.access_config.0.assigned_nat_ip}"] 7 | } 8 | 9 | output "private_ips" { 10 | value = ["${google_compute_instance.tf_test_vm.*.network_interface.0.address}"] 11 | } 12 | 13 | output "hostnames" { 14 | value = "${join("\n", 15 | "${formatlist("%v.%v.%v", 16 | google_compute_instance.tf_test_vm.*.name, 17 | google_compute_instance.tf_test_vm.*.zone, 18 | var.app 19 | )}" 20 | )}" 21 | } 22 | 23 | # /etc/hosts file for the Compute Engine instances: 24 | output "private_etc_hosts" { 25 | value = "${join("\n", 26 | "${formatlist("%v %v.%v.%v", 27 | google_compute_instance.tf_test_vm.*.network_interface.0.address, 28 | google_compute_instance.tf_test_vm.*.name, 29 | google_compute_instance.tf_test_vm.*.zone, 30 | var.app 31 | )}" 32 | )}" 33 | } 34 | 35 | # /etc/hosts file for the client: 36 | output "public_etc_hosts" { 37 | value = "${join("\n", 38 | "${formatlist("%v %v.%v.%v", 39 | google_compute_instance.tf_test_vm.*.network_interface.0.access_config.0.assigned_nat_ip, 40 | google_compute_instance.tf_test_vm.*.name, 41 | google_compute_instance.tf_test_vm.*.zone, 42 | var.app 43 | )}" 44 | )}" 45 | } 46 | 47 | output "ansible_inventory" { 48 | value = "${format("[all]\n%s", join("\n", 49 | "${formatlist("%v private_ip=%v", 50 | google_compute_instance.tf_test_vm.*.network_interface.0.access_config.0.assigned_nat_ip, 51 | google_compute_instance.tf_test_vm.*.network_interface.0.address 52 | )}" 53 | ))}" 54 | } 55 | 56 | output "private_key_path" { 57 | value = "${var.gcp_private_key_path}" 58 | } 59 | 60 | output "instances_names" { 61 | value = ["${google_compute_instance.tf_test_vm.*.name}"] 62 | } 63 | 64 | output "image" { 65 | value = "${var.gcp_image}" 66 | } 67 | 68 | output "zone" { 69 | value = "${var.gcp_zone}" 70 | } 71 | -------------------------------------------------------------------------------- /pkg/addons/vfs_importer.go: -------------------------------------------------------------------------------- 1 | package addons 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | "os" 7 | "path" 8 | 9 | "github.com/google/go-jsonnet" 10 | "github.com/weaveworks/wksctl/pkg/addons/assets" 11 | ) 12 | 13 | // vfsImport implements a jsonnet VM Importer for vfsgen static data. 14 | type vfsImporter struct { 15 | searchPaths []string 16 | assets http.FileSystem 17 | cache map[string]*cacheEntry 18 | } 19 | 20 | type cacheEntry struct { 21 | exists bool 22 | contents jsonnet.Contents 23 | } 24 | 25 | func newVFSImporter() *vfsImporter { 26 | return &vfsImporter{ 27 | cache: make(map[string]*cacheEntry), 28 | } 29 | } 30 | 31 | func (importer *vfsImporter) tryPath(dir, importedPath string) (found bool, contents jsonnet.Contents, foundHere string, err error) { 32 | var absPath string 33 | if path.IsAbs(importedPath) { 34 | absPath = importedPath 35 | } else { 36 | absPath = path.Join(dir, importedPath) 37 | } 38 | 39 | entry := importer.cache[absPath] 40 | if entry == nil { 41 | // Build cache entry. 42 | s, err := assets.ReadAll(absPath) 43 | if os.IsNotExist(err) { 44 | entry = &cacheEntry{ 45 | exists: false, 46 | } 47 | } else { 48 | entry = &cacheEntry{ 49 | exists: true, 50 | contents: jsonnet.MakeContents(s), 51 | } 52 | } 53 | 54 | importer.cache[absPath] = entry 55 | } 56 | 57 | return entry.exists, entry.contents, absPath, nil 58 | } 59 | 60 | func (importer *vfsImporter) Import(importedFrom, importedPath string) (contents jsonnet.Contents, foundAt string, err error) { 61 | dir, _ := path.Split(importedFrom) 62 | found, content, foundHere, err := importer.tryPath(dir, importedPath) 63 | 64 | for i := len(importer.searchPaths) - 1; !found && i >= 0; i-- { 65 | found, content, foundHere, err = importer.tryPath(importer.searchPaths[i], importedPath) 66 | if err != nil { 67 | return jsonnet.Contents{}, "", err 68 | } 69 | } 70 | 71 | if !found { 72 | return jsonnet.Contents{}, "", fmt.Errorf("couldn't open import %#v: no match locally or in the Jsonnet library paths", importedPath) 73 | } 74 | return content, foundHere, err 75 | 76 | } 77 | -------------------------------------------------------------------------------- /test/container/resource/service_test.go: -------------------------------------------------------------------------------- 1 | package resource 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | "github.com/weaveworks/cluster-api-provider-existinginfra/pkg/plan" 9 | "github.com/weaveworks/cluster-api-provider-existinginfra/pkg/plan/resource" 10 | "github.com/weaveworks/wksctl/test/container/images" 11 | ) 12 | 13 | func TestService(t *testing.T) { 14 | r, closer := NewRunnerForTest(t, images.CentOS7) 15 | defer closer() 16 | 17 | service := &resource.Service{ 18 | Name: "httpd", 19 | Enabled: true, 20 | Status: "active", 21 | } 22 | 23 | // Ensure the service isn't started when this tests begins. 24 | startingState, err := service.QueryState(context.Background(), r) 25 | startingDiff := plan.Diff{ 26 | CurrentState: startingState, 27 | InvalidatedDeps: []plan.Resource{}} 28 | 29 | assert.NoError(t, err) 30 | assert.Equal(t, "httpd", startingState.String("name")) 31 | assert.Equal(t, false, startingState.Bool("enabled")) 32 | assert.Equal(t, "inactive", startingState.String("status")) 33 | 34 | // Apply the desired state. 35 | _, err = service.Apply(context.Background(), r, startingDiff) 36 | assert.NoError(t, err) 37 | 38 | // Verify the state is correctly applied. 39 | realizedState, err := service.QueryState(context.Background(), r) 40 | assert.NoError(t, err) 41 | assert.Equal(t, "httpd", realizedState.String("name")) 42 | assert.Equal(t, true, realizedState.Bool("enabled")) 43 | assert.Equal(t, "active", realizedState.String("status")) 44 | 45 | // Verify that, if we apply again, no command will actually be issued. 46 | realizedDiff := plan.Diff{ 47 | CurrentState: realizedState, 48 | InvalidatedDeps: []plan.Resource{}} 49 | 50 | r.ResetOperations() 51 | _, err = service.Apply(context.Background(), r, realizedDiff) 52 | assert.NoError(t, err) 53 | assert.Equal(t, 0, len(r.Operations())) 54 | 55 | // Undo the install. 56 | err = service.Undo(context.Background(), r, realizedState) 57 | assert.NoError(t, err) 58 | undoState, err := service.QueryState(context.Background(), r) 59 | assert.NoError(t, err) 60 | assert.Equal(t, startingState, undoState) 61 | } 62 | -------------------------------------------------------------------------------- /test/integration/bin/internal/provisioning/gcp/variables.tf: -------------------------------------------------------------------------------- 1 | variable "gcp_username" { 2 | description = "Google Cloud Platform SSH username" 3 | } 4 | 5 | variable "app" { 6 | description = "Name of the application using the created Compute Engine instance(s)." 7 | default = "default" 8 | } 9 | 10 | variable "name" { 11 | description = "Name of the Compute Engine instance(s)." 12 | default = "test" 13 | } 14 | 15 | variable "num_hosts" { 16 | description = "Number of Compute Engine instance(s)." 17 | default = 1 18 | } 19 | 20 | variable "client_ip" { 21 | description = "IP address of the client machine" 22 | } 23 | 24 | variable "gcp_public_key_path" { 25 | description = "Path to file containing public key" 26 | default = "~/.ssh/id_rsa.pub" 27 | } 28 | 29 | variable "gcp_private_key_path" { 30 | description = "Path to file containing private key" 31 | default = "~/.ssh/id_rsa" 32 | } 33 | 34 | variable "gcp_project" { 35 | description = "Google Cloud Platform project" 36 | default = "weave-net-tests" 37 | } 38 | 39 | variable "gcp_image" { 40 | # See also: https://cloud.google.com/compute/docs/images 41 | # For example: 42 | # - "ubuntu-os-cloud/ubuntu-1604-lts" 43 | # - "debian-cloud/debian-8" 44 | # - "centos-cloud/centos-7" 45 | # - "rhel-cloud/rhel7" 46 | description = "Google Cloud Platform OS" 47 | 48 | default = "ubuntu-os-cloud/ubuntu-1604-lts" 49 | } 50 | 51 | variable "gcp_size" { 52 | # See also: 53 | # $ gcloud compute machine-types list 54 | description = "Google Cloud Platform's selected machine size" 55 | 56 | default = "n1-standard-2" 57 | } 58 | 59 | variable "gcp_region" { 60 | description = "Google Cloud Platform's selected region" 61 | default = "us-central1" 62 | } 63 | 64 | variable "gcp_zone" { 65 | description = "Google Cloud Platform's selected zone" 66 | default = "us-central1-a" 67 | } 68 | 69 | variable "gcp_network" { 70 | description = "Google Cloud Platform's selected network" 71 | default = "integration-tests" 72 | } 73 | 74 | variable "gcp_network_global_cidr" { 75 | description = "CIDR covering all regions for the selected Google Cloud Platform network" 76 | default = "10.128.0.0/9" 77 | } 78 | -------------------------------------------------------------------------------- /tools/build/golang/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1.12.1-stretch 2 | RUN apt-get update && \ 3 | apt-get install -y \ 4 | curl \ 5 | file \ 6 | git \ 7 | jq \ 8 | libprotobuf-dev \ 9 | make \ 10 | protobuf-compiler \ 11 | python-pip \ 12 | python-requests \ 13 | python-yaml \ 14 | shellcheck \ 15 | unzip && \ 16 | rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* 17 | RUN pip install attrs pyhcl yapf==0.16.2 flake8==3.3.0 18 | RUN curl -fsSLo shfmt https://github.com/mvdan/sh/releases/download/v1.3.0/shfmt_v1.3.0_linux_amd64 && \ 19 | echo "b1925c2c405458811f0c227266402cf1868b4de529f114722c2e3a5af4ac7bb2 shfmt" | sha256sum -c && \ 20 | chmod +x shfmt && \ 21 | mv shfmt /usr/bin 22 | RUN go clean -i net && \ 23 | go install -tags netgo std && \ 24 | go install -race -tags netgo std 25 | RUN go get -tags netgo \ 26 | github.com/FiloSottile/gvt \ 27 | github.com/client9/misspell/cmd/misspell \ 28 | github.com/fatih/hclfmt \ 29 | github.com/fzipp/gocyclo \ 30 | github.com/gogo/protobuf/gogoproto \ 31 | github.com/gogo/protobuf/protoc-gen-gogoslick \ 32 | github.com/golang/dep/... \ 33 | golang.org/x/lint/golint \ 34 | github.com/golang/protobuf/protoc-gen-go \ 35 | github.com/kisielk/errcheck \ 36 | github.com/mjibson/esc \ 37 | github.com/prometheus/prometheus/cmd/promtool && \ 38 | rm -rf /go/pkg /go/src 39 | RUN mkdir protoc && \ 40 | cd protoc && \ 41 | curl -O -L https://github.com/google/protobuf/releases/download/v3.1.0/protoc-3.1.0-linux-x86_64.zip && \ 42 | unzip protoc-3.1.0-linux-x86_64.zip && \ 43 | cp bin/protoc /usr/bin/ && \ 44 | chmod o+x /usr/bin/protoc && \ 45 | cd .. && \ 46 | rm -rf protoc 47 | RUN mkdir -p /var/run/secrets/kubernetes.io/serviceaccount && \ 48 | touch /var/run/secrets/kubernetes.io/serviceaccount/token 49 | COPY build.sh / 50 | ENTRYPOINT ["/build.sh"] 51 | 52 | ARG revision 53 | LABEL maintainer="Weaveworks " \ 54 | org.opencontainers.image.title="golang" \ 55 | org.opencontainers.image.source="https://github.com/weaveworks/build-tools/tree/master/build/golang" \ 56 | org.opencontainers.image.revision="${revision}" \ 57 | org.opencontainers.image.vendor="Weaveworks" 58 | -------------------------------------------------------------------------------- /examples/footloose/machines-multimaster.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: cluster.x-k8s.io/v1alpha3 2 | kind: Machine 3 | metadata: 4 | labels: 5 | set: master 6 | name: master-1 7 | spec: 8 | infrastructureRef: 9 | apiVersion: cluster.weave.works/v1alpha3 10 | kind: ExistingInfraMachine 11 | name: master-1-provider 12 | --- 13 | apiVersion: cluster.weave.works/v1alpha3 14 | kind: ExistingInfraMachine 15 | metadata: 16 | name: master-1-provider 17 | spec: 18 | private: 19 | address: 172.17.0.2 20 | port: 22 21 | public: 22 | address: 127.0.0.1 23 | port: 2222 24 | --- 25 | apiVersion: cluster.x-k8s.io/v1alpha3 26 | kind: Machine 27 | metadata: 28 | labels: 29 | set: master 30 | name: master-2 31 | spec: 32 | infrastructureRef: 33 | apiVersion: cluster.weave.works/v1alpha3 34 | kind: ExistingInfraMachine 35 | name: master-2-provider 36 | --- 37 | apiVersion: cluster.weave.works/v1alpha3 38 | kind: ExistingInfraMachine 39 | metadata: 40 | name: master-2-provider 41 | spec: 42 | private: 43 | address: 172.17.0.3 44 | port: 22 45 | public: 46 | address: 127.0.0.1 47 | port: 2223 48 | --- 49 | apiVersion: cluster.x-k8s.io/v1alpha3 50 | kind: Machine 51 | metadata: 52 | labels: 53 | set: master 54 | name: master-3 55 | spec: 56 | infrastructureRef: 57 | apiVersion: cluster.weave.works/v1alpha3 58 | kind: ExistingInfraMachine 59 | name: master-3-provider 60 | --- 61 | apiVersion: cluster.weave.works/v1alpha3 62 | kind: ExistingInfraMachine 63 | metadata: 64 | name: master-3-provider 65 | spec: 66 | private: 67 | address: 172.17.0.4 68 | port: 22 69 | public: 70 | address: 127.0.0.1 71 | port: 2224 72 | --- 73 | apiVersion: cluster.x-k8s.io/v1alpha3 74 | kind: Machine 75 | metadata: 76 | labels: 77 | set: worker 78 | name: worker-1 79 | spec: 80 | infrastructureRef: 81 | apiVersion: cluster.weave.works/v1alpha3 82 | kind: ExistingInfraMachine 83 | name: worker-1-provider 84 | --- 85 | apiVersion: cluster.weave.works/v1alpha3 86 | kind: ExistingInfraMachine 87 | metadata: 88 | name: worker-1-provider 89 | spec: 90 | private: 91 | address: 172.17.0.5 92 | port: 22 93 | public: 94 | address: 127.0.0.1 95 | port: 2225 -------------------------------------------------------------------------------- /cmd/wksctl/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "os" 5 | 6 | log "github.com/sirupsen/logrus" 7 | "github.com/spf13/cobra" 8 | "github.com/weaveworks/go-checkpoint" 9 | 10 | "github.com/weaveworks/wksctl/cmd/wksctl/addon" 11 | "github.com/weaveworks/wksctl/cmd/wksctl/apply" 12 | "github.com/weaveworks/wksctl/cmd/wksctl/applyaddons" 13 | "github.com/weaveworks/wksctl/cmd/wksctl/bashcompletions" 14 | initpkg "github.com/weaveworks/wksctl/cmd/wksctl/init" 15 | "github.com/weaveworks/wksctl/cmd/wksctl/kubeconfig" 16 | "github.com/weaveworks/wksctl/cmd/wksctl/plan" 17 | "github.com/weaveworks/wksctl/cmd/wksctl/profile" 18 | "github.com/weaveworks/wksctl/cmd/wksctl/registrysynccommands" 19 | "github.com/weaveworks/wksctl/cmd/wksctl/version" 20 | "github.com/weaveworks/wksctl/cmd/wksctl/zshcompletions" 21 | v "github.com/weaveworks/wksctl/pkg/version" 22 | ) 23 | 24 | var rootCmd = &cobra.Command{ 25 | Use: "wksctl", 26 | Short: "Weave Kubernetes System CLI", 27 | 28 | PersistentPreRun: configureLogger, 29 | } 30 | 31 | var options struct { 32 | verbose bool 33 | } 34 | 35 | func configureLogger(cmd *cobra.Command, args []string) { 36 | log.SetFormatter(&log.TextFormatter{ 37 | FullTimestamp: true, 38 | }) 39 | if options.verbose { 40 | log.SetLevel(log.DebugLevel) 41 | } 42 | } 43 | 44 | func main() { 45 | rootCmd.PersistentFlags().BoolVarP(&options.verbose, "verbose", "v", false, "Enable verbose output") 46 | 47 | rootCmd.AddCommand(addon.Cmd) 48 | rootCmd.AddCommand(apply.Cmd) 49 | rootCmd.AddCommand(applyaddons.Cmd) 50 | rootCmd.AddCommand(initpkg.Cmd) 51 | rootCmd.AddCommand(kubeconfig.Cmd) 52 | rootCmd.AddCommand(plan.Cmd) 53 | rootCmd.AddCommand(profile.Cmd) 54 | rootCmd.AddCommand(registrysynccommands.Cmd) 55 | rootCmd.AddCommand(version.Cmd) 56 | 57 | rootCmd.AddCommand(bashcompletions.Cmd) 58 | rootCmd.AddCommand(zshcompletions.Cmd) 59 | 60 | if checkResponse, err := checkpoint.Check(&checkpoint.CheckParams{ 61 | Product: "wksctl", 62 | Version: v.Version, 63 | }); err == nil && checkResponse.Outdated { 64 | log.Infof("wksctl version %s is available; please update at %s", 65 | checkResponse.CurrentVersion, checkResponse.CurrentDownloadURL) 66 | } 67 | 68 | if err := rootCmd.Execute(); err != nil { 69 | os.Exit(1) 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /cmd/mock-https-authz-server/main.go: -------------------------------------------------------------------------------- 1 | // A Kubernetes Webhook Authenticator for Kerboros 2 | 3 | package main 4 | 5 | import ( 6 | "crypto/tls" 7 | "crypto/x509" 8 | "encoding/json" 9 | "io/ioutil" 10 | "log" 11 | "net/http" 12 | "path/filepath" 13 | 14 | flag "github.com/spf13/pflag" 15 | authnv1 "k8s.io/api/authentication/v1" 16 | authzv1 "k8s.io/api/authorization/v1" 17 | ) 18 | 19 | func authorizeHandler(w http.ResponseWriter, r *http.Request) { 20 | // Decode the incoming request 21 | var sar authzv1.SubjectAccessReview 22 | err := json.NewDecoder(r.Body).Decode(&sar) 23 | if err != nil { 24 | log.Println("[Error]", err.Error()) 25 | w.WriteHeader(http.StatusBadRequest) 26 | return 27 | } 28 | 29 | log.Println(sar) 30 | 31 | if sar.Spec.ResourceAttributes == nil || sar.Spec.ResourceAttributes.Namespace != "kittensandponies" { 32 | sar.Status.Allowed = true 33 | } 34 | 35 | err = json.NewEncoder(w).Encode(sar) 36 | if err != nil { 37 | log.Println("[Error]", err.Error()) 38 | w.WriteHeader(http.StatusBadRequest) 39 | return 40 | } 41 | 42 | w.WriteHeader(http.StatusOK) 43 | } 44 | 45 | func authenticateHandler(w http.ResponseWriter, r *http.Request) { 46 | var tr authnv1.TokenReview 47 | err := json.NewDecoder(r.Body).Decode(&tr) 48 | if err != nil { 49 | log.Println("[Error]", err.Error()) 50 | w.WriteHeader(http.StatusBadRequest) 51 | return 52 | } 53 | 54 | log.Println(tr) 55 | tr.Status.Authenticated = true 56 | } 57 | 58 | func main() { 59 | listenAddress := flag.String("listen-address", "127.0.0.1:5001", "address to listen for webhook requests") 60 | pemDir := flag.String("pem-dir", ".", "where to find pem files") 61 | flag.Parse() 62 | pemFile := func(filename string) string { 63 | return filepath.Join(*pemDir, filename) 64 | } 65 | caCertPEM, _ := ioutil.ReadFile(pemFile("rootCA.pem")) 66 | roots := x509.NewCertPool() 67 | roots.AppendCertsFromPEM(caCertPEM) 68 | server := &http.Server{ 69 | Addr: *listenAddress, 70 | TLSConfig: &tls.Config{}, 71 | } 72 | 73 | http.HandleFunc("/authorize", authorizeHandler) 74 | http.HandleFunc("/authenticate", authenticateHandler) 75 | log.Printf("Listening for requests on %s\n", *listenAddress) 76 | log.Fatal(server.ListenAndServeTLS(pemFile("server.crt"), pemFile("server.key"))) 77 | } 78 | -------------------------------------------------------------------------------- /examples/gce/generate-machines-manifest.js: -------------------------------------------------------------------------------- 1 | import * as std from '@jkcfg/std'; 2 | import * as param from '@jkcfg/std/param'; 3 | 4 | const input = param.String("instances", "instances.json"); 5 | const user = param.String("user"); 6 | const numMasters = 1; 7 | const numWorkers = 2; 8 | 9 | function required(name, v) { 10 | if (v === undefined) { 11 | throw new Error(`'${name}' parameter must be provided`); 12 | } 13 | } 14 | 15 | // XXX: jk should support that use case, see: 16 | // https://github.com/jkcfg/jk/issues/153 17 | required("user", user); 18 | 19 | // vm is the name of the i th vm. 20 | const vm = i => `${user}-wks-${i}`; 21 | 22 | // getInstance returns the instance named name from a list of instances 23 | function getInstance(instances, name) { 24 | for (let i = 0; i < instances.length; i++) { 25 | if (instances[i].name == name) { 26 | return instances[i]; 27 | } 28 | } 29 | throw new Error(`instance '${name}' not found`); 30 | } 31 | 32 | // Machine returns a WKS machine description from a `gcloud compute instances 33 | // list` instance JSON. 34 | const Machine = (instance, role) => ({ 35 | apiVersion: 'cluster.k8s.io/v1alpha1', 36 | kind: 'Machine', 37 | metadata: { 38 | generateName: `${role}-`, 39 | labels: { 40 | set: role, 41 | }, 42 | }, 43 | spec: { 44 | providerSpec: { 45 | value: { 46 | apiVersion: 'baremetalproviderspec/v1alpha1', 47 | kind: 'BareMetalMachineProviderSpec', 48 | public: { 49 | address: instance.networkInterfaces[0].accessConfigs[0].natIP, 50 | port: 22, 51 | }, 52 | private: { 53 | address: instance.networkInterfaces[0].networkIP, 54 | port: 22, 55 | } 56 | } 57 | } 58 | } 59 | }); 60 | 61 | // List is a Kubernetes list. 62 | const List = items => ({ 63 | apiVersion: "v1", 64 | kind: "List", 65 | items 66 | }); 67 | 68 | std.read(input).then(instances => { 69 | let machines = []; 70 | 71 | for (let i = 1; i < numMasters + 1; i++) { 72 | machines.push(Machine(getInstance(instances, vm(i)), 'master')); 73 | } 74 | 75 | for (let i = numMasters + 1; i < numMasters + numWorkers + 1; i++) { 76 | machines.push(Machine(getInstance(instances, vm(i)), 'worker')); 77 | } 78 | 79 | std.write(List(machines), "machines.yaml"); 80 | }); 81 | 82 | -------------------------------------------------------------------------------- /test/integration/bin/internal/provisioning/README.md: -------------------------------------------------------------------------------- 1 | # Weaveworks provisioning 2 | 3 | ## Introduction 4 | 5 | This project allows you to get hold of some machine either locally or on one of the below cloud providers: 6 | 7 | * Google Cloud Platform 8 | 9 | ## Set up 10 | 11 | * You will need [Vagrant](https://www.vagrantup.com) installed on your machine and added to your `PATH` in order to be able to provision local (virtual) machines automatically. 12 | 13 | * On macOS: `brew install vagrant` 14 | * On Linux (via Aptitude): `sudo apt install vagrant` 15 | * For other platforms or more details, see [here](https://www.vagrantup.com/docs/installation/) 16 | 17 | * You will need [Terraform](https://www.terraform.io) installed on your machine and added to your `PATH` in order to be able to provision cloud-hosted machines automatically. 18 | 19 | * On macOS: `brew install terraform` 20 | * On Linux (via Aptitude): `sudo apt install terraform` 21 | * If you need a specific version: 22 | 23 | curl -fsS https://releases.hashicorp.com/terraform/x.y.z/terraform_x.y.z_linux_amd64.zip | gunzip > terraform && chmod +x terraform && sudo mv terraform /usr/bin 24 | * For other platforms or more details, see [here](https://www.terraform.io/intro/getting-started/install.html) 25 | 26 | * Depending on the cloud provider, you may have to create an account, manually onboard, create and register SSH keys, etc. 27 | Please refer to the `README.md` in each sub-folder for more details. 28 | 29 | ## Usage in scripts 30 | 31 | Source `setup.sh`, set the `SECRET_KEY` environment variable, and depending on the cloud provider you want to use, call either: 32 | 33 | * `gcp_on` / `gcp_off` 34 | * `do_on` / `do_off` 35 | * `aws_on` / `aws_off` 36 | 37 | ## Usage in shell 38 | 39 | Source `setup.sh`, set the `SECRET_KEY` environment variable, and depending on the cloud provider you want to use, call either: 40 | 41 | * `gcp_on` / `gcp_off` 42 | * `do_on` / `do_off` 43 | * `aws_on` / `aws_off` 44 | 45 | Indeed, the functions defined in `setup.sh` are also exported as aliases, so you can call them from your shell directly. 46 | 47 | Other aliases are also defined, in order to make your life easier: 48 | 49 | * `tf_ssh`: to ease SSH-ing into the virtual machines, reading the username and IP address to use from Terraform, as well as setting default SSH options. 50 | -------------------------------------------------------------------------------- /pkg/addons/transform_test.go: -------------------------------------------------------------------------------- 1 | package addons_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | "github.com/weaveworks/wksctl/pkg/addons" 8 | ) 9 | 10 | func TestUpdateImage(t *testing.T) { 11 | tests := []struct { 12 | image string 13 | repository string 14 | expectedImage string 15 | expectedError error 16 | }{ 17 | // CNI addon's images should just have their repository updated: 18 | { 19 | image: "docker.io/weaveworks/weave-kube:2.7.0", 20 | repository: "172.17.0.2:5000", 21 | expectedImage: "172.17.0.2:5000/weaveworks/weave-kube:2.7.0", 22 | expectedError: nil, 23 | }, 24 | // WKS controller's image should just have its repository updated: 25 | { 26 | image: "quay.io/wksctl/controller:master", 27 | repository: "172.17.0.2:5000", 28 | expectedImage: "172.17.0.2:5000/wksctl/controller:master", 29 | expectedError: nil, 30 | }, 31 | // Override the namespace a.k.a. organisation by what is provided in 32 | // the repository URL, as this is what we've recommended to customers 33 | // in the past, even though it diverges from upstream's naming: 34 | { 35 | image: "quay.io/wksctl/controller:master", 36 | repository: "registry.weave.works/wkp", 37 | expectedImage: "registry.weave.works/wkp/controller:master", 38 | expectedError: nil, 39 | }, 40 | // Override the namespace a.k.a. organisation by what is provided in 41 | // the repository URL, as this is what we've recommended to customers 42 | // in the past, even though it diverges from upstream's naming: 43 | { 44 | image: "grafana/grafana:x.y.z", 45 | repository: "registry.weave.works/wkp", 46 | expectedImage: "registry.weave.works/wkp/grafana:x.y.z", 47 | expectedError: nil, 48 | }, 49 | // WKS controller's image shouldn't change if no repository is specified: 50 | { 51 | image: "quay.io/wksctl/controller:master", 52 | repository: "", 53 | expectedImage: "quay.io/wksctl/controller:master", 54 | expectedError: nil, 55 | }, 56 | } 57 | for _, test := range tests { 58 | updatedImage, err := addons.UpdateImage(test.image, test.repository) 59 | if test.expectedError != nil { 60 | assert.Equal(t, test.expectedError, err) 61 | } else { 62 | assert.Equal(t, test.expectedImage, updatedImage) 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /addons/vendor/ksonnet/ksonnet.beta.3/k.libsonnet: -------------------------------------------------------------------------------- 1 | local k8s = import "k8s.libsonnet"; 2 | 3 | local apps = k8s.apps; 4 | local core = k8s.core; 5 | local extensions = k8s.extensions; 6 | 7 | local hidden = { 8 | mapContainers(f):: { 9 | local podContainers = super.spec.template.spec.containers, 10 | spec+: { 11 | template+: { 12 | spec+: { 13 | // IMPORTANT: This overwrites the 'containers' field 14 | // for this deployment. 15 | containers: std.map(f, podContainers), 16 | }, 17 | }, 18 | }, 19 | }, 20 | 21 | mapContainersWithName(names, f) :: 22 | local nameSet = 23 | if std.type(names) == "array" 24 | then std.set(names) 25 | else std.set([names]); 26 | local inNameSet(name) = std.length(std.setInter(nameSet, std.set([name]))) > 0; 27 | self.mapContainers( 28 | function(c) 29 | if std.objectHas(c, "name") && inNameSet(c.name) 30 | then f(c) 31 | else c 32 | ), 33 | }; 34 | 35 | k8s + { 36 | apps:: apps + { 37 | v1beta1:: apps.v1beta1 + { 38 | local v1beta1 = apps.v1beta1, 39 | 40 | daemonSet:: v1beta1.daemonSet + { 41 | mapContainers(f):: hidden.mapContainers(f), 42 | mapContainersWithName(names, f):: hidden.mapContainersWithName(names, f), 43 | }, 44 | 45 | deployment:: v1beta1.deployment + { 46 | mapContainers(f):: hidden.mapContainers(f), 47 | mapContainersWithName(names, f):: hidden.mapContainersWithName(names, f), 48 | }, 49 | }, 50 | }, 51 | 52 | core:: core + { 53 | v1:: core.v1 + { 54 | list:: { 55 | new(items):: 56 | {apiVersion: "v1"} + 57 | {kind: "List"} + 58 | self.items(items), 59 | 60 | items(items):: if std.type(items) == "array" then {items+: items} else {items+: [items]}, 61 | }, 62 | }, 63 | }, 64 | 65 | extensions:: extensions + { 66 | v1beta1:: extensions.v1beta1 + { 67 | local v1beta1 = extensions.v1beta1, 68 | 69 | daemonSet:: v1beta1.daemonSet + { 70 | mapContainers(f):: hidden.mapContainers(f), 71 | mapContainersWithName(names, f):: hidden.mapContainersWithName(names, f), 72 | }, 73 | 74 | deployment:: v1beta1.deployment + { 75 | mapContainers(f):: hidden.mapContainers(f), 76 | mapContainersWithName(names, f):: hidden.mapContainersWithName(names, f), 77 | }, 78 | }, 79 | }, 80 | } 81 | -------------------------------------------------------------------------------- /test/integration/test/terraform_test.go: -------------------------------------------------------------------------------- 1 | package test 2 | 3 | import ( 4 | "strings" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | const sampleTerraformOutput = `{ 11 | "ansible_inventory": { 12 | "sensitive": false, 13 | "type": "string", 14 | "value": "[all]\n35.238.98.255 private_ip=10.128.0.5\n35.238.50.88 private_ip=10.128.0.4" 15 | }, 16 | "hostnames": { 17 | "sensitive": false, 18 | "type": "string", 19 | "value": "test-131-0-0.us-central1-a.wks\ntest-131-0-1.us-central1-a.wks" 20 | }, 21 | "image": { 22 | "sensitive": false, 23 | "type": "string", 24 | "value": "wks-centos7-docker1706" 25 | }, 26 | "instances_names": { 27 | "sensitive": false, 28 | "type": "list", 29 | "value": [ 30 | "test-131-0-0", 31 | "test-131-0-1" 32 | ] 33 | }, 34 | "private_etc_hosts": { 35 | "sensitive": false, 36 | "type": "string", 37 | "value": "10.128.0.5 test-131-0-0.us-central1-a.wks\n10.128.0.4 test-131-0-1.us-central1-a.wks" 38 | }, 39 | "private_key_path": { 40 | "sensitive": false, 41 | "type": "string", 42 | "value": "/root/.ssh/wksctl_cit_id_rsa" 43 | }, 44 | "public_etc_hosts": { 45 | "sensitive": false, 46 | "type": "string", 47 | "value": "35.238.98.255 test-131-0-0.us-central1-a.wks\n35.238.50.88 test-131-0-1.us-central1-a.wks" 48 | }, 49 | "public_ips": { 50 | "sensitive": false, 51 | "type": "list", 52 | "value": [ 53 | "35.238.98.255", 54 | "35.238.50.88" 55 | ] 56 | }, 57 | "private_ips": { 58 | "sensitive": false, 59 | "type": "list", 60 | "value": [ 61 | "10.128.0.5", 62 | "10.128.0.4" 63 | ] 64 | }, 65 | "username": { 66 | "sensitive": false, 67 | "type": "string", 68 | "value": "wksctl-cit" 69 | }, 70 | "zone": { 71 | "sensitive": false, 72 | "type": "string", 73 | "value": "us-central1-a" 74 | } 75 | } 76 | ` 77 | 78 | func TestNewTerraformOutput(t *testing.T) { 79 | r := strings.NewReader(sampleTerraformOutput) 80 | output, err := newTerraformOutput(r) 81 | assert.NoError(t, err) 82 | assert.Equal(t, "wksctl-cit", output.stringVar("username")) 83 | assert.Equal(t, []string{"35.238.98.255", "35.238.50.88"}, output.stringArrayVar("public_ips")) 84 | 85 | } 86 | -------------------------------------------------------------------------------- /pkg/addons/transform.go: -------------------------------------------------------------------------------- 1 | package addons 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | ) 7 | 8 | type transform func(object) object 9 | 10 | func list(items []object) object { 11 | return object{ 12 | "apiVersion": "v1", 13 | "kind": "List", 14 | "items": items, 15 | } 16 | } 17 | 18 | func transformList(l object, transforms ...transform) object { 19 | items, err := l.GetObjectArray("items") 20 | if err != nil { 21 | fmt.Println(err) 22 | } 23 | 24 | var transformedItems []object 25 | for _, item := range items { 26 | for _, t := range transforms { 27 | item = t(item) 28 | } 29 | transformedItems = append(transformedItems, item) 30 | } 31 | 32 | n := list(transformedItems) 33 | return n 34 | } 35 | 36 | func forEachContainer(o object, cb func(container object)) { 37 | paths := []string{ 38 | "spec.template.spec.initContainers", 39 | "spec.template.spec.containers", 40 | "spec.jobTemplate.spec.template.spec.initContainers", 41 | "spec.jobTemplate.spec.template.spec.containers", 42 | } 43 | for _, path := range paths { 44 | containers, err := o.GetObjectArray(path) 45 | if err != nil { 46 | continue 47 | } 48 | for _, container := range containers { 49 | cb(container) 50 | } 51 | } 52 | 53 | } 54 | 55 | func withImageRepository(repository string) transform { 56 | return func(o object) object { 57 | forEachContainer(o, func(container object) { 58 | image, err := container.GetString("image") 59 | if err != nil { 60 | return 61 | } 62 | updatedImage, err := UpdateImage(image, repository) 63 | if err != nil { 64 | return 65 | } 66 | container.SetString("image", updatedImage) 67 | }) 68 | return o 69 | } 70 | } 71 | 72 | // UpdateImage updates the provided container image's fully-qualified name with 73 | // the provided repository. 74 | func UpdateImage(image, repository string) (string, error) { 75 | if repository == "" { 76 | return image, nil 77 | } 78 | ref, err := parseImageReference(image) 79 | if err != nil { 80 | return "", err 81 | } 82 | 83 | // e.g.: "host:port/org" -> {"host:port", "org"} 84 | repositoryParts := strings.Split(repository, "/") 85 | if len(repositoryParts) > 2 { 86 | return "", fmt.Errorf("Invalid repository. Expected: \"host:port\" or \"host:port/org\" but got: %s", repository) 87 | } 88 | ref.Domain = repositoryParts[0] 89 | if len(repositoryParts) == 2 { 90 | // Override the organisation with the one provided in the repository: 91 | ref.Organisation = repositoryParts[1] 92 | } 93 | 94 | return ref.String(), nil 95 | } 96 | -------------------------------------------------------------------------------- /addons/vendor/kubernetes-mixin/alerts/storage_alerts.libsonnet: -------------------------------------------------------------------------------- 1 | { 2 | prometheusAlerts+:: { 3 | groups+: [ 4 | { 5 | name: 'kubernetes-storage', 6 | rules: [ 7 | { 8 | alert: 'KubePersistentVolumeUsageCritical', 9 | expr: ||| 10 | 100 * kubelet_volume_stats_available_bytes{%(prefixedNamespaceSelector)s%(kubeletSelector)s} 11 | / 12 | kubelet_volume_stats_capacity_bytes{%(prefixedNamespaceSelector)s%(kubeletSelector)s} 13 | < 3 14 | ||| % $._config, 15 | 'for': '1m', 16 | labels: { 17 | severity: 'critical', 18 | }, 19 | annotations: { 20 | message: 'The PersistentVolume claimed by {{ $labels.persistentvolumeclaim }} in Namespace {{ $labels.namespace }} is only {{ printf "%0.2f" $value }}% free.', 21 | }, 22 | }, 23 | { 24 | alert: 'KubePersistentVolumeFullInFourDays', 25 | expr: ||| 26 | 100 * ( 27 | kubelet_volume_stats_available_bytes{%(prefixedNamespaceSelector)s%(kubeletSelector)s} 28 | / 29 | kubelet_volume_stats_capacity_bytes{%(prefixedNamespaceSelector)s%(kubeletSelector)s} 30 | ) < 15 31 | and 32 | predict_linear(kubelet_volume_stats_available_bytes{%(prefixedNamespaceSelector)s%(kubeletSelector)s}[%(volumeFullPredictionSampleTime)s], 4 * 24 * 3600) < 0 33 | ||| % $._config, 34 | 'for': '5m', 35 | labels: { 36 | severity: 'critical', 37 | }, 38 | annotations: { 39 | message: 'Based on recent sampling, the PersistentVolume claimed by {{ $labels.persistentvolumeclaim }} in Namespace {{ $labels.namespace }} is expected to fill up within four days. Currently {{ printf "%0.2f" $value }}% is available.', 40 | }, 41 | }, 42 | { 43 | alert: 'KubePersistentVolumeErrors', 44 | expr: ||| 45 | kube_persistentvolume_status_phase{phase=~"Failed|Pending",%(prefixedNamespaceSelector)s%(kubeStateMetricsSelector)s} > 0 46 | ||| % $._config, 47 | 'for': '5m', 48 | labels: { 49 | severity: 'critical', 50 | }, 51 | annotations: { 52 | message: 'The persistent volume {{ $labels.persistentvolume }} has status {{ $labels.phase }}.', 53 | }, 54 | }, 55 | ], 56 | }, 57 | ], 58 | }, 59 | } 60 | -------------------------------------------------------------------------------- /pkg/manifests/manifests_test.go: -------------------------------------------------------------------------------- 1 | package manifests 2 | 3 | import ( 4 | "crypto/rand" 5 | "crypto/rsa" 6 | "crypto/x509" 7 | "encoding/pem" 8 | "io/ioutil" 9 | "os" 10 | "path/filepath" 11 | 12 | "testing" 13 | 14 | "github.com/stretchr/testify/assert" 15 | "github.com/stretchr/testify/require" 16 | gogit "gopkg.in/src-d/go-git.v4" 17 | "gopkg.in/src-d/go-git.v4/plumbing" 18 | ) 19 | 20 | func TestNoDeployKey(t *testing.T) { 21 | co, err := cloneOptions("foo", "", "") 22 | assert.NoError(t, err) 23 | assert.Equal(t, gogit.CloneOptions{URL: "foo"}, co) 24 | 25 | } 26 | 27 | func TestSSHDeployKey(t *testing.T) { 28 | f, err := ioutil.TempFile("", "") 29 | assert.NoError(t, err) 30 | defer os.Remove(f.Name()) 31 | pk, err := rsa.GenerateKey(rand.Reader, 2048) 32 | assert.NoError(t, err) 33 | keyPem := pem.EncodeToMemory(&pem.Block{ 34 | Type: "RSA PRIVATE KEY", 35 | Bytes: x509.MarshalPKCS1PrivateKey(pk), 36 | }) 37 | _, err = f.Write(keyPem) 38 | assert.NoError(t, f.Close()) 39 | assert.NoError(t, err) 40 | co, err := cloneOptions("url", f.Name(), "") 41 | assert.NoError(t, err) 42 | assert.NotNil(t, co.Auth) 43 | } 44 | 45 | func TestBranchClone(t *testing.T) { 46 | co, err := cloneOptions("foo", "", "develop") 47 | assert.NoError(t, err) 48 | assert.Equal(t, gogit.CloneOptions{URL: "foo", SingleBranch: true, ReferenceName: plumbing.NewBranchReferenceName("develop")}, co) 49 | } 50 | 51 | func TestMachinesManifestPath(t *testing.T) { 52 | for _, tt := range []struct { 53 | name string 54 | subdir string 55 | }{ 56 | {"0 components", ""}, 57 | {"0 components, trailing slash", "/"}, 58 | {"1 component", "aa"}, 59 | {"1 component, trailing slash", "aa/"}, 60 | {"1 component, leading slash", "/aa"}, 61 | {"3 components", "aa/bb/cc"}, 62 | {"3 components, trailing slash", "aa/bb/cc/"}, 63 | {"3 components, leading slash", "/aa/bb/cc"}, 64 | {"3 components, trailing and leading slash", "/aa/bb/cc/"}, 65 | } { 66 | t.Run(tt.name, func(t *testing.T) { 67 | tmpdir, err := ioutil.TempDir("", "wksctl-pkg-manifests-test") 68 | require.NoError(t, err) 69 | defer os.RemoveAll(tmpdir) 70 | 71 | dir := filepath.Join(tmpdir, tt.subdir) 72 | require.NoError(t, os.MkdirAll(dir, 0700)) 73 | 74 | fp := filepath.Join(tmpdir, tt.subdir, "machines.yaml") 75 | file, err := os.Create(fp) 76 | require.NoError(t, err) 77 | file.Close() 78 | 79 | repo := ClusterAPIRepo{ 80 | worktreePath: tmpdir, 81 | subdir: tt.subdir, 82 | } 83 | gotPath, gotErr := repo.MachinesManifestPath() 84 | require.NoError(t, gotErr) 85 | assert.Equal(t, fp, gotPath) 86 | }) 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /test/integration/test/main_test.go: -------------------------------------------------------------------------------- 1 | package test 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "log" 7 | "os" 8 | "testing" 9 | 10 | harness "github.com/dlespiau/kube-test-harness" 11 | "github.com/dlespiau/kube-test-harness/logger" 12 | spawn "github.com/weaveworks/wksctl/test/integration/spawn" 13 | ) 14 | 15 | var ( 16 | // cmd is the name of the CLI binary to test. 17 | cmd string 18 | 19 | // kubectl is the path to a recent kubectl command 20 | kubectl string 21 | ) 22 | 23 | var options struct { 24 | run struct { 25 | interactive bool 26 | } 27 | terraform struct { 28 | outputPath string 29 | } 30 | Tags struct { 31 | WKSK8sKrb5Server string 32 | WKSMockAuthzServer string 33 | } 34 | Secrets struct { 35 | QuaySecret string 36 | } 37 | } 38 | 39 | var ( 40 | run *spawn.Run 41 | kube *harness.Harness 42 | ) 43 | 44 | const kubectlURL = "https://storage.googleapis.com/kubernetes-release/release/v%s/bin/linux/amd64/kubectl" 45 | 46 | func downloadKubectl(version string) error { 47 | const file = "kubectl" 48 | 49 | url := fmt.Sprintf(kubectlURL, version) 50 | if err := downloadFileWithRetries(file, url, 3); err != nil { 51 | return err 52 | } 53 | 54 | stats, err := os.Stat(file) 55 | if err != nil { 56 | return err 57 | } 58 | mode := stats.Mode() 59 | mode |= 0111 60 | return os.Chmod(file, mode) 61 | } 62 | 63 | func TestMain(m *testing.M) { 64 | flag.StringVar(&cmd, "cmd", "wksctl", "path of the command under test") 65 | flag.BoolVar(&options.run.interactive, "run.interactive", false, "print command output when running them") 66 | flag.StringVar(&options.terraform.outputPath, "terraform.output", "/tmp/terraform_output.json", "JSON file holding terraform output") 67 | flag.StringVar(&options.Tags.WKSK8sKrb5Server, "tags.wks-k8s-krb5-server", "latest", "Tag of wks-k8s-krb5-server image to use in test") 68 | flag.StringVar(&options.Tags.WKSMockAuthzServer, "tags.wks-mock-authz-server", "latest", "Tag of wks-mock-authz-server image to use in test") 69 | flag.Parse() 70 | 71 | options.Secrets.QuaySecret = os.Getenv("QUAY_SECRET") 72 | 73 | // Setup the executable runner. 74 | run = spawn.New(spawn.Options{ 75 | Verbose: options.run.interactive, 76 | }) 77 | 78 | // Setup the Kubernetes testing package. 79 | kubeOptions := harness.Options{ 80 | LogLevel: logger.Debug, 81 | } 82 | if options.run.interactive { 83 | kubeOptions.Logger = &logger.PrintfLogger{} 84 | } 85 | kube = harness.New(kubeOptions) 86 | 87 | // Download kubectl! 88 | if err := downloadKubectl("1.18.5"); err != nil { 89 | log.Fatalf("could not download kubectl: %v", err) 90 | } 91 | kubectl = "./kubectl" 92 | 93 | os.Exit(kube.Run(m)) 94 | } 95 | -------------------------------------------------------------------------------- /test/container/resource/dir_test.go: -------------------------------------------------------------------------------- 1 | package resource 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | "github.com/weaveworks/cluster-api-provider-existinginfra/pkg/plan" 9 | "github.com/weaveworks/cluster-api-provider-existinginfra/pkg/plan/resource" 10 | "github.com/weaveworks/cluster-api-provider-existinginfra/pkg/utilities/object" 11 | "github.com/weaveworks/wksctl/test/container/images" 12 | ) 13 | 14 | func TestDirRecursive(t *testing.T) { 15 | r, closer := NewRunnerForTest(t, images.CentOS7) 16 | defer closer() 17 | 18 | tmpDir := &resource.Dir{ 19 | Path: object.String("/tmp/dir-test"), 20 | RecursiveDelete: true, 21 | } 22 | 23 | emptyDiff := plan.EmptyDiff() 24 | 25 | // Check that the directory does not exist. 26 | runCmdOrFail(t, r, "[ ! -e /tmp/dir-test ]") 27 | 28 | // Create a directory. 29 | _, err := tmpDir.Apply(context.Background(), r, emptyDiff) 30 | assert.NoError(t, err, "tmpDir.Apply") 31 | 32 | // Check that the directory exists. 33 | runCmdOrFail(t, r, "[ -d /tmp/dir-test ]") 34 | 35 | // Create a file in that directory. 36 | runCmdOrFail(t, r, "echo potato > /tmp/dir-test/somefile") 37 | 38 | // Check that the directory exists. 39 | runCmdOrFail(t, r, "[ -f /tmp/dir-test/somefile ]") 40 | 41 | // Delete the directory. 42 | assert.NoError(t, tmpDir.Undo(context.Background(), r, tmpDir.State())) 43 | 44 | // Check that the directory does not exist. 45 | runCmdOrFail(t, r, "[ ! -e /tmp/dir-test ]") 46 | } 47 | 48 | func TestDirNotRecursive(t *testing.T) { 49 | r, closer := NewRunnerForTest(t, images.CentOS7) 50 | defer closer() 51 | 52 | tmpDir := &resource.Dir{ 53 | Path: object.String("/tmp/dir-test"), 54 | } 55 | 56 | emptyDiff := plan.EmptyDiff() 57 | 58 | // Check that the directory does not exist. 59 | runCmdOrFail(t, r, "[ ! -e /tmp/dir-test ]") 60 | 61 | // Create a directory. 62 | _, err := tmpDir.Apply(context.Background(), r, emptyDiff) 63 | assert.NoError(t, err, "tmpDir.Apply") 64 | 65 | // Check that the directory exists. 66 | runCmdOrFail(t, r, "[ -d /tmp/dir-test ]") 67 | 68 | // Create a file in that directory. 69 | runCmdOrFail(t, r, "echo potato > /tmp/dir-test/somefile") 70 | 71 | // Check that the directory exists. 72 | runCmdOrFail(t, r, "[ -f /tmp/dir-test/somefile ]") 73 | 74 | // Delete the directory. 75 | assert.NoError(t, tmpDir.Undo(context.Background(), r, tmpDir.State())) 76 | 77 | // Check that the directory and the file both exist. 78 | runCmdOrFail(t, r, "[ -d /tmp/dir-test ]") 79 | runCmdOrFail(t, r, "[ -f /tmp/dir-test/somefile ]") 80 | } 81 | 82 | func runCmdOrFail(t *testing.T, r plan.Runner, cmd string) { 83 | _, err := r.RunCommand(context.Background(), cmd, nil) 84 | assert.NoError(t, err, cmd) 85 | } 86 | -------------------------------------------------------------------------------- /environments/local-docker-registry/retag_push.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Description: 4 | # Retags the container images currently used by WKS, and pushes them to a 5 | # local Docker registry. 6 | # 7 | # N.B.: 8 | # Note that the below container images will change depending on the version 9 | # of Kubernetes WKS runs. You can retrieve these by running: 10 | # kubeadm config images list 11 | # (see also https://kubernetes.io/docs/reference/setup-tools/kubeadm/kubeadm-config/#cmd-config-images-list) 12 | # on the WKS seed master node, or by looking at the WKS 13 | # controller's logs. 14 | 15 | set -e 16 | 17 | # Images currently used by WKS: 18 | IMAGES=( 19 | k8s.gcr.io/kube-apiserver:v1.18.15 20 | k8s.gcr.io/kube-controller-manager:v1.18.15 21 | k8s.gcr.io/kube-scheduler:v1.18.15 22 | k8s.gcr.io/kube-proxy:v1.18.15 23 | k8s.gcr.io/pause:3.2 24 | k8s.gcr.io/etcd:3.4.3-0 25 | k8s.gcr.io/coredns:1.6.7 26 | k8s.gcr.io/kube-apiserver:v1.20.4 27 | k8s.gcr.io/kube-controller-manager:v1.20.4 28 | k8s.gcr.io/kube-scheduler:v1.20.4 29 | k8s.gcr.io/kube-proxy:v1.20.4 30 | k8s.gcr.io/pause:3.2 31 | k8s.gcr.io/etcd:3.4.13-0 32 | k8s.gcr.io/coredns:1.6.7 33 | docker.io/weaveworks/weave-npc:2.7.0 34 | docker.io/weaveworks/weave-kube:2.7.0 35 | ) 36 | 37 | # Default host for the local Docker registry: 38 | HOST=localhost 39 | # Default port for the local Docker registry: 40 | PORT=5000 41 | 42 | function print_remote() { 43 | for remote_img in ${IMAGES[@]}; do 44 | echo "${remote_img}" 45 | done 46 | } 47 | 48 | function localise() { 49 | echo ${1} | sed "s@^[^/]*@${HOST}:${PORT}@" 50 | } 51 | 52 | function print_local() { 53 | for remote_img in ${IMAGES[@]}; do 54 | echo "$(localise "${remote_img}")" 55 | done 56 | } 57 | 58 | function retag_push() { 59 | for remote_img in ${IMAGES[@]}; do 60 | docker pull "${remote_img}" 61 | local local_img="$(localise "${remote_img}")" 62 | docker tag "${remote_img}" "${local_img}" 63 | docker push "${local_img}" 64 | done 65 | } 66 | 67 | function main() { 68 | while true; do 69 | case "${1}" in 70 | -h|--host) 71 | shift 72 | HOST="${1}" 73 | ;; 74 | -p|--port) 75 | shift 76 | PORT="${1}" 77 | ;; 78 | --print-remote) 79 | print_remote 80 | exit 81 | ;; 82 | --print-local) 83 | print_local 84 | exit 85 | ;; 86 | *) 87 | [ -z "${1}" ] && break 88 | echo "Unknown option or argument: \"${1}\"" && exit 1 89 | ;; 90 | esac 91 | shift 92 | done 93 | retag_push 94 | } 95 | 96 | main "${@}" 97 | -------------------------------------------------------------------------------- /cmd/wksctl/registrysynccommands/registrysynccommands.go: -------------------------------------------------------------------------------- 1 | package registrysynccommands 2 | 3 | import ( 4 | "fmt" 5 | "sort" 6 | 7 | log "github.com/sirupsen/logrus" 8 | "github.com/spf13/cobra" 9 | "github.com/weaveworks/cluster-api-provider-existinginfra/pkg/kubernetes" 10 | "github.com/weaveworks/wksctl/pkg/addons" 11 | "github.com/weaveworks/wksctl/pkg/registry" 12 | ) 13 | 14 | var Cmd = &cobra.Command{ 15 | Use: "registry-sync-commands", 16 | Short: "Synchronize container images to an internal registry", 17 | Long: "Generate docker commands to STDOUT to pull, tag, and push the WKS container images to the provided destination organization and registry.", 18 | Run: registrySyncRun, 19 | } 20 | 21 | var registrySyncOptions struct { 22 | destRegistry string 23 | destOrganization string 24 | machinesManifestPath string 25 | versionsRange string 26 | } 27 | 28 | func init() { 29 | Cmd.Flags().StringVar(®istrySyncOptions.destRegistry, "dest-registry", "localhost:1337", "Destination registry that will be used to push images to") 30 | Cmd.Flags().StringVar(®istrySyncOptions.destOrganization, "dest-organization", "wks", "Destination organization that will be used to push images to") 31 | Cmd.Flags().StringVar(®istrySyncOptions.machinesManifestPath, "machines", "", "Location of machines manifest") 32 | Cmd.Flags().StringVar(®istrySyncOptions.versionsRange, "versions", "", "Range of Kubernetes semantic versions, e.g.: \""+kubernetes.DefaultVersionsRange+"\"") 33 | } 34 | 35 | func registrySyncRun(cmd *cobra.Command, args []string) { 36 | imagesSet := make(map[registry.Image]struct{}) // to deduplicate images. 37 | 38 | // Get addons' images: 39 | for _, addon := range addons.List() { 40 | addonImages, err := addon.ListImages() 41 | if err != nil { 42 | log.WithField("error", err).WithField("addon", addon.Name).Fatal("Failed to get addon's images.") 43 | } 44 | for _, image := range addonImages { 45 | imagesSet[image] = struct{}{} 46 | } 47 | } 48 | 49 | // Convert set back into a slice: 50 | images := make([]registry.Image, 0, len(imagesSet)) 51 | for image := range imagesSet { 52 | images = append(images, image) 53 | } 54 | sort.Sort(registry.ByCoordinate(images)) 55 | 56 | // Generate all commands: 57 | commands := make([]string, 0, 3*len(images)) 58 | for _, sourceImage := range images { 59 | // Make a copy of the source image and overrides the registry: 60 | destImage := sourceImage 61 | destImage.Registry = registrySyncOptions.destRegistry 62 | // set the organization for the image 63 | destImage.User = registrySyncOptions.destOrganization 64 | commands = append(commands, sourceImage.CommandsToRetagAs(destImage)...) 65 | } 66 | 67 | // Print all commands: 68 | for _, command := range commands { 69 | fmt.Println(command) 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /cmd/wksctl/addon/build/build.go: -------------------------------------------------------------------------------- 1 | package build 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "os" 7 | "strings" 8 | 9 | log "github.com/sirupsen/logrus" 10 | "github.com/spf13/cobra" 11 | "github.com/weaveworks/wksctl/pkg/addons" 12 | ) 13 | 14 | var Cmd = &cobra.Command{ 15 | Use: "build", 16 | Short: "Build addon manifests", 17 | Args: addonBuildArgs, 18 | Run: addonBuildRun, 19 | } 20 | 21 | var addonBuildOptions struct { 22 | outputDirectory string 23 | params []string 24 | imageRepository string 25 | } 26 | 27 | func init() { 28 | Cmd.Flags().StringVarP(&addonBuildOptions.outputDirectory, "output-directory", "o", "", "manifest output directory") 29 | Cmd.Flags().StringVarP(&addonBuildOptions.imageRepository, "image-repository", "r", "", "use this container repository for addon images") 30 | Cmd.Flags().StringArrayVarP(&addonBuildOptions.params, "params", "p", nil, "addon input parameters e.g. --params foo=bar --params baz=qux") 31 | } 32 | 33 | func addonBuildArgs(cmd *cobra.Command, args []string) error { 34 | if len(args) != 1 { 35 | return errors.New("build requires an addon name") 36 | } 37 | return nil 38 | } 39 | 40 | func parseParam(input string) (name, value string, err error) { 41 | parts := strings.SplitN(input, "=", 2) 42 | if len(parts) != 2 { 43 | return "", "", fmt.Errorf("expected key=value pair, got '%s'", input) 44 | } 45 | 46 | return parts[0], parts[1], nil 47 | } 48 | 49 | func makeParams(input []string) (map[string]string, error) { 50 | output := make(map[string]string) 51 | 52 | for _, desc := range input { 53 | name, value, err := parseParam(desc) 54 | if err != nil { 55 | return nil, err 56 | } 57 | output[name] = value 58 | } 59 | 60 | return output, nil 61 | } 62 | 63 | func addonBuildRun(cmd *cobra.Command, args []string) { 64 | opts := &addonBuildOptions 65 | 66 | addon, err := addons.Get(args[0]) 67 | if err != nil { 68 | log.Fatal(err) 69 | } 70 | 71 | params, err := makeParams(opts.params) 72 | if err != nil { 73 | log.Fatal(err) 74 | } 75 | 76 | if opts.outputDirectory != "" { 77 | if err = os.MkdirAll(opts.outputDirectory, 0770); err != nil { 78 | log.Fatal(err) 79 | } 80 | } 81 | 82 | addonOptions := addons.BuildOptions{ 83 | OutputDirectory: opts.outputDirectory, 84 | Params: params, 85 | ImageRepository: opts.imageRepository, 86 | YAML: true, 87 | } 88 | 89 | if err := addon.ValidateOptions(&addonOptions); err != nil { 90 | log.Fatalf("invalid options: %v\n", err) 91 | } 92 | 93 | manifests, err := addon.Build(addonOptions) 94 | if err != nil { 95 | log.Fatal(err) 96 | } 97 | 98 | for _, filename := range manifests { 99 | fmt.Printf("wrote %s\n", filename) 100 | } 101 | } 102 | --------------------------------------------------------------------------------