From 72231250ed81e10d66bfe70701e64fa5fe50f712 Mon Sep 17 00:00:00 2001 From: Jon Bratseth Date: Wed, 15 Jun 2016 23:09:44 +0200 Subject: Publish --- node-admin/scripts/node-repo.sh | 318 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 318 insertions(+) create mode 100755 node-admin/scripts/node-repo.sh (limited to 'node-admin/scripts/node-repo.sh') diff --git a/node-admin/scripts/node-repo.sh b/node-admin/scripts/node-repo.sh new file mode 100755 index 00000000000..38b30a4d662 --- /dev/null +++ b/node-admin/scripts/node-repo.sh @@ -0,0 +1,318 @@ +#!/bin/bash +# Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. + +set -e + +# Output from InnerCurlNodeRepo, see there for details. +declare CURL_RESPONSE + +function Usage { + cat < [...] +Script for manipulating the Node Repository. + +Commands + add [-c ] -p ... + Provision node in node repo with flavor "docker". + reprovision [-c ] -p ... + Fail node , then rm and add. + rm [-c ] ... + Remove nodes from node repo. + set-state [-c ] ... + Set the node repo state. + +By default, is config-server. + +Example + To remove docker-1--1 through docker-1--5 from the node repo at configserver.com, + + ${0##*/} rm -c configserver.com \ + docker-1--{1,2,3,4,5}.dockerhosts.com +EOF + + exit 1 +} + +function Fail { + printf "%s\nRun '${0##*/} help' for usage\n" "$*" + exit 1 +} + +# Invoke curl such that: +# +# - Arguments to this function are passed to curl. +# +# - Additional arguments are passed to curl to filter noise (--silent +# --show-error). +# +# - The curl stdout (i.e. the response) is stored in the global CURL_RESPONSE +# variable on return of the function. +# +# - If curl returns 0 (i.e. a successful HTTP response) with a JSON response +# that contains an "error-code" key, this function will instead return 22. 22 +# does not conflict with a curl return code, because curl only ever returns +# 22 when --fail is specified. +# +# Except, if the JSON response contains a "message" of the form "Cannot add +# tmp-cnode-0: A node with this name already exists", InnerCurlNodeRepo +# returns 0 instead of 22, even if the HTTP response status code is an error. +# +# Note: Why not use --fail with curl? Because as of 2015-11-24, if the node +# exists when provisioning a node, the node repo returns a 400 Bad Request +# with a JSON body containing a "message" field as described above. With +# --fail, this would result in curl exiting with code 22, which is +# indistinguishable from other HTTP errors. Can the output from --show-error +# be used in combination with --fail? No, because that ends up saying "curl: +# (22) The requested URL returned error: 400 Bad Request" when the node +# exists, making it indistinguishable from other malformed request error +# messages. +# +# TODO: Make node repo return a unique HTTP error code when node already +# exists. It's also fragile to test for the error message in the response. +function InnerCurlNodeRepo { + # --show-error causes error message to be printed on error, even with + # --silent, which is useful when we print the error message to Fail. + local -a command=(curl --silent --show-error "$@") + + # We need the 'if' here, because a non-zero exit code of a command will + # exit the process, with 'set -e'. + if CURL_RESPONSE=$("${command[@]}" 2>&1) + then + # Match a JSON of the form: + # { + # "error-code": "BAD_REQUEST", + # "message": "Cannot add cnode-0: A node with this name already exists" + # } + if [[ "$CURL_RESPONSE" =~ '"error-code"' ]] + then + if [[ "$CURL_RESPONSE" =~ '"message"'[^\"]*\"(.*)\" ]] + then + local message="${BASH_REMATCH[1]}" + if [[ "$message" =~ 'already exists' ]] + then + return 0 + fi + fi + + return 22 + fi + + return 0 + else + # Do not move this statement outside of this else: $? gets cleared when + # the execution passes out of the else-fi block. + return $? + fi +} + +function CurlOrFail { + if InnerCurlNodeRepo "$@" + then + : # This form of if-else is used to preserve $?. + else + local error_code=$? + + # Terminate the current progress-bar-like line + printf ' failed\n' + + Fail "Error ($error_code) from the node repo at '$url': '$CURL_RESPONSE'" + fi +} + +function ProvisionDockerNode { + local config_server_hostname="$1" + local container_hostname="$2" + local parent_hostname="$3" + + local url="http://$config_server_hostname:19071/nodes/v2/node" + + local json="[ + { + \"hostname\":\"$container_hostname\", + \"parentHostname\":\"$parent_hostname\", + \"openStackId\":\"fake-$container_hostname\", + \"flavor\":\"docker\" + } + ]" + + CurlOrFail -H "Content-Type: application/json" -X POST -d "$json" "$url" +} + +function SetNodeState { + local config_server_hostname="$1" + local hostname="$2" + local state="$3" + + local url="http://$config_server_hostname:19071/nodes/v2/state/$state/$hostname" + CurlOrFail -X PUT "$url" +} + +function AddCommand { + local config_server_hostname=config-server + local parent_hostname= + + OPTIND=1 + local option + while getopts "c:p:" option + do + case "$option" in + c) config_server_hostname="$OPTARG" ;; + p) parent_hostname="$OPTARG" ;; + ?) exit 1 ;; # E.g. option lacks argument, in case error has been + # already been printed + *) Fail "Unknown option '$option' with value '$OPTARG'" + esac + done + + if [ -z "$parent_hostname" ] + then + Fail "Parent hostname not specified (-d)" + fi + + shift $((OPTIND - 1)) + + if (($# == 0)) + then + Fail "No node hostnames were specified" + fi + + echo -n "Provisioning $# nodes" + + local container_hostname + for container_hostname in "$@" + do + ProvisionDockerNode "$config_server_hostname" \ + "$container_hostname" \ + "$parent_hostname" + echo -n . + done + + echo " done" +} + +function ReprovisionCommand { + local config_server_hostname=config-server + local parent_hostname= + + OPTIND=1 + local option + while getopts "c:p:" option + do + case "$option" in + c) config_server_hostname="$OPTARG" ;; + p) parent_hostname="$OPTARG" ;; + ?) exit 1 ;; # E.g. option lacks argument, in case error has been + # already been printed + *) Fail "Unknown option '$option' with value '$OPTARG'" + esac + done + + if [ -z "$parent_hostname" ] + then + Fail "Parent hostname not specified (-p)" + fi + + shift $((OPTIND - 1)) + + if (($# == 0)) + then + Fail "No node hostnames were specified" + fi + + # Simulate calls to the following commands. + SetStateCommand -c "$config_server_hostname" failed "$@" + RemoveCommand -c "$config_server_hostname" "$@" + AddCommand -c "$config_server_hostname" -p "$parent_hostname" "$@" +} + +function RemoveCommand { + local config_server_hostname=config-server + + OPTIND=1 + local option + while getopts "c:" option + do + case "$option" in + c) config_server_hostname="$OPTARG" ;; + ?) exit 1 ;; # E.g. option lacks argument, in case error has been + # already been printed + *) Fail "Unknown option '$option' with value '$OPTARG'" + esac + done + + shift $((OPTIND - 1)) + + if (($# == 0)) + then + Fail "No nodes were specified" + fi + + echo -n "Removing $# nodes" + + local hostname + for hostname in "$@" + do + local url="http://$config_server_hostname:19071/nodes/v2/node/$hostname" + CurlOrFail -X DELETE "$url" + echo -n . + done + + echo " done" +} + +function SetStateCommand { + local config_server_hostname=config-server + + OPTIND=1 + local option + while getopts "c:" option + do + case "$option" in + c) config_server_hostname="$OPTARG" ;; + ?) exit 1 ;; # E.g. option lacks argument, in case error has been + # already been printed + *) Fail "Unknown option '$option' with value '$OPTARG'" + esac + done + + shift $((OPTIND - 1)) + + if (($# <= 1)) + then + Fail "Too few arguments" + fi + + local state="$1" + shift + + echo -n "Setting $# nodes to $state" + + local hostname + for hostname in "$@" + do + SetNodeState "$config_server_hostname" "$hostname" "$state" + echo -n . + done + + echo " done" +} + +function Main { + if (($# == 0)) + then + Usage + fi + local command="$1" + shift + + case "$command" in + add) AddCommand "$@" ;; + reprovision) ReprovisionCommand "$@" ;; + rm) RemoveCommand "$@" ;; + set-state) SetStateCommand "$@" ;; + help) Usage "$@" ;; + *) Usage ;; + esac +} + +Main "$@" -- cgit v1.2.3