From 43c35b13388e4cbbdac4922bb3421700918fd915 Mon Sep 17 00:00:00 2001 From: davidplunkett Date: Fri, 8 Nov 2019 05:14:44 +0000 Subject: [PATCH] initial commit of SEBA example files Signed-off-by: davidplunkett Change-Id: Ib05f402f4ffcaecea69def3eb69b08e7c04d910a Signed-off-by: davidplunkett --- LICENSE | 1 + README.md | 16 +++ REC_blueprint.yaml | 46 +++++++++ index.rst | 165 ++++++++++++++++++++++++++++++ objects.yaml | 69 +++++++++++++ user_config.yaml | 127 +++++++++++++++++++++++ workflows/REC_create.py | 260 ++++++++++++++++++++++++++++++++++++++++++++++++ workflows/gencerts.sh | 214 +++++++++++++++++++++++++++++++++++++++ workflows/pod_create.sh | 227 ++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 1125 insertions(+) create mode 100644 README.md create mode 100644 REC_blueprint.yaml create mode 100644 index.rst create mode 100644 objects.yaml create mode 100644 user_config.yaml create mode 100755 workflows/REC_create.py create mode 100755 workflows/gencerts.sh create mode 100644 workflows/pod_create.sh diff --git a/LICENSE b/LICENSE index 261eeb9..d645695 100644 --- a/LICENSE +++ b/LICENSE @@ -1,3 +1,4 @@ + Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ diff --git a/README.md b/README.md new file mode 100644 index 0000000..e37cd24 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +Radio Edge Cloud +================ + +This repository contains the Akraino SEBA blueprint which is +intended to consumed by the Akraino Regional Controller in order to deploy the +software of the Akraino Telco Appliance blueprint familiy in a prescribed manner +onto a tested hardware configuration. + +The SEBA blueprint uses the Radio Edge Cloud (REC) build process and iso files +so you will see multiple reference to the REC in the included files. + +The SEBA blueprint may also be deployed in a semi-manual manner without the aid +of the Regional Controller, and may be deployed on hardware other than the +tested configurations, but in that case it will not be the full "appliance" that +conforms with a hardware+software configuration that was tested by the SEBA +Continuous Integration / Continuous Deployment (CI/CD) pipeline. diff --git a/REC_blueprint.yaml b/REC_blueprint.yaml new file mode 100644 index 0000000..e4f6a86 --- /dev/null +++ b/REC_blueprint.yaml @@ -0,0 +1,46 @@ +# +# Copyright (c) 2019 AT&T Intellectual Property. All rights reserved. +# +# 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 +# +# https://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 file defines version 1.0.0 of the REC (Radio Edge Cloud) blueprint, +# for use by the regional controller). It should be loaded into the RC +# (using the "rc_cli blueprint create" command) before a POD is created. +# +--- +blueprint: 1.0.0 +name: Radio Edge Cloud +version: 1.0.0 +description: This Blueprint defines an instance of the Radio Edge Cloud + (from the Telco Appliance family of blueprints). +yaml: + # Required hardware profiles (can match on either UUID or name) + # Note: UUIDs would likely require a global registry of HW profiles. + hardware_profile: + or: + - {uuid: 8a17384a-71d4-11e9-9e4c-0017f20fe1b8} + - {uuid: 9897a008-71d4-11e9-8bda-0017f20dbff8} + - {uuid: a4b4a570-71d4-11e9-adc2-0017f208759e} + workflow: + # Workflow that is invoked when the POD is created + create: + url: 'http://www.example.org/blueprints/REC/REC_create.py' + components: + # This script is used by the REC_create.py workflow to generate + # self-signed certs for the remote-installer + - 'http://www.example.org/blueprints/REC/gencerts.sh' + input_schema: + iso_primary: {type: string} + iso_secondary: {type: string} + input_yaml: {type: string} + rc_host: {type: string} diff --git a/index.rst b/index.rst new file mode 100644 index 0000000..62536b8 --- /dev/null +++ b/index.rst @@ -0,0 +1,165 @@ +.. + Copyright (c) 2019 AT&T Intellectual Property. All Rights Reserved. + + 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. + +Instructions for installing REC using the Regional Controller and the REC Blueprint +=================================================================================== + +1. The Regional Controller should already be running somewhere (hopefully on a machine or + VM dedicated for this purpose). See here_ for instructions on how to start the regional + controller. + + .. _here: https://wiki.akraino.org/display/AK/Starting+the+Regional+Controller + +2. Clone the *seba* repository using + + .. code-block:: bash + + git clone https://gerrit.akraino.org/r/seba.git + + We will use the following files from this repository: + + .. code-block:: bash + + ./REC_blueprint.yaml + ./objects.yaml + ./workflows/gencerts.sh + ./workflows/REC_create.py + + You will need to provide a web server where some of these files may be fetched by the + Regional Controller. + +3. Edit the file *objects.yaml*. + + - Update the *nodes* stanza to define the nodes in your cluster, including the Out of + Band IP address for each node, as well as the name of the hardware type. Currently REC + is defined to run on the three types of hardware listed in the *hardware* stanza. + - If you want to give the edgesite a different name, update the 'edgesites' stanza. + +4. Edit the file *REC_blueprint.yaml* to to update the URLs (the two lines that contain + ``www.example.org``) for the create workflow script (*REC_create.py*), and the + *gencerts.sh* script. These URLs should point to the web server and path where you will + store these files. The rest of the blueprint should be kept unchanged. + +5. Create and edit a copy of *user_config.yaml*. See these instructions_ on how to create + this file. + + .. _instructions: https://wiki.akraino.org/display/AK/REC+Installation+Guide#RECInstallationGuide-Aboutuser_config.yaml + +6. Copy the two workflows scripts and the *user_config.yaml* file to your web server. + Note: the provided *gencerts.sh* just generates some self-signed certificates for use + by the *remote-installer* Docker container, with some pre-defined defaults; if you want + to provide your own certificates, you will need to modify or replace this script. + Set and export the following variable: + + .. code-block:: bash + + export USER_CONFIG_URL= + +7. Clone the *api-server* repository. This provides the CLI tools used to interact with the + Regional Controller. Add the scripts from this repository to your PATH: + + .. code-block:: bash + + git clone https://gerrit.akraino.org/r/regional_controller/api-server + export PATH=$PATH:$PWD/api-server/scripts + +8. Define where the Regional Controller is located, as well as the login/password to use + (the login/password shown here are the built-in values and do not need to be changed + if you have not changed them on the Regional Controller): + + .. code-block:: bash + + export RC_HOST= + export USER=admin + export PW=admin123 + +9. Load the objects defined in *objects.yaml* into the Regional Controller using: + + .. code-block:: bash + + rc_loaddata -H $RC_HOST -u $USER -p $PW -A objects.yaml + +10. Load the blueprint into the Regional Controller using: + + .. code-block:: bash + + rc_cli -H $RC_HOST -u $USER -p $PW blueprint create REC_blueprint.yaml + +11. Get the UUIDs of the edgesite and the blueprint from the Regional Controller using: + + .. code-block:: bash + + rc_cli -H $RC_HOST -u $USER -p $PW blueprint list + rc_cli -H $RC_HOST -u $USER -p $PW edgesite list + + These are needed to create the POD. You will also see the UUID of the Blueprint displayed + when you create the Blueprint in step 10 (it is at the tail end of the URL that is printed). + Set and export them as the environment variables ESID and BPID. + + .. code-block:: bash + + export ESID= + export BPID= + +12. Figure out which REC ISO images you want to use to build your cluster. These are + located here: + https://nexus.akraino.org/content/repositories/images-snapshots/TA/release-1/images/ + Figure out which build you want, and then set and export the following variables: + + .. code-block:: bash + + export BUILD= + export ISO_PRIMARY_URL=https://nexus.akraino.org/content/repositories/images-snapshots/TA/release-1/images/$BUILD/install.iso + export ISO_SECONDARY_URL=https://nexus.akraino.org/content/repositories/images-snapshots/TA/release-1/images/$BUILD/bootcd.iso + + Note: the Akraino Release 1 image is build #9. + +13. Create the *POD.yaml* file as follows: + + .. code-block:: bash + + cat > POD.yaml < 0: + time.sleep(60) + response = requests.get(URL, cert=certs, verify=False) + j = response.json() + t = ( + str(j.get('status')), + str(j.get('percentage')), + str(j.get('description')) + ) + event = 'Status is %s (%s) %s' % t + print('%s: %s' % (datetime.datetime.now().strftime('%x %X'), event)) + if event != lastevent: + create_podevent(event) + lastevent = event + status = j.get('status') + ntimes = ntimes - 1 + return status != 'completed' + +def fetchURL(url, dest): + print('Fetching '+url+' ...') + r = requests.get(url) + with open(dest, 'wb') as f1: + f1.write(r.content) + +def initialize_RI(CLOUDNAME): + """ Create the directory structure needed by the remote-installer """ + dirs = ( + RI_DIR, + RI_DIR+'/certificates', + RI_DIR+'/images', + RI_DIR+'/installations', + RI_DIR+'/user-configs', + RI_DIR+'/user-configs/'+CLOUDNAME + ) + for dir in dirs: + if not os.path.isdir(dir): + print('mkdir '+dir) + os.mkdir(dir) + +def start_RI(client): + """ + Start the remote-installer container (assumed to already be built somewhere). + Before starting, make sure the certificates directory is populated. If not, + generate some self-signed certificates. + """ + # If needed, create certificates (11 files) in RI_DIR/certificates + if not os.path.exists(CERT_DIR+'/clientcert.pem') or not os.path.exists(CERT_DIR+'/clientkey.pem'): + print('Generating some self-signed certificates.') + script = WORKDIR + '/gencerts.sh' + cmd = 'bash %s %s' % (script, RI_DIR+'/certificates') + print('os.system('+cmd+')') + os.system(cmd) + + print('Starting %s.' % RI_NAME) + env = { + 'API_PORT': API_PORT, 'HOST_ADDR': HOST_IP, 'HTTPS_PORT': HTTPS_PORT, + 'PW': ADMIN_PASSWD, 'SSH_PORT': 22222 + } + vols = { + EXTERNALROOT+RI_DIR: {'bind': '/opt/remoteinstaller', 'mode': 'rw'} + } + try: + c = client.containers.run( + image=RI_IMAGE, + name=RI_NAME, + network_mode=NETWORK, + environment=env, + volumes=vols, + detach=True, + remove=True, + privileged=True + ) + + # Wait 5 minutes for it to be running + n = 0 + while c.status != 'running' and n < 10: + time.sleep(30) + c.reload() + n = n + 1 + if c.status != 'running' and n >= 10: + print('Container took to long to start!') + sys.exit(1) + return c + + except docker.errors.ImageNotFound as ex: + # If the specified image does not exist. + print(ex) + sys.exit(1) + + except docker.errors.APIError as ex: + # If the server returns an error. + print(ex) + sys.exit(1) + + except: + print('other error!') + sys.exit(1) diff --git a/workflows/gencerts.sh b/workflows/gencerts.sh new file mode 100755 index 0000000..8fff54a --- /dev/null +++ b/workflows/gencerts.sh @@ -0,0 +1,214 @@ +#!/bin/bash +# +# Script to create self-signed certificates in directory $1. +# + +cd $1 + +cat > openssl-ca.cnf << EOF +HOME = . +RANDFILE = \$ENV::HOME/.rnd + +#################################################################### +[ ca ] +default_ca = CA_default # The default ca section + +[ CA_default ] + +dir = /root/ca +default_days = 1000 # How long to certify for +default_crl_days = 30 # How long before next CRL +default_md = sha256 # Use public key default MD +preserve = no # Keep passed DN ordering + +x509_extensions = ca_extensions # The extensions to add to the cert + +email_in_dn = no # Don't concat the email in the DN +copy_extensions = copy # Required to copy SANs from CSR to cert + +#################################################################### +[ req ] +prompt = no +default_bits = 4096 +default_keyfile = cakey.pem +distinguished_name = ca_distinguished_name +x509_extensions = ca_extensions +string_mask = utf8only + +#################################################################### +[ ca_distinguished_name ] +countryName = FI +organizationName = Nokia OY +# commonName = Nokia +# commonName_default = Test Server +# emailAddress = test@server.com +stateOrProvinceName = Uusimaa +localityName = Espoo + +#################################################################### +[ ca_extensions ] + +subjectKeyIdentifier = hash +authorityKeyIdentifier = keyid:always, issuer +basicConstraints = critical, CA:true +keyUsage = keyCertSign, cRLSign +EOF + +cat > openssl-server.cnf << EOF +HOME = . +RANDFILE = \$ENV::HOME/.rnd + +#################################################################### +[ req ] +prompt = no +default_bits = 2048 +default_keyfile = serverkey.pem +distinguished_name = server_distinguished_name +req_extensions = server_req_extensions +string_mask = utf8only + +#################################################################### +[ server_distinguished_name ] +countryName = FI +organizationName = Nokia NET +commonName = Test Server +# emailAddress = test@server.com +stateOrProvinceName = Uusimaa +localityName = Espoo + +#################################################################### +[ server_req_extensions ] + +subjectKeyIdentifier = hash +basicConstraints = CA:FALSE +keyUsage = digitalSignature, keyEncipherment +subjectAltName = @alternate_names +nsComment = "OpenSSL Generated Certificate" + +#################################################################### +[ alternate_names ] + +DNS.1 = server.com +EOF + +cat > openssl-client.cnf << EOF +HOME = . +RANDFILE = \$ENV::HOME/.rnd + +#################################################################### +[ req ] +prompt = no +default_bits = 2048 +default_keyfile = clientkey.pem +distinguished_name = client_distinguished_name +req_extensions = client_req_extensions +string_mask = utf8only + +#################################################################### +[ client_distinguished_name ] +countryName = DE +organizationName = Customer X +commonName = Customer +emailAddress = test@client.com + +#################################################################### +[ client_req_extensions ] + +subjectKeyIdentifier = hash +basicConstraints = CA:FALSE +keyUsage = digitalSignature, keyEncipherment +subjectAltName = @alternate_names +nsComment = "OpenSSL Generated Certificate" + +#################################################################### +[ alternate_names ] + +DNS.1 = ramuller.zoo.dynamic.nsn-net.net +DNS.2 = www.client.com +DNS.3 = mail.client.com +DNS.4 = ftp.client.com +EOF + +cat > openssl-ca-sign.cnf << EOF +HOME = . +RANDFILE = \$ENV::HOME/.rnd + +#################################################################### +[ ca ] +default_ca = CA_default # The default ca section + +[ CA_default ] + +default_days = 1000 # How long to certify for +default_crl_days = 30 # How long before next CRL +default_md = sha256 # Use public key default MD +preserve = no # Keep passed DN ordering + +x509_extensions = ca_extensions # The extensions to add to the cert + +email_in_dn = no # Don't concat the email in the DN +copy_extensions = copy # Required to copy SANs from CSR to cert +base_dir = . +certificate = \$base_dir/cacert.pem # The CA certifcate +private_key = \$base_dir/cakey.pem # The CA private key +new_certs_dir = \$base_dir # Location for new certs after signing +database = \$base_dir/index.txt # Database index file +serial = \$base_dir/serial.txt # The current serial number + +unique_subject = no # Set to 'no' to allow creation of + # several certificates with same subject. + +#################################################################### +[ req ] +prompt = no +default_bits = 4096 +default_keyfile = cakey.pem +distinguished_name = ca_distinguished_name +x509_extensions = ca_extensions +string_mask = utf8only + +#################################################################### +[ ca_distinguished_name ] +countryName = FI +organizationName = Nokia OY +# commonName = Nokia +# commonName_default = Test Server +# emailAddress = test@server.com +stateOrProvinceName = Uusimaa +localityName = Espoo + +#################################################################### +[ ca_extensions ] + +subjectKeyIdentifier = hash +authorityKeyIdentifier = keyid:always, issuer +basicConstraints = critical, CA:true +keyUsage = keyCertSign, cRLSign + +#################################################################### +[ signing_policy ] +countryName = optional +stateOrProvinceName = optional +localityName = optional +organizationName = optional +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +#################################################################### +[ signing_req ] +subjectKeyIdentifier = hash +authorityKeyIdentifier = keyid,issuer +basicConstraints = CA:FALSE +keyUsage = digitalSignature, keyEncipherment +EOF + +openssl req -config openssl-ca.cnf -x509 -newkey rsa:2048 -sha256 -nodes -out cacert.pem -outform PEM +openssl req -config openssl-server.cnf -newkey rsa:2048 -sha256 -nodes -out servercert.csr -outform PEM +openssl req -config openssl-client.cnf -newkey rsa:2048 -sha256 -nodes -out clientcert.csr -outform PEM +echo -n > index.txt +echo '01' > serial.txt +echo -n > index-ri.txt +echo '01' > serial-ri.txt +echo -e "y\ny\n" | openssl ca -config openssl-ca-sign.cnf -policy signing_policy -extensions signing_req -out servercert.pem -infiles servercert.csr +echo -e "y\ny\n" | openssl ca -config openssl-ca-sign.cnf -policy signing_policy -extensions signing_req -out clientcert.pem -infiles clientcert.csr diff --git a/workflows/pod_create.sh b/workflows/pod_create.sh new file mode 100644 index 0000000..1116811 --- /dev/null +++ b/workflows/pod_create.sh @@ -0,0 +1,227 @@ +#!/bin/bash +# Copyright 2019 AT&T + +# 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. +# + +#Work-flow: +# +#0. Get values for the environment variables + +# The following must be provided. + HOST_IP= + CLOUDNAME= + ADMIN_PASSWD= + +# The next set may be modified if necessary but are best left as-is + HTTPS_PORT=8443 + API_PORT=15101 + # Max time (in minutes) to wait for the remote-installer to return completed + # Currently 2.5 hours + MAX_TIME=150 + + + # The rest should probably not be changed + WORKDIR=$(dirname $0) + BASEDIR=$WORKDIR + EXTERNALROOT=/data + NETWORK=host + + # these will come from the Blueprint file and are available in "INPUT.yaml" + tr , '\012' < $WORKDIR/INPUT.yaml |tr -d '{}'|sed -e 's/^ *//' -e 's/: /=/' >/tmp/env + . /tmp/env + REC_ISO_IMAGE_NAME=$iso_primary + REC_PROVISIONING_ISO_NAME=$iso_secondary + INPUT_YAML_URL=$input_yaml + cat < $FILENAME + +#3. Get REC booting image from REC Nexus artifacts and copy it to the images sub-directory under the directory created in (1). + + cd $BASEDIR/images/ + FILENAME=$(echo "${REC_PROVISIONING_ISO_NAME##*/}") + curl $REC_PROVISIONING_ISO_NAME > $FILENAME + +#4. Get the user-config.yaml file and admin_password file for the CD environment from the +# cd-environments repo and copy it to the user-configs sub-directory under the directory +# created in (1). Copy the files to a cloud-specific directory identified by the cloudname. + + cd $BASEDIR/user-configs/ + mkdir $CLOUDNAME + cd $CLOUDNAME + curl $INPUT_YAML_URL > user_config.yaml + ln user_config.yaml user_config.yml + echo $ADMIN_PASSWD > admin_passwd + +#5. Checkout the remote-installer repo from LF + + mkdir $BASEDIR/git + cd $BASEDIR/git + git clone https://gerrit.akraino.org/r/ta/remote-installer + +#6. Copy the sever certificates, the client certificates in addition to CA certificate to +# the certificates sub-directory under the directory created in (1). +# The following certificates are expected to be available in the directory: +# +# cacert.pem: The CA certificate +# servercert.pem: The server certificate signed by the CA +# serverkey.pem: The server key +# clientcert.pem: The client certificate signed by the CA +# clientkey.pem: The client key +# + + cd $BASEDIR/git/remote-installer/test/certificates + ./create.sh + cp *.pem $BASEDIR/certificates + +#7. Build the remote installer docker-image. + cd $BASEDIR/git/remote-installer/scripts/ + echo $0: ./build.sh "$HTTPS_PORT" "$API_PORT" + ./build.sh "$HTTPS_PORT" "$API_PORT" + +#8. Start the remote installer + + cd $BASEDIR/git/remote-installer/scripts/ + echo $0: ./start.sh -b "$EXTERNALROOT$BASEDIR" -e "$HOST_IP" -s "$HTTPS_PORT" -a "$API_PORT" -p "$ADMIN_PASSWD" + if ! ./start.sh -b "$EXTERNALROOT$BASEDIR" -e "$HOST_IP" -s "$HTTPS_PORT" -a "$API_PORT" -p "$ADMIN_PASSWD" + then + echo Failed to run workflow + exit 1 + fi + +#9. Wait for the remote installer to become running. +# check every 30 seconds to see if it has it has a status of "running" + + DOCKER_STATUS="" + + while [ ${#DOCKER_STATUS} -eq 0 ]; do + sleep 30 + + DOCKER_ID=$(docker ps | grep remote-installer | awk ' {print $1}') + DOCKER_STATUS=$(docker ps -f status=running | grep $DOCKER_ID) + done + +#10. Start the installation by sending the following http request to the installer API + +# POST url: https://localhost:$API_PORT/v1/installations +# REQ body json- encoded +# { +# 'cloudname': $CLOUDNAME, +# 'iso': $REC_ISO_IMAGE_NAME, +# 'provisioning-iso': $REC_PROVISIONING_ISO_NAME +# } +# REP body json-encoded +# { +# 'uuid': $INSTALLATION_UUID +# } + +rec=$(basename $REC_ISO_IMAGE_NAME) +boot=$(basename $REC_PROVISIONING_ISO_NAME) +cat >/tmp/data <, +# 'description': , +# 'percentage': +# } +# +# + +# check the status every minute until it has become "completed" +# (for a maximum of MAX_TIME minutes) + + STATUS="ongoing" + NTIMES=$MAX_TIME + while [ "$STATUS" == "ongoing" -a $NTIMES -gt 0 ]; do + sleep 60 + NTIMES=$((NTIMES - 1)) + RESPONSE=$(curl -k --silent \ + --cert $BASEDIR/certificates/clientcert.pem \ + --key $BASEDIR/certificates/clientkey.pem \ + https://$RI_IP:$API_PORT/v1/installations/$INSTALLATION_UUID/state) + STATUS=$(echo $RESPONSE | jq -r ".status") + PCT=$( echo $RESPONSE | jq -r ".percentage") + DESCR=$( echo $RESPONSE | jq -r ".description") + echo "$(date): Status is $STATUS ($PCT) $DESCR" + done + if [ "$STATUS" == "ongoing" -a $NTIMES -eq 0 ] + then + echo "Installation failed after $MAX_TIME minutes." + exit 1 + fi + echo "Installation complete!" + +#12. When installation is completed stop the remote installer. + + cd $BASEDIR/git/remote-installer/scripts/ + ./stop.sh + + exit 0 -- 2.16.6