From f7756c89de388a30fed7802a0658d2698709bb39 Mon Sep 17 00:00:00 2001 From: Chris Hoge Date: Tue, 6 Mar 2018 13:33:45 -0800 Subject: [PATCH] Removing old provider code to make room for new provider code This patch clears out all of the old provider code from this directory to make room for the new, maintained tree that will be imported into this project. Depends-On: I38e2168e311536cc63932d906a46e1b1cf3ac4bf Change-Id: I0d3b2c3805cc47edbb2aac14f757d5bdc114899a --- .gitreview | 5 + LICENSE | 191 ---- Makefile | 107 -- bindep.txt | 6 - contrib/gate_hook.sh | 18 - contrib/post_test_hook.sh | 176 --- contrib/pre_test_hook.sh | 19 - devstack/plugin.sh | 193 ---- devstack/settings | 4 - glide.lock | 677 ------------ glide.yaml | 61 -- main.go | 64 -- openstack/BUILD | 96 -- openstack/MAINTAINERS.md | 6 - openstack/OWNERS | 2 - openstack/glide.lock | 254 ----- openstack/metadata.go | 156 --- openstack/metadata_test.go | 86 -- openstack/openstack.go | 650 ----------- openstack/openstack_instances.go | 155 --- openstack/openstack_loadbalancer.go | 1577 --------------------------- openstack/openstack_routes.go | 278 ----- openstack/openstack_routes_test.go | 71 -- openstack/openstack_test.go | 435 -------- openstack/openstack_volumes.go | 422 ------- tools/install-distro-packages.sh | 44 - tools/test-setup.sh | 55 - 27 files changed, 5 insertions(+), 5803 deletions(-) create mode 100644 .gitreview delete mode 100644 LICENSE delete mode 100644 Makefile delete mode 100644 bindep.txt delete mode 100755 contrib/gate_hook.sh delete mode 100755 contrib/post_test_hook.sh delete mode 100755 contrib/pre_test_hook.sh delete mode 100755 devstack/plugin.sh delete mode 100644 devstack/settings delete mode 100644 glide.lock delete mode 100644 glide.yaml delete mode 100644 main.go delete mode 100644 openstack/BUILD delete mode 100644 openstack/MAINTAINERS.md delete mode 100644 openstack/OWNERS delete mode 100644 openstack/glide.lock delete mode 100644 openstack/metadata.go delete mode 100644 openstack/metadata_test.go delete mode 100644 openstack/openstack.go delete mode 100644 openstack/openstack_instances.go delete mode 100644 openstack/openstack_loadbalancer.go delete mode 100644 openstack/openstack_routes.go delete mode 100644 openstack/openstack_routes_test.go delete mode 100644 openstack/openstack_test.go delete mode 100644 openstack/openstack_volumes.go delete mode 100755 tools/install-distro-packages.sh delete mode 100755 tools/test-setup.sh diff --git a/.gitreview b/.gitreview new file mode 100644 index 0000000..2639da0 --- /dev/null +++ b/.gitreview @@ -0,0 +1,5 @@ +[gerrit] +host=review.openstack.org +port=29418 +project=openstack/k8s-cloud-provider + diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 2744858..0000000 --- a/LICENSE +++ /dev/null @@ -1,191 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - Copyright 2014 Docker, Inc. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/Makefile b/Makefile deleted file mode 100644 index 4ff256e..0000000 --- a/Makefile +++ /dev/null @@ -1,107 +0,0 @@ -# golang-client Makefile -# Follows the interface defined in the Golang CTI proposed -# in https://review.openstack.org/410355 - -#REPO_VERSION?=$(shell git describe --tags) - -GIT_HOST = git.openstack.org - -PWD := $(shell pwd) -BASE_DIR := $(shell basename $(PWD)) -# Keep an existing GOPATH, make a private one if it is undefined -GOPATH_DEFAULT := $(PWD)/.go -export GOPATH ?= $(GOPATH_DEFAULT) -PKG := $(shell awk '/^package: / { print $$2 }' glide.yaml) -DEST := $(GOPATH)/src/$(GIT_HOST)/openstack/$(BASE_DIR) -DEST := $(GOPATH)/src/$(PKG) - -# CTI targets - -depend: work - cd $(DEST) && glide install --strip-vendor - -depend-update: work - cd $(DEST) && glide update - -build: work - cd $(DEST) && go build -o openstack-controller-manager main.go - -test: unit functional - -unit: depend - cd $(DEST) && go test -tags=unit $(shell glide novendor) - -functional: - @echo "$@ not yet implemented" - -fmt: work - cd $(DEST) && CGO_ENABLED=0 go fmt ./... - -lint: - @echo "$@ not yet implemented" - -cover: - @echo "$@ not yet implemented" - -docs: - @echo "$@ not yet implemented" - -godoc: - @echo "$@ not yet implemented" - -releasenotes: - @echo "Reno not yet implemented for this repo" - -translation: - @echo "$@ not yet implemented" - -# Do the work here - -# Set up the development environment -env: - @echo "PWD: $(PWD)" - @echo "BASE_DIR: $(BASE_DIR)" - @echo "GOPATH: $(GOPATH)" - @echo "GOROOT: $(GOROOT)" - @echo "DEST: $(DEST)" - @echo "PKG: $(PKG)" - go version - go env - -# Get our dev/test dependencies in place -bootstrap: - tools/test-setup.sh - -work: $(GOPATH) $(DEST) - -$(GOPATH): - mkdir -p $(GOPATH) - -$(DEST): $(GOPATH) - mkdir -p $(shell dirname $(DEST)) - ln -s $(PWD) $(DEST) - -.bindep: - virtualenv .bindep - .bindep/bin/pip install -i https://pypi.python.org/simple bindep - -bindep: .bindep - @.bindep/bin/bindep -b -f bindep.txt || true - -install-distro-packages: - tools/install-distro-packages.sh - -clean: - rm -rf .bindep openstack-controller-manager - -realclean: clean - rm -rf vendor - if [ "$(GOPATH)" = "$(GOPATH_DEFAULT)" ]; then \ - rm -rf $(GOPATH); \ - fi - -shell: work - cd $(DEST) && $(SHELL) -i - -.PHONY: bindep build clean cover depend docs fmt functional lint realclean \ - relnotes test translation diff --git a/bindep.txt b/bindep.txt deleted file mode 100644 index 656f435..0000000 --- a/bindep.txt +++ /dev/null @@ -1,6 +0,0 @@ -pkg-config -build-essential -mercurial -golang-go -golint -make diff --git a/contrib/gate_hook.sh b/contrib/gate_hook.sh deleted file mode 100755 index 37d1d7d..0000000 --- a/contrib/gate_hook.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -set -ex - -echo "In gate_test_hook" -$BASE/new/devstack-gate/devstack-vm-gate.sh diff --git a/contrib/post_test_hook.sh b/contrib/post_test_hook.sh deleted file mode 100755 index 8ccdaa2..0000000 --- a/contrib/post_test_hook.sh +++ /dev/null @@ -1,176 +0,0 @@ -#!/bin/bash -xe - -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -# This script is executed inside post_test_hook function in devstack gate. - -BASE_DIR=$(cd $(dirname $BASH_SOURCE)/.. && pwd) - - -TESTS_LIST_REGEX=( - '\[Slow\]' - '\[Serial\]' - '\[Disruptive\]' - '\[Flaky\]' - '\[Feature:.+\]' - '\[HPA\]' -) - -FLAKY_TESTS_LIST=( - # https://github.com/kubernetes/kubernetes/issues/44226 - 'Downward API volume [It] should update labels on modification [Conformance] [Volume]' - 'Downward API volume [It] should update annotations on modification [Conformance] [Volume]' - 'Projected [It] should update labels on modification [Conformance] [Volume]' - 'Secrets [It] should be consumable from pods in volume with mappings [Conformance] [Volume]' -) - -FAILING_TESTS_LIST=( - 'Services [It] should be able to create a functioning NodePort service' - 'Services [It] should serve multiport endpoints from pods [Conformance]' -) - -function escape_test_name() { - sed 's/\[[^]]*\]//g' <<< "$1" | sed "s/[^[:alnum:]]/ /g" | tr -s " " | sed "s/^\s\+//" | sed "s/\s/.*/g" -} - -function test_names () { - local first=y - for name in "${TESTS_LIST_REGEX[@]}"; do - if [ -z "${first}" ]; then - echo -n "|" - else - first= - fi - echo -n "${name}" - done - for name in "${FLAKY_TESTS_LIST[@]}"; do - if [ -z "${first}" ]; then - echo -n "|" - else - first= - fi - echo -n "$(escape_test_name "${name}")" - done - for name in "${FAILING_TESTS_LIST[@]}"; do - if [ -z "${first}" ]; then - echo -n "|" - else - first= - fi - echo -n "$(escape_test_name "${name}")" - done -} - -cd $BASE/new/devstack -source openrc admin admin - -echo "In post_test_hook" - -# Get the latest stable version of kubernetes -export K8S_VERSION=$(curl -sS https://storage.googleapis.com/kubernetes-release/release/stable.txt) -echo "K8S_VERSION : ${K8S_VERSION}" - -echo "Download Kubernetes CLI" -sudo wget -O kubectl "http://storage.googleapis.com/kubernetes-release/release/${K8S_VERSION}/bin/linux/amd64/kubectl" -sudo chmod 755 kubectl - -export KUBECONFIG=/var/run/kubernetes/admin.kubeconfig - -echo "Waiting for kubernetes service to start..." -for i in {1..600} -do - if [[ -f $KUBECONFIG ]]; then - running_count=$(./kubectl get nodes --no-headers 2>/dev/null | grep "Ready" | wc -l) - if [ "$running_count" -ge 1 ]; then - break - fi - fi - echo -n "." - sleep 1 -done - -echo "Cluster created!" -echo "" - -sudo journalctl -u devstack@kubernetes.service - -echo "Dump Kubernetes Objects..." -./kubectl get componentstatuses -./kubectl get configmaps -./kubectl get daemonsets -./kubectl get deployments -./kubectl get events -./kubectl get endpoints -./kubectl get horizontalpodautoscalers -./kubectl get ingress -./kubectl get jobs -./kubectl get limitranges -./kubectl get nodes -./kubectl get namespaces -./kubectl get pods -./kubectl get persistentvolumes -./kubectl get persistentvolumeclaims -./kubectl get quota -./kubectl get resourcequotas -./kubectl get replicasets -./kubectl get replicationcontrollers -./kubectl get secrets -./kubectl get serviceaccounts -./kubectl get services - -echo "Clear the taint to make sure we can schedule jobs to the master node" -./kubectl taint nodes --all node.cloudprovider.kubernetes.io/uninitialized- - -./kubectl get node -o json - -echo "Create a default StorageClass since we do not have a cloud provider" -./kubectl create -f - </dev/null -sudo -E PATH=$GOPATH/bin:$PATH make all WHAT=cmd/kubectl -sudo -E PATH=$GOPATH/bin:$PATH make all WHAT=vendor/github.com/onsi/ginkgo/ginkgo - -# open up access for containers -sudo ifconfig -a -export HOST_INTERFACE=$(ip -f inet route | awk '/default/ {print $5}') -sudo iptables -t nat -A POSTROUTING -o $HOST_INTERFACE -s 10.0.0.0/24 -j MASQUERADE -sudo iptables -t nat -A POSTROUTING -o $HOST_INTERFACE -s 172.17.0.0/24 -j MASQUERADE - - -sudo -E PATH=$GOPATH/bin:$PATH make all WHAT=test/e2e/e2e.test -sudo -E PATH=$GOPATH/bin:$PATH go run hack/e2e.go -- -v --test --test_args="--ginkgo.trace=true --ginkgo.seed=1378936983 --logtostderr --v 4 --provider=local --report-dir=/opt/stack/logs/ --ginkgo.v --ginkgo.skip=$(test_names)" -popd >/dev/null diff --git a/contrib/pre_test_hook.sh b/contrib/pre_test_hook.sh deleted file mode 100755 index ce572a9..0000000 --- a/contrib/pre_test_hook.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/bash -xe -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -# This script is executed inside pre_test_hook function in devstack gate. - -export localconf=$BASE/new/devstack/local.conf - -echo "In pre_test_hook" diff --git a/devstack/plugin.sh b/devstack/plugin.sh deleted file mode 100755 index 7bc8918..0000000 --- a/devstack/plugin.sh +++ /dev/null @@ -1,193 +0,0 @@ -#!/bin/bash -# -# lib/dlm -# -# Functions to control the installation and configuration of kubernetes with the -# external OpenStack cloud provider enabled. - -# Save trace setting -_XTRACE_K8S_PROVIDER=$(set +o | grep xtrace) -set -o xtrace - - -BASE_DIR=$(cd $(dirname $BASH_SOURCE)/.. && pwd) - -# Defaults -# -------- - -export GOPATH=${BASE_DIR}/go - -CONFORMANCE_REPO=${CONFORMANCE_REPO:-github.com/kubernetes/kubernetes} -K8S_SRC=${GOPATH}/src/k8s.io/kubernetes - -function install_prereqs { - # Install pre-reqs - $BASE_DIR/tools/install-distro-packages.sh - $BASE_DIR/tools/test-setup.sh - - install_package nfs-common -} - - -function install_docker { - # Install docker if needed - if ! is_package_installed docker-engine; then - sudo apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys 58118E89F3A912897C070ADBF76221572C52609D || true - sudo apt-key adv --keyserver hkp://pgp.mit.edu:80 --recv-keys 58118E89F3A912897C070ADBF76221572C52609D || true - sudo apt-add-repository 'deb http://apt.dockerproject.org/repo ubuntu-xenial main' - sudo apt-get update - sudo apt-cache policy docker-engine - sudo apt-get install -y docker-engine=1.12.6-0~ubuntu-xenial - sudo cat /lib/systemd/system/docker.service - sudo sed -r -i "s|(ExecStart)=(.+)|\1=\2 --iptables=false|" /lib/systemd/system/docker.service - sudo cat /lib/systemd/system/docker.service - sudo systemctl daemon-reload - sudo systemctl restart docker - sudo systemctl status docker - sudo ifconfig -a - fi - docker --version - - # Get the latest stable version of kubernetes - export K8S_VERSION=$(curl -sS https://storage.googleapis.com/kubernetes-release/release/stable.txt) - echo "K8S_VERSION : ${K8S_VERSION}" - - echo "Starting docker service" - sudo systemctl enable docker.service - sudo systemctl start docker.service --ignore-dependencies - echo "Checking docker service" - sudo docker ps -} - -function install_k8s_cloud_provider { - echo_summary "Installing Devstack Plugin for k8s-cloud-provider" - - # golang env details - go env - go version - - go get -u github.com/jteeuwen/go-bindata/go-bindata || true - go get -u github.com/cloudflare/cfssl/cmd/... || true - - # Get Kubernetes from source - mkdir -p ${GOPATH}/src/k8s.io/ - if [ ! -d "${K8S_SRC}" ]; then - git clone https://${CONFORMANCE_REPO} ${K8S_SRC} - pushd ${K8S_SRC} >/dev/null - git remote update - git fetch --all --tags --prune - - popd >/dev/null - fi - - # Run the script that builds kubernetes from source and starts the processes - pushd ${K8S_SRC} >/dev/null - - # local-up-cluster needs the etcd path and the GOPATH bin as cf-ssl - # and go-bindata are located there - export PATH=$DEST/bin:$GOPATH/bin:${PATH} - - # Seed the log files so devstack-gate can capture the logs - export LOG_DIR=${SCREEN_LOGDIR:-/opt/stack/logs} - sudo mkdir -p $LOG_DIR - sudo touch $LOG_DIR/kube-apiserver.log;sudo ln -s $LOG_DIR/kube-apiserver.log $LOG_DIR/screen-kube-apiserver.log - sudo touch $LOG_DIR/kube-controller-manager.log;sudo ln -s $LOG_DIR/kube-controller-manager.log $LOG_DIR/screen-kube-controller-manager.log - sudo touch $LOG_DIR/kube-proxy.log;sudo ln -s $LOG_DIR/kube-proxy.log $LOG_DIR/screen-kube-proxy.log - sudo touch $LOG_DIR/kube-scheduler.log;sudo ln -s $LOG_DIR/kube-scheduler.log $LOG_DIR/screen-kube-scheduler.log - sudo touch $LOG_DIR/kubelet.log;sudo ln -s $LOG_DIR/kubelet.log $LOG_DIR/screen-kubelet.log - - echo "Stopping firewall and allow all traffic..." - sudo iptables -F - sudo iptables -X - sudo iptables -t nat -F - sudo iptables -t nat -X - sudo iptables -t mangle -F - sudo iptables -t mangle -X - sudo iptables -P INPUT ACCEPT - sudo iptables -P FORWARD ACCEPT - sudo iptables -P OUTPUT ACCEPT - - # Turn on/off a few things in local-up-cluster.sh - export ALLOW_PRIVILEGED=true - export ALLOW_SECURITY_CONTEXT=true - export CLOUD_PROVIDER=external - export ENABLE_CRI=false - export ENABLE_DAEMON=true - export ENABLE_HOSTPATH_PROVISIONER=true - export ENABLE_SINGLE_CA_SIGNER=true - export HOSTNAME_OVERRIDE=$(ip route get 1.1.1.1 | awk '{print $7}') - export KUBE_ENABLE_CLUSTER_DASHBOARD=true - export KUBE_ENABLE_CLUSTER_DNS=true - export LOG_LEVEL=10 - - # Listen on all interfaces - export KUBELET_HOST="0.0.0.0" - - # Use the docker0's ip address for kubedns to work - export API_HOST_IP="172.17.0.1" - - # kill etcd and let local-up-cluster start it up - $SYSTEMCTL stop $ETCD_SYSTEMD_SERVICE - - # local-up-cluster.sh compiles everything from source and starts the services. - sudo -E PATH=$PATH ./hack/local-up-cluster.sh - - popd >/dev/null -} - -# cleanup_k8s_cloud_provider() - Remove residual data files, anything left over from previous -# runs that a clean run would need to clean up -function cleanup_k8s_cloud_provider { - echo_summary "Cleaning up Devstack Plugin for k8s-cloud-provider" - # Kill the k8s processes - ps -ef | grep -e hyperkube | grep -v grep | awk '{print $2}' | xargs sudo kill -9 - - # Cleanup docker images and containers - sudo docker rm -f $(docker ps -a -q) || true - sudo docker rmi -f $(docker images -q -a) || true - - # Stop docker - sudo systemctl stop docker.service - sudo rm -rf "$K8S_SRC" -} - -function stop_k8s_cloud_provider { - echo_summary "Stop Devstack Plugin for k8s-cloud-provider" - stop_process kubernetes -} - -# check for service enabled -if is_service_enabled k8s-cloud-provider; then - - if [[ "$1" == "stack" && "$2" == "pre-install" ]]; then - # no-op - : - - elif [[ "$1" == "stack" && "$2" == "install" ]]; then - install_docker - install_prereqs - - elif [[ "$1" == "stack" && "$2" == "post-config" ]]; then - install_k8s_cloud_provider - - elif [[ "$1" == "stack" && "$2" == "extra" ]]; then - # no-op - : - fi - - if [[ "$1" == "unstack" ]]; then - stop_k8s_cloud_provider - fi - - if [[ "$1" == "clean" ]]; then - cleanup_k8s_cloud_provider - fi -fi - -# Restore xtrace -$_XTRACE_K8S_PROVIDER - -# Tell emacs to use shell-script-mode -## Local variables: -## mode: shell-script -## End: diff --git a/devstack/settings b/devstack/settings deleted file mode 100644 index cf458dd..0000000 --- a/devstack/settings +++ /dev/null @@ -1,4 +0,0 @@ -# settings file for devstack plugin - -enable_service k8s-cloud-provider -enable_service kubernetes \ No newline at end of file diff --git a/glide.lock b/glide.lock deleted file mode 100644 index 5e02238..0000000 --- a/glide.lock +++ /dev/null @@ -1,677 +0,0 @@ -hash: 55acf1401fca2a0eef9461c95e0e16b2fcf37239abb1894ff965b7c001f84517 -updated: 2017-03-24T09:48:00.184737937-04:00 -imports: -- name: bitbucket.org/ww/goautoneg - version: 75cd24fc2f2c2a2088577d12123ddee5f54e0675 -- name: cloud.google.com/go - version: 3b1ae45394a234c385be014e9a488f2bb6eef821 - subpackages: - - compute/metadata - - internal -- name: github.com/aws/aws-sdk-go - version: 63ce630574a5ec05ecd8e8de5cea16332a5a684d - subpackages: - - aws - - aws/awserr - - aws/awsutil - - aws/client - - aws/client/metadata - - aws/corehandlers - - aws/credentials - - aws/credentials/ec2rolecreds - - aws/credentials/endpointcreds - - aws/credentials/stscreds - - aws/defaults - - aws/ec2metadata - - aws/endpoints - - aws/request - - aws/session - - aws/signer/v4 - - private/protocol - - private/protocol/ec2query - - private/protocol/json/jsonutil - - private/protocol/jsonrpc - - private/protocol/query - - private/protocol/query/queryutil - - private/protocol/rest - - private/protocol/restxml - - private/protocol/xml/xmlutil - - private/waiter - - service/autoscaling - - service/ec2 - - service/ecr - - service/elb - - service/route53 - - service/sts -- name: github.com/Azure/azure-sdk-for-go - version: 0984e0641ae43b89283223034574d6465be93bf4 - subpackages: - - arm/compute - - arm/containerregistry - - arm/network - - arm/storage - - storage -- name: github.com/Azure/go-autorest - version: d7c034a8af24eda120dd6460bfcd6d9ed14e43ca - subpackages: - - autorest - - autorest/azure - - autorest/date - - autorest/to - - autorest/validation -- name: github.com/beorn7/perks - version: 3ac7bf7a47d159a033b107610db8a1b6575507a4 - subpackages: - - quantile -- name: github.com/davecgh/go-spew - version: 5215b55f46b2b919f50a1df0eaa5886afe4e3b3d - subpackages: - - spew -- name: github.com/dgrijalva/jwt-go - version: 01aeca54ebda6e0fbfafd0a524d234159c05ec20 -- name: github.com/docker/distribution - version: cd27f179f2c10c5d300e6d09025b538c475b0d51 - subpackages: - - digest - - reference -- name: github.com/docker/engine-api - version: dea108d3aa0c67d7162a3fd8aa65f38a430019fd - subpackages: - - client - - client/transport - - client/transport/cancellable - - types - - types/blkiodev - - types/container - - types/filters - - types/network - - types/reference - - types/registry - - types/strslice - - types/time - - types/versions -- name: github.com/docker/go-connections - version: f549a9393d05688dff0992ef3efd8bbe6c628aeb - subpackages: - - nat - - sockets - - tlsconfig -- name: github.com/docker/go-units - version: e30f1e79f3cd72542f2026ceec18d3bd67ab859c -- name: github.com/emicklei/go-restful - version: 09691a3b6378b740595c1002f40c34dd5f218a22 - subpackages: - - log - - swagger -- name: github.com/exponent-io/jsonpath - version: d6023ce2651d8eafb5c75bb0c7167536102ec9f5 -- name: github.com/ghodss/yaml - version: 73d445a93680fa1a78ae23a5839bad48f32ba1ee -- name: github.com/go-ini/ini - version: 2e44421e256d82ebbf3d4d4fcabe8930b905eff3 -- name: github.com/go-openapi/analysis - version: b44dc874b601d9e4e2f6e19140e794ba24bead3b -- name: github.com/go-openapi/jsonpointer - version: 46af16f9f7b149af66e5d1bd010e3574dc06de98 -- name: github.com/go-openapi/jsonreference - version: 13c6e3589ad90f49bd3e3bbe2c2cb3d7a4142272 -- name: github.com/go-openapi/loads - version: 18441dfa706d924a39a030ee2c3b1d8d81917b38 -- name: github.com/go-openapi/spec - version: 6aced65f8501fe1217321abf0749d354824ba2ff -- name: github.com/go-openapi/swag - version: 1d0bd113de87027671077d3c71eb3ac5d7dbba72 -- name: github.com/gogo/protobuf - version: c0656edd0d9eab7c66d1eb0c568f9039345796f7 - subpackages: - - proto - - sortkeys -- name: github.com/golang/glog - version: 23def4e6c14b4da8ac2ed8007337bc5eb5007998 -- name: github.com/golang/groupcache - version: 02826c3e79038b59d737d3b1c0a1d937f71a4433 - subpackages: - - lru -- name: github.com/golang/protobuf - version: 4bd1920723d7b7c925de087aa32e2187708897f7 - subpackages: - - jsonpb - - proto -- name: github.com/google/gofuzz - version: 44d81051d367757e1c7c6a5a86423ece9afcf63c -- name: github.com/gophercloud/gophercloud - version: b06120d13e262ceaf890ef38ee30898813696af0 - subpackages: - - openstack - - openstack/blockstorage/v1/apiversions - - openstack/blockstorage/v1/volumes - - openstack/blockstorage/v2/volumes - - openstack/common/extensions - - openstack/compute/v2/extensions/volumeattach - - openstack/compute/v2/flavors - - openstack/compute/v2/images - - openstack/compute/v2/servers - - openstack/identity/v2/tenants - - openstack/identity/v2/tokens - - openstack/identity/v3/extensions/trusts - - openstack/identity/v3/tokens - - openstack/networking/v2/extensions - - openstack/networking/v2/extensions/layer3/floatingips - - openstack/networking/v2/extensions/layer3/routers - - openstack/networking/v2/extensions/lbaas/members - - openstack/networking/v2/extensions/lbaas/monitors - - openstack/networking/v2/extensions/lbaas/pools - - openstack/networking/v2/extensions/lbaas/vips - - openstack/networking/v2/extensions/lbaas_v2/listeners - - openstack/networking/v2/extensions/lbaas_v2/loadbalancers - - openstack/networking/v2/extensions/lbaas_v2/monitors - - openstack/networking/v2/extensions/lbaas_v2/pools - - openstack/networking/v2/extensions/security/groups - - openstack/networking/v2/extensions/security/rules - - openstack/networking/v2/ports - - openstack/utils - - pagination -- name: github.com/howeyc/gopass - version: 3ca23474a7c7203e0a0a070fd33508f6efdb9b3d -- name: github.com/imdario/mergo - version: 6633656539c1639d9d78127b7d47c622b5d7b6dc -- name: github.com/inconshreveable/mousetrap - version: 76626ae9c91c4f2a10f34cad8ce83ea42c93bb75 -- name: github.com/jmespath/go-jmespath - version: 3433f3ea46d9f8019119e7dd41274e112a2359a9 -- name: github.com/juju/ratelimit - version: 77ed1c8a01217656d2080ad51981f6e99adaa177 -- name: github.com/mailru/easyjson - version: d5b7844b561a7bc640052f1b935f7b800330d7e0 - subpackages: - - buffer - - jlexer - - jwriter -- name: github.com/matttproud/golang_protobuf_extensions - version: fc2b8d3a73c4867e51861bbdd5ae3c1f0869dd6a - subpackages: - - pbutil -- name: github.com/mesos/mesos-go - version: 45c8b08e9af666add36a6f93ff8c1c75812367b0 - subpackages: - - detector - - detector/zoo - - mesosproto - - mesosutil - - upid -- name: github.com/mitchellh/mapstructure - version: cc8532a8e9a55ea36402aa21efdf403a60d34096 -- name: github.com/prometheus/client_golang - version: e51041b3fa41cece0dca035740ba6411905be473 - subpackages: - - prometheus -- name: github.com/prometheus/client_model - version: fa8ad6fec33561be4280a8f0514318c79d7f6cb6 - subpackages: - - go -- name: github.com/prometheus/common - version: ffe929a3f4c4faeaa10f2b9535c2b1be3ad15650 - subpackages: - - expfmt - - model -- name: github.com/prometheus/procfs - version: 454a56f35412459b5e684fd5ec0f9211b94f002a -- name: github.com/PuerkitoBio/purell - version: 8a290539e2e8629dbc4e6bad948158f790ec31f4 -- name: github.com/PuerkitoBio/urlesc - version: 5bd2802263f21d8788851d5305584c82a5c75d7e -- name: github.com/rackspace/gophercloud - version: e00690e87603abe613e9f02c816c7c4bef82e063 - subpackages: - - openstack - - openstack/blockstorage/v1/volumes - - openstack/compute/v2/extensions/bootfromvolume - - openstack/compute/v2/extensions/diskconfig - - openstack/compute/v2/extensions/volumeattach - - openstack/compute/v2/flavors - - openstack/compute/v2/images - - openstack/compute/v2/servers - - openstack/identity/v2/tenants - - openstack/identity/v2/tokens - - openstack/identity/v3/tokens - - openstack/utils - - pagination - - rackspace - - rackspace/blockstorage/v1/volumes - - rackspace/compute/v2/servers - - rackspace/compute/v2/volumeattach - - rackspace/identity/v2/tokens - - testhelper - - testhelper/client -- name: github.com/rubiojr/go-vhd - version: 0bfd3b39853cdde5762efda92289f14b0ac0491b - subpackages: - - vhd -- name: github.com/samuel/go-zookeeper - version: 177002e16a0061912f02377e2dd8951a8b3551bc - subpackages: - - zk -- name: github.com/spf13/cobra - version: f62e98d28ab7ad31d707ba837a966378465c7b57 - subpackages: - - doc -- name: github.com/spf13/pflag - version: c990990ab4981d84da820b7b00c85139ca150b5f -- name: github.com/ugorji/go - version: ded73eae5db7e7a0ef6f55aace87a2873c5d2b74 - subpackages: - - codec -- name: github.com/vmware/govmomi - version: 0a28e595c8e9e99879e8d2f796e82c5a68202ff0 - subpackages: - - find - - list - - object - - property - - session - - task - - vim25 - - vim25/debug - - vim25/methods - - vim25/mo - - vim25/progress - - vim25/soap - - vim25/types - - vim25/xml -- name: github.com/vmware/photon-controller-go-sdk - version: 4a435daef6ccd3d0edaac1161e76f51a70c2589a - subpackages: - - SSPI - - photon - - photon/lightwave -- name: github.com/xanzy/go-cloudstack - version: 1e2cbf647e57fa90353612074fdfc42faf5073bf - subpackages: - - cloudstack -- name: golang.org/x/crypto - version: d172538b2cfce0c13cee31e647d0367aa8cd2486 - subpackages: - - bcrypt - - blowfish - - ssh/terminal -- name: golang.org/x/net - version: f2499483f923065a842d38eb4c7f1927e6fc6e6d - subpackages: - - context - - context/ctxhttp - - html - - html/atom - - http2 - - http2/hpack - - idna - - internal/timeseries - - lex/httplex - - trace - - websocket -- name: golang.org/x/oauth2 - version: 3c3a985cb79f52a3190fbc056984415ca6763d01 - subpackages: - - google - - internal - - jws - - jwt -- name: golang.org/x/sys - version: 8f0908ab3b2457e2e15403d3697c9ef5cb4b57a9 - subpackages: - - unix -- name: golang.org/x/text - version: 2910a502d2bf9e43193af9d68ca516529614eed3 - subpackages: - - cases - - internal/tag - - language - - runes - - secure/bidirule - - secure/precis - - transform - - unicode/bidi - - unicode/norm - - width -- name: google.golang.org/api - version: 64485db7e8c8be51e572801d06cdbcfadd3546c1 - subpackages: - - cloudmonitoring/v2beta2 - - compute/v0.alpha - - compute/v1 - - container/v1 - - dns/v1 - - gensupport - - googleapi - - googleapi/internal/uritemplates - - logging/v2beta1 - - monitoring/v3 -- name: google.golang.org/appengine - version: 4f7eeb5305a4ba1966344836ba4af9996b7b4e05 - subpackages: - - internal - - internal/app_identity - - internal/base - - internal/datastore - - internal/log - - internal/modules - - internal/remote_api - - internal/urlfetch - - urlfetch -- name: gopkg.in/gcfg.v1 - version: 083575c3955c85df16fe9590cceab64d03f5eb6e - subpackages: - - scanner - - token - - types -- name: gopkg.in/inf.v0 - version: 3887ee99ecf07df5b447e9b00d9c0b2adaa9f3e4 -- name: gopkg.in/yaml.v2 - version: 53feefa2559fb8dfa8d81baad31be332c97d6c77 -- name: k8s.io/apimachinery - version: 592382eb7243e2379169a0ced0fb71a8353a5653 - subpackages: - - pkg/api/equality - - pkg/api/errors - - pkg/api/meta - - pkg/api/resource - - pkg/api/validation - - pkg/apimachinery - - pkg/apimachinery/announced - - pkg/apimachinery/registered - - pkg/apis/meta/v1 - - pkg/apis/meta/v1/unstructured - - pkg/apis/meta/v1/validation - - pkg/conversion - - pkg/conversion/queryparams - - pkg/fields - - pkg/labels - - pkg/openapi - - pkg/runtime - - pkg/runtime/schema - - pkg/runtime/serializer - - pkg/runtime/serializer/json - - pkg/runtime/serializer/protobuf - - pkg/runtime/serializer/recognizer - - pkg/runtime/serializer/streaming - - pkg/runtime/serializer/versioning - - pkg/selection - - pkg/types - - pkg/util/diff - - pkg/util/errors - - pkg/util/framer - - pkg/util/intstr - - pkg/util/json - - pkg/util/mergepatch - - pkg/util/net - - pkg/util/rand - - pkg/util/runtime - - pkg/util/sets - - pkg/util/strategicpatch - - pkg/util/validation - - pkg/util/validation/field - - pkg/util/wait - - pkg/util/yaml - - pkg/version - - pkg/watch - - third_party/forked/golang/json - - third_party/forked/golang/reflect -- name: k8s.io/apiserver - version: 6eb4e56e7999d0faa4ab9ecffa3d118c628e84aa - subpackages: - - pkg/authentication/authenticator - - pkg/authentication/serviceaccount - - pkg/authentication/user - - pkg/features - - pkg/server/healthz - - pkg/util/feature - - pkg/util/flag - - pkg/util/logs -- name: k8s.io/client-go - version: f1cb94b672d5cdaf5107430eab7cac84e54b8133 - subpackages: - - discovery - - kubernetes - - kubernetes/scheme - - kubernetes/typed/apps/v1beta1 - - kubernetes/typed/authentication/v1 - - kubernetes/typed/authentication/v1beta1 - - kubernetes/typed/authorization/v1 - - kubernetes/typed/authorization/v1beta1 - - kubernetes/typed/autoscaling/v1 - - kubernetes/typed/autoscaling/v2alpha1 - - kubernetes/typed/batch/v1 - - kubernetes/typed/batch/v2alpha1 - - kubernetes/typed/certificates/v1beta1 - - kubernetes/typed/core/v1 - - kubernetes/typed/extensions/v1beta1 - - kubernetes/typed/policy/v1beta1 - - kubernetes/typed/rbac/v1alpha1 - - kubernetes/typed/rbac/v1beta1 - - kubernetes/typed/settings/v1alpha1 - - kubernetes/typed/storage/v1 - - kubernetes/typed/storage/v1beta1 - - pkg/api - - pkg/api/install - - pkg/api/v1 - - pkg/api/v1/ref - - pkg/apis/apps - - pkg/apis/apps/install - - pkg/apis/apps/v1beta1 - - pkg/apis/authentication - - pkg/apis/authentication/install - - pkg/apis/authentication/v1 - - pkg/apis/authentication/v1beta1 - - pkg/apis/authorization - - pkg/apis/authorization/install - - pkg/apis/authorization/v1 - - pkg/apis/authorization/v1beta1 - - pkg/apis/autoscaling - - pkg/apis/autoscaling/install - - pkg/apis/autoscaling/v1 - - pkg/apis/autoscaling/v2alpha1 - - pkg/apis/batch - - pkg/apis/batch/install - - pkg/apis/batch/v1 - - pkg/apis/batch/v2alpha1 - - pkg/apis/certificates - - pkg/apis/certificates/install - - pkg/apis/certificates/v1beta1 - - pkg/apis/extensions - - pkg/apis/extensions/install - - pkg/apis/extensions/v1beta1 - - pkg/apis/policy - - pkg/apis/policy/install - - pkg/apis/policy/v1beta1 - - pkg/apis/rbac - - pkg/apis/rbac/install - - pkg/apis/rbac/v1alpha1 - - pkg/apis/rbac/v1beta1 - - pkg/apis/settings - - pkg/apis/settings/install - - pkg/apis/settings/v1alpha1 - - pkg/apis/storage - - pkg/apis/storage/install - - pkg/apis/storage/v1 - - pkg/apis/storage/v1beta1 - - pkg/util - - pkg/util/parsers - - pkg/version - - rest - - rest/watch - - tools/auth - - tools/cache - - tools/clientcmd - - tools/clientcmd/api - - tools/clientcmd/api/latest - - tools/clientcmd/api/v1 - - tools/metrics - - tools/record - - transport - - util/cert - - util/clock - - util/flowcontrol - - util/homedir - - util/integer - - util/workqueue -- name: k8s.io/kubernetes - version: 868da1e08b38d5d7ebd3cfc3a1974063ce41109f - subpackages: - - cmd/cloud-controller-manager/app - - cmd/cloud-controller-manager/app/options - - cmd/kubeadm/app/constants - - pkg/api - - pkg/api/helper - - pkg/api/install - - pkg/api/service - - pkg/api/util - - pkg/api/v1 - - pkg/api/v1/helper - - pkg/api/v1/node - - pkg/api/v1/pod - - pkg/api/v1/ref - - pkg/api/v1/service - - pkg/api/validation - - pkg/apis/apps - - pkg/apis/apps/install - - pkg/apis/apps/v1beta1 - - pkg/apis/authentication - - pkg/apis/authentication/install - - pkg/apis/authentication/v1 - - pkg/apis/authentication/v1beta1 - - pkg/apis/authorization - - pkg/apis/authorization/install - - pkg/apis/authorization/v1 - - pkg/apis/authorization/v1beta1 - - pkg/apis/autoscaling - - pkg/apis/autoscaling/install - - pkg/apis/autoscaling/v1 - - pkg/apis/autoscaling/v2alpha1 - - pkg/apis/batch - - pkg/apis/batch/install - - pkg/apis/batch/v1 - - pkg/apis/batch/v2alpha1 - - pkg/apis/certificates - - pkg/apis/certificates/install - - pkg/apis/certificates/v1beta1 - - pkg/apis/componentconfig - - pkg/apis/extensions - - pkg/apis/extensions/install - - pkg/apis/extensions/v1beta1 - - pkg/apis/policy - - pkg/apis/policy/install - - pkg/apis/policy/v1beta1 - - pkg/apis/rbac - - pkg/apis/rbac/install - - pkg/apis/rbac/v1alpha1 - - pkg/apis/rbac/v1beta1 - - pkg/apis/settings - - pkg/apis/settings/install - - pkg/apis/settings/v1alpha1 - - pkg/apis/storage - - pkg/apis/storage/install - - pkg/apis/storage/v1 - - pkg/apis/storage/v1beta1 - - pkg/capabilities - - pkg/client/clientset_generated/clientset - - pkg/client/clientset_generated/clientset/scheme - - pkg/client/clientset_generated/clientset/typed/apps/v1beta1 - - pkg/client/clientset_generated/clientset/typed/authentication/v1 - - pkg/client/clientset_generated/clientset/typed/authentication/v1beta1 - - pkg/client/clientset_generated/clientset/typed/authorization/v1 - - pkg/client/clientset_generated/clientset/typed/authorization/v1beta1 - - pkg/client/clientset_generated/clientset/typed/autoscaling/v1 - - pkg/client/clientset_generated/clientset/typed/autoscaling/v2alpha1 - - pkg/client/clientset_generated/clientset/typed/batch/v1 - - pkg/client/clientset_generated/clientset/typed/batch/v2alpha1 - - pkg/client/clientset_generated/clientset/typed/certificates/v1beta1 - - pkg/client/clientset_generated/clientset/typed/core/v1 - - pkg/client/clientset_generated/clientset/typed/extensions/v1beta1 - - pkg/client/clientset_generated/clientset/typed/policy/v1beta1 - - pkg/client/clientset_generated/clientset/typed/rbac/v1alpha1 - - pkg/client/clientset_generated/clientset/typed/rbac/v1beta1 - - pkg/client/clientset_generated/clientset/typed/settings/v1alpha1 - - pkg/client/clientset_generated/clientset/typed/storage/v1 - - pkg/client/clientset_generated/clientset/typed/storage/v1beta1 - - pkg/client/informers/informers_generated/externalversions - - pkg/client/informers/informers_generated/externalversions/apps - - pkg/client/informers/informers_generated/externalversions/apps/v1beta1 - - pkg/client/informers/informers_generated/externalversions/autoscaling - - pkg/client/informers/informers_generated/externalversions/autoscaling/v1 - - pkg/client/informers/informers_generated/externalversions/autoscaling/v2alpha1 - - pkg/client/informers/informers_generated/externalversions/batch - - pkg/client/informers/informers_generated/externalversions/batch/v1 - - pkg/client/informers/informers_generated/externalversions/batch/v2alpha1 - - pkg/client/informers/informers_generated/externalversions/certificates - - pkg/client/informers/informers_generated/externalversions/certificates/v1beta1 - - pkg/client/informers/informers_generated/externalversions/core - - pkg/client/informers/informers_generated/externalversions/core/v1 - - pkg/client/informers/informers_generated/externalversions/extensions - - pkg/client/informers/informers_generated/externalversions/extensions/v1beta1 - - pkg/client/informers/informers_generated/externalversions/internalinterfaces - - pkg/client/informers/informers_generated/externalversions/policy - - pkg/client/informers/informers_generated/externalversions/policy/v1beta1 - - pkg/client/informers/informers_generated/externalversions/rbac - - pkg/client/informers/informers_generated/externalversions/rbac/v1alpha1 - - pkg/client/informers/informers_generated/externalversions/rbac/v1beta1 - - pkg/client/informers/informers_generated/externalversions/settings - - pkg/client/informers/informers_generated/externalversions/settings/v1alpha1 - - pkg/client/informers/informers_generated/externalversions/storage - - pkg/client/informers/informers_generated/externalversions/storage/v1 - - pkg/client/informers/informers_generated/externalversions/storage/v1beta1 - - pkg/client/leaderelection - - pkg/client/leaderelection/resourcelock - - pkg/client/listers/apps/v1beta1 - - pkg/client/listers/autoscaling/v1 - - pkg/client/listers/autoscaling/v2alpha1 - - pkg/client/listers/batch/v1 - - pkg/client/listers/batch/v2alpha1 - - pkg/client/listers/certificates/v1beta1 - - pkg/client/listers/core/v1 - - pkg/client/listers/extensions/v1beta1 - - pkg/client/listers/policy/v1beta1 - - pkg/client/listers/rbac/v1alpha1 - - pkg/client/listers/rbac/v1beta1 - - pkg/client/listers/settings/v1alpha1 - - pkg/client/listers/storage/v1 - - pkg/client/listers/storage/v1beta1 - - pkg/client/metrics - - pkg/client/metrics/prometheus - - pkg/client/retry - - pkg/cloudprovider - - pkg/cloudprovider/providers - - pkg/cloudprovider/providers/aws - - pkg/cloudprovider/providers/azure - - pkg/cloudprovider/providers/cloudstack - - pkg/cloudprovider/providers/gce - - pkg/cloudprovider/providers/mesos - - pkg/cloudprovider/providers/openstack - - pkg/cloudprovider/providers/ovirt - - pkg/cloudprovider/providers/photon - - pkg/cloudprovider/providers/rackspace - - pkg/cloudprovider/providers/vsphere - - pkg/controller - - pkg/controller/cloud - - pkg/controller/route - - pkg/controller/service - - pkg/credentialprovider - - pkg/credentialprovider/aws - - pkg/features - - pkg/master/ports - - pkg/security/apparmor - - pkg/serviceaccount - - pkg/util - - pkg/util/configz - - pkg/util/exec - - pkg/util/hash - - pkg/util/io - - pkg/util/metrics - - pkg/util/mount - - pkg/util/net/sets - - pkg/util/node - - pkg/util/parsers - - pkg/version - - pkg/version/prometheus - - pkg/version/verflag - - pkg/volume - - pkg/volume/util -testImports: [] diff --git a/glide.yaml b/glide.yaml deleted file mode 100644 index 5ee6790..0000000 --- a/glide.yaml +++ /dev/null @@ -1,61 +0,0 @@ -package: git.openstack.org/openstack/k8s-cloud-provider -import: -- package: github.com/golang/glog -- package: github.com/gophercloud/gophercloud - subpackages: - - openstack - - openstack/blockstorage/v1/apiversions - - openstack/blockstorage/v1/volumes - - openstack/blockstorage/v2/volumes - - openstack/compute/v2/extensions/volumeattach - - openstack/compute/v2/flavors - - openstack/compute/v2/servers - - openstack/identity/v3/extensions/trusts - - openstack/identity/v3/tokens - - openstack/networking/v2/extensions - - openstack/networking/v2/extensions/layer3/floatingips - - openstack/networking/v2/extensions/layer3/routers - - openstack/networking/v2/extensions/lbaas/members - - openstack/networking/v2/extensions/lbaas/monitors - - openstack/networking/v2/extensions/lbaas/pools - - openstack/networking/v2/extensions/lbaas/vips - - openstack/networking/v2/extensions/lbaas_v2/listeners - - openstack/networking/v2/extensions/lbaas_v2/loadbalancers - - openstack/networking/v2/extensions/lbaas_v2/monitors - - openstack/networking/v2/extensions/lbaas_v2/pools - - openstack/networking/v2/extensions/security/groups - - openstack/networking/v2/extensions/security/rules - - openstack/networking/v2/ports - - pagination -- package: github.com/mitchellh/mapstructure -- package: github.com/spf13/pflag -- package: gopkg.in/gcfg.v1 -- package: k8s.io/apimachinery - subpackages: - - pkg/api/resource - - pkg/types - - pkg/util/net -- package: k8s.io/apiserver - subpackages: - - pkg/server/healthz - - pkg/util/flag - - pkg/util/logs -- package: k8s.io/client-go - subpackages: - - util/cert -- package: k8s.io/kubernetes - subpackages: - - cmd/cloud-controller-manager/app - - cmd/cloud-controller-manager/app/options - - pkg/api/v1 - - pkg/api/v1/service - - pkg/client/metrics/prometheus - - pkg/cloudprovider - - pkg/cloudprovider/providers - - pkg/util/exec - - pkg/util/mount - - pkg/version/prometheus - - pkg/version/verflag - - pkg/volume -ignore: - - git.openstack.org/openstack/k8s-cloud-provider/openstack diff --git a/main.go b/main.go deleted file mode 100644 index d794bba..0000000 --- a/main.go +++ /dev/null @@ -1,64 +0,0 @@ -/* -Copyright 2016 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// The external controller manager is responsible for running controller loops that -// are cloud provider dependent. It uses the API to listen to new events on resources. - -package main - -import ( - "fmt" - "os" - - "k8s.io/apiserver/pkg/server/healthz" - "k8s.io/apiserver/pkg/util/flag" - "k8s.io/apiserver/pkg/util/logs" - "k8s.io/kubernetes/cmd/cloud-controller-manager/app" - "k8s.io/kubernetes/cmd/cloud-controller-manager/app/options" - _ "k8s.io/kubernetes/pkg/client/metrics/prometheus" // for client metric registration - "k8s.io/kubernetes/pkg/cloudprovider" - _ "k8s.io/kubernetes/pkg/cloudprovider/providers" - _ "k8s.io/kubernetes/pkg/version/prometheus" // for version metric registration - "k8s.io/kubernetes/pkg/version/verflag" - - "github.com/golang/glog" - "github.com/spf13/pflag" -) - -func init() { - healthz.DefaultHealthz() -} - -func main() { - s := options.NewCloudControllerManagerServer() - s.AddFlags(pflag.CommandLine) - - flag.InitFlags() - logs.InitLogs() - defer logs.FlushLogs() - - verflag.PrintAndExitIfRequested() - - cloud, err := cloudprovider.InitCloudProvider("openstack", s.CloudConfigFile) - if err != nil { - glog.Fatalf("Cloud provider could not be initialized: %v", err) - } - - if err := app.Run(s, cloud); err != nil { - fmt.Fprintf(os.Stderr, "%v\n", err) - os.Exit(1) - } -} \ No newline at end of file diff --git a/openstack/BUILD b/openstack/BUILD deleted file mode 100644 index 4c31301..0000000 --- a/openstack/BUILD +++ /dev/null @@ -1,96 +0,0 @@ -package(default_visibility = ["//visibility:public"]) - -licenses(["notice"]) - -load( - "@io_bazel_rules_go//go:def.bzl", - "go_library", - "go_test", -) - -go_library( - name = "go_default_library", - srcs = [ - "metadata.go", - "openstack.go", - "openstack_instances.go", - "openstack_loadbalancer.go", - "openstack_routes.go", - "openstack_volumes.go", - ], - tags = ["automanaged"], - deps = [ - "//pkg/api/v1:go_default_library", - "//pkg/api/v1/service:go_default_library", - "//pkg/cloudprovider:go_default_library", - "//pkg/util/exec:go_default_library", - "//pkg/util/mount:go_default_library", - "//pkg/volume:go_default_library", - "//vendor:github.com/golang/glog", - "//vendor:github.com/gophercloud/gophercloud", - "//vendor:github.com/gophercloud/gophercloud/openstack", - "//vendor:github.com/gophercloud/gophercloud/openstack/blockstorage/v1/apiversions", - "//vendor:github.com/gophercloud/gophercloud/openstack/blockstorage/v1/volumes", - "//vendor:github.com/gophercloud/gophercloud/openstack/blockstorage/v2/volumes", - "//vendor:github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/volumeattach", - "//vendor:github.com/gophercloud/gophercloud/openstack/compute/v2/flavors", - "//vendor:github.com/gophercloud/gophercloud/openstack/compute/v2/servers", - "//vendor:github.com/gophercloud/gophercloud/openstack/identity/v3/extensions/trusts", - "//vendor:github.com/gophercloud/gophercloud/openstack/identity/v3/tokens", - "//vendor:github.com/gophercloud/gophercloud/openstack/networking/v2/extensions", - "//vendor:github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/floatingips", - "//vendor:github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/routers", - "//vendor:github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas/members", - "//vendor:github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas/monitors", - "//vendor:github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas/pools", - "//vendor:github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas/vips", - "//vendor:github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/listeners", - "//vendor:github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/loadbalancers", - "//vendor:github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/monitors", - "//vendor:github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/pools", - "//vendor:github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/security/groups", - "//vendor:github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/security/rules", - "//vendor:github.com/gophercloud/gophercloud/openstack/networking/v2/ports", - "//vendor:github.com/gophercloud/gophercloud/pagination", - "//vendor:github.com/mitchellh/mapstructure", - "//vendor:gopkg.in/gcfg.v1", - "//vendor:k8s.io/apimachinery/pkg/api/resource", - "//vendor:k8s.io/apimachinery/pkg/types", - "//vendor:k8s.io/apimachinery/pkg/util/net", - "//vendor:k8s.io/client-go/util/cert", - ], -) - -go_test( - name = "go_default_test", - srcs = [ - "metadata_test.go", - "openstack_routes_test.go", - "openstack_test.go", - ], - library = ":go_default_library", - tags = ["automanaged"], - deps = [ - "//pkg/api/v1:go_default_library", - "//pkg/cloudprovider:go_default_library", - "//vendor:github.com/gophercloud/gophercloud", - "//vendor:github.com/gophercloud/gophercloud/openstack/blockstorage/v1/apiversions", - "//vendor:github.com/gophercloud/gophercloud/openstack/compute/v2/servers", - "//vendor:k8s.io/apimachinery/pkg/apis/meta/v1", - "//vendor:k8s.io/apimachinery/pkg/types", - "//vendor:k8s.io/apimachinery/pkg/util/rand", - ], -) - -filegroup( - name = "package-srcs", - srcs = glob(["**"]), - tags = ["automanaged"], - visibility = ["//visibility:private"], -) - -filegroup( - name = "all-srcs", - srcs = [":package-srcs"], - tags = ["automanaged"], -) diff --git a/openstack/MAINTAINERS.md b/openstack/MAINTAINERS.md deleted file mode 100644 index f71afec..0000000 --- a/openstack/MAINTAINERS.md +++ /dev/null @@ -1,6 +0,0 @@ -# Maintainers - -* [Angus Lees](https://github.com/anguslees) - - -[![Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/pkg/cloudprovider/providers/openstack/MAINTAINERS.md?pixel)]() diff --git a/openstack/OWNERS b/openstack/OWNERS deleted file mode 100644 index da5f5db..0000000 --- a/openstack/OWNERS +++ /dev/null @@ -1,2 +0,0 @@ -approvers: -- anguslees diff --git a/openstack/glide.lock b/openstack/glide.lock deleted file mode 100644 index f2d4583..0000000 --- a/openstack/glide.lock +++ /dev/null @@ -1,254 +0,0 @@ -hash: dc2cb42b652f4df3a539065b9c5709386e88277587c0ea2ba0efc37bafe32e37 -updated: 2017-03-24T08:33:36.565832163-04:00 -imports: -- name: github.com/davecgh/go-spew - version: 5215b55f46b2b919f50a1df0eaa5886afe4e3b3d - subpackages: - - spew -- name: github.com/docker/distribution - version: cd27f179f2c10c5d300e6d09025b538c475b0d51 - subpackages: - - digest - - reference -- name: github.com/emicklei/go-restful - version: 09691a3b6378b740595c1002f40c34dd5f218a22 - subpackages: - - log - - swagger -- name: github.com/ghodss/yaml - version: 73d445a93680fa1a78ae23a5839bad48f32ba1ee -- name: github.com/go-openapi/jsonpointer - version: 46af16f9f7b149af66e5d1bd010e3574dc06de98 -- name: github.com/go-openapi/jsonreference - version: 13c6e3589ad90f49bd3e3bbe2c2cb3d7a4142272 -- name: github.com/go-openapi/spec - version: 6aced65f8501fe1217321abf0749d354824ba2ff -- name: github.com/go-openapi/swag - version: 1d0bd113de87027671077d3c71eb3ac5d7dbba72 -- name: github.com/gogo/protobuf - version: e18d7aa8f8c624c915db340349aad4c49b10d173 - subpackages: - - proto - - sortkeys -- name: github.com/golang/glog - version: 44145f04b68cf362d9c4df2182967c2275eaefed -- name: github.com/google/gofuzz - version: 44d81051d367757e1c7c6a5a86423ece9afcf63c -- name: github.com/gophercloud/gophercloud - version: 12f19e5e04d617182cffa5c11f189ef0013b9791 - subpackages: - - openstack - - openstack/blockstorage/v1/volumes - - openstack/common/extensions - - openstack/compute/v2/extensions/volumeattach - - openstack/compute/v2/flavors - - openstack/compute/v2/images - - openstack/compute/v2/servers - - openstack/identity/v2/tenants - - openstack/identity/v2/tokens - - openstack/identity/v3/extensions/trusts - - openstack/identity/v3/tokens - - openstack/networking/v2/extensions - - openstack/networking/v2/extensions/layer3/floatingips - - openstack/networking/v2/extensions/layer3/routers - - openstack/networking/v2/extensions/lbaas/members - - openstack/networking/v2/extensions/lbaas/monitors - - openstack/networking/v2/extensions/lbaas/pools - - openstack/networking/v2/extensions/lbaas/vips - - openstack/networking/v2/extensions/lbaas_v2/listeners - - openstack/networking/v2/extensions/lbaas_v2/loadbalancers - - openstack/networking/v2/extensions/lbaas_v2/monitors - - openstack/networking/v2/extensions/lbaas_v2/pools - - openstack/networking/v2/extensions/security/groups - - openstack/networking/v2/extensions/security/rules - - openstack/networking/v2/ports - - openstack/utils - - pagination -- name: github.com/juju/ratelimit - version: 77ed1c8a01217656d2080ad51981f6e99adaa177 -- name: github.com/mailru/easyjson - version: d5b7844b561a7bc640052f1b935f7b800330d7e0 - subpackages: - - buffer - - jlexer - - jwriter -- name: github.com/mitchellh/mapstructure - version: 740c764bc6149d3f1806231418adb9f52c11bcbf -- name: github.com/PuerkitoBio/purell - version: 8a290539e2e8629dbc4e6bad948158f790ec31f4 -- name: github.com/PuerkitoBio/urlesc - version: 5bd2802263f21d8788851d5305584c82a5c75d7e -- name: github.com/spf13/pflag - version: 9ff6c6923cfffbcd502984b8e0c80539a94968b7 -- name: github.com/ugorji/go - version: ded73eae5db7e7a0ef6f55aace87a2873c5d2b74 - subpackages: - - codec -- name: golang.org/x/net - version: e90d6d0afc4c315a0d87a568ae68577cc15149a0 - subpackages: - - http2 - - http2/hpack - - idna - - lex/httplex -- name: golang.org/x/text - version: 2910a502d2bf9e43193af9d68ca516529614eed3 - subpackages: - - cases - - internal/tag - - language - - runes - - secure/bidirule - - secure/precis - - transform - - unicode/bidi - - unicode/norm - - width -- name: gopkg.in/gcfg.v1 - version: 083575c3955c85df16fe9590cceab64d03f5eb6e - subpackages: - - scanner - - token - - types -- name: gopkg.in/inf.v0 - version: 3887ee99ecf07df5b447e9b00d9c0b2adaa9f3e4 -- name: gopkg.in/yaml.v2 - version: 53feefa2559fb8dfa8d81baad31be332c97d6c77 -- name: k8s.io/apimachinery - version: c1c4a7fe832857c75cc1d79c8e40d71d5da15fc6 - subpackages: - - pkg/api/errors - - pkg/api/meta - - pkg/api/resource - - pkg/apimachinery - - pkg/apimachinery/announced - - pkg/apimachinery/registered - - pkg/apis/meta/v1 - - pkg/apis/meta/v1/unstructured - - pkg/conversion - - pkg/conversion/queryparams - - pkg/fields - - pkg/labels - - pkg/openapi - - pkg/runtime - - pkg/runtime/schema - - pkg/runtime/serializer - - pkg/runtime/serializer/json - - pkg/runtime/serializer/protobuf - - pkg/runtime/serializer/recognizer - - pkg/runtime/serializer/streaming - - pkg/runtime/serializer/versioning - - pkg/selection - - pkg/types - - pkg/util/errors - - pkg/util/framer - - pkg/util/intstr - - pkg/util/json - - pkg/util/net - - pkg/util/rand - - pkg/util/runtime - - pkg/util/sets - - pkg/util/validation - - pkg/util/validation/field - - pkg/util/wait - - pkg/util/yaml - - pkg/version - - pkg/watch - - third_party/forked/golang/reflect -- name: k8s.io/client-go - version: 76153773eaa3a268131d3d993290a194a1370585 - subpackages: - - discovery - - pkg/api - - pkg/api/v1 - - pkg/apis/extensions - - pkg/util - - pkg/util/parsers - - pkg/version - - rest - - rest/watch - - tools/clientcmd/api - - tools/metrics - - transport - - util/cert - - util/clock - - util/flowcontrol - - util/integer -- name: k8s.io/kubernetes - version: a845e3e936e91cd14c4c5b462631233716d5839b - subpackages: - - pkg/api - - pkg/api/install - - pkg/api/v1 - - pkg/api/v1/service - - pkg/apis/apps - - pkg/apis/apps/install - - pkg/apis/apps/v1beta1 - - pkg/apis/authentication - - pkg/apis/authentication/install - - pkg/apis/authentication/v1 - - pkg/apis/authentication/v1beta1 - - pkg/apis/authorization - - pkg/apis/authorization/install - - pkg/apis/authorization/v1 - - pkg/apis/authorization/v1beta1 - - pkg/apis/autoscaling - - pkg/apis/autoscaling/install - - pkg/apis/autoscaling/v1 - - pkg/apis/autoscaling/v2alpha1 - - pkg/apis/batch - - pkg/apis/batch/install - - pkg/apis/batch/v1 - - pkg/apis/batch/v2alpha1 - - pkg/apis/certificates - - pkg/apis/certificates/install - - pkg/apis/certificates/v1beta1 - - pkg/apis/extensions - - pkg/apis/extensions/install - - pkg/apis/extensions/v1beta1 - - pkg/apis/policy - - pkg/apis/policy/install - - pkg/apis/policy/v1beta1 - - pkg/apis/rbac - - pkg/apis/rbac/install - - pkg/apis/rbac/v1alpha1 - - pkg/apis/rbac/v1beta1 - - pkg/apis/settings - - pkg/apis/settings/install - - pkg/apis/settings/v1alpha1 - - pkg/apis/storage - - pkg/apis/storage/install - - pkg/apis/storage/v1 - - pkg/apis/storage/v1beta1 - - pkg/client/clientset_generated/clientset - - pkg/client/clientset_generated/clientset/scheme - - pkg/client/clientset_generated/clientset/typed/apps/v1beta1 - - pkg/client/clientset_generated/clientset/typed/authentication/v1 - - pkg/client/clientset_generated/clientset/typed/authentication/v1beta1 - - pkg/client/clientset_generated/clientset/typed/authorization/v1 - - pkg/client/clientset_generated/clientset/typed/authorization/v1beta1 - - pkg/client/clientset_generated/clientset/typed/autoscaling/v1 - - pkg/client/clientset_generated/clientset/typed/autoscaling/v2alpha1 - - pkg/client/clientset_generated/clientset/typed/batch/v1 - - pkg/client/clientset_generated/clientset/typed/batch/v2alpha1 - - pkg/client/clientset_generated/clientset/typed/certificates/v1beta1 - - pkg/client/clientset_generated/clientset/typed/core/v1 - - pkg/client/clientset_generated/clientset/typed/extensions/v1beta1 - - pkg/client/clientset_generated/clientset/typed/policy/v1beta1 - - pkg/client/clientset_generated/clientset/typed/rbac/v1alpha1 - - pkg/client/clientset_generated/clientset/typed/rbac/v1beta1 - - pkg/client/clientset_generated/clientset/typed/settings/v1alpha1 - - pkg/client/clientset_generated/clientset/typed/storage/v1 - - pkg/client/clientset_generated/clientset/typed/storage/v1beta1 - - pkg/cloudprovider - - pkg/util - - pkg/util/chmod - - pkg/util/chown - - pkg/util/exec - - pkg/util/io - - pkg/util/mount - - pkg/util/net/sets - - pkg/util/parsers - - pkg/volume - - pkg/volume/util -testImports: [] diff --git a/openstack/metadata.go b/openstack/metadata.go deleted file mode 100644 index f26b28f..0000000 --- a/openstack/metadata.go +++ /dev/null @@ -1,156 +0,0 @@ -/* -Copyright 2016 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package openstack - -import ( - "encoding/json" - "errors" - "fmt" - "io" - "io/ioutil" - "net/http" - "os" - "path/filepath" - "strings" - - "github.com/golang/glog" - "k8s.io/kubernetes/pkg/util/exec" - "k8s.io/kubernetes/pkg/util/mount" -) - -// metadataUrl is URL to OpenStack metadata server. It's hardcoded IPv4 -// link-local address as documented in "OpenStack Cloud Administrator Guide", -// chapter Compute - Networking with nova-network. -// http://docs.openstack.org/admin-guide-cloud/compute-networking-nova.html#metadata-service -const metadataUrl = "http://169.254.169.254/openstack/2012-08-10/meta_data.json" - -// Config drive is defined as an iso9660 or vfat (deprecated) drive -// with the "config-2" label. -// http://docs.openstack.org/user-guide/cli-config-drive.html -const configDriveLabel = "config-2" -const configDrivePath = "openstack/2012-08-10/meta_data.json" - -var ErrBadMetadata = errors.New("Invalid OpenStack metadata, got empty uuid") - -// Assumes the "2012-08-10" meta_data.json format. -// See http://docs.openstack.org/user-guide/cli_config_drive.html -type Metadata struct { - Uuid string `json:"uuid"` - Name string `json:"name"` - AvailabilityZone string `json:"availability_zone"` - // .. and other fields we don't care about. Expand as necessary. -} - -// parseMetadataUUID reads JSON from OpenStack metadata server and parses -// instance ID out of it. -func parseMetadata(r io.Reader) (*Metadata, error) { - var metadata Metadata - json := json.NewDecoder(r) - if err := json.Decode(&metadata); err != nil { - return nil, err - } - - if metadata.Uuid == "" { - return nil, ErrBadMetadata - } - - return &metadata, nil -} - -func getMetadataFromConfigDrive() (*Metadata, error) { - // Try to read instance UUID from config drive. - dev := "/dev/disk/by-label/" + configDriveLabel - if _, err := os.Stat(dev); os.IsNotExist(err) { - out, err := exec.New().Command( - "blkid", "-l", - "-t", "LABEL="+configDriveLabel, - "-o", "device", - ).CombinedOutput() - if err != nil { - glog.V(2).Infof("Unable to run blkid: %v", err) - return nil, err - } - dev = strings.TrimSpace(string(out)) - } - - mntdir, err := ioutil.TempDir("", "configdrive") - if err != nil { - return nil, err - } - defer os.Remove(mntdir) - - glog.V(4).Infof("Attempting to mount configdrive %s on %s", dev, mntdir) - - mounter := mount.New("" /* default mount path */) - err = mounter.Mount(dev, mntdir, "iso9660", []string{"ro"}) - if err != nil { - err = mounter.Mount(dev, mntdir, "vfat", []string{"ro"}) - } - if err != nil { - glog.Errorf("Error mounting configdrive %s: %v", dev, err) - return nil, err - } - defer mounter.Unmount(mntdir) - - glog.V(4).Infof("Configdrive mounted on %s", mntdir) - - f, err := os.Open( - filepath.Join(mntdir, configDrivePath)) - if err != nil { - glog.Errorf("Error reading %s on config drive: %v", configDrivePath, err) - return nil, err - } - defer f.Close() - - return parseMetadata(f) -} - -func getMetadataFromMetadataService() (*Metadata, error) { - // Try to get JSON from metdata server. - glog.V(4).Infof("Attempting to fetch metadata from %s", metadataUrl) - resp, err := http.Get(metadataUrl) - if err != nil { - glog.V(3).Infof("Cannot read %s: %v", metadataUrl, err) - return nil, err - } - defer resp.Body.Close() - - if resp.StatusCode != http.StatusOK { - err = fmt.Errorf("Unexpected status code when reading metadata from %s: %s", metadataUrl, resp.Status) - glog.V(3).Infof("%v", err) - return nil, err - } - - return parseMetadata(resp.Body) -} - -// Metadata is fixed for the current host, so cache the value process-wide -var metadataCache *Metadata - -func getMetadata() (*Metadata, error) { - if metadataCache == nil { - md, err := getMetadataFromConfigDrive() - if err != nil { - md, err = getMetadataFromMetadataService() - } - if err != nil { - return nil, err - } - metadataCache = md - } - return metadataCache, nil -} diff --git a/openstack/metadata_test.go b/openstack/metadata_test.go deleted file mode 100644 index feeb04b..0000000 --- a/openstack/metadata_test.go +++ /dev/null @@ -1,86 +0,0 @@ -/* -Copyright 2016 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package openstack - -import ( - "strings" - "testing" -) - -var FakeMetadata = Metadata{ - Uuid: "83679162-1378-4288-a2d4-70e13ec132aa", - Name: "test", - AvailabilityZone: "nova", -} - -func SetMetadataFixture(value *Metadata) { - metadataCache = value -} - -func ClearMetadata() { - metadataCache = nil -} - -func TestParseMetadata(t *testing.T) { - _, err := parseMetadata(strings.NewReader("bogus")) - if err == nil { - t.Errorf("Should fail when bad data is provided: %s", err) - } - - data := strings.NewReader(` -{ - "availability_zone": "nova", - "files": [ - { - "content_path": "/content/0000", - "path": "/etc/network/interfaces" - }, - { - "content_path": "/content/0001", - "path": "known_hosts" - } - ], - "hostname": "test.novalocal", - "launch_index": 0, - "name": "test", - "meta": { - "role": "webservers", - "essential": "false" - }, - "public_keys": { - "mykey": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDBqUfVvCSez0/Wfpd8dLLgZXV9GtXQ7hnMN+Z0OWQUyebVEHey1CXuin0uY1cAJMhUq8j98SiW+cU0sU4J3x5l2+xi1bodDm1BtFWVeLIOQINpfV1n8fKjHB+ynPpe1F6tMDvrFGUlJs44t30BrujMXBe8Rq44cCk6wqyjATA3rQ== Generated by Nova\n" - }, - "uuid": "83679162-1378-4288-a2d4-70e13ec132aa" -} -`) - md, err := parseMetadata(data) - if err != nil { - t.Fatalf("Should succeed when provided with valid data: %s", err) - } - - if md.Name != "test" { - t.Errorf("incorrect name: %s", md.Name) - } - - if md.Uuid != "83679162-1378-4288-a2d4-70e13ec132aa" { - t.Errorf("incorrect uuid: %s", md.Uuid) - } - - if md.AvailabilityZone != "nova" { - t.Errorf("incorrect az: %s", md.AvailabilityZone) - } -} diff --git a/openstack/openstack.go b/openstack/openstack.go deleted file mode 100644 index 4ad0bfd..0000000 --- a/openstack/openstack.go +++ /dev/null @@ -1,650 +0,0 @@ -/* -Copyright 2014 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package openstack - -import ( - "crypto/tls" - "errors" - "fmt" - "io" - "io/ioutil" - "net/http" - "regexp" - "sort" - "strings" - "time" - - "github.com/gophercloud/gophercloud" - "github.com/gophercloud/gophercloud/openstack" - apiversions_v1 "github.com/gophercloud/gophercloud/openstack/blockstorage/v1/apiversions" - "github.com/gophercloud/gophercloud/openstack/compute/v2/servers" - "github.com/gophercloud/gophercloud/openstack/identity/v3/extensions/trusts" - tokens3 "github.com/gophercloud/gophercloud/openstack/identity/v3/tokens" - "github.com/gophercloud/gophercloud/pagination" - "github.com/mitchellh/mapstructure" - "gopkg.in/gcfg.v1" - - "github.com/golang/glog" - "k8s.io/apimachinery/pkg/types" - netutil "k8s.io/apimachinery/pkg/util/net" - certutil "k8s.io/client-go/util/cert" - "k8s.io/kubernetes/pkg/api/v1" - v1helper "k8s.io/kubernetes/pkg/api/v1/helper" - "k8s.io/kubernetes/pkg/cloudprovider" -) - -const ProviderName = "openstack" - -var ErrNotFound = errors.New("Failed to find object") -var ErrMultipleResults = errors.New("Multiple results where only one expected") -var ErrNoAddressFound = errors.New("No address found for host") - -const ( - MiB = 1024 * 1024 - GB = 1000 * 1000 * 1000 -) - -// encoding.TextUnmarshaler interface for time.Duration -type MyDuration struct { - time.Duration -} - -func (d *MyDuration) UnmarshalText(text []byte) error { - res, err := time.ParseDuration(string(text)) - if err != nil { - return err - } - d.Duration = res - return nil -} - -type LoadBalancer struct { - network *gophercloud.ServiceClient - compute *gophercloud.ServiceClient - opts LoadBalancerOpts -} - -type LoadBalancerOpts struct { - LBVersion string `gcfg:"lb-version"` // overrides autodetection. v1 or v2 - SubnetId string `gcfg:"subnet-id"` // required - FloatingNetworkId string `gcfg:"floating-network-id"` - LBMethod string `gcfg:"lb-method"` - CreateMonitor bool `gcfg:"create-monitor"` - MonitorDelay MyDuration `gcfg:"monitor-delay"` - MonitorTimeout MyDuration `gcfg:"monitor-timeout"` - MonitorMaxRetries uint `gcfg:"monitor-max-retries"` - ManageSecurityGroups bool `gcfg:"manage-security-groups"` - NodeSecurityGroupID string `gcfg:"node-security-group"` -} - -type BlockStorageOpts struct { - BSVersion string `gcfg:"bs-version"` // overrides autodetection. v1 or v2. Defaults to auto - TrustDevicePath bool `gcfg:"trust-device-path"` // See Issue #33128 -} - -type RouterOpts struct { - RouterId string `gcfg:"router-id"` // required -} - -// OpenStack is an implementation of cloud provider Interface for OpenStack. -type OpenStack struct { - provider *gophercloud.ProviderClient - region string - lbOpts LoadBalancerOpts - bsOpts BlockStorageOpts - routeOpts RouterOpts - // InstanceID of the server where this OpenStack object is instantiated. - localInstanceID string -} - -type Config struct { - Global struct { - AuthUrl string `gcfg:"auth-url"` - Username string - UserId string `gcfg:"user-id"` - Password string - TenantId string `gcfg:"tenant-id"` - TenantName string `gcfg:"tenant-name"` - TrustId string `gcfg:"trust-id"` - DomainId string `gcfg:"domain-id"` - DomainName string `gcfg:"domain-name"` - Region string - CAFile string `gcfg:"ca-file"` - } - LoadBalancer LoadBalancerOpts - BlockStorage BlockStorageOpts - Route RouterOpts -} - -func init() { - cloudprovider.RegisterCloudProvider(ProviderName, func(config io.Reader) (cloudprovider.Interface, error) { - cfg, err := readConfig(config) - if err != nil { - return nil, err - } - return newOpenStack(cfg) - }) -} - -func (cfg Config) toAuthOptions() gophercloud.AuthOptions { - return gophercloud.AuthOptions{ - IdentityEndpoint: cfg.Global.AuthUrl, - Username: cfg.Global.Username, - UserID: cfg.Global.UserId, - Password: cfg.Global.Password, - TenantID: cfg.Global.TenantId, - TenantName: cfg.Global.TenantName, - DomainID: cfg.Global.DomainId, - DomainName: cfg.Global.DomainName, - - // Persistent service, so we need to be able to renew tokens. - AllowReauth: true, - } -} - -func (cfg Config) toAuth3Options() tokens3.AuthOptions { - return tokens3.AuthOptions{ - IdentityEndpoint: cfg.Global.AuthUrl, - Username: cfg.Global.Username, - UserID: cfg.Global.UserId, - Password: cfg.Global.Password, - DomainID: cfg.Global.DomainId, - DomainName: cfg.Global.DomainName, - AllowReauth: true, - } -} - -func readConfig(config io.Reader) (Config, error) { - if config == nil { - err := fmt.Errorf("no OpenStack cloud provider config file given") - return Config{}, err - } - - var cfg Config - - // Set default values for config params - cfg.BlockStorage.BSVersion = "auto" - cfg.BlockStorage.TrustDevicePath = false - - err := gcfg.ReadInto(&cfg, config) - return cfg, err -} - -// Tiny helper for conditional unwind logic -type Caller bool - -func NewCaller() Caller { return Caller(true) } -func (c *Caller) Disarm() { *c = false } - -func (c *Caller) Call(f func()) { - if *c { - f() - } -} - -func readInstanceID() (string, error) { - // Try to find instance ID on the local filesystem (created by cloud-init) - const instanceIDFile = "/var/lib/cloud/data/instance-id" - idBytes, err := ioutil.ReadFile(instanceIDFile) - if err == nil { - instanceID := string(idBytes) - instanceID = strings.TrimSpace(instanceID) - glog.V(3).Infof("Got instance id from %s: %s", instanceIDFile, instanceID) - if instanceID != "" { - return instanceID, nil - } - // Fall through to metadata server lookup - } - - md, err := getMetadata() - if err != nil { - return "", err - } - - return md.Uuid, nil -} - -func newOpenStack(cfg Config) (*OpenStack, error) { - provider, err := openstack.NewClient(cfg.Global.AuthUrl) - if err != nil { - return nil, err - } - if cfg.Global.CAFile != "" { - roots, err := certutil.NewPool(cfg.Global.CAFile) - if err != nil { - return nil, err - } - config := &tls.Config{} - config.RootCAs = roots - provider.HTTPClient.Transport = netutil.SetOldTransportDefaults(&http.Transport{TLSClientConfig: config}) - - } - if cfg.Global.TrustId != "" { - opts := cfg.toAuth3Options() - authOptsExt := trusts.AuthOptsExt{ - TrustID: cfg.Global.TrustId, - AuthOptionsBuilder: &opts, - } - err = openstack.AuthenticateV3(provider, authOptsExt, gophercloud.EndpointOpts{}) - } else { - err = openstack.Authenticate(provider, cfg.toAuthOptions()) - } - - if err != nil { - return nil, err - } - - id, err := readInstanceID() - if err != nil { - return nil, err - } - - os := OpenStack{ - provider: provider, - region: cfg.Global.Region, - lbOpts: cfg.LoadBalancer, - bsOpts: cfg.BlockStorage, - routeOpts: cfg.Route, - localInstanceID: id, - } - - return &os, nil -} - -// mapNodeNameToServerName maps a k8s NodeName to an OpenStack Server Name -// This is a simple string cast. -func mapNodeNameToServerName(nodeName types.NodeName) string { - return string(nodeName) -} - -// mapServerToNodeName maps an OpenStack Server to a k8s NodeName -func mapServerToNodeName(server *servers.Server) types.NodeName { - // Node names are always lowercase, and (at least) - // routecontroller does case-sensitive string comparisons - // assuming this - return types.NodeName(strings.ToLower(server.Name)) -} - -func foreachServer(client *gophercloud.ServiceClient, opts servers.ListOptsBuilder, handler func(*servers.Server) (bool, error)) error { - pager := servers.List(client, opts) - - err := pager.EachPage(func(page pagination.Page) (bool, error) { - s, err := servers.ExtractServers(page) - if err != nil { - return false, err - } - for _, server := range s { - ok, err := handler(&server) - if !ok || err != nil { - return false, err - } - } - return true, nil - }) - return err -} - -func getServerByName(client *gophercloud.ServiceClient, name types.NodeName) (*servers.Server, error) { - opts := servers.ListOpts{ - Name: fmt.Sprintf("^%s$", regexp.QuoteMeta(mapNodeNameToServerName(name))), - Status: "ACTIVE", - } - pager := servers.List(client, opts) - - serverList := make([]servers.Server, 0, 1) - - err := pager.EachPage(func(page pagination.Page) (bool, error) { - s, err := servers.ExtractServers(page) - if err != nil { - return false, err - } - serverList = append(serverList, s...) - if len(serverList) > 1 { - return false, ErrMultipleResults - } - return true, nil - }) - if err != nil { - return nil, err - } - - if len(serverList) == 0 { - return nil, ErrNotFound - } - - return &serverList[0], nil -} - -func nodeAddresses(srv *servers.Server) ([]v1.NodeAddress, error) { - addrs := []v1.NodeAddress{} - - type Address struct { - IpType string `mapstructure:"OS-EXT-IPS:type"` - Addr string - } - - var addresses map[string][]Address - err := mapstructure.Decode(srv.Addresses, &addresses) - if err != nil { - return nil, err - } - - for network, addrList := range addresses { - for _, props := range addrList { - var addressType v1.NodeAddressType - if props.IpType == "floating" || network == "public" { - addressType = v1.NodeExternalIP - } else { - addressType = v1.NodeInternalIP - } - - v1helper.AddToNodeAddresses(&addrs, - v1.NodeAddress{ - Type: addressType, - Address: props.Addr, - }, - ) - } - } - - // AccessIPs are usually duplicates of "public" addresses. - if srv.AccessIPv4 != "" { - v1helper.AddToNodeAddresses(&addrs, - v1.NodeAddress{ - Type: v1.NodeExternalIP, - Address: srv.AccessIPv4, - }, - ) - } - - if srv.AccessIPv6 != "" { - v1helper.AddToNodeAddresses(&addrs, - v1.NodeAddress{ - Type: v1.NodeExternalIP, - Address: srv.AccessIPv6, - }, - ) - } - - return addrs, nil -} - -func getAddressesByName(client *gophercloud.ServiceClient, name types.NodeName) ([]v1.NodeAddress, error) { - srv, err := getServerByName(client, name) - if err != nil { - return nil, err - } - - return nodeAddresses(srv) -} - -func getAddressByName(client *gophercloud.ServiceClient, name types.NodeName) (string, error) { - addrs, err := getAddressesByName(client, name) - if err != nil { - return "", err - } else if len(addrs) == 0 { - return "", ErrNoAddressFound - } - - for _, addr := range addrs { - if addr.Type == v1.NodeInternalIP { - return addr.Address, nil - } - } - - return addrs[0].Address, nil -} - -func (os *OpenStack) Clusters() (cloudprovider.Clusters, bool) { - return nil, false -} - -// ProviderName returns the cloud provider ID. -func (os *OpenStack) ProviderName() string { - return ProviderName -} - -// ScrubDNS filters DNS settings for pods. -func (os *OpenStack) ScrubDNS(nameServers, searches []string) ([]string, []string) { - return nameServers, searches -} - -func (os *OpenStack) LoadBalancer() (cloudprovider.LoadBalancer, bool) { - glog.V(4).Info("openstack.LoadBalancer() called") - - // TODO: Search for and support Rackspace loadbalancer API, and others. - network, err := openstack.NewNetworkV2(os.provider, gophercloud.EndpointOpts{ - Region: os.region, - }) - if err != nil { - glog.Warningf("Failed to find network endpoint: %v", err) - return nil, false - } - - compute, err := openstack.NewComputeV2(os.provider, gophercloud.EndpointOpts{ - Region: os.region, - }) - if err != nil { - glog.Warningf("Failed to find compute endpoint: %v", err) - return nil, false - } - - lbVersion := os.lbOpts.LBVersion - if lbVersion == "" { - // No version specified, try newest supported by server - netExts, err := networkExtensions(network) - if err != nil { - glog.Warningf("Failed to list neutron extensions: %v", err) - return nil, false - } - - if netExts["lbaasv2"] { - lbVersion = "v2" - } else if netExts["lbaas"] { - lbVersion = "v1" - } else { - glog.Warningf("Failed to find neutron LBaaS extension (v1 or v2)") - return nil, false - } - glog.V(3).Infof("Using LBaaS extension %v", lbVersion) - } - - glog.V(1).Info("Claiming to support LoadBalancer") - - if lbVersion == "v2" { - return &LbaasV2{LoadBalancer{network, compute, os.lbOpts}}, true - } else if lbVersion == "v1" { - return &LbaasV1{LoadBalancer{network, compute, os.lbOpts}}, true - } else { - glog.Warningf("Config error: unrecognised lb-version \"%v\"", lbVersion) - return nil, false - } -} - -func isNotFound(err error) bool { - e, ok := err.(*gophercloud.ErrUnexpectedResponseCode) - return ok && e.Actual == http.StatusNotFound -} - -func (os *OpenStack) Zones() (cloudprovider.Zones, bool) { - glog.V(1).Info("Claiming to support Zones") - - return os, true -} -func (os *OpenStack) GetZone() (cloudprovider.Zone, error) { - md, err := getMetadata() - if err != nil { - return cloudprovider.Zone{}, err - } - - zone := cloudprovider.Zone{ - FailureDomain: md.AvailabilityZone, - Region: os.region, - } - glog.V(1).Infof("Current zone is %v", zone) - - return zone, nil -} - -func (os *OpenStack) Routes() (cloudprovider.Routes, bool) { - glog.V(4).Info("openstack.Routes() called") - - network, err := openstack.NewNetworkV2(os.provider, gophercloud.EndpointOpts{ - Region: os.region, - }) - if err != nil { - glog.Warningf("Failed to find network endpoint: %v", err) - return nil, false - } - - netExts, err := networkExtensions(network) - if err != nil { - glog.Warningf("Failed to list neutron extensions: %v", err) - return nil, false - } - - if !netExts["extraroute"] { - glog.V(3).Infof("Neutron extraroute extension not found, required for Routes support") - return nil, false - } - - compute, err := openstack.NewComputeV2(os.provider, gophercloud.EndpointOpts{ - Region: os.region, - }) - if err != nil { - glog.Warningf("Failed to find compute endpoint: %v", err) - return nil, false - } - - r, err := NewRoutes(compute, network, os.routeOpts) - if err != nil { - glog.Warningf("Error initialising Routes support: %v", err) - return nil, false - } - - glog.V(1).Info("Claiming to support Routes") - - return r, true -} - -// Implementation of sort interface for blockstorage version probing -type APIVersionsByID []apiversions_v1.APIVersion - -func (apiVersions APIVersionsByID) Len() int { - return len(apiVersions) -} - -func (apiVersions APIVersionsByID) Swap(i, j int) { - apiVersions[i], apiVersions[j] = apiVersions[j], apiVersions[i] -} - -func (apiVersions APIVersionsByID) Less(i, j int) bool { - return apiVersions[i].ID > apiVersions[j].ID -} - -func autoVersionSelector(apiVersion *apiversions_v1.APIVersion) string { - switch strings.ToLower(apiVersion.ID) { - case "v2.0": - return "v2" - case "v1.0": - return "v1" - default: - return "" - } -} - -func doBsApiVersionAutodetect(availableApiVersions []apiversions_v1.APIVersion) string { - sort.Sort(APIVersionsByID(availableApiVersions)) - for _, status := range []string{"CURRENT", "SUPPORTED"} { - for _, version := range availableApiVersions { - if strings.ToUpper(version.Status) == status { - if detectedApiVersion := autoVersionSelector(&version); detectedApiVersion != "" { - glog.V(3).Infof("Blockstorage API version probing has found a suitable %s api version: %s", status, detectedApiVersion) - return detectedApiVersion - } - } - } - } - - return "" - -} - -func (os *OpenStack) volumeService(forceVersion string) (volumeService, error) { - bsVersion := "" - if forceVersion == "" { - bsVersion = os.bsOpts.BSVersion - } else { - bsVersion = forceVersion - } - - switch bsVersion { - case "v1": - sClient, err := openstack.NewBlockStorageV1(os.provider, gophercloud.EndpointOpts{ - Region: os.region, - }) - if err != nil || sClient == nil { - glog.Errorf("Unable to initialize cinder client for region: %s", os.region) - return nil, err - } - return &VolumesV1{sClient, os.bsOpts}, nil - case "v2": - sClient, err := openstack.NewBlockStorageV2(os.provider, gophercloud.EndpointOpts{ - Region: os.region, - }) - if err != nil || sClient == nil { - glog.Errorf("Unable to initialize cinder v2 client for region: %s", os.region) - return nil, err - } - return &VolumesV2{sClient, os.bsOpts}, nil - case "auto": - sClient, err := openstack.NewBlockStorageV1(os.provider, gophercloud.EndpointOpts{ - Region: os.region, - }) - if err != nil || sClient == nil { - glog.Errorf("Unable to initialize cinder client for region: %s", os.region) - return nil, err - } - availableApiVersions := []apiversions_v1.APIVersion{} - err = apiversions_v1.List(sClient).EachPage(func(page pagination.Page) (bool, error) { - // returning false from this handler stops page iteration, error is propagated to the upper function - apiversions, err := apiversions_v1.ExtractAPIVersions(page) - if err != nil { - glog.Errorf("Unable to extract api versions from page: %v", err) - return false, err - } - availableApiVersions = append(availableApiVersions, apiversions...) - return true, nil - }) - - if err != nil { - glog.Errorf("Error when retrieving list of supported blockstorage api versions: %v", err) - return nil, err - } - if autodetectedVersion := doBsApiVersionAutodetect(availableApiVersions); autodetectedVersion != "" { - return os.volumeService(autodetectedVersion) - } else { - // Nothing suitable found, failed autodetection - return nil, errors.New("BS API version autodetection failed.") - } - - default: - err_txt := fmt.Sprintf("Config error: unrecognised bs-version \"%v\"", os.bsOpts.BSVersion) - glog.Warningf(err_txt) - return nil, errors.New(err_txt) - } -} diff --git a/openstack/openstack_instances.go b/openstack/openstack_instances.go deleted file mode 100644 index 3d4f749..0000000 --- a/openstack/openstack_instances.go +++ /dev/null @@ -1,155 +0,0 @@ -/* -Copyright 2016 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package openstack - -import ( - "errors" - - "github.com/golang/glog" - "github.com/gophercloud/gophercloud" - "github.com/gophercloud/gophercloud/openstack" - "github.com/gophercloud/gophercloud/openstack/compute/v2/servers" - "github.com/gophercloud/gophercloud/pagination" - - "k8s.io/apimachinery/pkg/types" - "k8s.io/kubernetes/pkg/api/v1" - "k8s.io/kubernetes/pkg/cloudprovider" -) - -type Instances struct { - compute *gophercloud.ServiceClient -} - -// Instances returns an implementation of Instances for OpenStack. -func (os *OpenStack) Instances() (cloudprovider.Instances, bool) { - glog.V(4).Info("openstack.Instances() called") - - compute, err := openstack.NewComputeV2(os.provider, gophercloud.EndpointOpts{ - Region: os.region, - }) - if err != nil { - glog.Warningf("Failed to find compute endpoint: %v", err) - return nil, false - } - - glog.V(1).Info("Claiming to support Instances") - - return &Instances{compute}, true -} - -func (i *Instances) List(name_filter string) ([]types.NodeName, error) { - glog.V(4).Infof("openstack List(%v) called", name_filter) - - opts := servers.ListOpts{ - Name: name_filter, - Status: "ACTIVE", - } - pager := servers.List(i.compute, opts) - - ret := make([]types.NodeName, 0) - err := pager.EachPage(func(page pagination.Page) (bool, error) { - sList, err := servers.ExtractServers(page) - if err != nil { - return false, err - } - for i := range sList { - ret = append(ret, mapServerToNodeName(&sList[i])) - } - return true, nil - }) - if err != nil { - return nil, err - } - - glog.V(3).Infof("Found %v instances matching %v: %v", - len(ret), name_filter, ret) - - return ret, nil -} - -// Implementation of Instances.CurrentNodeName -// Note this is *not* necessarily the same as hostname. -func (i *Instances) CurrentNodeName(hostname string) (types.NodeName, error) { - md, err := getMetadata() - if err != nil { - return "", err - } - return types.NodeName(md.Name), nil -} - -func (i *Instances) AddSSHKeyToAllInstances(user string, keyData []byte) error { - return errors.New("unimplemented") -} - -func (i *Instances) NodeAddresses(name types.NodeName) ([]v1.NodeAddress, error) { - glog.V(4).Infof("NodeAddresses(%v) called", name) - - addrs, err := getAddressesByName(i.compute, name) - if err != nil { - return nil, err - } - - glog.V(4).Infof("NodeAddresses(%v) => %v", name, addrs) - return addrs, nil -} - -// NodeAddressesByProviderID returns the node addresses of an instances with the specified unique providerID -// This method will not be called from the node that is requesting this ID. i.e. metadata service -// and other local methods cannot be used here -func (i *Instances) NodeAddressesByProviderID(providerID string) ([]v1.NodeAddress, error) { - return []v1.NodeAddress{}, errors.New("unimplemented") -} - -// ExternalID returns the cloud provider ID of the specified instance (deprecated). -func (i *Instances) ExternalID(name types.NodeName) (string, error) { - srv, err := getServerByName(i.compute, name) - if err != nil { - if err == ErrNotFound { - return "", cloudprovider.InstanceNotFound - } - return "", err - } - return srv.ID, nil -} - -// InstanceID returns the kubelet's cloud provider ID. -func (os *OpenStack) InstanceID() (string, error) { - return os.localInstanceID, nil -} - -// InstanceID returns the cloud provider ID of the specified instance. -func (i *Instances) InstanceID(name types.NodeName) (string, error) { - srv, err := getServerByName(i.compute, name) - if err != nil { - return "", err - } - // In the future it is possible to also return an endpoint as: - // / - return "/" + srv.ID, nil -} - -// InstanceTypeByProviderID returns the cloudprovider instance type of the node with the specified unique providerID -// This method will not be called from the node that is requesting this ID. i.e. metadata service -// and other local methods cannot be used here -func (i *Instances) InstanceTypeByProviderID(providerID string) (string, error) { - return "", errors.New("unimplemented") -} - -// InstanceType returns the type of the specified instance. -func (i *Instances) InstanceType(name types.NodeName) (string, error) { - return "", nil -} diff --git a/openstack/openstack_loadbalancer.go b/openstack/openstack_loadbalancer.go deleted file mode 100644 index b255286..0000000 --- a/openstack/openstack_loadbalancer.go +++ /dev/null @@ -1,1577 +0,0 @@ -/* -Copyright 2016 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package openstack - -import ( - "fmt" - "net" - "strings" - "time" - - "github.com/golang/glog" - "github.com/gophercloud/gophercloud" - "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions" - "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/floatingips" - "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas/members" - "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas/monitors" - "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas/pools" - "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas/vips" - "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/listeners" - "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/loadbalancers" - v2monitors "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/monitors" - v2pools "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/pools" - "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/security/groups" - "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/security/rules" - neutronports "github.com/gophercloud/gophercloud/openstack/networking/v2/ports" - "github.com/gophercloud/gophercloud/pagination" - - "k8s.io/kubernetes/pkg/api/v1" - "k8s.io/kubernetes/pkg/api/v1/service" - "k8s.io/kubernetes/pkg/cloudprovider" -) - -// Note: when creating a new Loadbalancer (VM), it can take some time before it is ready for use, -// this timeout is used for waiting until the Loadbalancer provisioning status goes to ACTIVE state. -const loadbalancerActiveTimeoutSeconds = 120 -const loadbalancerDeleteTimeoutSeconds = 30 - -// LoadBalancer implementation for LBaaS v1 -type LbaasV1 struct { - LoadBalancer -} - -// LoadBalancer implementation for LBaaS v2 -type LbaasV2 struct { - LoadBalancer -} - -type empty struct{} - -func networkExtensions(client *gophercloud.ServiceClient) (map[string]bool, error) { - seen := make(map[string]bool) - - pager := extensions.List(client) - err := pager.EachPage(func(page pagination.Page) (bool, error) { - exts, err := extensions.ExtractExtensions(page) - if err != nil { - return false, err - } - for _, ext := range exts { - seen[ext.Alias] = true - } - return true, nil - }) - - return seen, err -} - -func getPortByIP(client *gophercloud.ServiceClient, ipAddress string) (neutronports.Port, error) { - var targetPort neutronports.Port - var portFound = false - - err := neutronports.List(client, neutronports.ListOpts{}).EachPage(func(page pagination.Page) (bool, error) { - portList, err := neutronports.ExtractPorts(page) - if err != nil { - return false, err - } - - for _, port := range portList { - for _, ip := range port.FixedIPs { - if ip.IPAddress == ipAddress { - targetPort = port - portFound = true - return false, nil - } - } - } - - return true, nil - }) - if err == nil && !portFound { - err = ErrNotFound - } - return targetPort, err -} - -func getFloatingIPByPortID(client *gophercloud.ServiceClient, portID string) (*floatingips.FloatingIP, error) { - opts := floatingips.ListOpts{ - PortID: portID, - } - pager := floatingips.List(client, opts) - - floatingIPList := make([]floatingips.FloatingIP, 0, 1) - - err := pager.EachPage(func(page pagination.Page) (bool, error) { - f, err := floatingips.ExtractFloatingIPs(page) - if err != nil { - return false, err - } - floatingIPList = append(floatingIPList, f...) - if len(floatingIPList) > 1 { - return false, ErrMultipleResults - } - return true, nil - }) - if err != nil { - if isNotFound(err) { - return nil, ErrNotFound - } - return nil, err - } - - if len(floatingIPList) == 0 { - return nil, ErrNotFound - } else if len(floatingIPList) > 1 { - return nil, ErrMultipleResults - } - - return &floatingIPList[0], nil -} - -func getPoolByName(client *gophercloud.ServiceClient, name string) (*pools.Pool, error) { - opts := pools.ListOpts{ - Name: name, - } - pager := pools.List(client, opts) - - poolList := make([]pools.Pool, 0, 1) - - err := pager.EachPage(func(page pagination.Page) (bool, error) { - p, err := pools.ExtractPools(page) - if err != nil { - return false, err - } - poolList = append(poolList, p...) - if len(poolList) > 1 { - return false, ErrMultipleResults - } - return true, nil - }) - if err != nil { - if isNotFound(err) { - return nil, ErrNotFound - } - return nil, err - } - - if len(poolList) == 0 { - return nil, ErrNotFound - } else if len(poolList) > 1 { - return nil, ErrMultipleResults - } - - return &poolList[0], nil -} - -func getVipByName(client *gophercloud.ServiceClient, name string) (*vips.VirtualIP, error) { - opts := vips.ListOpts{ - Name: name, - } - pager := vips.List(client, opts) - - vipList := make([]vips.VirtualIP, 0, 1) - - err := pager.EachPage(func(page pagination.Page) (bool, error) { - v, err := vips.ExtractVIPs(page) - if err != nil { - return false, err - } - vipList = append(vipList, v...) - if len(vipList) > 1 { - return false, ErrMultipleResults - } - return true, nil - }) - if err != nil { - if isNotFound(err) { - return nil, ErrNotFound - } - return nil, err - } - - if len(vipList) == 0 { - return nil, ErrNotFound - } else if len(vipList) > 1 { - return nil, ErrMultipleResults - } - - return &vipList[0], nil -} - -func getLoadbalancerByName(client *gophercloud.ServiceClient, name string) (*loadbalancers.LoadBalancer, error) { - opts := loadbalancers.ListOpts{ - Name: name, - } - pager := loadbalancers.List(client, opts) - - loadbalancerList := make([]loadbalancers.LoadBalancer, 0, 1) - - err := pager.EachPage(func(page pagination.Page) (bool, error) { - v, err := loadbalancers.ExtractLoadBalancers(page) - if err != nil { - return false, err - } - loadbalancerList = append(loadbalancerList, v...) - if len(loadbalancerList) > 1 { - return false, ErrMultipleResults - } - return true, nil - }) - if err != nil { - if isNotFound(err) { - return nil, ErrNotFound - } - return nil, err - } - - if len(loadbalancerList) == 0 { - return nil, ErrNotFound - } else if len(loadbalancerList) > 1 { - return nil, ErrMultipleResults - } - - return &loadbalancerList[0], nil -} - -func getListenersByLoadBalancerID(client *gophercloud.ServiceClient, id string) ([]listeners.Listener, error) { - var existingListeners []listeners.Listener - err := listeners.List(client, listeners.ListOpts{LoadbalancerID: id}).EachPage(func(page pagination.Page) (bool, error) { - listenerList, err := listeners.ExtractListeners(page) - if err != nil { - return false, err - } - for _, l := range listenerList { - for _, lb := range l.Loadbalancers { - if lb.ID == id { - existingListeners = append(existingListeners, l) - break - } - } - } - - return true, nil - }) - if err != nil { - return nil, err - } - - return existingListeners, nil -} - -// get listener for a port or nil if does not exist -func getListenerForPort(existingListeners []listeners.Listener, port v1.ServicePort) *listeners.Listener { - for _, l := range existingListeners { - if listeners.Protocol(l.Protocol) == toListenersProtocol(port.Protocol) && l.ProtocolPort == int(port.Port) { - return &l - } - } - - return nil -} - -// Get pool for a listener. A listener always has exactly one pool. -func getPoolByListenerID(client *gophercloud.ServiceClient, loadbalancerID string, listenerID string) (*v2pools.Pool, error) { - listenerPools := make([]v2pools.Pool, 0, 1) - err := v2pools.List(client, v2pools.ListOpts{LoadbalancerID: loadbalancerID}).EachPage(func(page pagination.Page) (bool, error) { - poolsList, err := v2pools.ExtractPools(page) - if err != nil { - return false, err - } - for _, p := range poolsList { - for _, l := range p.Listeners { - if l.ID == listenerID { - listenerPools = append(listenerPools, p) - } - } - } - if len(listenerPools) > 1 { - return false, ErrMultipleResults - } - return true, nil - }) - if err != nil { - if isNotFound(err) { - return nil, ErrNotFound - } - return nil, err - } - - if len(listenerPools) == 0 { - return nil, ErrNotFound - } else if len(listenerPools) > 1 { - return nil, ErrMultipleResults - } - - return &listenerPools[0], nil -} - -func getMembersByPoolID(client *gophercloud.ServiceClient, id string) ([]v2pools.Member, error) { - var members []v2pools.Member - err := v2pools.ListMembers(client, id, v2pools.ListMembersOpts{}).EachPage(func(page pagination.Page) (bool, error) { - membersList, err := v2pools.ExtractMembers(page) - if err != nil { - return false, err - } - members = append(members, membersList...) - - return true, nil - }) - if err != nil { - return nil, err - } - - return members, nil -} - -// Each pool has exactly one or zero monitors. ListOpts does not seem to filter anything. -func getMonitorByPoolID(client *gophercloud.ServiceClient, id string) (*v2monitors.Monitor, error) { - var monitorList []v2monitors.Monitor - err := v2monitors.List(client, v2monitors.ListOpts{PoolID: id}).EachPage(func(page pagination.Page) (bool, error) { - monitorsList, err := v2monitors.ExtractMonitors(page) - if err != nil { - return false, err - } - - for _, monitor := range monitorsList { - // bugfix, filter by poolid - for _, pool := range monitor.Pools { - if pool.ID == id { - monitorList = append(monitorList, monitor) - } - } - } - if len(monitorList) > 1 { - return false, ErrMultipleResults - } - return true, nil - }) - if err != nil { - if isNotFound(err) { - return nil, ErrNotFound - } - return nil, err - } - - if len(monitorList) == 0 { - return nil, ErrNotFound - } else if len(monitorList) > 1 { - return nil, ErrMultipleResults - } - - return &monitorList[0], nil -} - -// Check if a member exists for node -func memberExists(members []v2pools.Member, addr string, port int) bool { - for _, member := range members { - if member.Address == addr && member.ProtocolPort == port { - return true - } - } - - return false -} - -func popListener(existingListeners []listeners.Listener, id string) []listeners.Listener { - for i, existingListener := range existingListeners { - if existingListener.ID == id { - existingListeners[i] = existingListeners[len(existingListeners)-1] - existingListeners = existingListeners[:len(existingListeners)-1] - break - } - } - - return existingListeners -} - -func popMember(members []v2pools.Member, addr string, port int) []v2pools.Member { - for i, member := range members { - if member.Address == addr && member.ProtocolPort == port { - members[i] = members[len(members)-1] - members = members[:len(members)-1] - } - } - - return members -} - -func getSecurityGroupName(clusterName string, service *v1.Service) string { - return fmt.Sprintf("lb-sg-%s-%v", clusterName, service.Name) -} - -func getSecurityGroupRules(client *gophercloud.ServiceClient, opts rules.ListOpts) ([]rules.SecGroupRule, error) { - - pager := rules.List(client, opts) - - var securityRules []rules.SecGroupRule - - err := pager.EachPage(func(page pagination.Page) (bool, error) { - ruleList, err := rules.ExtractRules(page) - if err != nil { - return false, err - } - securityRules = append(securityRules, ruleList...) - return true, nil - }) - - if err != nil { - return nil, err - } - - return securityRules, nil -} - -func waitLoadbalancerActiveProvisioningStatus(client *gophercloud.ServiceClient, loadbalancerID string) (string, error) { - start := time.Now().Second() - for { - loadbalancer, err := loadbalancers.Get(client, loadbalancerID).Extract() - if err != nil { - return "", err - } - if loadbalancer.ProvisioningStatus == "ACTIVE" { - return "ACTIVE", nil - } else if loadbalancer.ProvisioningStatus == "ERROR" { - return "ERROR", fmt.Errorf("Loadbalancer has gone into ERROR state") - } - - time.Sleep(1 * time.Second) - - if time.Now().Second()-start >= loadbalancerActiveTimeoutSeconds { - return loadbalancer.ProvisioningStatus, fmt.Errorf("Loadbalancer failed to go into ACTIVE provisioning status within alloted time") - } - } -} - -func waitLoadbalancerDeleted(client *gophercloud.ServiceClient, loadbalancerID string) error { - start := time.Now().Second() - for { - _, err := loadbalancers.Get(client, loadbalancerID).Extract() - if err != nil { - if err == ErrNotFound { - return nil - } else { - return err - } - } - - time.Sleep(1 * time.Second) - - if time.Now().Second()-start >= loadbalancerDeleteTimeoutSeconds { - return fmt.Errorf("Loadbalancer failed to delete within the alloted time") - } - - } -} - -func toRuleProtocol(protocol v1.Protocol) rules.RuleProtocol { - switch protocol { - case v1.ProtocolTCP: - return rules.ProtocolTCP - case v1.ProtocolUDP: - return rules.ProtocolUDP - default: - return rules.RuleProtocol(strings.ToLower(string(protocol))) - } -} - -func toListenersProtocol(protocol v1.Protocol) listeners.Protocol { - switch protocol { - case v1.ProtocolTCP: - return listeners.ProtocolTCP - default: - return listeners.Protocol(string(protocol)) - } -} - -func createNodeSecurityGroup(client *gophercloud.ServiceClient, nodeSecurityGroupID string, port int, protocol v1.Protocol, lbSecGroup string) error { - v4NodeSecGroupRuleCreateOpts := rules.CreateOpts{ - Direction: rules.DirIngress, - PortRangeMax: port, - PortRangeMin: port, - Protocol: toRuleProtocol(protocol), - RemoteGroupID: lbSecGroup, - SecGroupID: nodeSecurityGroupID, - EtherType: rules.EtherType4, - } - - v6NodeSecGroupRuleCreateOpts := rules.CreateOpts{ - Direction: rules.DirIngress, - PortRangeMax: port, - PortRangeMin: port, - Protocol: toRuleProtocol(protocol), - RemoteGroupID: lbSecGroup, - SecGroupID: nodeSecurityGroupID, - EtherType: rules.EtherType6, - } - - _, err := rules.Create(client, v4NodeSecGroupRuleCreateOpts).Extract() - - if err != nil { - return err - } - - _, err = rules.Create(client, v6NodeSecGroupRuleCreateOpts).Extract() - - if err != nil { - return err - } - return nil -} - -func (lbaas *LbaasV2) createLoadBalancer(service *v1.Service, name string) (*loadbalancers.LoadBalancer, error) { - createOpts := loadbalancers.CreateOpts{ - Name: name, - Description: fmt.Sprintf("Kubernetes external service %s", name), - VipSubnetID: lbaas.opts.SubnetId, - } - - loadBalancerIP := service.Spec.LoadBalancerIP - if loadBalancerIP != "" { - createOpts.VipAddress = loadBalancerIP - } - - loadbalancer, err := loadbalancers.Create(lbaas.network, createOpts).Extract() - if err != nil { - return nil, fmt.Errorf("Error creating loadbalancer %v: %v", createOpts, err) - } - return loadbalancer, nil -} - -func stringInArray(x string, list []string) bool { - for _, y := range list { - if y == x { - return true - } - } - return false -} - -func (lbaas *LbaasV2) GetLoadBalancer(clusterName string, service *v1.Service) (*v1.LoadBalancerStatus, bool, error) { - loadBalancerName := cloudprovider.GetLoadBalancerName(service) - loadbalancer, err := getLoadbalancerByName(lbaas.network, loadBalancerName) - if err == ErrNotFound { - return nil, false, nil - } - if loadbalancer == nil { - return nil, false, err - } - - status := &v1.LoadBalancerStatus{} - status.Ingress = []v1.LoadBalancerIngress{{IP: loadbalancer.VipAddress}} - - return status, true, err -} - -// The LB needs to be configured with instance addresses on the same -// subnet as the LB (aka opts.SubnetId). Currently we're just -// guessing that the node's InternalIP is the right address - and that -// should be sufficient for all "normal" cases. -func nodeAddressForLB(node *v1.Node) (string, error) { - addrs := node.Status.Addresses - if len(addrs) == 0 { - return "", ErrNoAddressFound - } - - for _, addr := range addrs { - if addr.Type == v1.NodeInternalIP { - return addr.Address, nil - } - } - - return addrs[0].Address, nil -} - -// TODO: This code currently ignores 'region' and always creates a -// loadbalancer in only the current OpenStack region. We should take -// a list of regions (from config) and query/create loadbalancers in -// each region. - -func (lbaas *LbaasV2) EnsureLoadBalancer(clusterName string, apiService *v1.Service, nodes []*v1.Node) (*v1.LoadBalancerStatus, error) { - glog.V(4).Infof("EnsureLoadBalancer(%v, %v, %v, %v, %v, %v, %v)", clusterName, apiService.Namespace, apiService.Name, apiService.Spec.LoadBalancerIP, apiService.Spec.Ports, nodes, apiService.Annotations) - - ports := apiService.Spec.Ports - if len(ports) == 0 { - return nil, fmt.Errorf("no ports provided to openstack load balancer") - } - - // Check for TCP protocol on each port - // TODO: Convert all error messages to use an event recorder - for _, port := range ports { - if port.Protocol != v1.ProtocolTCP { - return nil, fmt.Errorf("Only TCP LoadBalancer is supported for openstack load balancers") - } - } - - sourceRanges, err := service.GetLoadBalancerSourceRanges(apiService) - if err != nil { - return nil, err - } - - if !service.IsAllowAll(sourceRanges) && !lbaas.opts.ManageSecurityGroups { - return nil, fmt.Errorf("Source range restrictions are not supported for openstack load balancers without managing security groups") - } - - affinity := v1.ServiceAffinityNone - var persistence *v2pools.SessionPersistence - switch affinity { - case v1.ServiceAffinityNone: - persistence = nil - case v1.ServiceAffinityClientIP: - persistence = &v2pools.SessionPersistence{Type: "SOURCE_IP"} - default: - return nil, fmt.Errorf("unsupported load balancer affinity: %v", affinity) - } - - name := cloudprovider.GetLoadBalancerName(apiService) - loadbalancer, err := getLoadbalancerByName(lbaas.network, name) - if err != nil { - if err != ErrNotFound { - return nil, fmt.Errorf("Error getting loadbalancer %s: %v", name, err) - } - glog.V(2).Infof("Creating loadbalancer %s", name) - loadbalancer, err = lbaas.createLoadBalancer(apiService, name) - if err != nil { - // Unknown error, retry later - return nil, fmt.Errorf("Error creating loadbalancer %s: %v", name, err) - } - } else { - glog.V(2).Infof("LoadBalancer %s already exists", name) - } - - waitLoadbalancerActiveProvisioningStatus(lbaas.network, loadbalancer.ID) - - lbmethod := v2pools.LBMethod(lbaas.opts.LBMethod) - if lbmethod == "" { - lbmethod = v2pools.LBMethodRoundRobin - } - - oldListeners, err := getListenersByLoadBalancerID(lbaas.network, loadbalancer.ID) - if err != nil { - return nil, fmt.Errorf("Error getting LB %s listeners: %v", name, err) - } - for portIndex, port := range ports { - listener := getListenerForPort(oldListeners, port) - if listener == nil { - glog.V(4).Infof("Creating listener for port %d", int(port.Port)) - listener, err = listeners.Create(lbaas.network, listeners.CreateOpts{ - Name: fmt.Sprintf("listener_%s_%d", name, portIndex), - Protocol: listeners.Protocol(port.Protocol), - ProtocolPort: int(port.Port), - LoadbalancerID: loadbalancer.ID, - }).Extract() - if err != nil { - // Unknown error, retry later - return nil, fmt.Errorf("Error creating LB listener: %v", err) - } - waitLoadbalancerActiveProvisioningStatus(lbaas.network, loadbalancer.ID) - } - - glog.V(4).Infof("Listener for %s port %d: %s", string(port.Protocol), int(port.Port), listener.ID) - - // After all ports have been processed, remaining listeners are removed as obsolete. - // Pop valid listeners. - oldListeners = popListener(oldListeners, listener.ID) - pool, err := getPoolByListenerID(lbaas.network, loadbalancer.ID, listener.ID) - if err != nil && err != ErrNotFound { - // Unknown error, retry later - return nil, fmt.Errorf("Error getting pool for listener %s: %v", listener.ID, err) - } - if pool == nil { - glog.V(4).Infof("Creating pool for listener %s", listener.ID) - pool, err = v2pools.Create(lbaas.network, v2pools.CreateOpts{ - Name: fmt.Sprintf("pool_%s_%d", name, portIndex), - Protocol: v2pools.Protocol(port.Protocol), - LBMethod: lbmethod, - ListenerID: listener.ID, - Persistence: persistence, - }).Extract() - if err != nil { - // Unknown error, retry later - return nil, fmt.Errorf("Error creating pool for listener %s: %v", listener.ID, err) - } - waitLoadbalancerActiveProvisioningStatus(lbaas.network, loadbalancer.ID) - } - - glog.V(4).Infof("Pool for listener %s: %s", listener.ID, pool.ID) - members, err := getMembersByPoolID(lbaas.network, pool.ID) - if err != nil && !isNotFound(err) { - return nil, fmt.Errorf("Error getting pool members %s: %v", pool.ID, err) - } - for _, node := range nodes { - addr, err := nodeAddressForLB(node) - if err != nil { - if err == ErrNotFound { - // Node failure, do not create member - glog.Warningf("Failed to create LB pool member for node %s: %v", node.Name, err) - continue - } else { - return nil, fmt.Errorf("Error getting address for node %s: %v", node.Name, err) - } - } - - if !memberExists(members, addr, int(port.NodePort)) { - glog.V(4).Infof("Creating member for pool %s", pool.ID) - _, err := v2pools.CreateMember(lbaas.network, pool.ID, v2pools.CreateMemberOpts{ - ProtocolPort: int(port.NodePort), - Address: addr, - SubnetID: lbaas.opts.SubnetId, - }).Extract() - if err != nil { - return nil, fmt.Errorf("Error creating LB pool member for node: %s, %v", node.Name, err) - } - - waitLoadbalancerActiveProvisioningStatus(lbaas.network, loadbalancer.ID) - } else { - // After all members have been processed, remaining members are deleted as obsolete. - members = popMember(members, addr, int(port.NodePort)) - } - - glog.V(4).Infof("Ensured pool %s has member for %s at %s", pool.ID, node.Name, addr) - } - - // Delete obsolete members for this pool - for _, member := range members { - glog.V(4).Infof("Deleting obsolete member %s for pool %s address %s", member.ID, pool.ID, member.Address) - err := v2pools.DeleteMember(lbaas.network, pool.ID, member.ID).ExtractErr() - if err != nil && !isNotFound(err) { - return nil, fmt.Errorf("Error deleting obsolete member %s for pool %s address %s: %v", member.ID, pool.ID, member.Address, err) - } - waitLoadbalancerActiveProvisioningStatus(lbaas.network, loadbalancer.ID) - } - - monitorID := pool.MonitorID - if monitorID == "" && lbaas.opts.CreateMonitor { - glog.V(4).Infof("Creating monitor for pool %s", pool.ID) - monitor, err := v2monitors.Create(lbaas.network, v2monitors.CreateOpts{ - PoolID: pool.ID, - Type: string(port.Protocol), - Delay: int(lbaas.opts.MonitorDelay.Duration.Seconds()), - Timeout: int(lbaas.opts.MonitorTimeout.Duration.Seconds()), - MaxRetries: int(lbaas.opts.MonitorMaxRetries), - }).Extract() - if err != nil { - return nil, fmt.Errorf("Error creating LB pool healthmonitor: %v", err) - } - waitLoadbalancerActiveProvisioningStatus(lbaas.network, loadbalancer.ID) - monitorID = monitor.ID - } - - glog.V(4).Infof("Monitor for pool %s: %s", pool.ID, monitorID) - } - - // All remaining listeners are obsolete, delete - for _, listener := range oldListeners { - glog.V(4).Infof("Deleting obsolete listener %s:", listener.ID) - // get pool for listener - pool, err := getPoolByListenerID(lbaas.network, loadbalancer.ID, listener.ID) - if err != nil && err != ErrNotFound { - return nil, fmt.Errorf("Error getting pool for obsolete listener %s: %v", listener.ID, err) - } - if pool != nil { - // get and delete monitor - monitorID := pool.MonitorID - if monitorID != "" { - glog.V(4).Infof("Deleting obsolete monitor %s for pool %s", monitorID, pool.ID) - err = v2monitors.Delete(lbaas.network, monitorID).ExtractErr() - if err != nil && !isNotFound(err) { - return nil, fmt.Errorf("Error deleting obsolete monitor %s for pool %s: %v", monitorID, pool.ID, err) - } - waitLoadbalancerActiveProvisioningStatus(lbaas.network, loadbalancer.ID) - } - // get and delete pool members - members, err := getMembersByPoolID(lbaas.network, pool.ID) - if err != nil && !isNotFound(err) { - return nil, fmt.Errorf("Error getting members for pool %s: %v", pool.ID, err) - } - if members != nil { - for _, member := range members { - glog.V(4).Infof("Deleting obsolete member %s for pool %s address %s", member.ID, pool.ID, member.Address) - err := v2pools.DeleteMember(lbaas.network, pool.ID, member.ID).ExtractErr() - if err != nil && !isNotFound(err) { - return nil, fmt.Errorf("Error deleting obsolete member %s for pool %s address %s: %v", member.ID, pool.ID, member.Address, err) - } - waitLoadbalancerActiveProvisioningStatus(lbaas.network, loadbalancer.ID) - } - } - glog.V(4).Infof("Deleting obsolete pool %s for listener %s", pool.ID, listener.ID) - // delete pool - err = v2pools.Delete(lbaas.network, pool.ID).ExtractErr() - if err != nil && !isNotFound(err) { - return nil, fmt.Errorf("Error deleting obsolete pool %s for listener %s: %v", pool.ID, listener.ID, err) - } - waitLoadbalancerActiveProvisioningStatus(lbaas.network, loadbalancer.ID) - } - // delete listener - err = listeners.Delete(lbaas.network, listener.ID).ExtractErr() - if err != nil && !isNotFound(err) { - return nil, fmt.Errorf("Error deleteting obsolete listener: %v", err) - } - waitLoadbalancerActiveProvisioningStatus(lbaas.network, loadbalancer.ID) - glog.V(2).Infof("Deleted obsolete listener: %s", listener.ID) - } - - status := &v1.LoadBalancerStatus{} - - status.Ingress = []v1.LoadBalancerIngress{{IP: loadbalancer.VipAddress}} - - portID := loadbalancer.VipPortID - floatIP, err := getFloatingIPByPortID(lbaas.network, portID) - if err != nil && err != ErrNotFound { - return nil, fmt.Errorf("Error getting floating ip for port %s: %v", portID, err) - } - if floatIP == nil && lbaas.opts.FloatingNetworkId != "" { - glog.V(4).Infof("Creating floating ip for loadbalancer %s port %s", loadbalancer.ID, portID) - floatIPOpts := floatingips.CreateOpts{ - FloatingNetworkID: lbaas.opts.FloatingNetworkId, - PortID: portID, - } - floatIP, err = floatingips.Create(lbaas.network, floatIPOpts).Extract() - if err != nil { - return nil, fmt.Errorf("Error creating LB floatingip %+v: %v", floatIPOpts, err) - } - } - if floatIP != nil { - status.Ingress = append(status.Ingress, v1.LoadBalancerIngress{IP: floatIP.FloatingIP}) - } - - if lbaas.opts.ManageSecurityGroups { - lbSecGroupCreateOpts := groups.CreateOpts{ - Name: getSecurityGroupName(clusterName, apiService), - Description: fmt.Sprintf("Securty Group for %v Service LoadBalancer", apiService.Name), - } - - lbSecGroup, err := groups.Create(lbaas.network, lbSecGroupCreateOpts).Extract() - - if err != nil { - // cleanup what was created so far - _ = lbaas.EnsureLoadBalancerDeleted(clusterName, apiService) - return nil, err - } - - for _, port := range ports { - - for _, sourceRange := range sourceRanges.StringSlice() { - ethertype := rules.EtherType4 - network, _, err := net.ParseCIDR(sourceRange) - - if err != nil { - // cleanup what was created so far - glog.Errorf("Error parsing source range %s as a CIDR", sourceRange) - _ = lbaas.EnsureLoadBalancerDeleted(clusterName, apiService) - return nil, err - } - - if network.To4() == nil { - ethertype = rules.EtherType6 - } - - lbSecGroupRuleCreateOpts := rules.CreateOpts{ - Direction: rules.DirIngress, - PortRangeMax: int(port.Port), - PortRangeMin: int(port.Port), - Protocol: toRuleProtocol(port.Protocol), - RemoteIPPrefix: sourceRange, - SecGroupID: lbSecGroup.ID, - EtherType: ethertype, - } - - _, err = rules.Create(lbaas.network, lbSecGroupRuleCreateOpts).Extract() - - if err != nil { - // cleanup what was created so far - _ = lbaas.EnsureLoadBalancerDeleted(clusterName, apiService) - return nil, err - } - } - - err := createNodeSecurityGroup(lbaas.network, lbaas.opts.NodeSecurityGroupID, int(port.NodePort), port.Protocol, lbSecGroup.ID) - if err != nil { - glog.Errorf("Error occured creating security group for loadbalancer %s:", loadbalancer.ID) - _ = lbaas.EnsureLoadBalancerDeleted(clusterName, apiService) - return nil, err - } - } - - lbSecGroupRuleCreateOpts := rules.CreateOpts{ - Direction: rules.DirIngress, - PortRangeMax: 4, // ICMP: Code - Values for ICMP "Destination Unreachable: Fragmentation Needed and Don't Fragment was Set" - PortRangeMin: 3, // ICMP: Type - Protocol: rules.ProtocolICMP, - RemoteIPPrefix: "0.0.0.0/0", // The Fragmentation packet can come from anywhere along the path back to the sourceRange - we need to all this from all - SecGroupID: lbSecGroup.ID, - EtherType: rules.EtherType4, - } - - _, err = rules.Create(lbaas.network, lbSecGroupRuleCreateOpts).Extract() - - if err != nil { - // cleanup what was created so far - _ = lbaas.EnsureLoadBalancerDeleted(clusterName, apiService) - return nil, err - } - - lbSecGroupRuleCreateOpts = rules.CreateOpts{ - Direction: rules.DirIngress, - PortRangeMax: 0, // ICMP: Code - Values for ICMP "Packet Too Big" - PortRangeMin: 2, // ICMP: Type - Protocol: rules.ProtocolICMP, - RemoteIPPrefix: "::/0", // The Fragmentation packet can come from anywhere along the path back to the sourceRange - we need to all this from all - SecGroupID: lbSecGroup.ID, - EtherType: rules.EtherType6, - } - - _, err = rules.Create(lbaas.network, lbSecGroupRuleCreateOpts).Extract() - - if err != nil { - // cleanup what was created so far - _ = lbaas.EnsureLoadBalancerDeleted(clusterName, apiService) - return nil, err - } - - portID := loadbalancer.VipPortID - update_opts := neutronports.UpdateOpts{SecurityGroups: []string{lbSecGroup.ID}} - res := neutronports.Update(lbaas.network, portID, update_opts) - if res.Err != nil { - glog.Errorf("Error occured updating port: %s", portID) - // cleanup what was created so far - _ = lbaas.EnsureLoadBalancerDeleted(clusterName, apiService) - return nil, res.Err - } - } - - return status, nil -} - -func (lbaas *LbaasV2) UpdateLoadBalancer(clusterName string, service *v1.Service, nodes []*v1.Node) error { - loadBalancerName := cloudprovider.GetLoadBalancerName(service) - glog.V(4).Infof("UpdateLoadBalancer(%v, %v, %v)", clusterName, loadBalancerName, nodes) - - ports := service.Spec.Ports - if len(ports) == 0 { - return fmt.Errorf("no ports provided to openstack load balancer") - } - - loadbalancer, err := getLoadbalancerByName(lbaas.network, loadBalancerName) - if err != nil { - return err - } - if loadbalancer == nil { - return fmt.Errorf("Loadbalancer %s does not exist", loadBalancerName) - } - - // Get all listeners for this loadbalancer, by "port key". - type portKey struct { - Protocol listeners.Protocol - Port int - } - - lbListeners := make(map[portKey]listeners.Listener) - err = listeners.List(lbaas.network, listeners.ListOpts{LoadbalancerID: loadbalancer.ID}).EachPage(func(page pagination.Page) (bool, error) { - listenersList, err := listeners.ExtractListeners(page) - if err != nil { - return false, err - } - for _, l := range listenersList { - for _, lb := range l.Loadbalancers { - // Double check this Listener belongs to the LB we're updating. Neutron's API filtering - // can't be counted on in older releases (i.e Liberty). - if loadbalancer.ID == lb.ID { - key := portKey{Protocol: listeners.Protocol(l.Protocol), Port: l.ProtocolPort} - lbListeners[key] = l - break - } - } - } - return true, nil - }) - if err != nil { - return err - } - - // Get all pools for this loadbalancer, by listener ID. - lbPools := make(map[string]v2pools.Pool) - err = v2pools.List(lbaas.network, v2pools.ListOpts{LoadbalancerID: loadbalancer.ID}).EachPage(func(page pagination.Page) (bool, error) { - poolsList, err := v2pools.ExtractPools(page) - if err != nil { - return false, err - } - for _, p := range poolsList { - for _, l := range p.Listeners { - // Double check this Pool belongs to the LB we're deleting. Neutron's API filtering - // can't be counted on in older releases (i.e Liberty). - for _, val := range lbListeners { - if val.ID == l.ID { - lbPools[l.ID] = p - break - } - } - } - } - return true, nil - }) - if err != nil { - return err - } - - // Compose Set of member (addresses) that _should_ exist - addrs := map[string]empty{} - for _, node := range nodes { - addr, err := nodeAddressForLB(node) - if err != nil { - return err - } - addrs[addr] = empty{} - } - - // Check for adding/removing members associated with each port - for _, port := range ports { - // Get listener associated with this port - listener, ok := lbListeners[portKey{ - Protocol: toListenersProtocol(port.Protocol), - Port: int(port.Port), - }] - if !ok { - return fmt.Errorf("Loadbalancer %s does not contain required listener for port %d and protocol %s", loadBalancerName, port.Port, port.Protocol) - } - - // Get pool associated with this listener - pool, ok := lbPools[listener.ID] - if !ok { - return fmt.Errorf("Loadbalancer %s does not contain required pool for listener %s", loadBalancerName, listener.ID) - } - - // Find existing pool members (by address) for this port - members := make(map[string]v2pools.Member) - err := v2pools.ListMembers(lbaas.network, pool.ID, v2pools.ListMembersOpts{}).EachPage(func(page pagination.Page) (bool, error) { - membersList, err := v2pools.ExtractMembers(page) - if err != nil { - return false, err - } - for _, member := range membersList { - members[member.Address] = member - } - return true, nil - }) - if err != nil { - return err - } - - // Add any new members for this port - for addr := range addrs { - if _, ok := members[addr]; ok && members[addr].ProtocolPort == int(port.NodePort) { - // Already exists, do not create member - continue - } - _, err := v2pools.CreateMember(lbaas.network, pool.ID, v2pools.CreateMemberOpts{ - Address: addr, - ProtocolPort: int(port.NodePort), - SubnetID: lbaas.opts.SubnetId, - }).Extract() - if err != nil { - return err - } - waitLoadbalancerActiveProvisioningStatus(lbaas.network, loadbalancer.ID) - } - - // Remove any old members for this port - for _, member := range members { - if _, ok := addrs[member.Address]; ok && member.ProtocolPort == int(port.NodePort) { - // Still present, do not delete member - continue - } - err = v2pools.DeleteMember(lbaas.network, pool.ID, member.ID).ExtractErr() - if err != nil && !isNotFound(err) { - return err - } - waitLoadbalancerActiveProvisioningStatus(lbaas.network, loadbalancer.ID) - } - } - return nil -} - -func (lbaas *LbaasV2) EnsureLoadBalancerDeleted(clusterName string, service *v1.Service) error { - loadBalancerName := cloudprovider.GetLoadBalancerName(service) - glog.V(4).Infof("EnsureLoadBalancerDeleted(%v, %v)", clusterName, loadBalancerName) - - loadbalancer, err := getLoadbalancerByName(lbaas.network, loadBalancerName) - if err != nil && err != ErrNotFound { - return err - } - if loadbalancer == nil { - return nil - } - - if lbaas.opts.FloatingNetworkId != "" && loadbalancer != nil { - portID := loadbalancer.VipPortID - floatingIP, err := getFloatingIPByPortID(lbaas.network, portID) - if err != nil && err != ErrNotFound { - return err - } - if floatingIP != nil { - err = floatingips.Delete(lbaas.network, floatingIP.ID).ExtractErr() - if err != nil && !isNotFound(err) { - return err - } - } - } - - // get all listeners associated with this loadbalancer - var listenerIDs []string - err = listeners.List(lbaas.network, listeners.ListOpts{LoadbalancerID: loadbalancer.ID}).EachPage(func(page pagination.Page) (bool, error) { - listenerList, err := listeners.ExtractListeners(page) - if err != nil { - return false, err - } - - for _, listener := range listenerList { - listenerIDs = append(listenerIDs, listener.ID) - } - - return true, nil - }) - if err != nil { - return err - } - - // get all pools (and health monitors) associated with this loadbalancer - var poolIDs []string - var monitorIDs []string - err = v2pools.List(lbaas.network, v2pools.ListOpts{LoadbalancerID: loadbalancer.ID}).EachPage(func(page pagination.Page) (bool, error) { - poolsList, err := v2pools.ExtractPools(page) - if err != nil { - return false, err - } - - for _, pool := range poolsList { - poolIDs = append(poolIDs, pool.ID) - monitorIDs = append(monitorIDs, pool.MonitorID) - } - - return true, nil - }) - if err != nil { - return err - } - - // get all members associated with each poolIDs - var memberIDs []string - for _, poolID := range poolIDs { - err := v2pools.ListMembers(lbaas.network, poolID, v2pools.ListMembersOpts{}).EachPage(func(page pagination.Page) (bool, error) { - membersList, err := v2pools.ExtractMembers(page) - if err != nil { - return false, err - } - - for _, member := range membersList { - memberIDs = append(memberIDs, member.ID) - } - - return true, nil - }) - if err != nil { - return err - } - } - - // delete all monitors - for _, monitorID := range monitorIDs { - err := v2monitors.Delete(lbaas.network, monitorID).ExtractErr() - if err != nil && !isNotFound(err) { - return err - } - waitLoadbalancerActiveProvisioningStatus(lbaas.network, loadbalancer.ID) - } - - // delete all members and pools - for _, poolID := range poolIDs { - // delete all members for this pool - for _, memberID := range memberIDs { - err := v2pools.DeleteMember(lbaas.network, poolID, memberID).ExtractErr() - if err != nil && !isNotFound(err) { - return err - } - waitLoadbalancerActiveProvisioningStatus(lbaas.network, loadbalancer.ID) - } - - // delete pool - err := v2pools.Delete(lbaas.network, poolID).ExtractErr() - if err != nil && !isNotFound(err) { - return err - } - waitLoadbalancerActiveProvisioningStatus(lbaas.network, loadbalancer.ID) - } - - // delete all listeners - for _, listenerID := range listenerIDs { - err := listeners.Delete(lbaas.network, listenerID).ExtractErr() - if err != nil && !isNotFound(err) { - return err - } - waitLoadbalancerActiveProvisioningStatus(lbaas.network, loadbalancer.ID) - } - - // delete loadbalancer - err = loadbalancers.Delete(lbaas.network, loadbalancer.ID).ExtractErr() - if err != nil && !isNotFound(err) { - return err - } - waitLoadbalancerDeleted(lbaas.network, loadbalancer.ID) - - // Delete the Security Group - if lbaas.opts.ManageSecurityGroups { - // Generate Name - lbSecGroupName := getSecurityGroupName(clusterName, service) - lbSecGroupID, err := groups.IDFromName(lbaas.network, lbSecGroupName) - if err != nil { - glog.V(1).Infof("Error occurred finding security group: %s: %v", lbSecGroupName, err) - return nil - } - - lbSecGroup := groups.Delete(lbaas.network, lbSecGroupID) - if lbSecGroup.Err != nil && !isNotFound(lbSecGroup.Err) { - return lbSecGroup.Err - } - - // Delete the rules in the Node Security Group - opts := rules.ListOpts{ - SecGroupID: lbaas.opts.NodeSecurityGroupID, - RemoteGroupID: lbSecGroupID, - } - secGroupRules, err := getSecurityGroupRules(lbaas.network, opts) - - if err != nil && !isNotFound(err) { - glog.Errorf("Error finding rules for remote group id %s in security group id %s", lbSecGroupID, lbaas.opts.NodeSecurityGroupID) - return err - } - - for _, rule := range secGroupRules { - res := rules.Delete(lbaas.network, rule.ID) - if res.Err != nil && !isNotFound(res.Err) { - glog.V(1).Infof("Error occurred deleting security group rule: %s: %v", rule.ID, res.Err) - } - } - } - - return nil -} - -func (lb *LbaasV1) GetLoadBalancer(clusterName string, service *v1.Service) (*v1.LoadBalancerStatus, bool, error) { - loadBalancerName := cloudprovider.GetLoadBalancerName(service) - vip, err := getVipByName(lb.network, loadBalancerName) - if err == ErrNotFound { - return nil, false, nil - } - if vip == nil { - return nil, false, err - } - - status := &v1.LoadBalancerStatus{} - status.Ingress = []v1.LoadBalancerIngress{{IP: vip.Address}} - - return status, true, err -} - -// TODO: This code currently ignores 'region' and always creates a -// loadbalancer in only the current OpenStack region. We should take -// a list of regions (from config) and query/create loadbalancers in -// each region. - -func (lb *LbaasV1) EnsureLoadBalancer(clusterName string, apiService *v1.Service, nodes []*v1.Node) (*v1.LoadBalancerStatus, error) { - glog.V(4).Infof("EnsureLoadBalancer(%v, %v, %v, %v, %v, %v, %v)", clusterName, apiService.Namespace, apiService.Name, apiService.Spec.LoadBalancerIP, apiService.Spec.Ports, nodes, apiService.Annotations) - - ports := apiService.Spec.Ports - if len(ports) > 1 { - return nil, fmt.Errorf("multiple ports are not supported in openstack v1 load balancers") - } else if len(ports) == 0 { - return nil, fmt.Errorf("no ports provided to openstack load balancer") - } - - // The service controller verified all the protocols match on the ports, just check and use the first one - // TODO: Convert all error messages to use an event recorder - if ports[0].Protocol != v1.ProtocolTCP { - return nil, fmt.Errorf("Only TCP LoadBalancer is supported for openstack load balancers") - } - - affinity := apiService.Spec.SessionAffinity - var persistence *vips.SessionPersistence - switch affinity { - case v1.ServiceAffinityNone: - persistence = nil - case v1.ServiceAffinityClientIP: - persistence = &vips.SessionPersistence{Type: "SOURCE_IP"} - default: - return nil, fmt.Errorf("unsupported load balancer affinity: %v", affinity) - } - - sourceRanges, err := service.GetLoadBalancerSourceRanges(apiService) - if err != nil { - return nil, err - } - - if !service.IsAllowAll(sourceRanges) { - return nil, fmt.Errorf("Source range restrictions are not supported for openstack load balancers") - } - - glog.V(2).Infof("Checking if openstack load balancer already exists: %s", cloudprovider.GetLoadBalancerName(apiService)) - _, exists, err := lb.GetLoadBalancer(clusterName, apiService) - if err != nil { - return nil, fmt.Errorf("error checking if openstack load balancer already exists: %v", err) - } - - // TODO: Implement a more efficient update strategy for common changes than delete & create - // In particular, if we implement hosts update, we can get rid of UpdateHosts - if exists { - err := lb.EnsureLoadBalancerDeleted(clusterName, apiService) - if err != nil { - return nil, fmt.Errorf("error deleting existing openstack load balancer: %v", err) - } - } - - lbmethod := pools.LBMethod(lb.opts.LBMethod) - if lbmethod == "" { - lbmethod = pools.LBMethodRoundRobin - } - name := cloudprovider.GetLoadBalancerName(apiService) - pool, err := pools.Create(lb.network, pools.CreateOpts{ - Name: name, - Protocol: pools.ProtocolTCP, - SubnetID: lb.opts.SubnetId, - LBMethod: lbmethod, - }).Extract() - if err != nil { - return nil, err - } - - for _, node := range nodes { - addr, err := nodeAddressForLB(node) - if err != nil { - return nil, err - } - - _, err = members.Create(lb.network, members.CreateOpts{ - PoolID: pool.ID, - ProtocolPort: int(ports[0].NodePort), //Note: only handles single port - Address: addr, - }).Extract() - if err != nil { - pools.Delete(lb.network, pool.ID) - return nil, err - } - } - - var mon *monitors.Monitor - if lb.opts.CreateMonitor { - mon, err = monitors.Create(lb.network, monitors.CreateOpts{ - Type: monitors.TypeTCP, - Delay: int(lb.opts.MonitorDelay.Duration.Seconds()), - Timeout: int(lb.opts.MonitorTimeout.Duration.Seconds()), - MaxRetries: int(lb.opts.MonitorMaxRetries), - }).Extract() - if err != nil { - pools.Delete(lb.network, pool.ID) - return nil, err - } - - _, err = pools.AssociateMonitor(lb.network, pool.ID, mon.ID).Extract() - if err != nil { - monitors.Delete(lb.network, mon.ID) - pools.Delete(lb.network, pool.ID) - return nil, err - } - } - - createOpts := vips.CreateOpts{ - Name: name, - Description: fmt.Sprintf("Kubernetes external service %s", name), - Protocol: "TCP", - ProtocolPort: int(ports[0].Port), //TODO: need to handle multi-port - PoolID: pool.ID, - SubnetID: lb.opts.SubnetId, - Persistence: persistence, - } - - loadBalancerIP := apiService.Spec.LoadBalancerIP - if loadBalancerIP != "" { - createOpts.Address = loadBalancerIP - } - - vip, err := vips.Create(lb.network, createOpts).Extract() - if err != nil { - if mon != nil { - monitors.Delete(lb.network, mon.ID) - } - pools.Delete(lb.network, pool.ID) - return nil, err - } - - status := &v1.LoadBalancerStatus{} - - status.Ingress = []v1.LoadBalancerIngress{{IP: vip.Address}} - - if lb.opts.FloatingNetworkId != "" { - floatIPOpts := floatingips.CreateOpts{ - FloatingNetworkID: lb.opts.FloatingNetworkId, - PortID: vip.PortID, - } - floatIP, err := floatingips.Create(lb.network, floatIPOpts).Extract() - if err != nil { - return nil, err - } - - status.Ingress = append(status.Ingress, v1.LoadBalancerIngress{IP: floatIP.FloatingIP}) - } - - return status, nil - -} - -func (lb *LbaasV1) UpdateLoadBalancer(clusterName string, service *v1.Service, nodes []*v1.Node) error { - loadBalancerName := cloudprovider.GetLoadBalancerName(service) - glog.V(4).Infof("UpdateLoadBalancer(%v, %v, %v)", clusterName, loadBalancerName, nodes) - - vip, err := getVipByName(lb.network, loadBalancerName) - if err != nil { - return err - } - - // Set of member (addresses) that _should_ exist - addrs := map[string]bool{} - for _, node := range nodes { - addr, err := nodeAddressForLB(node) - if err != nil { - return err - } - - addrs[addr] = true - } - - // Iterate over members that _do_ exist - pager := members.List(lb.network, members.ListOpts{PoolID: vip.PoolID}) - err = pager.EachPage(func(page pagination.Page) (bool, error) { - memList, err := members.ExtractMembers(page) - if err != nil { - return false, err - } - - for _, member := range memList { - if _, found := addrs[member.Address]; found { - // Member already exists - delete(addrs, member.Address) - } else { - // Member needs to be deleted - err = members.Delete(lb.network, member.ID).ExtractErr() - if err != nil { - return false, err - } - } - } - - return true, nil - }) - if err != nil { - return err - } - - // Anything left in addrs is a new member that needs to be added - for addr := range addrs { - _, err := members.Create(lb.network, members.CreateOpts{ - PoolID: vip.PoolID, - Address: addr, - ProtocolPort: vip.ProtocolPort, - }).Extract() - if err != nil { - return err - } - } - - return nil -} - -func (lb *LbaasV1) EnsureLoadBalancerDeleted(clusterName string, service *v1.Service) error { - loadBalancerName := cloudprovider.GetLoadBalancerName(service) - glog.V(4).Infof("EnsureLoadBalancerDeleted(%v, %v)", clusterName, loadBalancerName) - - vip, err := getVipByName(lb.network, loadBalancerName) - if err != nil && err != ErrNotFound { - return err - } - - if lb.opts.FloatingNetworkId != "" && vip != nil { - floatingIP, err := getFloatingIPByPortID(lb.network, vip.PortID) - if err != nil && !isNotFound(err) { - return err - } - if floatingIP != nil { - err = floatingips.Delete(lb.network, floatingIP.ID).ExtractErr() - if err != nil && !isNotFound(err) { - return err - } - } - } - - // We have to delete the VIP before the pool can be deleted, - // so no point continuing if this fails. - if vip != nil { - err := vips.Delete(lb.network, vip.ID).ExtractErr() - if err != nil && !isNotFound(err) { - return err - } - } - - var pool *pools.Pool - if vip != nil { - pool, err = pools.Get(lb.network, vip.PoolID).Extract() - if err != nil && !isNotFound(err) { - return err - } - } else { - // The VIP is gone, but it is conceivable that a Pool - // still exists that we failed to delete on some - // previous occasion. Make a best effort attempt to - // cleanup any pools with the same name as the VIP. - pool, err = getPoolByName(lb.network, service.Name) - if err != nil && err != ErrNotFound { - return err - } - } - - if pool != nil { - for _, monId := range pool.MonitorIDs { - _, err = pools.DisassociateMonitor(lb.network, pool.ID, monId).Extract() - if err != nil { - return err - } - - err = monitors.Delete(lb.network, monId).ExtractErr() - if err != nil && !isNotFound(err) { - return err - } - } - for _, memberId := range pool.MemberIDs { - err = members.Delete(lb.network, memberId).ExtractErr() - if err != nil && !isNotFound(err) { - return err - } - } - err = pools.Delete(lb.network, pool.ID).ExtractErr() - if err != nil && !isNotFound(err) { - return err - } - } - - return nil -} diff --git a/openstack/openstack_routes.go b/openstack/openstack_routes.go deleted file mode 100644 index 28e5160..0000000 --- a/openstack/openstack_routes.go +++ /dev/null @@ -1,278 +0,0 @@ -/* -Copyright 2016 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package openstack - -import ( - "errors" - - "github.com/gophercloud/gophercloud" - "github.com/gophercloud/gophercloud/openstack/compute/v2/servers" - "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/routers" - neutronports "github.com/gophercloud/gophercloud/openstack/networking/v2/ports" - - "github.com/golang/glog" - "k8s.io/apimachinery/pkg/types" - "k8s.io/kubernetes/pkg/cloudprovider" -) - -var ErrNoRouterId = errors.New("router-id not set in cloud provider config") - -type Routes struct { - compute *gophercloud.ServiceClient - network *gophercloud.ServiceClient - opts RouterOpts -} - -func NewRoutes(compute *gophercloud.ServiceClient, network *gophercloud.ServiceClient, opts RouterOpts) (cloudprovider.Routes, error) { - if opts.RouterId == "" { - return nil, ErrNoRouterId - } - - return &Routes{ - compute: compute, - network: network, - opts: opts, - }, nil -} - -func (r *Routes) ListRoutes(clusterName string) ([]*cloudprovider.Route, error) { - glog.V(4).Infof("ListRoutes(%v)", clusterName) - - nodeNamesByAddr := make(map[string]types.NodeName) - err := foreachServer(r.compute, servers.ListOpts{Status: "ACTIVE"}, func(srv *servers.Server) (bool, error) { - addrs, err := nodeAddresses(srv) - if err != nil { - return false, err - } - - name := mapServerToNodeName(srv) - for _, addr := range addrs { - nodeNamesByAddr[addr.Address] = name - } - - return true, nil - }) - if err != nil { - return nil, err - } - - router, err := routers.Get(r.network, r.opts.RouterId).Extract() - if err != nil { - return nil, err - } - - var routes []*cloudprovider.Route - for _, item := range router.Routes { - nodeName, ok := nodeNamesByAddr[item.NextHop] - if !ok { - // Not one of our routes? - glog.V(4).Infof("Skipping route with unknown nexthop %v", item.NextHop) - continue - } - route := cloudprovider.Route{ - Name: item.DestinationCIDR, - TargetNode: nodeName, - DestinationCIDR: item.DestinationCIDR, - } - routes = append(routes, &route) - } - - return routes, nil -} - -func updateRoutes(network *gophercloud.ServiceClient, router *routers.Router, newRoutes []routers.Route) (func(), error) { - origRoutes := router.Routes // shallow copy - - _, err := routers.Update(network, router.ID, routers.UpdateOpts{ - Routes: newRoutes, - }).Extract() - if err != nil { - return nil, err - } - - unwinder := func() { - glog.V(4).Info("Reverting routes change to router ", router.ID) - _, err := routers.Update(network, router.ID, routers.UpdateOpts{ - Routes: origRoutes, - }).Extract() - if err != nil { - glog.Warning("Unable to reset routes during error unwind: ", err) - } - } - - return unwinder, nil -} - -func updateAllowedAddressPairs(network *gophercloud.ServiceClient, port *neutronports.Port, newPairs []neutronports.AddressPair) (func(), error) { - origPairs := port.AllowedAddressPairs // shallow copy - - _, err := neutronports.Update(network, port.ID, neutronports.UpdateOpts{ - AllowedAddressPairs: newPairs, - }).Extract() - if err != nil { - return nil, err - } - - unwinder := func() { - glog.V(4).Info("Reverting allowed-address-pairs change to port ", port.ID) - _, err := neutronports.Update(network, port.ID, neutronports.UpdateOpts{ - AllowedAddressPairs: origPairs, - }).Extract() - if err != nil { - glog.Warning("Unable to reset allowed-address-pairs during error unwind: ", err) - } - } - - return unwinder, nil -} - -func (r *Routes) CreateRoute(clusterName string, nameHint string, route *cloudprovider.Route) error { - glog.V(4).Infof("CreateRoute(%v, %v, %v)", clusterName, nameHint, route) - - onFailure := NewCaller() - - addr, err := getAddressByName(r.compute, route.TargetNode) - if err != nil { - return err - } - - glog.V(4).Infof("Using nexthop %v for node %v", addr, route.TargetNode) - - router, err := routers.Get(r.network, r.opts.RouterId).Extract() - if err != nil { - return err - } - - routes := router.Routes - - for _, item := range routes { - if item.DestinationCIDR == route.DestinationCIDR && item.NextHop == addr { - glog.V(4).Infof("Skipping existing route: %v", route) - return nil - } - } - - routes = append(routes, routers.Route{ - DestinationCIDR: route.DestinationCIDR, - NextHop: addr, - }) - - unwind, err := updateRoutes(r.network, router, routes) - if err != nil { - return err - } - defer onFailure.Call(unwind) - - port, err := getPortByIP(r.network, addr) - if err != nil { - return err - } - - found := false - for _, item := range port.AllowedAddressPairs { - if item.IPAddress == route.DestinationCIDR { - glog.V(4).Info("Found existing allowed-address-pair: ", item) - found = true - break - } - } - - if !found { - newPairs := append(port.AllowedAddressPairs, neutronports.AddressPair{ - IPAddress: route.DestinationCIDR, - }) - unwind, err := updateAllowedAddressPairs(r.network, &port, newPairs) - if err != nil { - return err - } - defer onFailure.Call(unwind) - } - - glog.V(4).Infof("Route created: %v", route) - onFailure.Disarm() - return nil -} - -func (r *Routes) DeleteRoute(clusterName string, route *cloudprovider.Route) error { - glog.V(4).Infof("DeleteRoute(%v, %v)", clusterName, route) - - onFailure := NewCaller() - - addr, err := getAddressByName(r.compute, route.TargetNode) - if err != nil { - return err - } - - router, err := routers.Get(r.network, r.opts.RouterId).Extract() - if err != nil { - return err - } - - routes := router.Routes - index := -1 - for i, item := range routes { - if item.DestinationCIDR == route.DestinationCIDR && item.NextHop == addr { - index = i - break - } - } - - if index == -1 { - glog.V(4).Infof("Skipping non-existent route: %v", route) - return nil - } - - // Delete element `index` - routes[index] = routes[len(routes)-1] - routes = routes[:len(routes)-1] - - unwind, err := updateRoutes(r.network, router, routes) - if err != nil { - return err - } - defer onFailure.Call(unwind) - - port, err := getPortByIP(r.network, addr) - if err != nil { - return err - } - - addr_pairs := port.AllowedAddressPairs - index = -1 - for i, item := range addr_pairs { - if item.IPAddress == route.DestinationCIDR { - index = i - break - } - } - - if index != -1 { - // Delete element `index` - addr_pairs[index] = addr_pairs[len(routes)-1] - addr_pairs = addr_pairs[:len(routes)-1] - - unwind, err := updateAllowedAddressPairs(r.network, &port, addr_pairs) - if err != nil { - return err - } - defer onFailure.Call(unwind) - } - - glog.V(4).Infof("Route deleted: %v", route) - onFailure.Disarm() - return nil -} diff --git a/openstack/openstack_routes_test.go b/openstack/openstack_routes_test.go deleted file mode 100644 index 2cfdc7d..0000000 --- a/openstack/openstack_routes_test.go +++ /dev/null @@ -1,71 +0,0 @@ -/* -Copyright 2016 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package openstack - -import ( - "net" - "testing" - - "k8s.io/apimachinery/pkg/types" - "k8s.io/kubernetes/pkg/cloudprovider" -) - -func TestRoutes(t *testing.T) { - const clusterName = "ignored" - - cfg, ok := configFromEnv() - if !ok { - t.Skipf("No config found in environment") - } - - os, err := newOpenStack(cfg) - if err != nil { - t.Fatalf("Failed to construct/authenticate OpenStack: %s", err) - } - - r, ok := os.Routes() - if !ok { - t.Fatalf("Routes() returned false - perhaps your stack doens't support Neutron?") - } - - newroute := cloudprovider.Route{ - DestinationCIDR: "10.164.2.0/24", - TargetNode: types.NodeName("testinstance"), - } - err = r.CreateRoute(clusterName, "myhint", &newroute) - if err != nil { - t.Fatalf("CreateRoute error: %v", err) - } - - routelist, err := r.ListRoutes(clusterName) - if err != nil { - t.Fatalf("ListRoutes() error: %v", err) - } - for _, route := range routelist { - _, cidr, err := net.ParseCIDR(route.DestinationCIDR) - if err != nil { - t.Logf("Ignoring route %s, unparsable CIDR: %v", route.Name, err) - continue - } - t.Logf("%s via %s", cidr, route.TargetNode) - } - - err = r.DeleteRoute(clusterName, &newroute) - if err != nil { - t.Fatalf("DeleteRoute error: %v", err) - } -} diff --git a/openstack/openstack_test.go b/openstack/openstack_test.go deleted file mode 100644 index 2f91722..0000000 --- a/openstack/openstack_test.go +++ /dev/null @@ -1,435 +0,0 @@ -/* -Copyright 2014 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package openstack - -import ( - "fmt" - "github.com/gophercloud/gophercloud" - "github.com/gophercloud/gophercloud/openstack/blockstorage/v1/apiversions" - "github.com/gophercloud/gophercloud/openstack/compute/v2/servers" - "os" - "reflect" - "sort" - "strings" - "testing" - "time" - - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/util/rand" - "k8s.io/kubernetes/pkg/api/v1" -) - -const volumeAvailableStatus = "available" -const volumeInUseStatus = "in-use" -const volumeCreateTimeoutSeconds = 30 -const testClusterName = "testCluster" - -func WaitForVolumeStatus(t *testing.T, os *OpenStack, volumeName string, status string, timeoutSeconds int) { - timeout := timeoutSeconds - start := time.Now().Second() - for { - time.Sleep(1 * time.Second) - - if timeout >= 0 && time.Now().Second()-start >= timeout { - t.Logf("Volume (%s) status did not change to %s after %v seconds\n", - volumeName, - status, - timeout) - return - } - - getVol, err := os.getVolume(volumeName) - if err != nil { - t.Fatalf("Cannot get existing Cinder volume (%s): %v", volumeName, err) - } - if getVol.Status == status { - t.Logf("Volume (%s) status changed to %s after %v seconds\n", - volumeName, - status, - timeout) - return - } - } -} - -func TestReadConfig(t *testing.T) { - _, err := readConfig(nil) - if err == nil { - t.Errorf("Should fail when no config is provided: %s", err) - } - - cfg, err := readConfig(strings.NewReader(` - [Global] - auth-url = http://auth.url - username = user - [LoadBalancer] - create-monitor = yes - monitor-delay = 1m - monitor-timeout = 30s - monitor-max-retries = 3 - [BlockStorage] - bs-version = auto - trust-device-path = yes - - `)) - if err != nil { - t.Fatalf("Should succeed when a valid config is provided: %s", err) - } - if cfg.Global.AuthUrl != "http://auth.url" { - t.Errorf("incorrect authurl: %s", cfg.Global.AuthUrl) - } - - if !cfg.LoadBalancer.CreateMonitor { - t.Errorf("incorrect lb.createmonitor: %t", cfg.LoadBalancer.CreateMonitor) - } - if cfg.LoadBalancer.MonitorDelay.Duration != 1*time.Minute { - t.Errorf("incorrect lb.monitordelay: %s", cfg.LoadBalancer.MonitorDelay) - } - if cfg.LoadBalancer.MonitorTimeout.Duration != 30*time.Second { - t.Errorf("incorrect lb.monitortimeout: %s", cfg.LoadBalancer.MonitorTimeout) - } - if cfg.LoadBalancer.MonitorMaxRetries != 3 { - t.Errorf("incorrect lb.monitormaxretries: %d", cfg.LoadBalancer.MonitorMaxRetries) - } - if cfg.BlockStorage.TrustDevicePath != true { - t.Errorf("incorrect bs.trustdevicepath: %v", cfg.BlockStorage.TrustDevicePath) - } - if cfg.BlockStorage.BSVersion != "auto" { - t.Errorf("incorrect bs.bs-version: %v", cfg.BlockStorage.BSVersion) - } -} - -func TestToAuthOptions(t *testing.T) { - cfg := Config{} - cfg.Global.Username = "user" - // etc. - - ao := cfg.toAuthOptions() - - if !ao.AllowReauth { - t.Errorf("Will need to be able to reauthenticate") - } - if ao.Username != cfg.Global.Username { - t.Errorf("Username %s != %s", ao.Username, cfg.Global.Username) - } -} - -func TestCaller(t *testing.T) { - called := false - myFunc := func() { called = true } - - c := NewCaller() - c.Call(myFunc) - - if !called { - t.Errorf("Caller failed to call function in default case") - } - - c.Disarm() - called = false - c.Call(myFunc) - - if called { - t.Error("Caller still called function when disarmed") - } - - // Confirm the "usual" deferred Caller pattern works as expected - - called = false - success_case := func() { - c := NewCaller() - defer c.Call(func() { called = true }) - c.Disarm() - } - if success_case(); called { - t.Error("Deferred success case still invoked unwind") - } - - called = false - failure_case := func() { - c := NewCaller() - defer c.Call(func() { called = true }) - } - if failure_case(); !called { - t.Error("Deferred failure case failed to invoke unwind") - } -} - -// An arbitrary sort.Interface, just for easier comparison -type AddressSlice []v1.NodeAddress - -func (a AddressSlice) Len() int { return len(a) } -func (a AddressSlice) Less(i, j int) bool { return a[i].Address < a[j].Address } -func (a AddressSlice) Swap(i, j int) { a[i], a[j] = a[j], a[i] } - -func TestNodeAddresses(t *testing.T) { - srv := servers.Server{ - Status: "ACTIVE", - HostID: "29d3c8c896a45aa4c34e52247875d7fefc3d94bbcc9f622b5d204362", - AccessIPv4: "50.56.176.99", - AccessIPv6: "2001:4800:790e:510:be76:4eff:fe04:82a8", - Addresses: map[string]interface{}{ - "private": []interface{}{ - map[string]interface{}{ - "OS-EXT-IPS-MAC:mac_addr": "fa:16:3e:7c:1b:2b", - "version": float64(4), - "addr": "10.0.0.32", - "OS-EXT-IPS:type": "fixed", - }, - map[string]interface{}{ - "version": float64(4), - "addr": "50.56.176.36", - "OS-EXT-IPS:type": "floating", - }, - map[string]interface{}{ - "version": float64(4), - "addr": "10.0.0.31", - // No OS-EXT-IPS:type - }, - }, - "public": []interface{}{ - map[string]interface{}{ - "version": float64(4), - "addr": "50.56.176.35", - }, - map[string]interface{}{ - "version": float64(6), - "addr": "2001:4800:780e:510:be76:4eff:fe04:84a8", - }, - }, - }, - } - - addrs, err := nodeAddresses(&srv) - if err != nil { - t.Fatalf("nodeAddresses returned error: %v", err) - } - - sort.Sort(AddressSlice(addrs)) - t.Logf("addresses is %v", addrs) - - want := []v1.NodeAddress{ - {Type: v1.NodeInternalIP, Address: "10.0.0.31"}, - {Type: v1.NodeInternalIP, Address: "10.0.0.32"}, - {Type: v1.NodeExternalIP, Address: "2001:4800:780e:510:be76:4eff:fe04:84a8"}, - {Type: v1.NodeExternalIP, Address: "2001:4800:790e:510:be76:4eff:fe04:82a8"}, - {Type: v1.NodeExternalIP, Address: "50.56.176.35"}, - {Type: v1.NodeExternalIP, Address: "50.56.176.36"}, - {Type: v1.NodeExternalIP, Address: "50.56.176.99"}, - } - - if !reflect.DeepEqual(want, addrs) { - t.Errorf("nodeAddresses returned incorrect value %v", addrs) - } -} - -// This allows acceptance testing against an existing OpenStack -// install, using the standard OS_* OpenStack client environment -// variables. -// FIXME: it would be better to hermetically test against canned JSON -// requests/responses. -func configFromEnv() (cfg Config, ok bool) { - cfg.Global.AuthUrl = os.Getenv("OS_AUTH_URL") - - cfg.Global.TenantId = os.Getenv("OS_TENANT_ID") - // Rax/nova _insists_ that we don't specify both tenant ID and name - if cfg.Global.TenantId == "" { - cfg.Global.TenantName = os.Getenv("OS_TENANT_NAME") - } - - cfg.Global.Username = os.Getenv("OS_USERNAME") - cfg.Global.Password = os.Getenv("OS_PASSWORD") - cfg.Global.Region = os.Getenv("OS_REGION_NAME") - cfg.Global.DomainId = os.Getenv("OS_DOMAIN_ID") - cfg.Global.DomainName = os.Getenv("OS_DOMAIN_NAME") - - ok = (cfg.Global.AuthUrl != "" && - cfg.Global.Username != "" && - cfg.Global.Password != "" && - (cfg.Global.TenantId != "" || cfg.Global.TenantName != "" || - cfg.Global.DomainId != "" || cfg.Global.DomainName != "")) - - return -} - -func TestNewOpenStack(t *testing.T) { - cfg, ok := configFromEnv() - if !ok { - t.Skipf("No config found in environment") - } - - _, err := newOpenStack(cfg) - if err != nil { - t.Fatalf("Failed to construct/authenticate OpenStack: %s", err) - } -} - -func TestLoadBalancer(t *testing.T) { - cfg, ok := configFromEnv() - if !ok { - t.Skipf("No config found in environment") - } - - versions := []string{"v1", "v2", ""} - - for _, v := range versions { - t.Logf("Trying LBVersion = '%s'\n", v) - cfg.LoadBalancer.LBVersion = v - - os, err := newOpenStack(cfg) - if err != nil { - t.Fatalf("Failed to construct/authenticate OpenStack: %s", err) - } - - lb, ok := os.LoadBalancer() - if !ok { - t.Fatalf("LoadBalancer() returned false - perhaps your stack doesn't support Neutron?") - } - - _, exists, err := lb.GetLoadBalancer(testClusterName, &v1.Service{ObjectMeta: metav1.ObjectMeta{Name: "noexist"}}) - if err != nil { - t.Fatalf("GetLoadBalancer(\"noexist\") returned error: %s", err) - } - if exists { - t.Fatalf("GetLoadBalancer(\"noexist\") returned exists") - } - } -} - -func TestZones(t *testing.T) { - SetMetadataFixture(&FakeMetadata) - defer ClearMetadata() - - os := OpenStack{ - provider: &gophercloud.ProviderClient{ - IdentityBase: "http://auth.url/", - }, - region: "myRegion", - } - - z, ok := os.Zones() - if !ok { - t.Fatalf("Zones() returned false") - } - - zone, err := z.GetZone() - if err != nil { - t.Fatalf("GetZone() returned error: %s", err) - } - - if zone.Region != "myRegion" { - t.Fatalf("GetZone() returned wrong region (%s)", zone.Region) - } - - if zone.FailureDomain != "nova" { - t.Fatalf("GetZone() returned wrong failure domain (%s)", zone.FailureDomain) - } -} - -func TestVolumes(t *testing.T) { - cfg, ok := configFromEnv() - if !ok { - t.Skipf("No config found in environment") - } - - os, err := newOpenStack(cfg) - if err != nil { - t.Fatalf("Failed to construct/authenticate OpenStack: %s", err) - } - - tags := map[string]string{ - "test": "value", - } - vol, err := os.CreateVolume("kubernetes-test-volume-"+rand.String(10), 1, "", "", &tags) - if err != nil { - t.Fatalf("Cannot create a new Cinder volume: %v", err) - } - t.Logf("Volume (%s) created\n", vol) - - WaitForVolumeStatus(t, os, vol, volumeAvailableStatus, volumeCreateTimeoutSeconds) - - diskId, err := os.AttachDisk(os.localInstanceID, vol) - if err != nil { - t.Fatalf("Cannot AttachDisk Cinder volume %s: %v", vol, err) - } - t.Logf("Volume (%s) attached, disk ID: %s\n", vol, diskId) - - WaitForVolumeStatus(t, os, vol, volumeInUseStatus, volumeCreateTimeoutSeconds) - - devicePath := os.GetDevicePath(diskId) - if !strings.HasPrefix(devicePath, "/dev/disk/by-id/") { - t.Fatalf("GetDevicePath returned and unexpected path for Cinder volume %s, returned %s", vol, devicePath) - } - t.Logf("Volume (%s) found at path: %s\n", vol, devicePath) - - err = os.DetachDisk(os.localInstanceID, vol) - if err != nil { - t.Fatalf("Cannot DetachDisk Cinder volume %s: %v", vol, err) - } - t.Logf("Volume (%s) detached\n", vol) - - WaitForVolumeStatus(t, os, vol, volumeAvailableStatus, volumeCreateTimeoutSeconds) - - err = os.DeleteVolume(vol) - if err != nil { - t.Fatalf("Cannot delete Cinder volume %s: %v", vol, err) - } - t.Logf("Volume (%s) deleted\n", vol) - -} - -func TestCinderAutoDetectApiVersion(t *testing.T) { - updated := "" // not relevant to this test, can be set to any value - status_current := "CURRENT" - status_supported := "SUPpORTED" // lowercase to test regression resitance if api returns different case - status_deprecated := "DEPRECATED" - - var result_version, api_version [4]string - - for ver := 0; ver <= 3; ver++ { - api_version[ver] = fmt.Sprintf("v%d.0", ver) - result_version[ver] = fmt.Sprintf("v%d", ver) - } - result_version[0] = "" - api_current_v1 := apiversions.APIVersion{ID: api_version[1], Status: status_current, Updated: updated} - api_current_v2 := apiversions.APIVersion{ID: api_version[2], Status: status_current, Updated: updated} - api_current_v3 := apiversions.APIVersion{ID: api_version[3], Status: status_current, Updated: updated} - - api_supported_v1 := apiversions.APIVersion{ID: api_version[1], Status: status_supported, Updated: updated} - api_supported_v2 := apiversions.APIVersion{ID: api_version[2], Status: status_supported, Updated: updated} - - api_deprecated_v1 := apiversions.APIVersion{ID: api_version[1], Status: status_deprecated, Updated: updated} - api_deprecated_v2 := apiversions.APIVersion{ID: api_version[2], Status: status_deprecated, Updated: updated} - - var testCases = []struct { - test_case []apiversions.APIVersion - wanted_result string - }{ - {[]apiversions.APIVersion{api_current_v1}, result_version[1]}, - {[]apiversions.APIVersion{api_current_v2}, result_version[2]}, - {[]apiversions.APIVersion{api_supported_v1, api_current_v2}, result_version[2]}, // current always selected - {[]apiversions.APIVersion{api_current_v1, api_supported_v2}, result_version[1]}, // current always selected - {[]apiversions.APIVersion{api_current_v3, api_supported_v2, api_deprecated_v1}, result_version[2]}, // with current v3, but should fall back to v2 - {[]apiversions.APIVersion{api_current_v3, api_deprecated_v2, api_deprecated_v1}, result_version[0]}, // v3 is not supported - } - - for _, suite := range testCases { - if autodetectedVersion := doBsApiVersionAutodetect(suite.test_case); autodetectedVersion != suite.wanted_result { - t.Fatalf("Autodetect for suite: %s, failed with result: '%s', wanted '%s'", suite.test_case, autodetectedVersion, suite.wanted_result) - } - } -} diff --git a/openstack/openstack_volumes.go b/openstack/openstack_volumes.go deleted file mode 100644 index 48f77d5..0000000 --- a/openstack/openstack_volumes.go +++ /dev/null @@ -1,422 +0,0 @@ -/* -Copyright 2016 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package openstack - -import ( - "errors" - "fmt" - "io/ioutil" - "path" - "strings" - - k8s_volume "k8s.io/kubernetes/pkg/volume" - - "github.com/gophercloud/gophercloud" - "github.com/gophercloud/gophercloud/openstack" - volumes_v1 "github.com/gophercloud/gophercloud/openstack/blockstorage/v1/volumes" - volumes_v2 "github.com/gophercloud/gophercloud/openstack/blockstorage/v2/volumes" - "github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/volumeattach" - "github.com/gophercloud/gophercloud/pagination" - - "github.com/golang/glog" -) - -type volumeService interface { - createVolume(opts VolumeCreateOpts) (string, error) - getVolume(diskName string) (Volume, error) - deleteVolume(volumeName string) error -} - -// Volumes implementation for v1 -type VolumesV1 struct { - blockstorage *gophercloud.ServiceClient - opts BlockStorageOpts -} - -// Volumes implementation for v2 -type VolumesV2 struct { - blockstorage *gophercloud.ServiceClient - opts BlockStorageOpts -} - -type Volume struct { - // ID of the instance, to which this volume is attached. "" if not attached - AttachedServerId string - // Device file path - AttachedDevice string - // Unique identifier for the volume. - ID string - // Human-readable display name for the volume. - Name string - // Current status of the volume. - Status string -} - -type VolumeCreateOpts struct { - Size int - Availability string - Name string - VolumeType string - Metadata map[string]string -} - -func (volumes *VolumesV1) createVolume(opts VolumeCreateOpts) (string, error) { - - create_opts := volumes_v1.CreateOpts{ - Name: opts.Name, - Size: opts.Size, - VolumeType: opts.VolumeType, - AvailabilityZone: opts.Availability, - Metadata: opts.Metadata, - } - - vol, err := volumes_v1.Create(volumes.blockstorage, create_opts).Extract() - if err != nil { - return "", err - } - return vol.ID, nil -} - -func (volumes *VolumesV2) createVolume(opts VolumeCreateOpts) (string, error) { - - create_opts := volumes_v2.CreateOpts{ - Name: opts.Name, - Size: opts.Size, - VolumeType: opts.VolumeType, - AvailabilityZone: opts.Availability, - Metadata: opts.Metadata, - } - - vol, err := volumes_v2.Create(volumes.blockstorage, create_opts).Extract() - if err != nil { - return "", err - } - return vol.ID, nil -} - -func (volumes *VolumesV1) getVolume(diskName string) (Volume, error) { - var volume_v1 volumes_v1.Volume - var volume Volume - err := volumes_v1.List(volumes.blockstorage, nil).EachPage(func(page pagination.Page) (bool, error) { - vols, err := volumes_v1.ExtractVolumes(page) - if err != nil { - glog.Errorf("Failed to extract volumes: %v", err) - return false, err - } else { - for _, v := range vols { - glog.V(4).Infof("%s %s %v", v.ID, v.Name, v.Attachments) - if v.Name == diskName || strings.Contains(v.ID, diskName) { - volume_v1 = v - return true, nil - } - } - } - // if it reached here then no disk with the given name was found. - errmsg := fmt.Sprintf("Unable to find disk: %s", diskName) - return false, errors.New(errmsg) - }) - if err != nil { - glog.Errorf("Error occurred getting volume: %s", diskName) - return volume, err - } - - volume.ID = volume_v1.ID - volume.Name = volume_v1.Name - volume.Status = volume_v1.Status - - if len(volume_v1.Attachments) > 0 && volume_v1.Attachments[0]["server_id"] != nil { - volume.AttachedServerId = volume_v1.Attachments[0]["server_id"].(string) - volume.AttachedDevice = volume_v1.Attachments[0]["device"].(string) - } - - return volume, nil -} - -func (volumes *VolumesV2) getVolume(diskName string) (Volume, error) { - var volume_v2 volumes_v2.Volume - var volume Volume - err := volumes_v2.List(volumes.blockstorage, nil).EachPage(func(page pagination.Page) (bool, error) { - vols, err := volumes_v2.ExtractVolumes(page) - if err != nil { - glog.Errorf("Failed to extract volumes: %v", err) - return false, err - } else { - for _, v := range vols { - glog.V(4).Infof("%s %s %v", v.ID, v.Name, v.Attachments) - if v.Name == diskName || strings.Contains(v.ID, diskName) { - volume_v2 = v - return true, nil - } - } - } - // if it reached here then no disk with the given name was found. - errmsg := fmt.Sprintf("Unable to find disk: %s", diskName) - return false, errors.New(errmsg) - }) - if err != nil { - glog.Errorf("Error occurred getting volume: %s", diskName) - return volume, err - } - - volume.ID = volume_v2.ID - volume.Name = volume_v2.Name - volume.Status = volume_v2.Status - - if len(volume_v2.Attachments) > 0 { - volume.AttachedServerId = volume_v2.Attachments[0].ServerID - volume.AttachedDevice = volume_v2.Attachments[0].Device - } - - return volume, nil -} - -func (volumes *VolumesV1) deleteVolume(volumeName string) error { - - err := volumes_v1.Delete(volumes.blockstorage, volumeName).ExtractErr() - if err != nil { - glog.Errorf("Cannot delete volume %s: %v", volumeName, err) - } - return err -} - -func (volumes *VolumesV2) deleteVolume(volumeName string) error { - err := volumes_v2.Delete(volumes.blockstorage, volumeName).ExtractErr() - if err != nil { - glog.Errorf("Cannot delete volume %s: %v", volumeName, err) - } - return err -} - -// Attaches given cinder volume to the compute running kubelet -func (os *OpenStack) AttachDisk(instanceID string, diskName string) (string, error) { - volume, err := os.getVolume(diskName) - if err != nil { - return "", err - } - cClient, err := openstack.NewComputeV2(os.provider, gophercloud.EndpointOpts{ - Region: os.region, - }) - if err != nil || cClient == nil { - glog.Errorf("Unable to initialize nova client for region: %s", os.region) - return "", err - } - - if volume.AttachedServerId != "" { - if instanceID == volume.AttachedServerId { - glog.V(4).Infof("Disk: %q is already attached to compute: %q", diskName, instanceID) - return volume.ID, nil - } - glog.V(2).Infof("Disk %q is attached to a different compute (%q), detaching", diskName, volume.AttachedServerId) - err = os.DetachDisk(volume.AttachedServerId, diskName) - if err != nil { - return "", err - } - } - - // add read only flag here if possible spothanis - _, err = volumeattach.Create(cClient, instanceID, &volumeattach.CreateOpts{ - VolumeID: volume.ID, - }).Extract() - if err != nil { - glog.Errorf("Failed to attach %s volume to %s compute: %v", diskName, instanceID, err) - return "", err - } - glog.V(2).Infof("Successfully attached %s volume to %s compute", diskName, instanceID) - return volume.ID, nil -} - -// Detaches given cinder volume from the compute running kubelet -func (os *OpenStack) DetachDisk(instanceID string, partialDiskId string) error { - volume, err := os.getVolume(partialDiskId) - if err != nil { - return err - } - cClient, err := openstack.NewComputeV2(os.provider, gophercloud.EndpointOpts{ - Region: os.region, - }) - if err != nil || cClient == nil { - glog.Errorf("Unable to initialize nova client for region: %s", os.region) - return err - } - if volume.AttachedServerId != instanceID { - errMsg := fmt.Sprintf("Disk: %s has no attachments or is not attached to compute: %s", volume.Name, instanceID) - glog.Errorf(errMsg) - return errors.New(errMsg) - } else { - // This is a blocking call and effects kubelet's performance directly. - // We should consider kicking it out into a separate routine, if it is bad. - err = volumeattach.Delete(cClient, instanceID, volume.ID).ExtractErr() - if err != nil { - glog.Errorf("Failed to delete volume %s from compute %s attached %v", volume.ID, instanceID, err) - return err - } - glog.V(2).Infof("Successfully detached volume: %s from compute: %s", volume.ID, instanceID) - } - - return nil -} - -// Takes a partial/full disk id or diskname -func (os *OpenStack) getVolume(diskName string) (Volume, error) { - - volumes, err := os.volumeService("") - if err != nil || volumes == nil { - glog.Errorf("Unable to initialize cinder client for region: %s", os.region) - return Volume{}, err - } - - return volumes.getVolume(diskName) -} - -// Create a volume of given size (in GiB) -func (os *OpenStack) CreateVolume(name string, size int, vtype, availability string, tags *map[string]string) (volumeName string, err error) { - - volumes, err := os.volumeService("") - if err != nil || volumes == nil { - glog.Errorf("Unable to initialize cinder client for region: %s", os.region) - return "", err - } - opts := VolumeCreateOpts{ - Name: name, - Size: size, - VolumeType: vtype, - Availability: availability, - } - if tags != nil { - opts.Metadata = *tags - } - volume_id, err := volumes.createVolume(opts) - - if err != nil { - glog.Errorf("Failed to create a %d GB volume: %v", size, err) - return "", err - } - - glog.Infof("Created volume %v", volume_id) - return volume_id, nil -} - -// GetDevicePath returns the path of an attached block storage volume, specified by its id. -func (os *OpenStack) GetDevicePath(diskId string) string { - // Build a list of candidate device paths - candidateDeviceNodes := []string{ - // KVM - fmt.Sprintf("virtio-%s", diskId[:20]), - // ESXi - fmt.Sprintf("wwn-0x%s", strings.Replace(diskId, "-", "", -1)), - } - - files, _ := ioutil.ReadDir("/dev/disk/by-id/") - - for _, f := range files { - for _, c := range candidateDeviceNodes { - if c == f.Name() { - glog.V(4).Infof("Found disk attached as %q; full devicepath: %s\n", f.Name(), path.Join("/dev/disk/by-id/", f.Name())) - return path.Join("/dev/disk/by-id/", f.Name()) - } - } - } - - glog.Warningf("Failed to find device for the diskid: %q\n", diskId) - return "" -} - -func (os *OpenStack) DeleteVolume(volumeName string) error { - used, err := os.diskIsUsed(volumeName) - if err != nil { - return err - } - if used { - msg := fmt.Sprintf("Cannot delete the volume %q, it's still attached to a node", volumeName) - return k8s_volume.NewDeletedVolumeInUseError(msg) - } - - volumes, err := os.volumeService("") - if err != nil || volumes == nil { - glog.Errorf("Unable to initialize cinder client for region: %s", os.region) - return err - } - - err = volumes.deleteVolume(volumeName) - if err != nil { - glog.Errorf("Cannot delete volume %s: %v", volumeName, err) - } - return nil - -} - -// Get device path of attached volume to the compute running kubelet, as known by cinder -func (os *OpenStack) GetAttachmentDiskPath(instanceID string, diskName string) (string, error) { - // See issue #33128 - Cinder does not always tell you the right device path, as such - // we must only use this value as a last resort. - volume, err := os.getVolume(diskName) - if err != nil { - return "", err - } - if volume.AttachedServerId != "" { - if instanceID == volume.AttachedServerId { - // Attachment[0]["device"] points to the device path - // see http://developer.openstack.org/api-ref-blockstorage-v1.html - return volume.AttachedDevice, nil - } else { - errMsg := fmt.Sprintf("Disk %q is attached to a different compute: %q, should be detached before proceeding", diskName, volume.AttachedServerId) - glog.Errorf(errMsg) - return "", errors.New(errMsg) - } - } - return "", fmt.Errorf("volume %s is not attached to %s", diskName, instanceID) -} - -// query if a volume is attached to a compute instance -func (os *OpenStack) DiskIsAttached(diskName, instanceID string) (bool, error) { - volume, err := os.getVolume(diskName) - if err != nil { - return false, err - } - - if instanceID == volume.AttachedServerId { - return true, nil - } - return false, nil -} - -// query if a list of volumes are attached to a compute instance -func (os *OpenStack) DisksAreAttached(diskNames []string, instanceID string) (map[string]bool, error) { - attached := make(map[string]bool) - for _, diskName := range diskNames { - is_attached, _ := os.DiskIsAttached(diskName, instanceID) - attached[diskName] = is_attached - } - return attached, nil -} - -// diskIsUsed returns true a disk is attached to any node. -func (os *OpenStack) diskIsUsed(diskName string) (bool, error) { - volume, err := os.getVolume(diskName) - if err != nil { - return false, err - } - if volume.AttachedServerId != "" { - return true, nil - } - return false, nil -} - -// query if we should trust the cinder provide deviceName, See issue #33128 -func (os *OpenStack) ShouldTrustDevicePath() bool { - return os.bsOpts.TrustDevicePath -} diff --git a/tools/install-distro-packages.sh b/tools/install-distro-packages.sh deleted file mode 100755 index 31aa41f..0000000 --- a/tools/install-distro-packages.sh +++ /dev/null @@ -1,44 +0,0 @@ -#!/bin/bash -xe - -BASE_DIR=$(cd $(dirname $BASH_SOURCE)/.. && pwd) - -# Local version to install bindep packages -# Suitable for use for development - -function is_fedora { - [ -f /usr/bin/yum ] && cat /etc/*release | grep -q -e "Fedora" -} - -PACKAGES="" -if ! which virtualenv; then - PACKAGES="$PACKAGES virtualenv" -fi -if ! which make; then - PACKAGES="$PACKAGES make" -fi -if [[ -n $PACKAGES ]]; then - sudo apt-get -q --assume-yes install virtualenv -fi - -# Check for bindep -if ! which bindep; then - pushd $BASE_DIR >/dev/null - make bindep - popd >/dev/null -fi - -PACKAGES=$(make bindep || true) - -# inspired from project-config install-distro-packages.sh -if apt-get -v >/dev/null 2>&1 ; then - sudo apt-get -qq update - sudo PATH=/usr/sbin:/sbin:$PATH DEBIAN_FRONTEND=noninteractive \ - apt-get -q --option "Dpkg::Options::=--force-confold" \ - --assume-yes install $PACKAGES -elif emerge --version >/dev/null 2>&1 ; then - sudo emerge -uDNq --jobs=4 @world - sudo PATH=/usr/sbin:/sbin:$PATH emerge -q --jobs=4 $PACKAGES -else - is_fedora && YUM=dnf || YUM=yum - sudo PATH=/usr/sbin:/sbin:$PATH $YUM install -y $PACKAGES -fi diff --git a/tools/test-setup.sh b/tools/test-setup.sh deleted file mode 100755 index cc51bb3..0000000 --- a/tools/test-setup.sh +++ /dev/null @@ -1,55 +0,0 @@ -#!/bin/bash -xe -# test-setup.sh - Install required stuffs -# Used in both CI jobs and locally -# -# Install the following tools: -# * glide - -# Get OS -case $(uname -s) in - Darwin) - OS=darwin - ;; - Linux) - if LSB_RELEASE=$(which lsb_release); then - OS=$($LSB_RELEASE -s -c) - else - # No lsb-release, trya hack or two - if which dpkg 1>/dev/null; then - OS=debian - elif which yum 1>/dev/null || which dnf 1>/dev/null; then - OS=redhat - else - echo "Linux distro not yet supported" - exit 1 - fi - fi - ;; - *) - echo "Unsupported OS" - exit 1 - ;; -esac - -case $OS in - darwin) - if which brew 1>/dev/null; then - if ! which glide 1>/dev/null; then - brew install glide - fi - else - echo "Homebrew not found, install Glide from source?" - fi - ;; - xenial) - APT_GET="DEBIAN_FRONTEND=noninteractive \ - apt-get -q --option "Dpkg::Options::=--force-confold" \ - --assume-yes" - if ! which add-apt-repository 1>/dev/null; then - sudo $APT_GET install software-properties-common - fi - sudo add-apt-repository --yes ppa:longsleep/golang-backports - sudo add-apt-repository --yes ppa:masterminds/glide - sudo apt-get update && sudo $APT_GET install golang-go glide - ;; -esac