summaryrefslogtreecommitdiffstats
path: root/clover/spinnaker
diff options
context:
space:
mode:
authorwutianwei <wutianwei1@huawei.com>2018-08-22 10:49:56 +0800
committerwutianwei <wutianwei1@huawei.com>2018-09-05 09:03:26 +0800
commit8371ccd29229c418dd8bb534fda3d28184c4e986 (patch)
treec08d9deca85364ef3b1d33ab4078aa3d488ae4cc /clover/spinnaker
parente35bd25993a9bce37f17cf4353f0aa97d20e9c13 (diff)
Spinnaker as a Service
JIRA: CLOVER-52 1. Add mainfest to install the spinnaker in kubernetes cluster 2. after using mainfest to install spinnaker, we can interacte with the halyard daemon with its REST API and we can add/delete/list the dockerRegistry/kubernetes accounts. 3. Add the cloverctl to interate with the halyard daemon Change-Id: I71bc5977f2d65aab88fa55f7d7a53ab75eb6a46b Signed-off-by: wutianwei <wutianwei1@huawei.com>
Diffstat (limited to 'clover/spinnaker')
-rw-r--r--clover/spinnaker/__init__.py0
-rwxr-xr-xclover/spinnaker/halyard.py120
-rw-r--r--clover/spinnaker/halyard_sample.py41
-rw-r--r--clover/spinnaker/install/quick-install-spinnaker.yml376
-rw-r--r--clover/spinnaker/lib/__init__.py0
-rwxr-xr-xclover/spinnaker/lib/halyard_base.py157
6 files changed, 694 insertions, 0 deletions
diff --git a/clover/spinnaker/__init__.py b/clover/spinnaker/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/clover/spinnaker/__init__.py
diff --git a/clover/spinnaker/halyard.py b/clover/spinnaker/halyard.py
new file mode 100755
index 0000000..20c0f4b
--- /dev/null
+++ b/clover/spinnaker/halyard.py
@@ -0,0 +1,120 @@
+#!/bin/python
+
+import lib.halyard_base as base
+import time
+from clover.orchestration.kube_client import KubeClient
+
+namespace = 'spinnaker'
+client = KubeClient()
+
+def list_accounts(provider):
+ account_list = base.list_accounts(provider)
+ return account_list
+
+def delete_account(provider, accountname):
+ result = base.delete_account(provider, accountname)
+ if result != "SUCCEEDED":
+ print "Delete account failed"
+ return result
+
+ apply_result = base.apply_deploy()
+ if apply_result == "SUCCEEDED":
+ print "Delete account successfully"
+ else:
+ print "Delete account failed"
+
+ return apply_result
+
+def add_k8s_account(accountname, kubeconfigfile,
+ providerversion=None, registries=[]):
+ # Note: if providerversion is V1, must provider registries.
+ if base.is_account_exist("kubernetes",accountname):
+ return "FAILED"
+ if providerversion == None or providerversion == 'V1':
+ providerversion = None
+ if 0 == len(registries) or isinstance(registries, list) == False:
+ print "please provider docker registries or the type of registries is not list"
+ return "FAILED"
+ # Copy kubectl file to halyard pod
+ hal_kubeconfigfile = "/home/spinnaker/config" + \
+ time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime())
+ spinnaker_pods = client.find_pod_by_namespace(namespace)
+ for pod in spinnaker_pods:
+ if pod.find("spin-halyard") == 0:
+ client.copy_file_to_pod(kubeconfigfile,
+ hal_kubeconfigfile,
+ pod, namespace)
+ dockerRegistries = []
+ for registry in registries:
+ if not base.is_account_exist("dockerRegistry",registry):
+ print ("Please add docker registry: %s" %registry)
+ return "FAILED"
+ docker_dict = {"accountName":registry, "namespaces":[]}
+ dockerRegistries.append(docker_dict)
+
+ data = {
+ "name": accountname,
+ "requiredGroupMembership": [],
+ "providerVersion": providerversion,
+ "permissions": {},
+ "dockerRegistries": dockerRegistries,
+ "context": None,
+ "cluster": None,
+ "user": None,
+ "configureImagePullSecrets": "true",
+ "serviceAccount": None,
+ "cacheThreads": 1,
+ "namespaces": [],
+ "omitNamespaces": [],
+ "kinds": [],
+ "omitKinds": [],
+ "customResources": [],
+ "cachingPolicies": [],
+ "kubeconfigFile": hal_kubeconfigfile,
+ "kubeconfigContents": None,
+ "kubectlPath": None,
+ "namingStrategy": None,
+ "skin": None,
+ "debug": None,
+ "oauthScopes": [],
+ "oauthServiceAccount": None,
+ "oAuthServiceAccount": None,
+ "oAuthScopes": []
+ }
+# print data
+ result = base.add_account("kubernetes",data)
+ return result
+
+def add_docker_account(address, accountname, repositories=[],
+ username=None, password=None, validate='true'):
+
+ if base.is_account_exist("dockerRegistry",accountname):
+ return "FAILED"
+
+ data = {
+ "name": accountname,
+ "requiredGroupMembership": [],
+ "providerVersion": None,
+ "permissions": {},
+ "address": address,
+ "username": username,
+ "password": password,
+ "email": "fake.email@spinnaker.io",
+ "cacheIntervalSeconds": 30,
+ "clientTimeoutMillis": 60000,
+ "cacheThreads": 1,
+ "paginateSize": 100,
+ "sortTagsByDate": False,
+ "trackDigests": False,
+ "insecureRegistry": False,
+ "repositories": repositories,
+ "passwordFile": None,
+ "dockerconfigFile": None
+ }
+ result = base.add_account("dockerRegistry",data)
+ if result == "SUCCEEDED":
+ print "Add account successfully"
+ else:
+ print "Add account failed"
+ return result
+
diff --git a/clover/spinnaker/halyard_sample.py b/clover/spinnaker/halyard_sample.py
new file mode 100644
index 0000000..b78be9b
--- /dev/null
+++ b/clover/spinnaker/halyard_sample.py
@@ -0,0 +1,41 @@
+# Copyright (c) Authors of Clover
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+
+import halyard
+
+
+# please install the spinnaker useing the spinnaker/install/quick-install-spinnaker.yml first
+print "######## add docker provider ##########"
+address = "https://index.docker.io"
+repositories = ['wtwde/onap', 'wtwde/spinnaker', 'library/nginx']
+add_docker = halyard.add_docker_account(address, "docker-test", repositories)
+print "######## result ##########"
+print add_docker
+
+print "######## add kubernetes provider ##########"
+add_k8s = halyard.add_k8s_account('my-k8s-v1-t11561', "/root/config.115", "V1", ['dockerhub'])
+print "######## result ##########"
+print add_k8s
+
+print "######## k8s account list ##########"
+k8s_list = halyard.list_accounts('kubernetes')
+print "####### result ##########"
+print k8s_list
+
+print "######## docker account list ##########"
+docker_list = halyard.list_accounts('dockerRegistry')
+print "####### result ##########"
+print docker_list
+
+print "######## delete kubernetes provider ##########"
+del_k8s = halyard.delete_account('kubernetes','my-k8s-v1-t11561')
+print "######## result ##########"
+
+print "######## delete docker registry provider ##########"
+del_docker = halyard.delete_account('dockerRegistry','docker-test')
+print "######## result ##########"
+print del_docker
diff --git a/clover/spinnaker/install/quick-install-spinnaker.yml b/clover/spinnaker/install/quick-install-spinnaker.yml
new file mode 100644
index 0000000..c935453
--- /dev/null
+++ b/clover/spinnaker/install/quick-install-spinnaker.yml
@@ -0,0 +1,376 @@
+apiVersion: v1
+kind: Namespace
+metadata:
+ name: spinnaker
+
+---
+
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRoleBinding
+metadata:
+ name: spinnaker-admin
+roleRef:
+ apiGroup: rbac.authorization.k8s.io
+ kind: ClusterRole
+ name: cluster-admin
+subjects:
+- kind: ServiceAccount
+ name: default
+ namespace: spinnaker
+
+---
+
+apiVersion: v1
+kind: Pod
+metadata:
+ name: spin-halyard
+ namespace: spinnaker
+ labels:
+ app: spin
+ stack: halyard
+spec:
+ containers:
+ - name: halyard-daemon
+ # todo - make :stable or digest of :stable
+ image: gcr.io/spinnaker-marketplace/halyard:stable
+ imagePullPolicy: Always
+ command:
+ - /bin/sh
+ args:
+ - -c
+ # when the configmap is mounted directly at /home/spinnaker/.hal the halyard daemon
+ # isn't able to replace the contents of the mount with user modifications.
+ # so instead we mount the configmap elsewhere and copy the files into
+ # place when the container starts.
+ - "cp -R /home/spinnaker/staging/.hal /home/spinnaker/.hal && /opt/halyard/bin/halyard"
+ readinessProbe:
+ exec:
+ command:
+ - wget
+ - -q
+ - --spider
+ - http://localhost:8064/health
+ ports:
+ - containerPort: 8064
+ volumeMounts:
+ - name: halconfig
+ mountPath: /home/spinnaker/staging/.hal/config
+ subPath: config
+ - name: halconfig
+ mountPath: /home/spinnaker/staging/.hal/default/service-settings/deck.yml
+ subPath: deck.yml
+ - name: halconfig
+ mountPath: /home/spinnaker/staging/.hal/default/service-settings/gate.yml
+ subPath: gate.yml
+ - name: halconfig
+ mountPath: /home/spinnaker/staging/.hal/default/service-settings/igor.yml
+ subPath: igor.yml
+ - name: halconfig
+ mountPath: /home/spinnaker/staging/.hal/default/service-settings/fiat.yml
+ subPath: fiat.yml
+ - name: halconfig
+ mountPath: /home/spinnaker/staging/.hal/default/profiles/front50-local.yml
+ subPath: front50-local.yml
+ volumes:
+ - name: halconfig
+ configMap:
+ name: halconfig
+---
+
+apiVersion: v1
+kind: Service
+metadata:
+ name: spin-halyard
+ namespace: spinnaker
+spec:
+ ports:
+ - port: 8064
+ targetPort: 8064
+ protocol: TCP
+ selector:
+ app: spin
+ stack: halyard
+
+---
+
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ name: halconfig
+ namespace: spinnaker
+data:
+ igor.yml: |
+ enabled: true
+ fiat.yml: |
+ enabled: false
+ skipLifeCycleManagement: true
+ front50-local.yml: |
+ spinnaker.s3.versioning: false
+ gate.yml: |
+ host: 0.0.0.0
+ deck.yml: |
+ host: 0.0.0.0
+ env:
+ API_HOST: http://spin-gate.spinnaker:8084/
+ config: |
+ currentDeployment: default
+ deploymentConfigurations:
+ - name: default
+ version: 1.7.0
+ providers:
+ appengine:
+ enabled: false
+ accounts: []
+ aws:
+ enabled: false
+ accounts: []
+ defaultKeyPairTemplate: '{{name}}-keypair'
+ defaultRegions:
+ - name: us-west-2
+ defaults:
+ iamRole: BaseIAMRole
+ azure:
+ enabled: false
+ accounts: []
+ bakeryDefaults:
+ templateFile: azure-linux.json
+ baseImages: []
+ dcos:
+ enabled: false
+ accounts: []
+ clusters: []
+ dockerRegistry:
+ enabled: true
+ accounts:
+ - name: dockerhub
+ address: https://index.docker.io
+ repositories:
+ - opnfv/clover
+ google:
+ enabled: false
+ accounts: []
+ bakeryDefaults:
+ templateFile: gce.json
+ baseImages: []
+ zone: us-central1-f
+ network: default
+ useInternalIp: false
+ kubernetes:
+ enabled: true
+ accounts:
+ - name: my-kubernetes-account
+ requiredGroupMembership: []
+ providerVersion: V2
+ dockerRegistries: []
+ configureImagePullSecrets: true
+ serviceAccount: true
+ namespaces: []
+ omitNamespaces: []
+ kinds: []
+ omitKinds: []
+ customResources: []
+ oauthScopes: []
+ oAuthScopes: []
+ primaryAccount: my-kubernetes-account
+ openstack:
+ enabled: false
+ accounts: []
+ bakeryDefaults:
+ baseImages: []
+ oraclebmcs:
+ enabled: false
+ accounts: []
+ deploymentEnvironment:
+ size: SMALL
+ type: Distributed
+ accountName: my-kubernetes-account
+ updateVersions: true
+ consul:
+ enabled: false
+ vault:
+ enabled: false
+ customSizing: {}
+ gitConfig:
+ upstreamUser: spinnaker
+ persistentStorage:
+ persistentStoreType: s3
+ azs: {}
+ gcs:
+ rootFolder: front50
+ redis: {}
+ s3:
+ bucket: spinnaker-artifacts
+ rootFolder: front50
+ endpoint: http://minio-service.spinnaker:9000
+ accessKeyId: dont-use-this
+ secretAccessKey: for-production
+ oraclebmcs: {}
+ features:
+ auth: false
+ fiat: false
+ chaos: false
+ entityTags: false
+ jobs: false
+ metricStores:
+ datadog:
+ enabled: false
+ prometheus:
+ enabled: false
+ add_source_metalabels: true
+ stackdriver:
+ enabled: false
+ period: 30
+ enabled: false
+ notifications:
+ slack:
+ enabled: false
+ timezone: America/Los_Angeles
+ ci:
+ jenkins:
+ enabled: true
+ masters: []
+ travis:
+ enabled: false
+ masters: []
+ security:
+ apiSecurity:
+ ssl:
+ enabled: false
+ overrideBaseUrl: /gate
+ uiSecurity:
+ ssl:
+ enabled: false
+ authn:
+ oauth2:
+ enabled: false
+ client: {}
+ resource: {}
+ userInfoMapping: {}
+ saml:
+ enabled: false
+ ldap:
+ enabled: false
+ x509:
+ enabled: false
+ enabled: false
+ authz:
+ groupMembership:
+ service: EXTERNAL
+ google:
+ roleProviderType: GOOGLE
+ github:
+ roleProviderType: GITHUB
+ file:
+ roleProviderType: FILE
+ enabled: false
+ artifacts:
+ gcs:
+ enabled: false
+ accounts: []
+ github:
+ enabled: false
+ accounts: []
+ http:
+ enabled: false
+ accounts: []
+ pubsub:
+ google:
+ enabled: false
+ subscriptions: []
+
+---
+
+apiVersion: v1
+kind: PersistentVolumeClaim
+metadata:
+ name: minio-pv-claim
+ namespace: spinnaker
+ labels:
+ app: minio-storage-claim
+spec:
+ accessModes:
+ - ReadWriteOnce
+ resources:
+ requests:
+ storage: 10Gi
+ storageClassName: standard
+
+---
+
+apiVersion: apps/v1beta1
+kind: Deployment
+metadata:
+ # This name uniquely identifies the Deployment
+ name: minio-deployment
+ namespace: spinnaker
+spec:
+ strategy:
+ type: Recreate
+ template:
+ metadata:
+ labels:
+ app: minio
+ spec:
+ volumes:
+ - name: storage
+ persistentVolumeClaim:
+ claimName: minio-pv-claim
+ containers:
+ - name: minio
+ image: minio/minio
+ args:
+ - server
+ - /storage
+ env:
+ - name: MINIO_ACCESS_KEY
+ value: "dont-use-this"
+ - name: MINIO_SECRET_KEY
+ value: "for-production"
+ ports:
+ - containerPort: 9000
+ volumeMounts:
+ - name: storage
+ mountPath: /storage
+
+---
+
+apiVersion: v1
+kind: Service
+metadata:
+ name: minio-service
+ namespace: spinnaker
+spec:
+ ports:
+ - port: 9000
+ targetPort: 9000
+ protocol: TCP
+ selector:
+ app: minio
+
+---
+
+apiVersion: batch/v1
+kind: Job
+metadata:
+ name: hal-deploy-apply
+ namespace: spinnaker
+ labels:
+ app: job
+ stack: hal-deploy
+spec:
+ template:
+ metadata:
+ labels:
+ app: job
+ stack: hal-deploy
+ spec:
+ restartPolicy: OnFailure
+ containers:
+ - name: hal-deploy-apply
+ # todo use a custom image
+ image: gcr.io/spinnaker-marketplace/halyard:stable
+ command:
+ - /bin/sh
+ args:
+ - -c
+ - "hal deploy apply --daemon-endpoint http://spin-halyard.spinnaker:8064"
diff --git a/clover/spinnaker/lib/__init__.py b/clover/spinnaker/lib/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/clover/spinnaker/lib/__init__.py
diff --git a/clover/spinnaker/lib/halyard_base.py b/clover/spinnaker/lib/halyard_base.py
new file mode 100755
index 0000000..7245d6a
--- /dev/null
+++ b/clover/spinnaker/lib/halyard_base.py
@@ -0,0 +1,157 @@
+#!/bin/python
+
+
+import requests
+import json
+import time
+
+base_url="http://spin-halyard.spinnaker:8064/v1"
+namespace= 'spinnaker'
+headers = {'content-type': 'application/json; charset=UTF-8'}
+debug = False
+
+def get(url):
+ result = requests.get(url)
+ return result.json()
+
+def post(url, data = None, headers = None):
+ result = requests.post(url, data=data, headers=headers)
+ return result.json()
+
+def put(url, data = None, headers = None):
+ result = requests.put(url, data=data, headers=headers)
+ return result.json()
+
+def delete(url):
+ result = requests.delete(url)
+ return result.json()
+
+def print_dict_info(dict_info, debug = False):
+ if dict_info == None:
+ return None
+
+ if debug == True:
+ for v,k in dict_info.items():
+ print('{v}:{k}'.format(v = v, k = k))
+ else:
+ print dict_info.get('name')
+ print dict_info.get('state')
+
+def is_account_exist(provider, accountname):
+ exist_accounts = list_accounts(provider)
+ if accountname in exist_accounts:
+ print "account exists"
+ return True
+ print "account doesn't exist"
+ return False
+
+def get_task_info(uuid):
+ if uuid == None:
+ return None
+ url = base_url + "/tasks/" + uuid + "/"
+ result = get(url)
+ return result
+
+def wait_task_successful(uuid):
+ flag = ""
+ while True:
+ resp = get_task_info(uuid)
+ state = resp.get('state')
+ if flag != state:
+ print_dict_info(resp, debug)
+ flag = state
+ if state == "SUCCEEDED":
+ return "SUCCEEDED", resp
+ if state == "FAILED":
+ return "FAILED", resp
+ if resp.get('timedOut'):
+ return "TimeOut", resp
+
+def get_current_deployment():
+ '''get the current deployment and check the state'''
+
+ url = base_url + "/config/currentDeployment"
+ result = get(url)
+ uuid = result.get('uuid')
+ task_info = get_task_info(uuid)
+ print_dict_info(task_info, debug)
+
+ return task_info
+
+def apply_deploy():
+ """
+ after using api to config halyard, it need ruan apply deploy.
+ """
+ prep_url = base_url + "/config/deployments/default/prep/?validate=true"
+ deploy_url = base_url + "/config/deployments/default/deploy/?validate=false"
+ data='""'
+ result = post(prep_url, data=data, headers=headers)
+ uuid = result.get('uuid')
+ result, task_info = wait_task_successful(uuid)
+ if result != "SUCCEEDED":
+ return result
+ result = post(deploy_url, data=data, headers=headers)
+ uuid = result.get('uuid')
+ result, task_info = wait_task_successful(uuid)
+ return result
+
+def list_accounts(provider):
+ """
+ According to the provider, list all accounts
+ """
+ url = base_url + "/config/deployments/default/providers/" + \
+ provider + "/?validate=true"
+ resp = get(url)
+ uuid = resp.get('uuid')
+ result, task_info = wait_task_successful(uuid)
+ if result != "SUCCEEDED":
+ print "Get account failed"
+ return None
+ accounts = task_info.get('response').get('responseBody').get('accounts')
+ account_list = []
+ for account in accounts:
+ account_name = account.get('name')
+ account_list.append(account_name)
+ return account_list
+
+def enable_provider(provider, data='true'):
+ """
+ if needs to add a provider, it is necessary to enable the provider
+ """
+ url = base_url + "/config/deployments/default/providers/" + \
+ provider + "/enabled/?validate=true"
+ resp = put(url,data=data,headers=headers)
+ uuid = resp.get('uuid')
+ result, task_info = wait_task_successful(uuid)
+ return result
+
+def add_account(provider, data):
+ url = base_url + "/config/deployments/default/providers/" + \
+ provider + "/accounts/?validate=true"
+
+ enable_provider(provider)
+
+ resp = post(url, data=json.dumps(data), headers=headers)
+ uuid = resp.get('uuid')
+ result, task_info = wait_task_successful(uuid)
+ if result != "SUCCEEDED":
+ print "Add account failed"
+ return result
+ apply_result = apply_deploy()
+ if apply_result == "SUCCEEDED":
+ print "Deployment successful"
+ else:
+ print "Deployment failed"
+ return apply_result
+
+def delete_account(provider, accountname):
+ if not is_account_exist(provider, accountname):
+ return "FAILED"
+ url = base_url + "/config/deployments/default/providers/" + \
+ provider + "/accounts/account/" + accountname + "/?validate=true"
+ resp = delete(url)
+ uuid = resp.get('uuid')
+ result, task_info = wait_task_successful(uuid)
+
+ return result
+