diff --git a/CloudComp-openrc b/CloudComp-openrc new file mode 100644 index 0000000..402cbdf --- /dev/null +++ b/CloudComp-openrc @@ -0,0 +1,47 @@ +#!/usr/bin/env bash +# To use an OpenStack cloud you need to authenticate against the Identity +# service named keystone, which returns a **Token** and **Service Catalog**. +# The catalog contains the endpoints for all services the user/tenant has +# access to - such as Compute, Image Service, Identity, Object Storage, Block +# Storage, and Networking (code-named nova, glance, keystone, swift, +# cinder, and neutron). + +# unset all OPENSTACK ENV VARS +unset $(env | grep OS_ | cut -d "=" -f 1) + +export OS_CACERT=./root-ca.crt +export GROUP_NUMBER=0 + +# +# *NOTE*: Using the 3 *Identity API* does not necessarily mean any other +# OpenStack API is version 3. For example, your cloud provider may implement +# Image API v1.1, Block Storage API v2, and Compute API v2.0. OS_AUTH_URL is +# only for the Identity API served through keystone. +export OS_AUTH_URL=https://10.32.4.182:5000/v3 +# With the addition of Keystone we have standardized on the term **project** +# as the entity that owns the resources. +#export OS_PROJECT_ID=bba62cf6bf0b447491829d207e1b05f9 +export OS_PROJECT_NAME="CloudComp$GROUP_NUMBER" +unset OS_DOMAIN_NAME +export OS_USER_DOMAIN_NAME="Default" +if [ -z "$OS_USER_DOMAIN_NAME" ]; then unset OS_USER_DOMAIN_NAME; fi +export OS_PROJECT_DOMAIN_ID="default" +if [ -z "$OS_PROJECT_DOMAIN_ID" ]; then unset OS_PROJECT_DOMAIN_ID; fi +# unset v2.0 items in case set +unset OS_TENANT_ID +unset OS_TENANT_NAME +# In addition to the owning entity (tenant), OpenStack stores the entity +# performing the action as the **user**. +export OS_USERNAME="CloudComp$GROUP_NUMBER" +# With Keystone you pass the keystone password. +#echo "Please enter your OpenStack Password for project $OS_PROJECT_NAME as user $OS_USERNAME: " +#read -sr OS_PASSWORD_INPUT +#export OS_PASSWORD=$OS_PASSWORD_INPUT +export OS_PASSWORD="demo" +# If your configuration has multiple regions, we set that information here. +# OS_REGION_NAME is optional and only valid in certain environments. +export OS_REGION_NAME="RegionOne" +# Don't leave a blank variable, unset it if it was empty +if [ -z "$OS_REGION_NAME" ]; then unset OS_REGION_NAME; fi +export OS_INTERFACE=public +export OS_IDENTITY_API_VERSION=3 \ No newline at end of file diff --git a/demo1-getting-started.py b/demo1_getting_started.py similarity index 59% rename from demo1-getting-started.py rename to demo1_getting_started.py index 86d11f9..d8dd3ab 100644 --- a/demo1-getting-started.py +++ b/demo1_getting_started.py @@ -1,47 +1,64 @@ -# Example for Cloud Computing Course Master AI / GSD +"""Example for Cloud Computing Course Master AI / GSD""" + +# This script demonstrates how to use libcloud to start an instance in an OpenStack environment. +# The script will start an instance, list all instances, and then destroy the instance again. +# +# The script uses the libcloud library to interact with the OpenStack API. +# Need to install libcloud first: pip install apache-libcloud # -# uses libCloud: https://libcloud.apache.org/ +# libCloud: https://libcloud.apache.org/ # libCloud API documentation: https://libcloud.readthedocs.io/en/latest/ # OpenStack API documentation: https://developer.openstack.org/ -# this code was initially based on the former tutorial: https://developer.openstack.org/firstapp-libcloud/ +# this code was initially based on the former tutorial: +# https://developer.openstack.org/firstapp-libcloud/ -import getpass +# Only needed for the password prompt: +# import getpass from libcloud.compute.providers import get_driver from libcloud.compute.types import Provider -# Please use 1-29 for X in the following variable to specify your group number. (will be used for the username, -# project etc., as coordinated in the lab sessions) +# For our new Charmed OpenStack private cloud, we need to specify the path to the +# root CA certificate +import libcloud.security +libcloud.security.CA_CERTS_PATH = ['./root-ca.crt'] +# Disable SSL certificate verification (not recommended for production) +# libcloud.security.VERIFY_SSL_CERT = False + +# Please use 1-29 for 0 in the following variable to specify your group number. +# (will be used for the username, project etc., as coordinated in the lab sessions) -group_number = X +GROUP_NUMBER = 0 -######################################################################################################################## +############################################################################################### # # no changes necessary below this line in this example # -######################################################################################################################## +############################################################################################### # web service endpoint of the private cloud infrastructure -auth_url = 'https://private-cloud.informatik.hs-fulda.de:5000' +# auth_url = 'https://private-cloud.informatik.hs-fulda.de:5000' +AUTH_URL = 'https://10.32.4.182:5000' +# auth_url = 'https://private-cloud2.informatik.hs-fulda.de:5000' # your username in OpenStack -auth_username = 'CloudComp' + str(group_number) +AUTH_USERNAME = 'CloudComp' + str(GROUP_NUMBER) # your project in OpenStack -project_name = 'CloudComp' + str(group_number) +PROJECT_NAME = 'CloudComp' + str(GROUP_NUMBER) # A network in the project the started instance will be attached to -project_network = 'CloudComp' + str(group_number) + '-net' +PROJECT_NETWORK = 'CloudComp' + str(GROUP_NUMBER) + '-net' # The image to look for and use for the started instance -#ubuntu_image_name = "Ubuntu 20.04 - Focal Fossa - 64-bit - Cloud Based Image" -ubuntu_image_name = "Ubuntu 22.04 - Jammy Jellyfish - 64-bit - Cloud Based Image" +# ubuntu_image_name = "Ubuntu 18.04 - Bionic Beaver - 64-bit - Cloud Based Image" +UBUNTU_IMAGE_NAME = "auto-sync/ubuntu-jammy-22.04-amd64-server-20240319-disk1.img" # default region -region_name = 'RegionOne' -# domain to use, "default" for local accounts, "hsfulda" for RZ LDAP, e.g., using fdaiXXXX as auth_username +REGION_NAME = 'RegionOne' +# domain to use, "default" for local accounts, formerly "hsfulda" for LDAP accounts etc. # domain_name = "default" -def main(): +def main(): # noqa: C901 pylint: disable=too-many-branches,too-many-statements,too-many-locals,missing-function-docstring # get the password from user # auth_password = getpass.getpass("Enter your OpenStack password:") auth_password = "demo" @@ -50,14 +67,14 @@ def main(): # make sure to include ex_force_auth_version='3.x_password', as needed in our environment provider = get_driver(Provider.OPENSTACK) - print(("Opening connection to %s as %s..." % (auth_url, auth_username))) + print(f"Opening connection to {AUTH_URL} as {AUTH_USERNAME}...") - conn = provider(auth_username, + conn = provider(AUTH_USERNAME, auth_password, - ex_force_auth_url=auth_url, + ex_force_auth_url=AUTH_URL, ex_force_auth_version='3.x_password', - ex_tenant_name=project_name, - ex_force_service_region=region_name) + ex_tenant_name=PROJECT_NAME, + ex_force_service_region=REGION_NAME) # ex_domain_name=domain_name) print("Getting images and selecting desired one...") @@ -67,7 +84,7 @@ def main(): images = conn.list_images() image = '' for img in images: - if img.name == ubuntu_image_name: + if img.name == UBUNTU_IMAGE_NAME: image = img print(img) @@ -94,7 +111,7 @@ def main(): networks = conn.ex_list_networks() network = '' for net in networks: - if net.name == project_network: + if net.name == PROJECT_NETWORK: network = net print("Create instance 'testing'...") @@ -103,7 +120,8 @@ def main(): # create a new instance with the name "testing" # make sure to provide networks (networks={network}) the instance should be attached to instance_name = 'testing' - testing_instance = conn.create_node(name=instance_name, image=image, size=flavor, networks={network}) + testing_instance = conn.create_node(name=instance_name, image=image, size=flavor, + networks={network}) print(testing_instance) print("Showing all running instances...") diff --git a/demo2-instance-with-init-script.py b/demo2_instance_with_init_script.py similarity index 56% rename from demo2-instance-with-init-script.py rename to demo2_instance_with_init_script.py index dc5130c..881ee9c 100644 --- a/demo2-instance-with-init-script.py +++ b/demo2_instance_with_init_script.py @@ -1,47 +1,75 @@ +"""Example for Cloud Computing Course Master AI / GSD""" + +# This script demonstrates how to use libcloud to start an instance in an OpenStack environment. +# The script will create and install a new SSH key pair, create a security group, start an instance +# and deploy a demo app (faafo) using cloud-init and assign a floating IP to the instance. +# +# cloud-init is a multi-distribution package that handles early initialization of a cloud instance. +# It is supported by many major cloud providers, including OpenStack. +# cloud-init documentation: https://cloudinit.readthedocs.io/en/latest/ + +# Needed if the password should be prompted for: # import getpass -# import os +import os +import sys from libcloud.compute.providers import get_driver from libcloud.compute.types import Provider -# Please use 1-29 for X in the following variable to specify your group number. (will be used for the username, -# project etc., as coordinated in the lab sessions) +# For our new Charmed OpenStack private cloud, we need to specify the path to the root +# CA certificate +import libcloud.security +libcloud.security.CA_CERTS_PATH = ['./root-ca.crt'] +# Disable SSL certificate verification (not recommended for production) +# libcloud.security.VERIFY_SSL_CERT = False + +# Please use 1-29 as environment variable GROUP_NUMBER to specify your group number. +# (will be used for the username, project etc., as coordinated in the lab sessions) -group_number = X +group_number = os.environ.get('GROUP_NUMBER') +if group_number is None: + sys.exit('Please set the GROUP_NUMBER environment variable to your group number,\n' + 'e.g., on Windows:\n' + ' "$env:GROUP_NUMBER=0" or "set GROUP_NUMBER=0"\n' + 'or on Linux/MacOS:\n' + ' "export GROUP_NUMBER=0" or "set GROUP_NUMBER=0"') # web service endpoint of the private cloud infrastructure -auth_url = 'https://private-cloud.informatik.hs-fulda.de:5000' +# auth_url = 'https://private-cloud.informatik.hs-fulda.de:5000' +AUTH_URL = 'https://10.32.4.182:5000' +# auth_url = 'https://private-cloud2.informatik.hs-fulda.de:5000' # your username in OpenStack -auth_username = 'CloudComp' + str(group_number) +AUTH_USERNAME = 'CloudComp' + str(group_number) +print(f'Using username: {AUTH_USERNAME}\n') # your project in OpenStack -project_name = 'CloudComp' + str(group_number) +PROJECT_NAME = 'CloudComp' + str(group_number) # A network in the project the started instance will be attached to -project_network = 'CloudComp' + str(group_number) + '-net' +PROJECT_NETWORK = 'CloudComp' + str(group_number) + '-net' # The image to look for and use for the started instance -#ubuntu_image_name = "Ubuntu 20.04 - Focal Fossa - 64-bit - Cloud Based Image" -ubuntu_image_name = "Ubuntu 22.04 - Jammy Jellyfish - 64-bit - Cloud Based Image" +# ubuntu_image_name = "Ubuntu 18.04 - Bionic Beaver - 64-bit - Cloud Based Image" +UBUNTU_IMAGE_NAME = "auto-sync/ubuntu-jammy-22.04-amd64-server-20240319-disk1.img" -# The public key to be used for SSH connection, please make sure, that you have the corresponding private key +# The public key to be used for SSH connection, please make sure, that you have the +# corresponding private key # # id_rsa.pub should look like this (standard sshd pubkey format): # ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAw+J...F3w2mleybgT1w== user@HOSTNAME -#keypair_name = 'CloudComp30-keypair' -keypair_name = "srieger-pub" -pub_key_file = '~/.ssh/id_rsa.pub' +KEYPAIR_NAME = 'srieger-pub' +PUB_KEY_FILE = '~/.ssh/id_rsa.pub' -flavor_name = 'm1.small' +FLAVOR_NAME = 'm1.small' # default region -region_name = 'RegionOne' -# domain to use, "default" for local accounts, "hsfulda" for RZ LDAP, e.g., using fdaiXXXX as auth_username +REGION_NAME = 'RegionOne' +# domain to use, "default" for local accounts, formerly "hsfulda" for LDAP accounts etc. # domain_name = "default" -def main(): +def main(): # noqa: C901 pylint: disable=too-many-branches,too-many-statements,too-many-locals,missing-function-docstring ########################################################################### # # get credentials @@ -61,12 +89,12 @@ def main(): ########################################################################### provider = get_driver(Provider.OPENSTACK) - conn = provider(auth_username, + conn = provider(AUTH_USERNAME, auth_password, - ex_force_auth_url=auth_url, + ex_force_auth_url=AUTH_URL, ex_force_auth_version='3.x_password', - ex_tenant_name=project_name, - ex_force_service_region=region_name) + ex_tenant_name=PROJECT_NAME, + ex_force_service_region=REGION_NAME) # ex_domain_name=domain_name) ########################################################################### @@ -77,19 +105,19 @@ def main(): images = conn.list_images() image = '' for img in images: - if img.name == ubuntu_image_name: + if img.name == UBUNTU_IMAGE_NAME: image = img flavors = conn.list_sizes() flavor = '' for flav in flavors: - if flav.name == flavor_name: + if flav.name == FLAVOR_NAME: flavor = conn.ex_get_size(flav.id) networks = conn.ex_list_networks() network = '' for net in networks: - if net.name == project_network: + if net.name == PROJECT_NETWORK: network = net ########################################################################### @@ -101,14 +129,14 @@ def main(): print('Checking for existing SSH key pair...') keypair_exists = False for keypair in conn.list_key_pairs(): - if keypair.name == keypair_name: + if keypair.name == KEYPAIR_NAME: keypair_exists = True if keypair_exists: - print(('Keypair ' + keypair_name + ' already exists. Skipping import.')) + print('Keypair ' + KEYPAIR_NAME + ' already exists. Skipping import.') else: print('adding keypair...') - conn.import_key_pair_from_file(keypair_name, pub_key_file) + conn.import_key_pair_from_file(KEYPAIR_NAME, PUB_KEY_FILE) for keypair in conn.list_key_pairs(): print(keypair) @@ -129,10 +157,12 @@ def main(): security_group_exists = True if security_group_exists: - print(('Security Group ' + all_in_one_security_group.name + ' already exists. Skipping creation.')) + print('Security Group ' + all_in_one_security_group.name + ' already exists. ' + 'Skipping creation.') else: all_in_one_security_group = conn.ex_create_security_group(security_group_name, - 'network access for all-in-one application.') + 'network access for ' + 'all-in-one application.') conn.ex_create_security_group_rule(all_in_one_security_group, 'TCP', 80, 80) conn.ex_create_security_group_rule(all_in_one_security_group, 'TCP', 22, 22) @@ -145,14 +175,14 @@ def main(): # ########################################################################### - #hsfd_faafo_cloud_init_script = 'https://gogs.informatik.hs-fulda.de/srieger/cloud-computing-msc-ai-examples/raw/master/faafo/contrib/install.sh' + hsfd_faafo_cloud_init_script = 'https://gogs.informatik.hs-fulda.de/srieger/cloud-computing-msc-ai-examples/raw/master/faafo/contrib/install.sh' # noqa: E501 pylint: disable=line-too-long # testing / faafo dev branch: - hsfd_faafo_cloud_init_script = 'https://gogs.informatik.hs-fulda.de/srieger/cloud-computing-msc-ai-examples/raw/branch/dev_faafo/faafo/contrib/install.sh' + # hsfd_faafo_cloud_init_script = 'https://gogs.informatik.hs-fulda.de/srieger/cloud-computing-msc-ai-examples/raw/branch/dev_faafo/faafo/contrib/install.sh' # noqa: E501 pylint: disable=line-too-long - userdata = '''#!/usr/bin/env bash - curl -L -s ''' + hsfd_faafo_cloud_init_script + ''' | bash -s -- \ - -i faafo -i messaging -r api -r worker -r demo - ''' + userdata = '#!/usr/bin/env bash\n' \ + f'curl -L -s {hsfd_faafo_cloud_init_script} | bash -s -- ' \ + '-i faafo -i messaging -r api -r worker -r demo\n' + print('\nUsing cloud-init userdata:\n"' + userdata + '"\n') print('Checking for existing instance...') instance_name = 'all-in-one' @@ -164,7 +194,7 @@ def main(): instance_exists = True if instance_exists: - print(('Instance ' + testing_instance.name + ' already exists. Skipping creation.')) + print('Instance ' + testing_instance.name + ' already exists. Skipping creation.') exit() else: print('Starting new all-in-one instance and wait until it is running...') @@ -172,7 +202,7 @@ def main(): image=image, size=flavor, networks=[network], - ex_keyname=keypair_name, + ex_keyname=KEYPAIR_NAME, ex_userdata=userdata, ex_security_groups=[all_in_one_security_group]) conn.wait_until_running(nodes=[testing_instance], timeout=120, ssh_interface='private_ips') @@ -186,12 +216,12 @@ def main(): private_ip = None if len(testing_instance.private_ips): private_ip = testing_instance.private_ips[0] - print(('Private IP found: {}'.format(private_ip))) + print(f'Private IP found: {private_ip}') public_ip = None if len(testing_instance.public_ips): public_ip = testing_instance.public_ips[0] - print(('Public IP found: {}'.format(public_ip))) + print(f'Public IP found: {public_ip}') print('Checking for unused Floating IP...') unused_floating_ip = None @@ -202,11 +232,11 @@ def main(): if not unused_floating_ip and len(conn.ex_list_floating_ip_pools()): pool = conn.ex_list_floating_ip_pools()[0] - print(('Allocating new Floating IP from pool: {}'.format(pool))) + print(f'Allocating new Floating IP from pool: {pool}') unused_floating_ip = pool.create_floating_ip() if public_ip: - print(('Instance ' + testing_instance.name + ' already has a public ip. Skipping attachment.')) + print('Instance ' + testing_instance.name + ' already has a public ip. Skipping attachment.') elif unused_floating_ip: conn.ex_attach_floating_ip_to_node(testing_instance, unused_floating_ip) @@ -218,17 +248,20 @@ def main(): elif private_ip: actual_ip_address = private_ip - print('\n') - print(('The Fractals app will be deployed to http://{}\n'.format(actual_ip_address))) + print('\n\n#### Deployment finished\n\n') + print('After some minutes, as soon as cloud-init installed required packages and the\n' + 'faafo app, (First App Application For OpenStack) fractals demo will be available\n' + f'at http://{actual_ip_address}\n') print('You can use ssh to login to the instance using your private key. Default user name for official Ubuntu\n' - 'Cloud Images is: ubuntu, so you can use, e.g.: "ssh -i ~/.ssh/id_rsa ubuntu@" if your private\n' - 'key is in the default location.\n\n' - 'After login, you can list or "ssh ubuntu@" available fractals using "faafo list". To request\n' - 'the generation of new fractals, you can use "faafo create".\n\n' + f'Cloud Images is: ubuntu, so you can use, e.g.: "ssh -i ~/.ssh/id_rsa ubuntu@{actual_ip_address}" if your\n' + 'private key is in the default location.\n\n' + 'After login, you can list available fractals using "faafo list". \n' + 'To request the generation of new fractals, you can use "faafo create".\n\n' 'You can also see other options to use the faafo example cloud service using "faafo -h".\n\n' 'If you cannot start faafo command and/or do not see the webpage, you can check the Instance Console Log of\n' - 'the instance, e.g., in OpenStack web interface.') + 'the instance, e.g., in OpenStack web interface or look at "tail -f /var/log/cloud-init*.log" for the\n' + 'cloud-init log files.\n') if __name__ == '__main__': diff --git a/demo3-microservice.py b/demo3_microservice.py similarity index 60% rename from demo3-microservice.py rename to demo3_microservice.py index f5e616a..1fbb48b 100644 --- a/demo3-microservice.py +++ b/demo3_microservice.py @@ -1,51 +1,73 @@ +"""Example for Cloud Computing Course Master AI / GSD""" + +# This script demonstrates how to use libcloud to start an instance in an OpenStack environment. +# The script will create start multiple instances splitting up the faafo monolithic application into +# a (minimalistic but already scalable) microservice architecture. +# Also introduces the concept of different security groups and corresponding frontend/backend +# separation. + +# Needed if the password should be prompted for: # import getpass -# import os +import os +import sys from libcloud.compute.providers import get_driver from libcloud.compute.types import Provider -# reqs: -# services: nova, glance, neutron -# resources: 2 instances, 2 floating ips (1 keypair, 2 security groups) +# For our new Charmed OpenStack private cloud, we need to specify the path to the root +# CA certificate +import libcloud.security +libcloud.security.CA_CERTS_PATH = ['./root-ca.crt'] +# Disable SSL certificate verification (not recommended for production) +# libcloud.security.VERIFY_SSL_CERT = False -# Please use 1-29 for X in the following variable to specify your group number. (will be used for the username, -# project etc., as coordinated in the lab sessions) +# Please use 1-29 as environment variable GROUP_NUMBER to specify your group number. +# (will be used for the username, project etc., as coordinated in the lab sessions) -group_number = X +group_number = os.environ.get('GROUP_NUMBER') +if group_number is None: + sys.exit('Please set the GROUP_NUMBER environment variable to your group number,\n' + 'e.g., on Windows:\n' + ' "$env:GROUP_NUMBER=0" or "set GROUP_NUMBER=0"\n' + 'or on Linux/MacOS:\n' + ' "export GROUP_NUMBER=0" or "set GROUP_NUMBER=0"') # web service endpoint of the private cloud infrastructure -auth_url = 'https://private-cloud.informatik.hs-fulda.de:5000' +# auth_url = 'https://private-cloud.informatik.hs-fulda.de:5000' +AUTH_URL = 'https://10.32.4.182:5000' +# auth_url = 'https://private-cloud2.informatik.hs-fulda.de:5000' # your username in OpenStack -auth_username = 'CloudComp' + str(group_number) +AUTH_USERNAME = 'CloudComp' + str(group_number) +print(f'Using username: {AUTH_USERNAME}\n') # your project in OpenStack -project_name = 'CloudComp' + str(group_number) +PROJECT_NAME = 'CloudComp' + str(group_number) # A network in the project the started instance will be attached to -project_network = 'CloudComp' + str(group_number) + '-net' +PROJECT_NETWORK = 'CloudComp' + str(group_number) + '-net' # The image to look for and use for the started instance -#ubuntu_image_name = "Ubuntu 20.04 - Focal Fossa - 64-bit - Cloud Based Image" -ubuntu_image_name = "Ubuntu 22.04 - Jammy Jellyfish - 64-bit - Cloud Based Image" +# ubuntu_image_name = "Ubuntu 18.04 - Bionic Beaver - 64-bit - Cloud Based Image" +UBUNTU_IMAGE_NAME = "auto-sync/ubuntu-jammy-22.04-amd64-server-20240319-disk1.img" -# The public key to be used for SSH connection, please make sure, that you have the corresponding private key +# The public key to be used for SSH connection, please make sure, that you have the +# corresponding private key # # id_rsa.pub should look like this (standard sshd pubkey format): # ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAw+J...F3w2mleybgT1w== user@HOSTNAME -#keypair_name = 'CloudComp30-keypair' -keypair_name = "srieger-pub" -pub_key_file = '~/.ssh/id_rsa.pub' +KEYPAIR_NAME = 'srieger-pub' +PUB_KEY_FILE = '~/.ssh/id_rsa.pub' -flavor_name = 'm1.small' +FLAVOR_NAME = 'm1.small' # default region -region_name = 'RegionOne' -# domain to use, "default" for local accounts, "hsfulda" for RZ LDAP, e.g., using fdaiXXXX as auth_username +REGION_NAME = 'RegionOne' +# domain to use, "default" for local accounts, formerly "hsfulda" for LDAP accounts etc. # domain_name = "default" -def main(): +def main(): # noqa: C901 pylint: disable=too-many-branches,too-many-statements,too-many-locals,missing-function-docstring ########################################################################### # # get credentials @@ -65,12 +87,12 @@ def main(): ########################################################################### provider = get_driver(Provider.OPENSTACK) - conn = provider(auth_username, + conn = provider(AUTH_USERNAME, auth_password, - ex_force_auth_url=auth_url, + ex_force_auth_url=AUTH_URL, ex_force_auth_version='3.x_password', - ex_tenant_name=project_name, - ex_force_service_region=region_name) + ex_tenant_name=PROJECT_NAME, + ex_force_service_region=REGION_NAME) # ex_domain_name=domain_name) ########################################################################### @@ -82,19 +104,19 @@ def main(): images = conn.list_images() image = '' for img in images: - if img.name == ubuntu_image_name: + if img.name == UBUNTU_IMAGE_NAME: image = img flavors = conn.list_sizes() flavor = '' for flav in flavors: - if flav.name == flavor_name: + if flav.name == FLAVOR_NAME: flavor = conn.ex_get_size(flav.id) networks = conn.ex_list_networks() network = '' for net in networks: - if net.name == project_network: + if net.name == PROJECT_NETWORK: network = net ########################################################################### @@ -106,14 +128,14 @@ def main(): print('Checking for existing SSH key pair...') keypair_exists = False for keypair in conn.list_key_pairs(): - if keypair.name == keypair_name: + if keypair.name == KEYPAIR_NAME: keypair_exists = True if keypair_exists: - print(('Keypair ' + keypair_name + ' already exists. Skipping import.')) + print('Keypair ' + KEYPAIR_NAME + ' already exists. Skipping import.') else: print('adding keypair...') - conn.import_key_pair_from_file(keypair_name, pub_key_file) + conn.import_key_pair_from_file(KEYPAIR_NAME, PUB_KEY_FILE) for keypair in conn.list_key_pairs(): print(keypair) @@ -134,9 +156,11 @@ def main(): security_group_exists = True if security_group_exists: - print(('Worker Security Group ' + worker_security_group.name + ' already exists. Skipping creation.')) + print('Worker Security Group ' + worker_security_group.name + ' already exists. ' + 'Skipping creation.') else: - worker_security_group = conn.ex_create_security_group('worker', 'for services that run on a worker node') + worker_security_group = conn.ex_create_security_group('worker', 'for services ' + 'that run on a worker node') conn.ex_create_security_group_rule(worker_security_group, 'TCP', 22, 22) print('Checking for existing controller security group...') @@ -149,9 +173,11 @@ def main(): security_group_exists = True if security_group_exists: - print(('Controller Security Group ' + controller_security_group.name + ' already exists. Skipping creation.')) + print('Controller Security Group ' + controller_security_group.name + ' already exists. ' + 'Skipping creation.') else: - controller_security_group = conn.ex_create_security_group('control', 'for services that run on a control node') + controller_security_group = conn.ex_create_security_group('control', 'for services that ' + 'run on a control node') conn.ex_create_security_group_rule(controller_security_group, 'TCP', 22, 22) conn.ex_create_security_group_rule(controller_security_group, 'TCP', 80, 80) conn.ex_create_security_group_rule(controller_security_group, 'TCP', 5672, 5672, @@ -166,24 +192,18 @@ def main(): # ########################################################################### - #hsfd_faafo_cloud_init_script = 'https://gogs.informatik.hs-fulda.de/srieger/cloud-computing-msc-ai-examples/raw/master/faafo/contrib/install.sh' - # testing / faafo dev branch: - hsfd_faafo_cloud_init_script = 'https://gogs.informatik.hs-fulda.de/srieger/cloud-computing-msc-ai-examples/raw/branch/dev_faafo/faafo/contrib/install.sh' - - userdata = '''#!/usr/bin/env bash - curl -L -s ''' + hsfd_faafo_cloud_init_script + ''' | bash -s -- \ - -i messaging -i faafo -r api - rabbitmqctl add_user faafo guest - rabbitmqctl set_user_tags faafo administrator - rabbitmqctl set_permissions -p / faafo ".*" ".*" ".*" - ''' + userdata = '#!/usr/bin/env bash\n' \ + 'curl -L -s https://gogs.informatik.hs-fulda.de/srieger/cloud-computing-msc-ai-' \ + 'examples/raw/master/faafo/contrib/install.sh | bash -s -- ' \ + '-i messaging -i faafo -r api\n' + print('\nUsing cloud-init userdata for controller:\n"' + userdata + '"\n') print('Starting new app-controller instance and wait until it is running...') instance_controller_1 = conn.create_node(name='app-controller', image=image, size=flavor, networks=[network], - ex_keyname=keypair_name, + ex_keyname=KEYPAIR_NAME, ex_userdata=userdata, ex_security_groups=[controller_security_group]) @@ -204,11 +224,12 @@ def main(): if not unused_floating_ip: pool = conn.ex_list_floating_ip_pools()[0] - print(('Allocating new Floating IP from pool: {}'.format(pool))) + print(f'Allocating new Floating IP from pool: {pool}') unused_floating_ip = pool.create_floating_ip() conn.ex_attach_floating_ip_to_node(instance_controller_1, unused_floating_ip) - print(('Controller Application will be deployed to http://%s' % unused_floating_ip.ip_address)) + print(f'Controller Application will be deployed to http://{unused_floating_ip.ip_address}') + actual_ip_address = unused_floating_ip.ip_address ########################################################################### # @@ -218,6 +239,7 @@ def main(): # instance should not have a public ip? floating ips are assigned later instance_controller_1 = conn.ex_get_node_details(instance_controller_1.id) + ip_controller = '' if instance_controller_1.public_ips: ip_controller = instance_controller_1.public_ips[0] else: @@ -229,17 +251,19 @@ def main(): # ########################################################################### - userdata = '''#!/usr/bin/env bash - curl -L -s ''' + hsfd_faafo_cloud_init_script + ''' | bash -s -- \ - -i faafo -r worker -e 'http://%(ip_controller)s' -m 'amqp://faafo:guest@%(ip_controller)s:5672/' - ''' % {'ip_controller': ip_controller} + userdata = '#!/usr/bin/env bash\n' \ + 'curl -L -s https://gogs.informatik.hs-fulda.de/srieger/cloud-computing-msc-ai-' \ + 'examples/raw/master/faafo/contrib/install.sh | bash -s -- ' \ + f'-i faafo -r worker -e "http://{ip_controller}" -m "amqp://faafo:guest@' \ + f'{ip_controller}:5672/"\n' + print('\nUsing cloud-init userdata for worker:\n"' + userdata + '"\n') print('Starting new app-worker-1 instance and wait until it is running...') instance_worker_1 = conn.create_node(name='app-worker-1', image=image, size=flavor, networks=[network], - ex_keyname=keypair_name, + ex_keyname=KEYPAIR_NAME, ex_userdata=userdata, ex_security_groups=[worker_security_group]) @@ -260,15 +284,23 @@ def main(): if not unused_floating_ip: pool = conn.ex_list_floating_ip_pools()[0] - print(('Allocating new Floating IP from pool: {}'.format(pool))) + print(f'Allocating new Floating IP from pool: {pool}') unused_floating_ip = pool.create_floating_ip() conn.ex_attach_floating_ip_to_node(instance_worker_1, unused_floating_ip) - print(('The worker will be available for SSH at %s' % unused_floating_ip.ip_address)) - - print('You can use ssh to login to the controller using your private key. After login, you can list available ' - 'fractals using "faafo list". To request the generation of new fractals, you can use "faafo create". ' - 'You can also see other options to use the faafo example cloud service using "faafo -h".') + print(f'The worker will be available for SSH at {unused_floating_ip.ip_address}') + + print('\n\n#### Deployment finished\n\n') + print('After some minutes, as soon as cloud-init installed required packages and the\n' + 'faafo app, (First App Application For OpenStack) fractals demo will be available\n' + f'at http://{actual_ip_address}\n') + + print('You can use ssh to login to the controller using your private key.\n' + f'E.g., "ssh -i ~/.ssh/id_rsa ubuntu@{actual_ip_address}". After login,\n' + 'you can list available fractals using "faafo list". To request the generation of\n' + 'new fractals, you can use "faafo create". \n' + 'You can also see other options to use the faafo example cloud service using ' + '"faafo -h".') if __name__ == '__main__': diff --git a/destroy-all-demo-instances.py b/destroy-all-demo-instances.py deleted file mode 100644 index fe4aeb9..0000000 --- a/destroy-all-demo-instances.py +++ /dev/null @@ -1,97 +0,0 @@ -# import getpass -# import os -# import libcloud.security - -import time -from libcloud.compute.providers import get_driver -from libcloud.compute.types import Provider - -# reqs: -# services: nova, glance, neutron -# resources: 2 instances (m1.small), 2 floating ips (1 keypair, 2 security groups) - -# Please use 1-29 for X in the following variable to specify your group number. (will be used for the username, -# project etc., as coordinated in the lab sessions) - -group_number = X - - -# web service endpoint of the private cloud infrastructure -auth_url = 'https://private-cloud.informatik.hs-fulda.de:5000' -# your username in OpenStack -auth_username = 'CloudComp' + str(group_number) -# your project in OpenStack -project_name = 'CloudComp' + str(group_number) - - -# default region -region_name = 'RegionOne' -# domain to use, "default" for local accounts, "hsfulda" for RZ LDAP, e.g., using fdaiXXXX as auth_username -domain_name = "default" - - -def main(): - ########################################################################### - # - # get credentials - # - ########################################################################### - - # if "OS_PASSWORD" in os.environ: - # auth_password = os.environ["OS_PASSWORD"] - # else: - # auth_password = getpass.getpass("Enter your OpenStack password:") - auth_password = "demo" - - ########################################################################### - # - # create connection - # - ########################################################################### - - # libcloud.security.VERIFY_SSL_CERT = False - - provider = get_driver(Provider.OPENSTACK) - conn = provider(auth_username, - auth_password, - ex_force_auth_url=auth_url, - ex_force_auth_version='3.x_password', - ex_tenant_name=project_name, - ex_force_service_region=region_name, - ex_domain_name=domain_name) - - ########################################################################### - # - # clean up resources from previous demos - # - ########################################################################### - - # destroy running demo instances - for instance in conn.list_nodes(): - if instance.name in ['all-in-one', 'app-worker-1', 'app-worker-2', 'app-worker-3', 'app-controller', - 'app-services', 'app-api-1', 'app-api-2']: - print(('Destroying Instance: %s' % instance.name)) - conn.destroy_node(instance) - - # wait until all nodes are destroyed to be able to remove depended security groups - nodes_still_running = True - while nodes_still_running: - nodes_still_running = False - time.sleep(3) - instances = conn.list_nodes() - for instance in instances: - # if we see any demo instances still running continue to wait for them to stop - if instance.name in ['all-in-one', 'app-worker-1', 'app-worker-2', 'app-worker-3', 'app-controller', - 'app-services', 'app-api-1', 'app-api-2']: - nodes_still_running = True - print('There are still instances running, waiting for them to be destroyed...') - - # delete security groups - for group in conn.ex_list_security_groups(): - if group.name in ['control', 'worker', 'api', 'services']: - print(('Deleting security group: %s' % group.name)) - conn.ex_delete_security_group(group) - - -if __name__ == '__main__': - main() diff --git a/destroy_all_demo_instances.py b/destroy_all_demo_instances.py new file mode 100644 index 0000000..1173ea8 --- /dev/null +++ b/destroy_all_demo_instances.py @@ -0,0 +1,126 @@ +"""Example for Cloud Computing Course Master AI / GSD""" + + +# This script demonstrates how to use libcloud to cleanup all instances used in the demos +# for our OpenStack private cloud environment. + +# import getpass +import os +import sys + +import time +from libcloud.compute.providers import get_driver +from libcloud.compute.types import Provider + +# For our new Charmed OpenStack private cloud, we need to specify the path to the +# root CA certificate +import libcloud.security +libcloud.security.CA_CERTS_PATH = ['./root-ca.crt'] +# Disable SSL certificate verification (not recommended for production) +# libcloud.security.VERIFY_SSL_CERT = False + +# Please use 1-29 for X in the following variable to specify your group number. +# (will be used for the username, project etc., as coordinated in the lab sessions) + +group_number = os.environ.get('GROUP_NUMBER') +if group_number is None: + sys.exit('Please set the GROUP_NUMBER environment variable to your group number,\n' + 'e.g., on Windows:\n' + ' "$env:GROUP_NUMBER=0" or "set GROUP_NUMBER=0"\n' + 'or on Linux/MacOS:\n' + ' "export GROUP_NUMBER=0" or "set GROUP_NUMBER=0"') + + +############################################################################################### +# +# no changes necessary below this line in this example +# +############################################################################################### + +# web service endpoint of the private cloud infrastructure +# auth_url = 'https://private-cloud.informatik.hs-fulda.de:5000' +AUTH_URL = 'https://10.32.4.182:5000' +# auth_url = 'https://private-cloud2.informatik.hs-fulda.de:5000' +# your username in OpenStack +AUTH_USERNAME = 'CloudComp' + str(group_number) +# your project in OpenStack +PROJECT_NAME = 'CloudComp' + str(group_number) +# A network in the project the started instance will be attached to +PROJET_NETWORK = 'CloudComp' + str(group_number) + '-net' + +# The image to look for and use for the started instance +# ubuntu_image_name = "Ubuntu 18.04 - Bionic Beaver - 64-bit - Cloud Based Image" +UBUNTU_IMAGE_NAME = "auto-sync/ubuntu-jammy-22.04-amd64-server-20240319-disk1.img" + +# default region +REGION_NAME = 'RegionOne' +# domain to use, "default" for local accounts, formerly "hsfulda" for LDAP accounts etc. +# domain_name = "default" + + +def main(): # noqa: C901 pylint: disable=too-many-branches,too-many-statements,too-many-locals,missing-function-docstring + ########################################################################### + # + # get credentials + # + ########################################################################### + + # if "OS_PASSWORD" in os.environ: + # auth_password = os.environ["OS_PASSWORD"] + # else: + # auth_password = getpass.getpass("Enter your OpenStack password:") + auth_password = "demo" + + ########################################################################### + # + # create connection + # + ########################################################################### + + # libcloud.security.VERIFY_SSL_CERT = False + + provider = get_driver(Provider.OPENSTACK) + conn = provider(AUTH_USERNAME, + auth_password, + ex_force_auth_url=AUTH_URL, + ex_force_auth_version='3.x_password', + ex_tenant_name=PROJECT_NAME, + ex_force_service_region=REGION_NAME) +# ex_domain_name=domain_name) + + ########################################################################### + # + # clean up resources from previous demos + # + ########################################################################### + + # destroy running demo instances + for instance in conn.list_nodes(): + if instance.name in ['all-in-one', 'app-worker-1', 'app-worker-2', 'app-worker-3', + 'app-controller', + 'app-services', 'app-api-1', 'app-api-2']: + print(f'Destroying Instance: {instance.name}') + conn.destroy_node(instance) + + # wait until all nodes are destroyed to be able to remove depended security groups + nodes_still_running = True + while nodes_still_running: + nodes_still_running = False + time.sleep(3) + instances = conn.list_nodes() + for instance in instances: + # if we see any demo instances still running continue to wait for them to stop + if instance.name in ['all-in-one', 'app-worker-1', 'app-worker-2', 'app-worker-3', + 'app-controller', 'app-services', 'app-api-1', 'app-api-2']: + nodes_still_running = True + print('There are still instances running, waiting for them to be destroyed...') + + # delete security groups + for group in conn.ex_list_security_groups(): + if group.name in ['control', 'worker', 'api', 'services']: + print(f'Deleting security group: {group.name}') + conn.ex_delete_security_group(group) + + +if __name__ == '__main__': + main() diff --git a/root-ca.crt b/root-ca.crt new file mode 100644 index 0000000..1fcd3e7 --- /dev/null +++ b/root-ca.crt @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDazCCAlOgAwIBAgIUEQjSqiZ86fhawQU09G8hn3i9dIwwDQYJKoZIhvcNAQEL +BQAwPTE7MDkGA1UEAxMyVmF1bHQgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkg +KGNoYXJtLXBraS1sb2NhbCkwHhcNMjQwMzI1MTMxNDU0WhcNMzQwMzIzMTIxNTIz +WjA9MTswOQYDVQQDEzJWYXVsdCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAo +Y2hhcm0tcGtpLWxvY2FsKTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +ALcax5l2zU1ELCtF/k6yq3HUv7gFq6f/sl8rX0VRhzZyEy4hcMgRSZDAM14viTVZ +8d7+ptY3+GwuLSpEY2UUlX5kJSDb4pUNRXDhxzRatbByG8pr5FQE8pX9W7y4C0TU +3PQA4uIjAsPFKayFxXjJjOQN0HX3K6MCQz/BTV81U3fmdFrKma3x/PXyUYndjQH6 +zlIiQSdYh7FMTbS2FlpvwWbT9zKOpp+2M0odI8Y8fjCSUdSdKDFhVu02zQTq6/h0 +Q1/sNHz2IP9F83sNW+ro0bvv5CJ2iCyAk/RiFoB+RoSO6HncOtYHxa/guwTy4eHh +VQVJXkEI2PutCw6S3lWqLEcCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgEGMA8GA1Ud +EwEB/wQFMAMBAf8wHQYDVR0OBBYEFDKQHfpVHJgge6RRC5uDwMByLbV3MB8GA1Ud +IwQYMBaAFDKQHfpVHJgge6RRC5uDwMByLbV3MA0GCSqGSIb3DQEBCwUAA4IBAQCa +ajIRi/+7Yy7l46yFURLyELMWayRpdx2KCxIuAiSkTlNSVOPCmwZvgnYLPVffXWpt +IXJGQk//9+5q18LiZat5MbvUU3ffLc/ZCxIeQiWNuYKziLYNFHmpfMvxNxzAJ6Pi +2fj5ZP/cA4Vie3M1iHfdSXmYPvyw76i9/sA2+F7Wy8fzK53S1OaMaeADNGljHTaW +ovRxreLKJZybqe/YWlcEiP4dC4VMHLl+H5RmZ5ojrRiy1c3uUssNnIJU+ilkY8TP +0VV17+wQBaJbbp4jh8acwvOJbN8Y1EHQWhxkEf3PfjJRv+b1NI/Iai27DfYto7Dm +rZvaFnAMCcyFXyJv3WdJ +-----END CERTIFICATE----- \ No newline at end of file