You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

308 lines
13 KiB

  1. """Example for Cloud Computing Course Master AI / GSD"""
  2. # This script demonstrates how to use libcloud to start an instance in an OpenStack environment.
  3. # The script will create start multiple instances splitting up the faafo monolithic application into
  4. # a (minimalistic but already scalable) microservice architecture.
  5. # Also introduces the concept of different security groups and corresponding frontend/backend
  6. # separation.
  7. # Needed if the password should be prompted for:
  8. # import getpass
  9. import os
  10. import sys
  11. from libcloud.compute.providers import get_driver
  12. from libcloud.compute.types import Provider
  13. # For our new Charmed OpenStack private cloud, we need to specify the path to the root
  14. # CA certificate
  15. import libcloud.security
  16. libcloud.security.CA_CERTS_PATH = ['./root-ca.crt']
  17. # Disable SSL certificate verification (not recommended for production)
  18. # libcloud.security.VERIFY_SSL_CERT = False
  19. # Please use 1-29 as environment variable GROUP_NUMBER to specify your group number.
  20. # (will be used for the username, project etc., as coordinated in the lab sessions)
  21. group_number = os.environ.get('GROUP_NUMBER')
  22. if group_number is None:
  23. sys.exit('Please set the GROUP_NUMBER environment variable to your group number,\n'
  24. 'e.g., on Windows:\n'
  25. ' "$env:GROUP_NUMBER=0" or "set GROUP_NUMBER=0"\n'
  26. 'or on Linux/MacOS:\n'
  27. ' "export GROUP_NUMBER=0" or "set GROUP_NUMBER=0"')
  28. # web service endpoint of the private cloud infrastructure
  29. # auth_url = 'https://private-cloud.informatik.hs-fulda.de:5000'
  30. AUTH_URL = 'https://10.32.4.182:5000'
  31. # auth_url = 'https://private-cloud2.informatik.hs-fulda.de:5000'
  32. # your username in OpenStack
  33. AUTH_USERNAME = 'CloudComp' + str(group_number)
  34. print(f'Using username: {AUTH_USERNAME}\n')
  35. # your project in OpenStack
  36. PROJECT_NAME = 'CloudComp' + str(group_number)
  37. # A network in the project the started instance will be attached to
  38. PROJECT_NETWORK = 'CloudComp' + str(group_number) + '-net'
  39. # The image to look for and use for the started instance
  40. # ubuntu_image_name = "Ubuntu 18.04 - Bionic Beaver - 64-bit - Cloud Based Image"
  41. #UBUNTU_IMAGE_NAME = "auto-sync/ubuntu-jammy-22.04-amd64-server-20240319-disk1.img"
  42. UBUNTU_IMAGE_NAME = "ubuntu-22.04-jammy-x86_64"
  43. # The public key to be used for SSH connection, please make sure, that you have the
  44. # corresponding private key
  45. #
  46. # id_rsa.pub should look like this (standard sshd pubkey format):
  47. # ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAw+J...F3w2mleybgT1w== user@HOSTNAME
  48. KEYPAIR_NAME = 'srieger-pub'
  49. PUB_KEY_FILE = '~/.ssh/id_rsa.pub'
  50. FLAVOR_NAME = 'm1.small'
  51. # default region
  52. REGION_NAME = 'RegionOne'
  53. # domain to use, "default" for local accounts, formerly "hsfulda" for LDAP accounts etc.
  54. # domain_name = "default"
  55. def main(): # noqa: C901 pylint: disable=too-many-branches,too-many-statements,too-many-locals,missing-function-docstring
  56. ###########################################################################
  57. #
  58. # get credentials
  59. #
  60. ###########################################################################
  61. # if "OS_PASSWORD" in os.environ:
  62. # auth_password = os.environ["OS_PASSWORD"]
  63. # else:
  64. # auth_password = getpass.getpass("Enter your OpenStack password:")
  65. auth_password = "demo"
  66. ###########################################################################
  67. #
  68. # create connection
  69. #
  70. ###########################################################################
  71. provider = get_driver(Provider.OPENSTACK)
  72. conn = provider(AUTH_USERNAME,
  73. auth_password,
  74. ex_force_auth_url=AUTH_URL,
  75. ex_force_auth_version='3.x_password',
  76. ex_tenant_name=PROJECT_NAME,
  77. ex_force_service_region=REGION_NAME)
  78. # ex_domain_name=domain_name)
  79. ###########################################################################
  80. #
  81. # get image, flavor, network for instance creation
  82. #
  83. ###########################################################################
  84. images = conn.list_images()
  85. image = ''
  86. for img in images:
  87. if img.name == UBUNTU_IMAGE_NAME:
  88. image = img
  89. flavors = conn.list_sizes()
  90. flavor = ''
  91. for flav in flavors:
  92. if flav.name == FLAVOR_NAME:
  93. flavor = conn.ex_get_size(flav.id)
  94. networks = conn.ex_list_networks()
  95. network = ''
  96. for net in networks:
  97. if net.name == PROJECT_NETWORK:
  98. network = net
  99. ###########################################################################
  100. #
  101. # create keypair dependency
  102. #
  103. ###########################################################################
  104. print('Checking for existing SSH key pair...')
  105. keypair_exists = False
  106. for keypair in conn.list_key_pairs():
  107. if keypair.name == KEYPAIR_NAME:
  108. keypair_exists = True
  109. if keypair_exists:
  110. print('Keypair ' + KEYPAIR_NAME + ' already exists. Skipping import.')
  111. else:
  112. print('adding keypair...')
  113. conn.import_key_pair_from_file(KEYPAIR_NAME, PUB_KEY_FILE)
  114. for keypair in conn.list_key_pairs():
  115. print(keypair)
  116. ###########################################################################
  117. #
  118. # create security group dependency
  119. #
  120. ###########################################################################
  121. print('Checking for existing worker security group...')
  122. security_group_name = 'worker'
  123. security_group_exists = False
  124. worker_security_group = ''
  125. for security_group in conn.ex_list_security_groups():
  126. if security_group.name == security_group_name:
  127. worker_security_group = security_group
  128. security_group_exists = True
  129. if security_group_exists:
  130. print('Worker Security Group ' + worker_security_group.name + ' already exists. '
  131. 'Skipping creation.')
  132. else:
  133. worker_security_group = conn.ex_create_security_group('worker', 'for services '
  134. 'that run on a worker node')
  135. conn.ex_create_security_group_rule(worker_security_group, 'TCP', 22, 22)
  136. print('Checking for existing controller security group...')
  137. security_group_name = 'control'
  138. security_group_exists = False
  139. controller_security_group = ''
  140. for security_group in conn.ex_list_security_groups():
  141. if security_group.name == security_group_name:
  142. controller_security_group = security_group
  143. security_group_exists = True
  144. if security_group_exists:
  145. print('Controller Security Group ' + controller_security_group.name + ' already exists. '
  146. 'Skipping creation.')
  147. else:
  148. controller_security_group = conn.ex_create_security_group('control', 'for services that '
  149. 'run on a control node')
  150. conn.ex_create_security_group_rule(controller_security_group, 'TCP', 22, 22)
  151. conn.ex_create_security_group_rule(controller_security_group, 'TCP', 80, 80)
  152. conn.ex_create_security_group_rule(controller_security_group, 'TCP', 5672, 5672,
  153. source_security_group=worker_security_group)
  154. for security_group in conn.ex_list_security_groups():
  155. print(security_group)
  156. ###########################################################################
  157. #
  158. # create app-controller
  159. #
  160. ###########################################################################
  161. userdata = '#!/usr/bin/env bash\n' \
  162. 'curl -L -s https://gogs.informatik.hs-fulda.de/srieger/cloud-computing-msc-ai-' \
  163. 'examples/raw/master/faafo/contrib/install.sh | bash -s -- ' \
  164. '-i messaging -i faafo -r api\n'
  165. print('\nUsing cloud-init userdata for controller:\n"' + userdata + '"\n')
  166. print('Starting new app-controller instance and wait until it is running...')
  167. instance_controller_1 = conn.create_node(name='app-controller',
  168. image=image,
  169. size=flavor,
  170. networks=[network],
  171. ex_keyname=KEYPAIR_NAME,
  172. ex_userdata=userdata,
  173. ex_security_groups=[controller_security_group])
  174. conn.wait_until_running(nodes=[instance_controller_1], timeout=120, ssh_interface='private_ips')
  175. ###########################################################################
  176. #
  177. # assign app-controller floating ip
  178. #
  179. ###########################################################################
  180. print('Checking for unused Floating IP...')
  181. unused_floating_ip = None
  182. for floating_ip in conn.ex_list_floating_ips():
  183. if not floating_ip.node_id:
  184. unused_floating_ip = floating_ip
  185. break
  186. if not unused_floating_ip:
  187. pool = conn.ex_list_floating_ip_pools()[0]
  188. print(f'Allocating new Floating IP from pool: {pool}')
  189. unused_floating_ip = pool.create_floating_ip()
  190. conn.ex_attach_floating_ip_to_node(instance_controller_1, unused_floating_ip)
  191. print(f'Controller Application will be deployed to http://{unused_floating_ip.ip_address}')
  192. actual_ip_address = unused_floating_ip.ip_address
  193. ###########################################################################
  194. #
  195. # getting id and ip address of app-controller instance
  196. #
  197. ###########################################################################
  198. # instance should not have a public ip? floating ips are assigned later
  199. instance_controller_1 = conn.ex_get_node_details(instance_controller_1.id)
  200. ip_controller = ''
  201. if instance_controller_1.public_ips:
  202. ip_controller = instance_controller_1.public_ips[0]
  203. else:
  204. ip_controller = instance_controller_1.private_ips[0]
  205. ###########################################################################
  206. #
  207. # create app-worker-1
  208. #
  209. ###########################################################################
  210. userdata = '#!/usr/bin/env bash\n' \
  211. 'curl -L -s https://gogs.informatik.hs-fulda.de/srieger/cloud-computing-msc-ai-' \
  212. 'examples/raw/master/faafo/contrib/install.sh | bash -s -- ' \
  213. f'-i faafo -r worker -e "http://{ip_controller}" -m "amqp://faafo:guest@' \
  214. f'{ip_controller}:5672/"\n'
  215. print('\nUsing cloud-init userdata for worker:\n"' + userdata + '"\n')
  216. print('Starting new app-worker-1 instance and wait until it is running...')
  217. instance_worker_1 = conn.create_node(name='app-worker-1',
  218. image=image,
  219. size=flavor,
  220. networks=[network],
  221. ex_keyname=KEYPAIR_NAME,
  222. ex_userdata=userdata,
  223. ex_security_groups=[worker_security_group])
  224. conn.wait_until_running(nodes=[instance_worker_1], timeout=120, ssh_interface='private_ips')
  225. ###########################################################################
  226. #
  227. # assign app-worker floating ip
  228. #
  229. ###########################################################################
  230. print('Checking for unused Floating IP...')
  231. unused_floating_ip = None
  232. for floating_ip in conn.ex_list_floating_ips():
  233. if not floating_ip.node_id:
  234. unused_floating_ip = floating_ip
  235. break
  236. if not unused_floating_ip:
  237. pool = conn.ex_list_floating_ip_pools()[0]
  238. print(f'Allocating new Floating IP from pool: {pool}')
  239. unused_floating_ip = pool.create_floating_ip()
  240. conn.ex_attach_floating_ip_to_node(instance_worker_1, unused_floating_ip)
  241. print(f'The worker will be available for SSH at {unused_floating_ip.ip_address}')
  242. print('\n\n#### Deployment finished\n\n')
  243. print('After some minutes, as soon as cloud-init installed required packages and the\n'
  244. 'faafo app, (First App Application For OpenStack) fractals demo will be available\n'
  245. f'at http://{actual_ip_address}\n')
  246. print('You can use ssh to login to the controller using your private key.\n'
  247. f'E.g., "ssh -i ~/.ssh/id_rsa ubuntu@{actual_ip_address}". After login,\n'
  248. 'you can list available fractals using "faafo list". To request the generation of\n'
  249. 'new fractals, you can use "faafo create". \n'
  250. 'You can also see other options to use the faafo example cloud service using '
  251. '"faafo -h".')
  252. if __name__ == '__main__':
  253. main()