Add cloudify API method for demo start/stop
[models.git] / tools / cloudify / k8s-cloudify.sh
1 #!/bin/bash
2 # Copyright 2017 AT&T Intellectual Property, Inc
3 #
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at
7 #
8 # http://www.apache.org/licenses/LICENSE-2.0
9 #
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15 #
16 #. What this is: Setup script for Cloudify use with Kubernetes.
17 #. Prerequisites:
18 #. - Kubernetes cluster installed per k8s-cluster.sh (in this repo)
19 #. Usage:
20 #.   From a server with access to the kubernetes master node:
21 #.   $ git clone https://gerrit.opnfv.org/gerrit/models ~/models
22 #.   $ scp -r ~/models/tools/cloudify ubuntu@<k8s-master>:/home/ubuntu/.
23 #.     <k8s-master>: IP or hostname of kubernetes master server
24 #.   $ ssh -x ubuntu@<k8s-master> cloudify/k8s-cloudify.sh prereqs
25 #.     prereqs: installs prerequisites and configures ubuntu user for kvm use
26 #.   $ ssh -x ubuntu@<k8s-master> bash cloudify/k8s-cloudify.sh setup
27 #.     setup: installs cloudify CLI and Manager
28 #.   $ source ~/models/tools/cloudify/k8s-cloudify.sh demo <start|stop> <k8s-master>
29 #.     demo: control demo blueprint
30 #.     start|stop: start or stop the demo
31 #.     <k8s-master>: IP or hostname of kubernetes master server
32 #.   $ ssh -x ubuntu@<k8s-master> bash cloudify/k8s-cloudify.sh clean
33 #.     clean: uninstalls cloudify CLI and Manager
34
35 #. Status: this is a work in progress, under test.
36
37 function log() {
38   f=$(caller 0 | awk '{print $2}')
39   l=$(caller 0 | awk '{print $1}')
40   echo ""
41   echo "$f:$l ($(date)) $1"
42 }
43
44 function prereqs() {
45   log "Install prerequisites"
46   sudo apt-get install -y virtinst qemu-kvm libguestfs-tools virtualenv git \
47     python-pip
48   log "Setup $USER for kvm use"
49   # Per http://libguestfs.org/guestfs-faq.1.html
50   # workaround for virt-customize warning: libguestfs: warning: current user is not a member of the KVM group (group ID 121). This user cannot access /dev/kvm, so libguestfs may run very slowly. It is recommended that you 'chmod 0666 /dev/kvm' or add the current user to the KVM group (you might need to log out and log in again).
51   # Also see: https://help.ubuntu.com/community/KVM/Installation
52   # also to avoid permission denied errors in guestfish, from http://manpages.ubuntu.com/manpages/zesty/man1/guestfs-faq.1.html
53   sudo usermod -a -G kvm $USER
54   sudo chmod 0644 /boot/vmlinuz*
55   log "Clone repo"
56 }
57
58 function setup () {
59   cd ~/cloudify
60   log "Setup Cloudify-CLI"
61   # Per http://docs.getcloudify.org/4.1.0/installation/bootstrapping/#installing-cloudify-manager-in-an-offline-environment
62   wget -q http://repository.cloudifysource.org/cloudify/17.9.21/community-release/cloudify-cli-community-17.9.21.deb
63   # Installs into /opt/cfy/
64   sudo dpkg -i cloudify-cli-community-17.9.21.deb
65   export MANAGER_BLUEPRINTS_DIR=/opt/cfy/cloudify-manager-blueprints
66   virtualenv ~/cloudify/env
67   source ~/cloudify/env/bin/activate
68
69   log "Setup Cloudify-Manager"
70   # to start over
71   # sudo virsh destroy cloudify-manager; sudo virsh undefine cloudify-manager
72   wget -q http://repository.cloudifysource.org/cloudify/17.9.21/community-release/cloudify-manager-community-17.9.21.qcow2
73   # nohup and redirection of output is a workaround for some issue with virt-install never outputting anything beyond "Creadint domain..." and thus not allowing the script to continue.
74   nohup virt-install --connect qemu:///system --virt-type kvm \
75     --name cloudify-manager --vcpus 4 --memory 16192 \
76     --disk cloudify-manager-community-17.9.21.qcow2 --import \
77     --network network=default --os-type=linux  \
78     --os-variant=rhel7 > /dev/null 2>&1 &
79
80   VM_IP=""
81   n=0
82   while [[ "x$VM_IP" == "x" ]]; do
83     log "$n minutes so far; waiting 60 seconds for cloudify-manager IP to be assigned"
84     sleep 60
85     ((n++))
86     VM_MAC=$(virsh domiflist cloudify-manager | grep default | grep -Eo "[0-9a-f\]+:[0-9a-f\]+:[0-9a-f\]+:[0-9a-f\]+:[0-9a-f\]+:[0-9a-f\]+")
87     VM_IP=$(/usr/sbin/arp -e | grep ${VM_MAC} | awk {'print $1'})
88   done
89   log "cloudify-manager IP=$VM_IP"
90   while ! cfy profiles use $VM_IP -u admin -p admin -t default_tenant ; do
91     log "waiting 60 seconds for cloudify-manager API to be active"
92     sleep 60
93   done
94   cfy status
95
96   log "Install Cloudify Kubernetes Plugin"
97   # Per http://docs.getcloudify.org/4.1.0/plugins/container-support/
98   # Per https://github.com/cloudify-incubator/cloudify-kubernetes-plugin
99   pip install kubernetes wagon
100   # From https://github.com/cloudify-incubator/cloudify-kubernetes-plugin/releases
101   wget -q https://github.com/cloudify-incubator/cloudify-kubernetes-plugin/releases/download/1.2.1/cloudify_kubernetes_plugin-1.2.1-py27-none-linux_x86_64-centos-Core.wgn
102   # For Cloudify-CLI per http://docs.getcloudify.org/4.1.0/plugins/using-plugins/
103   wagon install  \
104     cloudify_kubernetes_plugin-1.2.1-py27-none-linux_x86_64-centos-Core.wgn
105   # For Cloudify-Manager per https://github.com/cloudify-incubator/cloudify-kubernetes-plugin/blob/master/examples/persistent-volumes-blueprint.yaml
106   cfy plugins upload cloudify_kubernetes_plugin-1.2.1-py27-none-linux_x86_64-centos-Core.wgn
107
108   log "Create secrets for kubernetes as referenced in blueprints"
109   cfy secrets create -s $(grep server ~/.kube/config | awk -F '/' '{print $3}' \
110     | awk -F ':' '{print $1}') kubernetes_master_ip
111   cfy secrets create -s $(grep server ~/.kube/config | awk -F '/' '{print $3}' \
112     | awk -F ':' '{print $2}') kubernetes_master_port
113   cfy secrets create -s  \
114     $(grep 'certificate-authority-data: ' ~/.kube/config |  \
115     awk -F ' ' '{print $2}') kubernetes_certificate_authority_data
116   cfy secrets create -s $(grep 'client-certificate-data: ' ~/.kube/config \
117     | awk -F ' ' '{print $2}') kubernetes-admin_client_certificate_data
118   cfy secrets create -s $(grep 'client-key-data: ' ~/.kube/config \
119     | awk -F ' ' '{print $2}') kubernetes-admin_client_key_data
120   cfy secrets list
121
122   # get manager VM IP
123   VM_MAC=$(sudo virsh domiflist cloudify-manager | grep default | grep -Eo "[0-9a-f\]+:[0-9a-f\]+:[0-9a-f\]+:[0-9a-f\]+:[0-9a-f\]+:[0-9a-f\]+")
124   VM_IP=$(/usr/sbin/arp -e | grep ${VM_MAC} | awk {'print $1'})
125
126   # get host IP
127   HOST_IP=$(ip route get 8.8.8.8 | awk '{print $NF; exit}')
128
129   # Forward host port 80 to VM
130   sudo iptables -t nat -I PREROUTING -p tcp -d $HOST_IP --dport 80 -j DNAT --to-destination $VM_IP:80
131   sudo iptables -I FORWARD -m state -d $VM_IP/32 --state NEW,RELATED,ESTABLISHED -j ACCEPT
132   sudo iptables -t nat -A POSTROUTING -j MASQUERADE
133
134   while ! curl -u admin:admin --header 'Tenant: default_tenant' http://$HOST_IP/api/v3.1/status ; do
135     log "Cloudify API is not yet responding, waiting 10 seconds"
136     sleep 10
137   done
138   log "Cloudify CLI config is at ~/.cloudify/config.yaml"
139   log "Cloudify CLI log is at ~/.cloudify/logs/cli.log"
140   log "Cloudify API access example: curl -u admin:admin --header 'Tenant: default_tenant' http://$HOST_IP/api/v3.1/status"
141   log "Cloudify setup is complete!"
142 }
143
144 function demo() {
145   # Per http://docs.getcloudify.org/4.1.0/plugins/container-support/
146   # Per https://github.com/cloudify-incubator/cloudify-kubernetes-plugin
147   # Also per guidance at https://github.com/cloudify-incubator/cloudify-kubernetes-plugin/issues/18
148 #  echo "master-ip: $(grep server ~/.kube/config | awk -F '/' '{print $3}' | awk -F ':' '{print $1}')" >~/cloudify/blueprints/k8s-hello-world/inputs.yaml
149 #  echo "master-port: $(grep server ~/.kube/config | awk -F '/' '{print $3}' | awk -F ':' '{print $2}')" >>~/cloudify/blueprints/k8s-hello-world/inputs.yaml
150 #  echo "file_content:" >>~/cloudify/blueprints/k8s-hello-world/inputs.yaml
151 #  sed 's/^/  /' ~/.kube/config | tee -a ~/cloudify/blueprints/k8s-hello-world/inputs.yaml
152   manager_ip=$2
153   cd ~/models/tools/cloudify/blueprints
154
155   if [[ "$1" == "start" ]]; then
156     log "copy kube config from k8s master for insertion into blueprint"
157     scp -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no  \
158       ubuntu@$manager_ip:/home/ubuntu/.kube/config k8s-hello-world/kube.config
159
160     log "package the blueprint"
161     # CLI: cfy blueprints package -o ~/cloudify/blueprints/k8s-hello-world ~/cloudify/blueprints/k8s-hello-world
162     tar ckf /tmp/blueprint.tar k8s-hello-world
163
164     log "upload the blueprint"
165     # CLI: cfy blueprints upload -t default_tenant -b k8s-hello-world ~/cloudify/blueprints/k8s-hello-world.tar.gz
166     curl -X PUT -u admin:admin --header 'Tenant: default_tenant'  \
167       --header "Content-Type: application/octet-stream"  \
168       http://$manager_ip/api/v3.1/blueprints/k8s-hello-world?application_file_name=blueprint.yaml  \
169       -T /tmp/blueprint.tar | jq
170
171     log "create a deployment for the blueprint"
172     # CLI: cfy deployments create -t default_tenant -b k8s-hello-world k8s-hello-world
173     curl -X PUT -u admin:admin --header 'Tenant: default_tenant'  \
174       --header "Content-Type: application/json"  \
175       -d '{"blueprint_id": "k8s-hello-world", "inputs": {}}'  \
176       http://$manager_ip/api/v3.1/deployments/k8s-hello-world
177     sleep 10
178
179     # CLI: cfy workflows list -d k8s-hello-world
180
181     log "install the deployment pod and service"
182     # CLI: cfy executions start install -d k8s-hello-world
183     curl -X POST -u admin:admin --header 'Tenant: default_tenant'  \
184       --header "Content-Type: application/json"  \
185       -d '{"deployment_id":"k8s-hello-world", "workflow_id":"install"}'  \
186       http://$manager_ip/api/v3.1/executions | jq
187
188     log "get the service's assigned node_port"
189     port=$(curl -u admin:admin --header 'Tenant: default_tenant'  \
190       http://$manager_ip/api/v3.1/node-instances |  \
191       jq -r '.items[0].runtime_properties.kubernetes.spec.ports[0].node_port')
192     while [[ "$port" == "null" ]]; do
193       sleep 10
194       port=$(curl -u admin:admin --header 'Tenant: default_tenant'  \
195         http://$manager_ip/api/v3.1/node-instances |  \
196         jq -r '.items[0].runtime_properties.kubernetes.spec.ports[0].node_port')
197     done
198     log "node_port = $port"
199
200     log "verify service is responding"
201     while ! curl http://$manager_ip:$port ; do
202       log "nginx service is not yet responding at http://$manager_ip:$port, waiting 10 seconds"
203       sleep 10
204     done
205     log "service is active at http://$manager_ip:$port"
206   else
207     log "uninstall the service"
208     curl -X POST -u admin:admin --header 'Tenant: default_tenant' \
209       --header "Content-Type: application/json" \
210       -d '{"deployment_id":"k8s-hello-world", "workflow_id":"uninstall", "force": "true"}' \
211       http://$manager_ip/api/v3.1/executions
212     count=1
213     state=$(curl -u admin:admin --header 'Tenant: default_tenant' \
214       http://$manager_ip/api/v3.1/node-instances | jq -r '.items[0].state')
215     while [[ "$state" == "deleting" ]]; do
216       if [[ $count > 10 ]]; then
217         log "try to cancel all current executions"
218         exs=$(curl -u admin:admin --header 'Tenant: default_tenant' \
219           http://$manager_ip/api/v3.1/executions | jq -r '.items[].status')
220         i=0
221         for status in $exs; do
222           log "checking execution $i in state $status"
223           if [[ "$status" == "started" ]]; then
224             id=$(curl -u admin:admin --header 'Tenant: default_tenant' \
225               http://$manager_ip/api/v3.1/executions | jq -r ".items[$i].id")
226             curl -X POST -u admin:admin --header 'Tenant: default_tenant' \
227               --header "Content-Type: application/json" \
228               -d '{"deployment_id": "k8s-hello-world", "action": "cancel"}' \
229               http://$manager_ip/api/v3.1/executions/$id
230           fi
231           ((i++))
232         done
233         log "force delete deployment via cfy CLI"
234         ssh -x -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no \
235           ubuntu@$manager_ip cfy deployment delete -f \
236           -t default_tenant k8s-hello-world
237       fi
238       ((count ++))
239       state=$(curl -u admin:admin --header 'Tenant: default_tenant' \
240         http://$manager_ip/api/v3.1/node-instances | jq -r '.items[0].state')
241     done
242
243     log "delete the deployment"
244     curl -X DELETE -u admin:admin --header 'Tenant: default_tenant' \
245       http://$manager_ip/api/v3.1/deployments/k8s-hello-world
246     sleep 10
247     log "delete the blueprint"
248     curl -X DELETE -u admin:admin --header 'Tenant: default_tenant' \
249       http://$manager_ip/api/v3.1/blueprints/k8s-hello-world
250     sleep 10
251     log "verify the blueprint is deleted"
252     curl -u admin:admin --header 'Tenant: default_tenant' \
253       http://$manager_ip/api/v3.1/blueprints | jq
254   fi
255
256 # API examples: use '| jq' to format JSON output
257 # curl -u admin:admin --header 'Tenant: default_tenant' http://$manager_ip/api/v3.1/blueprints | jq
258 # curl -u admin:admin --header 'Tenant: default_tenant' http://$manager_ip/api/v3.1/deployments | jq
259 # curl -u admin:admin --header 'Tenant: default_tenant' http://$manager_ip/api/v3.1/executions | jq
260 # curl -u admin:admin --header 'Tenant: default_tenant' http://$manager_ip/api/v3.1/deployments | jq -r '.items[0].blueprint_id'
261 # curl -u admin:admin --header 'Tenant: default_tenant' http://$manager_ip/api/v3.1/node-instances | jq
262 }
263
264 function clean () {
265   log "Cleanup cloudify"
266   # TODO
267 }
268
269 dist=`grep DISTRIB_ID /etc/*-release | awk -F '=' '{print $2}'`
270 case "$1" in
271   "prereqs")
272     prereqs
273     ;;
274   "setup")
275     setup
276     ;;
277   "demo")
278     demo $2 $3
279     ;;
280   "clean")
281     clean
282     ;;
283   *)
284     grep '#. ' $0
285 esac
286