From 5e17f171ba069d87c343edbdd8a2e6ad374d49dc Mon Sep 17 00:00:00 2001 From: Sebastian Rieger Date: Fri, 12 Apr 2024 13:51:56 +0200 Subject: [PATCH 1/3] updated demo1,2 and 3 --- demo1-getting-started.py | 126 ------------- demo2-instance-with-init-script.py | 235 ------------------------ demo3-microservice.py | 275 ----------------------------- destroy-all-demo-instances.py | 97 ---------- 4 files changed, 733 deletions(-) delete mode 100644 demo1-getting-started.py delete mode 100644 demo2-instance-with-init-script.py delete mode 100644 demo3-microservice.py delete mode 100644 destroy-all-demo-instances.py diff --git a/demo1-getting-started.py b/demo1-getting-started.py deleted file mode 100644 index 86d11f9..0000000 --- a/demo1-getting-started.py +++ /dev/null @@ -1,126 +0,0 @@ -# Example for Cloud Computing Course Master AI / GSD -# -# uses 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/ - -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) - -group_number = X - - -######################################################################################################################## -# -# 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' -# 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 -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" - -# 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 the password from user - # auth_password = getpass.getpass("Enter your OpenStack password:") - auth_password = "demo" - - # instantiate a connection to the OpenStack private cloud - # 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))) - - 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) - - print("Getting images and selecting desired one...") - print("=========================================================================") - - # get a list of images offered in the cloud context (e.g. Ubuntu 20.04, cirros, ...) - images = conn.list_images() - image = '' - for img in images: - if img.name == ubuntu_image_name: - image = img - print(img) - - print("Getting flavors...") - print("=========================================================================") - - # get a list of flavors offered in the cloud context (e.g. m1.small, m1.medium, ...) - flavors = conn.list_sizes() - for flavor in flavors: - print(flavor) - - print("Selecting desired flavor...") - print("=========================================================================") - - # get the flavor with id 2 - flavor_id = '2' - flavor = conn.ex_get_size(flavor_id) - print(flavor) - - print("Selecting desired network...") - print("=========================================================================") - - # get a list of networks in the cloud context - networks = conn.ex_list_networks() - network = '' - for net in networks: - if net.name == project_network: - network = net - - print("Create instance 'testing'...") - print("=========================================================================") - - # 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}) - print(testing_instance) - - print("Showing all running instances...") - print("=========================================================================") - - # show all instances (running nodes) in the cloud context - instances = conn.list_nodes() - for instance in instances: - print(instance) - - print("Destroying instance...") - print("=========================================================================") - - # destroy the instance we have just created - conn.destroy_node(testing_instance) - - -# method that is called when the script is started from the command line -if __name__ == '__main__': - main() diff --git a/demo2-instance-with-init-script.py b/demo2-instance-with-init-script.py deleted file mode 100644 index dc5130c..0000000 --- a/demo2-instance-with-init-script.py +++ /dev/null @@ -1,235 +0,0 @@ -# import getpass -# import os - -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) - -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) -# A network in the project the started instance will be attached to -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" - -# 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' - -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 -# 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 - # - ########################################################################### - - 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) - - ########################################################################### - # - # get image, flavor, network for instance creation - # - ########################################################################### - images = conn.list_images() - image = '' - for img in images: - if img.name == ubuntu_image_name: - image = img - - flavors = conn.list_sizes() - flavor = '' - for flav in flavors: - 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: - network = net - - ########################################################################### - # - # create keypair dependency - # - ########################################################################### - - print('Checking for existing SSH key pair...') - keypair_exists = False - for keypair in conn.list_key_pairs(): - if keypair.name == keypair_name: - keypair_exists = True - - if keypair_exists: - print(('Keypair ' + keypair_name + ' already exists. Skipping import.')) - else: - print('adding keypair...') - conn.import_key_pair_from_file(keypair_name, pub_key_file) - - for keypair in conn.list_key_pairs(): - print(keypair) - - ########################################################################### - # - # create security group dependency - # - ########################################################################### - - print('Checking for existing security group...') - security_group_name = 'all-in-one' - security_group_exists = False - all_in_one_security_group = '' - for security_group in conn.ex_list_security_groups(): - if security_group.name == security_group_name: - all_in_one_security_group = security_group - security_group_exists = True - - if security_group_exists: - 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.') - 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) - - for security_group in conn.ex_list_security_groups(): - print(security_group) - - ########################################################################### - # - # create all-in-one instance - # - ########################################################################### - - #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 faafo -i messaging -r api -r worker -r demo - ''' - - print('Checking for existing instance...') - instance_name = 'all-in-one' - instance_exists = False - testing_instance = '' - for instance in conn.list_nodes(): - if instance.name == instance_name: - testing_instance = instance - instance_exists = True - - if instance_exists: - print(('Instance ' + testing_instance.name + ' already exists. Skipping creation.')) - exit() - else: - print('Starting new all-in-one instance and wait until it is running...') - testing_instance = conn.create_node(name=instance_name, - image=image, - size=flavor, - networks=[network], - 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') - - ########################################################################### - # - # assign all-in-one instance floating ip - # - ########################################################################### - - private_ip = None - if len(testing_instance.private_ips): - private_ip = testing_instance.private_ips[0] - print(('Private IP found: {}'.format(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('Checking for unused Floating IP...') - unused_floating_ip = None - for floating_ip in conn.ex_list_floating_ips(): - if not floating_ip.node_id: - unused_floating_ip = floating_ip - break - - 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))) - unused_floating_ip = pool.create_floating_ip() - - if public_ip: - 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) - - actual_ip_address = None - if public_ip: - actual_ip_address = public_ip - elif unused_floating_ip: - actual_ip_address = unused_floating_ip.ip_address - 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('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' - '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.') - - -if __name__ == '__main__': - main() diff --git a/demo3-microservice.py b/demo3-microservice.py deleted file mode 100644 index f5e616a..0000000 --- a/demo3-microservice.py +++ /dev/null @@ -1,275 +0,0 @@ -# import getpass -# import os - -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) - -# 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) -# A network in the project the started instance will be attached to -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" - -# 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' - -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 -# 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 - # - ########################################################################### - - 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) - - ########################################################################### - # - # get image, flavor, network for instance creation - # - ########################################################################### - - images = conn.list_images() - image = '' - for img in images: - if img.name == ubuntu_image_name: - image = img - - flavors = conn.list_sizes() - flavor = '' - for flav in flavors: - 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: - network = net - - ########################################################################### - # - # create keypair dependency - # - ########################################################################### - - print('Checking for existing SSH key pair...') - keypair_exists = False - for keypair in conn.list_key_pairs(): - if keypair.name == keypair_name: - keypair_exists = True - - if keypair_exists: - print(('Keypair ' + keypair_name + ' already exists. Skipping import.')) - else: - print('adding keypair...') - conn.import_key_pair_from_file(keypair_name, pub_key_file) - - for keypair in conn.list_key_pairs(): - print(keypair) - - ########################################################################### - # - # create security group dependency - # - ########################################################################### - - print('Checking for existing worker security group...') - security_group_name = 'worker' - security_group_exists = False - worker_security_group = '' - for security_group in conn.ex_list_security_groups(): - if security_group.name == security_group_name: - worker_security_group = security_group - security_group_exists = True - - if security_group_exists: - 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') - conn.ex_create_security_group_rule(worker_security_group, 'TCP', 22, 22) - - print('Checking for existing controller security group...') - security_group_name = 'control' - security_group_exists = False - controller_security_group = '' - for security_group in conn.ex_list_security_groups(): - if security_group.name == security_group_name: - controller_security_group = security_group - security_group_exists = True - - if security_group_exists: - 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') - 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, - source_security_group=worker_security_group) - - for security_group in conn.ex_list_security_groups(): - print(security_group) - - ########################################################################### - # - # create app-controller - # - ########################################################################### - - #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 ".*" ".*" ".*" - ''' - - 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_userdata=userdata, - ex_security_groups=[controller_security_group]) - - conn.wait_until_running(nodes=[instance_controller_1], timeout=120, ssh_interface='private_ips') - - ########################################################################### - # - # assign app-controller floating ip - # - ########################################################################### - - print('Checking for unused Floating IP...') - unused_floating_ip = None - for floating_ip in conn.ex_list_floating_ips(): - if not floating_ip.node_id: - unused_floating_ip = floating_ip - break - - if not unused_floating_ip: - pool = conn.ex_list_floating_ip_pools()[0] - print(('Allocating new Floating IP from pool: {}'.format(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)) - - ########################################################################### - # - # getting id and ip address of app-controller instance - # - ########################################################################### - - # instance should not have a public ip? floating ips are assigned later - instance_controller_1 = conn.ex_get_node_details(instance_controller_1.id) - if instance_controller_1.public_ips: - ip_controller = instance_controller_1.public_ips[0] - else: - ip_controller = instance_controller_1.private_ips[0] - - ########################################################################### - # - # create app-worker-1 - # - ########################################################################### - - 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} - - 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_userdata=userdata, - ex_security_groups=[worker_security_group]) - - conn.wait_until_running(nodes=[instance_worker_1], timeout=120, ssh_interface='private_ips') - - ########################################################################### - # - # assign app-worker floating ip - # - ########################################################################### - - print('Checking for unused Floating IP...') - unused_floating_ip = None - for floating_ip in conn.ex_list_floating_ips(): - if not floating_ip.node_id: - unused_floating_ip = floating_ip - break - - if not unused_floating_ip: - pool = conn.ex_list_floating_ip_pools()[0] - print(('Allocating new Floating IP from pool: {}'.format(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".') - - -if __name__ == '__main__': - 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() From f63e5ebd8d38382943df736b5dced2807635fc90 Mon Sep 17 00:00:00 2001 From: Sebastian Rieger Date: Fri, 12 Apr 2024 13:53:47 +0200 Subject: [PATCH 2/3] adapted demos for new Charmed OpenStack environment --- CloudComp-openrc | 47 +++++ demo1_getting_started.py | 144 +++++++++++++ demo2_instance_with_init_script.py | 268 ++++++++++++++++++++++++ demo3_microservice.py | 317 +++++++++++++++++++++++++++++ destroy_all_demo_instances.py | 126 ++++++++++++ root-ca.crt | 21 ++ 6 files changed, 923 insertions(+) create mode 100644 CloudComp-openrc create mode 100644 demo1_getting_started.py create mode 100644 demo2_instance_with_init_script.py create mode 100644 demo3_microservice.py create mode 100644 destroy_all_demo_instances.py create mode 100644 root-ca.crt 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 new file mode 100644 index 0000000..d8dd3ab --- /dev/null +++ b/demo1_getting_started.py @@ -0,0 +1,144 @@ +"""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 +# +# 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/ + +# Only needed for the password prompt: +# import getpass + +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 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 = 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 +PROJECT_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 the password from user + # auth_password = getpass.getpass("Enter your OpenStack password:") + auth_password = "demo" + + # instantiate a connection to the OpenStack private cloud + # make sure to include ex_force_auth_version='3.x_password', as needed in our environment + provider = get_driver(Provider.OPENSTACK) + + print(f"Opening connection to {AUTH_URL} as {AUTH_USERNAME}...") + + 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) + + print("Getting images and selecting desired one...") + print("=========================================================================") + + # get a list of images offered in the cloud context (e.g. Ubuntu 20.04, cirros, ...) + images = conn.list_images() + image = '' + for img in images: + if img.name == UBUNTU_IMAGE_NAME: + image = img + print(img) + + print("Getting flavors...") + print("=========================================================================") + + # get a list of flavors offered in the cloud context (e.g. m1.small, m1.medium, ...) + flavors = conn.list_sizes() + for flavor in flavors: + print(flavor) + + print("Selecting desired flavor...") + print("=========================================================================") + + # get the flavor with id 2 + flavor_id = '2' + flavor = conn.ex_get_size(flavor_id) + print(flavor) + + print("Selecting desired network...") + print("=========================================================================") + + # get a list of networks in the cloud context + networks = conn.ex_list_networks() + network = '' + for net in networks: + if net.name == PROJECT_NETWORK: + network = net + + print("Create instance 'testing'...") + print("=========================================================================") + + # 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}) + print(testing_instance) + + print("Showing all running instances...") + print("=========================================================================") + + # show all instances (running nodes) in the cloud context + instances = conn.list_nodes() + for instance in instances: + print(instance) + + print("Destroying instance...") + print("=========================================================================") + + # destroy the instance we have just created + conn.destroy_node(testing_instance) + + +# method that is called when the script is started from the command line +if __name__ == '__main__': + main() diff --git a/demo2_instance_with_init_script.py b/demo2_instance_with_init_script.py new file mode 100644 index 0000000..881ee9c --- /dev/null +++ b/demo2_instance_with_init_script.py @@ -0,0 +1,268 @@ +"""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 sys + +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 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 = 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://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) +print(f'Using username: {AUTH_USERNAME}\n') +# your project in OpenStack +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' + +# 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" + +# 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 = 'srieger-pub' +PUB_KEY_FILE = '~/.ssh/id_rsa.pub' + +FLAVOR_NAME = 'm1.small' + + +# 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 + # + ########################################################################### + + 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) + + ########################################################################### + # + # get image, flavor, network for instance creation + # + ########################################################################### + images = conn.list_images() + image = '' + for img in images: + if img.name == UBUNTU_IMAGE_NAME: + image = img + + flavors = conn.list_sizes() + flavor = '' + for flav in flavors: + 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: + network = net + + ########################################################################### + # + # create keypair dependency + # + ########################################################################### + + print('Checking for existing SSH key pair...') + keypair_exists = False + for keypair in conn.list_key_pairs(): + if keypair.name == KEYPAIR_NAME: + keypair_exists = True + + if keypair_exists: + print('Keypair ' + KEYPAIR_NAME + ' already exists. Skipping import.') + else: + print('adding keypair...') + conn.import_key_pair_from_file(KEYPAIR_NAME, PUB_KEY_FILE) + + for keypair in conn.list_key_pairs(): + print(keypair) + + ########################################################################### + # + # create security group dependency + # + ########################################################################### + + print('Checking for existing security group...') + security_group_name = 'all-in-one' + security_group_exists = False + all_in_one_security_group = '' + for security_group in conn.ex_list_security_groups(): + if security_group.name == security_group_name: + all_in_one_security_group = security_group + security_group_exists = True + + if security_group_exists: + 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.') + 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) + + for security_group in conn.ex_list_security_groups(): + print(security_group) + + ########################################################################### + # + # create all-in-one instance + # + ########################################################################### + + 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' # noqa: E501 pylint: disable=line-too-long + + 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' + instance_exists = False + testing_instance = '' + for instance in conn.list_nodes(): + if instance.name == instance_name: + testing_instance = instance + instance_exists = True + + if instance_exists: + print('Instance ' + testing_instance.name + ' already exists. Skipping creation.') + exit() + else: + print('Starting new all-in-one instance and wait until it is running...') + testing_instance = conn.create_node(name=instance_name, + image=image, + size=flavor, + networks=[network], + 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') + + ########################################################################### + # + # assign all-in-one instance floating ip + # + ########################################################################### + + private_ip = None + if len(testing_instance.private_ips): + private_ip = testing_instance.private_ips[0] + print(f'Private IP found: {private_ip}') + + public_ip = None + if len(testing_instance.public_ips): + public_ip = testing_instance.public_ips[0] + print(f'Public IP found: {public_ip}') + + print('Checking for unused Floating IP...') + unused_floating_ip = None + for floating_ip in conn.ex_list_floating_ips(): + if not floating_ip.node_id: + unused_floating_ip = floating_ip + break + + if not unused_floating_ip and len(conn.ex_list_floating_ip_pools()): + pool = conn.ex_list_floating_ip_pools()[0] + 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.') + elif unused_floating_ip: + conn.ex_attach_floating_ip_to_node(testing_instance, unused_floating_ip) + + actual_ip_address = None + if public_ip: + actual_ip_address = public_ip + elif unused_floating_ip: + actual_ip_address = unused_floating_ip.ip_address + elif private_ip: + actual_ip_address = private_ip + + 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' + 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 or look at "tail -f /var/log/cloud-init*.log" for the\n' + 'cloud-init log files.\n') + + +if __name__ == '__main__': + main() diff --git a/demo3_microservice.py b/demo3_microservice.py new file mode 100644 index 0000000..bef866f --- /dev/null +++ b/demo3_microservice.py @@ -0,0 +1,317 @@ +"""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 sys + +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 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 = 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://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) +print(f'Using username: {AUTH_USERNAME}\n') +# your project in OpenStack +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' + +# 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" + +# 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 = 'srieger-pub' +PUB_KEY_FILE = '~/.ssh/id_rsa.pub' + +FLAVOR_NAME = 'm1.small' + + +# 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 + # + ########################################################################### + + 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) + + ########################################################################### + # + # get image, flavor, network for instance creation + # + ########################################################################### + + images = conn.list_images() + image = '' + for img in images: + if img.name == UBUNTU_IMAGE_NAME: + image = img + + flavors = conn.list_sizes() + flavor = '' + for flav in flavors: + 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: + network = net + + ########################################################################### + # + # create keypair dependency + # + ########################################################################### + + print('Checking for existing SSH key pair...') + keypair_exists = False + for keypair in conn.list_key_pairs(): + if keypair.name == KEYPAIR_NAME: + keypair_exists = True + + if keypair_exists: + print('Keypair ' + KEYPAIR_NAME + ' already exists. Skipping import.') + else: + print('adding keypair...') + conn.import_key_pair_from_file(KEYPAIR_NAME, PUB_KEY_FILE) + + for keypair in conn.list_key_pairs(): + print(keypair) + + ########################################################################### + # + # create security group dependency + # + ########################################################################### + + print('Checking for existing worker security group...') + security_group_name = 'worker' + security_group_exists = False + worker_security_group = '' + for security_group in conn.ex_list_security_groups(): + if security_group.name == security_group_name: + worker_security_group = security_group + security_group_exists = True + + if security_group_exists: + 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') + conn.ex_create_security_group_rule(worker_security_group, 'TCP', 22, 22) + + print('Checking for existing controller security group...') + security_group_name = 'control' + security_group_exists = False + controller_security_group = '' + for security_group in conn.ex_list_security_groups(): + if security_group.name == security_group_name: + controller_security_group = security_group + security_group_exists = True + + if security_group_exists: + 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') + 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, + source_security_group=worker_security_group) + + for security_group in conn.ex_list_security_groups(): + print(security_group) + + ########################################################################### + # + # create app-controller + # + ########################################################################### + + # https://git.openstack.org/cgit/openstack/faafo/plain/contrib/install.sh + # is currently broken, hence the "rabbitctl" lines were added in the example + # below, see also https://bugs.launchpad.net/faafo/+bug/1679710 + # + # Thanks to Stefan Friedmann for finding this fix ;) + # TODO: still needed for new version of faafo and Ubuntu 22.04? + + 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' \ + 'rabbitmqctl add_user faafo guest\n' \ + 'rabbitmqctl set_user_tags faafo administrator\n' \ + 'rabbitmqctl set_permissions -p / faafo ".*" ".*" ".*"\n' + print('\nUsing cloud-init userdata:\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_userdata=userdata, + ex_security_groups=[controller_security_group]) + + conn.wait_until_running(nodes=[instance_controller_1], timeout=120, ssh_interface='private_ips') + + ########################################################################### + # + # assign app-controller floating ip + # + ########################################################################### + + print('Checking for unused Floating IP...') + unused_floating_ip = None + for floating_ip in conn.ex_list_floating_ips(): + if not floating_ip.node_id: + unused_floating_ip = floating_ip + break + + if not unused_floating_ip: + pool = conn.ex_list_floating_ip_pools()[0] + 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(f'Controller Application will be deployed to http://{unused_floating_ip.ip_address}') + actual_ip_address = unused_floating_ip.ip_address + + ########################################################################### + # + # getting id and ip address of app-controller instance + # + ########################################################################### + + # 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: + ip_controller = instance_controller_1.private_ips[0] + + ########################################################################### + # + # create app-worker-1 + # + ########################################################################### + + 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:\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_userdata=userdata, + ex_security_groups=[worker_security_group]) + + conn.wait_until_running(nodes=[instance_worker_1], timeout=120, ssh_interface='private_ips') + + ########################################################################### + # + # assign app-worker floating ip + # + ########################################################################### + + print('Checking for unused Floating IP...') + unused_floating_ip = None + for floating_ip in conn.ex_list_floating_ips(): + if not floating_ip.node_id: + unused_floating_ip = floating_ip + break + + if not unused_floating_ip: + pool = conn.ex_list_floating_ip_pools()[0] + 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(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__': + 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 From 8350862a4a94a09a61141f9c5769329ff7e7c51c Mon Sep 17 00:00:00 2001 From: Sebastian Rieger Date: Fri, 12 Apr 2024 14:10:21 +0200 Subject: [PATCH 3/3] fixed type in cloud-init for microservice worker, removed rabitmq fix as it is not needed anymore --- demo3_microservice.py | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/demo3_microservice.py b/demo3_microservice.py index bef866f..1fbb48b 100644 --- a/demo3_microservice.py +++ b/demo3_microservice.py @@ -192,21 +192,11 @@ def main(): # noqa: C901 pylint: disable=too-many-branches,too-many-statements, # ########################################################################### - # https://git.openstack.org/cgit/openstack/faafo/plain/contrib/install.sh - # is currently broken, hence the "rabbitctl" lines were added in the example - # below, see also https://bugs.launchpad.net/faafo/+bug/1679710 - # - # Thanks to Stefan Friedmann for finding this fix ;) - # TODO: still needed for new version of faafo and Ubuntu 22.04? - 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' \ - 'rabbitmqctl add_user faafo guest\n' \ - 'rabbitmqctl set_user_tags faafo administrator\n' \ - 'rabbitmqctl set_permissions -p / faafo ".*" ".*" ".*"\n' - print('\nUsing cloud-init userdata:\n"' + userdata + '"\n') + '-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', @@ -265,8 +255,8 @@ def main(): # noqa: C901 pylint: disable=too-many-branches,too-many-statements, '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:\n"' + userdata + '"\n') + 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',