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.

247 lines
9.6 KiB

  1. import time
  2. import boto3
  3. from botocore.exceptions import ClientError
  4. ################################################################################################
  5. #
  6. # Configuration Parameters
  7. #
  8. ################################################################################################
  9. # place your credentials in ~/.aws/credentials, as mentioned in AWS Educate Classroom,
  10. # Account Details, AWC CLI -> Show (Copy and paste the following into ~/.aws/credentials)
  11. # changed to use us-east, to be able to use AWS Educate Classroom
  12. region = 'us-east-1'
  13. availabilityZone = 'us-east-1a'
  14. # region = 'eu-central-1'
  15. # availabilityZone = 'eu-central-1b'
  16. # AMI ID of Amazon Linux 2 image 64-bit x86 in us-east-1 (can be retrieved, e.g., at
  17. # https://console.aws.amazon.com/ec2/v2/home?region=us-east-1#LaunchInstanceWizard:)
  18. # TODO update to recent version of Amazon Linux 2 AMI?
  19. imageId = 'ami-0d5eff06f840b45e9'
  20. # for eu-central-1, AMI ID of Amazon Linux 2 would be:
  21. # imageId = 'ami-0cc293023f983ed53'
  22. # potentially change instanceType to t2.micro for "free tier" if using a regular account
  23. # for production, t3.nano seams better
  24. # as of SoSe 2022 t2.nano seams to be a bit too low on memory, mariadb first start can fail
  25. # due to innodb cache out of memory, therefore t2.micro or swap in t2.nano currently recommended
  26. # instanceType = 't2.nano'
  27. instanceType = 't2.micro'
  28. # keyName = 'srieger-pub'
  29. keyName = 'vockey'
  30. ################################################################################################
  31. #
  32. # boto3 code
  33. #
  34. ################################################################################################
  35. client = boto3.setup_default_session(region_name=region)
  36. ec2Client = boto3.client("ec2")
  37. ec2Resource = boto3.resource('ec2')
  38. # if you only have one VPC, vpc_id can be retrieved using:
  39. response = ec2Client.describe_vpcs()
  40. vpc_id = response.get('Vpcs', [{}])[0].get('VpcId', '')
  41. # if you have more than one VPC, vpc_id should be specified, and code
  42. # top retrieve VPC id below needs to be commented out
  43. # vpc_id = 'vpc-eedd4187'
  44. subnet_id = ec2Client.describe_subnets(
  45. Filters=[
  46. {
  47. 'Name': 'availability-zone', 'Values': [availabilityZone]
  48. }
  49. ])['Subnets'][0]['SubnetId']
  50. print("Deleting old instance...")
  51. print("------------------------------------")
  52. response = ec2Client.describe_instances(Filters=[{'Name': 'tag-key', 'Values': ['tug-of-war']}])
  53. print(response)
  54. reservations = response['Reservations']
  55. for reservation in reservations:
  56. for instance in reservation['Instances']:
  57. if instance['State']['Name'] == "running" or instance['State']['Name'] == "pending":
  58. response = ec2Client.terminate_instances(InstanceIds=[instance['InstanceId']])
  59. print(response)
  60. instanceToTerminate = ec2Resource.Instance(instance['InstanceId'])
  61. instanceToTerminate.wait_until_terminated()
  62. print("Delete old security group...")
  63. print("------------------------------------")
  64. try:
  65. response = ec2Client.delete_security_group(GroupName='tug-of-war')
  66. except ClientError as e:
  67. print(e)
  68. print("Create security group...")
  69. print("------------------------------------")
  70. try:
  71. response = ec2Client.create_security_group(GroupName='tug-of-war',
  72. Description='tug-of-war',
  73. VpcId=vpc_id)
  74. security_group_id = response['GroupId']
  75. print('Security Group Created %s in vpc %s.' % (security_group_id, vpc_id))
  76. data = ec2Client.authorize_security_group_ingress(
  77. GroupId=security_group_id,
  78. IpPermissions=[
  79. {'IpProtocol': 'tcp',
  80. 'FromPort': 3306,
  81. 'ToPort': 3306,
  82. 'IpRanges': [{'CidrIp': '0.0.0.0/0'}]},
  83. {'IpProtocol': 'tcp',
  84. 'FromPort': 22,
  85. 'ToPort': 22,
  86. 'IpRanges': [{'CidrIp': '0.0.0.0/0'}]},
  87. {'IpProtocol': 'tcp',
  88. 'FromPort': 80,
  89. 'ToPort': 80,
  90. 'IpRanges': [{'CidrIp': '0.0.0.0/0'}]},
  91. {'IpProtocol': 'tcp',
  92. 'FromPort': 443,
  93. 'ToPort': 443,
  94. 'IpRanges': [{'CidrIp': '0.0.0.0/0'}]}
  95. ])
  96. print('Ingress Successfully Set %s' % data)
  97. except ClientError as e:
  98. print(e)
  99. userDataDB = ('#!/bin/bash\n'
  100. '# extra repo for RedHat rpms\n'
  101. 'yum install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm\n'
  102. '# essential tools\n'
  103. 'yum install -y joe htop git\n'
  104. '# mysql\n'
  105. 'yum install -y mariadb mariadb-server\n'
  106. '\n'
  107. 'service mariadb start\n'
  108. '\n'
  109. 'echo "create database cloud_tug_of_war" | mysql -u root\n'
  110. '\n'
  111. 'echo "create table clouds ( cloud_id INT AUTO_INCREMENT, name VARCHAR(255) NOT NULL, value INT, max_value INT, PRIMARY KEY (cloud_id))" | mysql -u root cloud_tug_of_war\n'
  112. '\n'
  113. 'echo "CREATE USER \'cloud_tug_of_war\'@\'%\' IDENTIFIED BY \'cloudpass\';" | mysql -u root\n'
  114. 'echo "GRANT ALL PRIVILEGES ON cloud_tug_of_war.* TO \'cloud_tug_of_war\'@\'%\';" | mysql -u root\n'
  115. 'echo "FLUSH PRIVILEGES" | mysql -u root\n'
  116. )
  117. # convert user-data from script with: cat install-mysql | sed "s/^/'/; s/$/\\\n'/"
  118. print("Running new DB instance...")
  119. print("------------------------------------")
  120. response = ec2Client.run_instances(
  121. ImageId=imageId,
  122. InstanceType=instanceType,
  123. Placement={'AvailabilityZone': availabilityZone, },
  124. KeyName=keyName,
  125. MinCount=1,
  126. MaxCount=1,
  127. UserData=userDataDB,
  128. SecurityGroupIds=[
  129. security_group_id,
  130. ],
  131. TagSpecifications=[
  132. {
  133. 'ResourceType': 'instance',
  134. 'Tags': [
  135. {'Key': 'Name', 'Value': 'tug-of-war-db1'},
  136. {'Key': 'tug-of-war', 'Value': 'db'}
  137. ],
  138. }
  139. ],
  140. )
  141. instanceIdDB = response['Instances'][0]['InstanceId']
  142. privateIpDB = response['Instances'][0]['PrivateIpAddress']
  143. # privateIpDB = response['Instances'][0]['NetworkInterfaces'][0]['NetworkInterfaceId']
  144. print("Using private IP to connect to the db: " + privateIpDB);
  145. instance = ec2Resource.Instance(instanceIdDB)
  146. instance.wait_until_running()
  147. print(instanceIdDB)
  148. userDataWebServer = ('#!/bin/bash\n'
  149. '# extra repo for RedHat rpms\n'
  150. 'yum install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm\n'
  151. '# essential tools\n'
  152. 'yum install -y joe htop git\n'
  153. '# mysql\n'
  154. 'yum install -y httpd php php-mysql\n'
  155. '\n'
  156. 'service httpd start\n'
  157. '\n'
  158. # 'wget http://mmnet.informatik.hs-fulda.de/cloudcomp/tug-of-war-in-the-clouds.tar.gz\n'
  159. # 'cp tug-of-war-in-the-clouds.tar.gz /var/www/html/\n'
  160. # 'tar zxvf tug-of-war-in-the-clouds.tar.gz\n'
  161. 'cd /var/www/html\n'
  162. 'wget https://gogs.informatik.hs-fulda.de/srieger/cloud-computing-msc-ai-examples/raw/master/example-projects/tug-of-war-in-the-clouds/web-content/index.php\n'
  163. 'wget https://gogs.informatik.hs-fulda.de/srieger/cloud-computing-msc-ai-examples/raw/master/example-projects/tug-of-war-in-the-clouds/web-content/cloud.php\n'
  164. 'wget https://gogs.informatik.hs-fulda.de/srieger/cloud-computing-msc-ai-examples/raw/master/example-projects/tug-of-war-in-the-clouds/web-content/config.php\n'
  165. '\n'
  166. '# change hostname of db connection\n'
  167. 'sed -i s/localhost/' + privateIpDB + '/g /var/www/html/config.php\n'
  168. )
  169. for i in range(1, 3):
  170. print("Running new Web Server instance...")
  171. print("------------------------------------")
  172. response = ec2Client.run_instances(
  173. ImageId=imageId,
  174. InstanceType=instanceType,
  175. Placement={'AvailabilityZone': availabilityZone, },
  176. KeyName=keyName,
  177. MinCount=1,
  178. MaxCount=1,
  179. UserData=userDataWebServer,
  180. SecurityGroupIds=[
  181. security_group_id,
  182. ],
  183. TagSpecifications=[
  184. {
  185. 'ResourceType': 'instance',
  186. 'Tags': [
  187. {'Key': 'Name', 'Value': 'tug-of-war-webserver' + str(i)},
  188. {'Key': 'tug-of-war', 'Value': 'webserver'}
  189. ],
  190. }
  191. ],
  192. )
  193. instanceIdWeb = response['Instances'][0]['InstanceId']
  194. instance = ec2Resource.Instance(instanceIdWeb)
  195. instance.wait_until_running()
  196. instance.load()
  197. # sometimes even after reloading instance details, public IP cannot be retrieved using current boto3 version and
  198. # AWS Educate accounts, try for 10 secs, and ask user to get it from AWS console otherwise
  199. timeout = 10
  200. while instance.public_ip_address is None and timeout > 0:
  201. print("Waiting for public IP to become available...")
  202. instance.load()
  203. time.sleep(1)
  204. timeout -= 1
  205. if instance.public_ip_address is not None:
  206. print("tug-of-war-in-the-clouds can be accessed at: http://" + instance.public_ip_address)
  207. print("Using AWS Academy Lab you should be able to login as shown in the lab README using:")
  208. print("ssh -i ~/.ssh/labsuser.pem ec2-user@" + instance.public_ip_address)
  209. else:
  210. print("Could not get public IP using boto3, this is likely an AWS Educate problem. You can however lookup the "
  211. "public ip from the AWS management console.")