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
This commit is contained in:
Chris Hoge 2018-03-06 13:33:45 -08:00
parent 965e34806d
commit f7756c89de
27 changed files with 5 additions and 5803 deletions

5
.gitreview Normal file
View File

@ -0,0 +1,5 @@
[gerrit]
host=review.openstack.org
port=29418
project=openstack/k8s-cloud-provider

191
LICENSE
View File

@ -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.

107
Makefile
View File

@ -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

View File

@ -1,6 +0,0 @@
pkg-config
build-essential
mercurial
golang-go
golint
make

View File

@ -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

View File

@ -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 - <<EOF || true
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
namespace: kube-system
name: standard
annotations:
storageclass.beta.kubernetes.io/is-default-class: "true"
labels:
addonmanager.kubernetes.io/mode: Reconcile
provisioner: kubernetes.io/host-path
EOF
echo "Running tests..."
set -ex
export GOPATH=${BASE_DIR}/go
export KUBE_MASTER=local
export KUBERNETES_PROVIDER=skeleton
export KUBERNETES_CONFORMANCE_TEST=y
export GINKGO_PARALLEL=y
export GINKGO_PARALLELISM=5
export GINKGO_NO_COLOR=y
export KUBE_MASTER_IP=https://127.0.0.1:6443/
pushd $GOPATH/src/k8s.io/kubernetes >/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

View File

@ -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"

View File

@ -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:

View File

@ -1,4 +0,0 @@
# settings file for devstack plugin
enable_service k8s-cloud-provider
enable_service kubernetes

677
glide.lock generated
View File

@ -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: []

View File

@ -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

64
main.go
View File

@ -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)
}
}

View File

@ -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"],
)

View File

@ -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)]()

View File

@ -1,2 +0,0 @@
approvers:
- anguslees

254
openstack/glide.lock generated
View File

@ -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: []

View File

@ -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
}

View File

@ -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)
}
}

View File

@ -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)
}
}

View File

@ -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:
// <endpoint>/<instanceid>
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
}

File diff suppressed because it is too large Load Diff

View File

@ -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
}

View File

@ -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)
}
}

View File

@ -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)
}
}
}

View File

@ -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
}

View File

@ -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

View File

@ -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