· 3 years ago · Jan 06, 2022, 02:20 AM
1import oci
2import logging
3import time
4import sys
5import requests
6
7LOG_FORMAT = '[%(levelname)s] %(asctime)s - %(message)s'
8logging.basicConfig(
9 level=logging.INFO,
10 format=LOG_FORMAT,
11 handlers=[
12 logging.FileHandler("oci.log"),
13 logging.StreamHandler(sys.stdout)
14 ]
15)
16
17##################################### SCRIPT SETTING, CHANGE THIS #########################################
18# Script Setting, change this (Each VM.Standard.A1.Flex ocpus = 6 GB memroy)
19# instance_type = "VM.Standard.A1.Flex"
20# OCI API_KEY and other parametter: https://github.com/hitrov/oci-arm-host-capacity (intercept request from web console)
21ocpus = 4
22memory_in_gbs = ocpus*6
23wait_s_for_retry = 30
24instance_display_name = 'ubuntu-sg-oci'
25compartment_id = 'ocid1.tenancy.oc1..**********************************'
26domain = "rhNU:AP-SINGAPORE-1-AD-1" # availability_domain
27image_id = "ocid1.image.oc1.ap-singapore-1.*******************************"
28subnet_id = 'ocid1.subnet.oc1.ap-singapore-1.********************'
29
30ssh_key = "ssh-rsa ************************"
31# Telegram setting
32# https://medium.com/@ManHay_Hong/how-to-create-a-telegram-bot-and-send-messages-with-python-4cf314d9fa3e
33# Create bot with BotFather, get the API key
34# Start the bot via conversation/chat with command /start
35# Get chat_id: https://api.telegram.org/bot<yourtoken>/getUpdates if not get chat_id, chat some thing to the bot and retry
36# Start a chat with your bot, add [@get_id_bot](https://telegram.me/get_id_bot), and issue the `/my_id` command
37session = requests.Session()
38bot_api = '*******'
39chat_id = '*******'
40######################################################################################################################
41
42
43def telegram_notify(session, bot_api, chat_id, message):
44 '''Notify via telegram'''
45 pass # Disable telegram notification
46
47
48#######################################################################################################################
49logging.info("#####################################################")
50logging.info("Script to spawn VM.Standard.A1.Flex instance")
51
52
53message = f'Start spawning instance VM.Standard.A1.Flex - {ocpus} ocpus - {memory_in_gbs} GB'
54logging.info(message)
55telegram_notify(session, bot_api, chat_id, message)
56
57# Loading config file
58logging.info("Loading OCI config")
59config = oci.config.from_file(file_location="./config")
60
61# Initialize service client
62logging.info("Initialize service client with default config file")
63to_launch_instance = oci.core.ComputeClient(config)
64
65
66message = f"Instance to create: VM.Standard.A1.Flex - {ocpus} ocpus - {memory_in_gbs} GB"
67logging.info(message)
68telegram_notify(session, bot_api, chat_id, message)
69
70########################### Check current existing instance(s) in account ##############################
71logging.info("Check current instances in account")
72logging.info(
73 "Note: Free upto 4xVM.Standard.A1.Flex instance, total of 4 ocpus and 24 GB of memory")
74current_instance = to_launch_instance.list_instances(
75 compartment_id=compartment_id)
76response = current_instance.data
77# oci.core.models.InstanceShapeConfig
78# print(type(response[0]))
79total_ocpus = total_memory = _A1_Flex = 0
80instance_names = []
81if response:
82 logging.info(f"{len(response)} instance(s) found!")
83 for instance in response:
84 logging.info(f"{instance.display_name} - {instance.shape} - {int(instance.shape_config.ocpus)} ocpu(s) - {instance.shape_config.memory_in_gbs} GB(s) | State: {instance.lifecycle_state}")
85 instance_names.append(instance.display_name)
86 if instance.shape == "VM.Standard.A1.Flex" and instance.lifecycle_state not in ("TERMINATING", "TERMINATED"):
87 _A1_Flex += 1
88 total_ocpus += int(instance.shape_config.ocpus)
89 total_memory += int(instance.shape_config.memory_in_gbs)
90
91 message = f"Current: {_A1_Flex} active VM.Standard.A1.Flex instance(s) (including RUNNING OR STOPPED)"
92 logging.info(message)
93 telegram_notify(session, bot_api, chat_id, message)
94else:
95 logging.info(f"No instance(s) found!")
96
97
98message = f"Total ocpus: {total_ocpus} - Total memory: {total_memory} (GB) || Free {4-total_ocpus} ocpus - Free memory: {24-total_memory} (GB)"
99logging.info(message)
100telegram_notify(session, bot_api, chat_id, message)
101
102
103# Pre-check to verify total resource of current VM.Standard.A1.Flex (max 4 ocpus/24GB ram)
104if total_ocpus + ocpus > 4 or total_memory + memory_in_gbs > 24:
105 message = "Total maximum resource exceed free tier limit (Over 4 ocpus/24GB total). **SCRIPT STOPPED**"
106 logging.critical(message)
107 telegram_notify(session, bot_api, chat_id, message)
108 sys.exit()
109
110# Check for duplicate display name
111if instance_display_name in instance_names:
112 message = f"Duplicate display name: >>>{instance_display_name}<<< Change this! **SCRIPT STOPPED**"
113 logging.critical(message)
114 telegram_notify(session, bot_api, chat_id, message)
115 sys.exit()
116
117message = f"Precheck pass! Create new instance VM.Standard.A1.Flex: {ocpus} opus - {memory_in_gbs} GB"
118logging.info(message)
119telegram_notify(session, bot_api, chat_id, message)
120######################################################################################################################
121
122# Instance-detail
123instance_detail = oci.core.models.LaunchInstanceDetails(
124 metadata={
125 "ssh_authorized_keys": ssh_key
126 },
127 availability_domain=domain,
128 shape='VM.Standard.A1.Flex',
129 compartment_id=compartment_id,
130 display_name=instance_display_name,
131 source_details=oci.core.models.InstanceSourceViaImageDetails(
132 source_type="image", image_id=image_id),
133 create_vnic_details=oci.core.models.CreateVnicDetails(
134 assign_public_ip=False, subnet_id=subnet_id, assign_private_dns_record=True),
135 agent_config=oci.core.models.LaunchInstanceAgentConfigDetails(
136 is_monitoring_disabled=False,
137 is_management_disabled=False,
138 plugins_config=[oci.core.models.InstanceAgentPluginConfigDetails(
139 name='Vulnerability Scanning', desired_state='DISABLED'), oci.core.models.InstanceAgentPluginConfigDetails(name='Compute Instance Monitoring', desired_state='ENABLED'), oci.core.models.InstanceAgentPluginConfigDetails(name='Bastion', desired_state='DISABLED')]
140 ),
141 defined_tags={},
142 freeform_tags={},
143 instance_options=oci.core.models.InstanceOptions(
144 are_legacy_imds_endpoints_disabled=False),
145 availability_config=oci.core.models.LaunchInstanceAvailabilityConfigDetails(
146 recovery_action="RESTORE_INSTANCE"),
147 shape_config=oci.core.models.LaunchInstanceShapeConfigDetails(
148 ocpus=ocpus, memory_in_gbs=memory_in_gbs)
149)
150
151####################################### Main loop - program ####################################################
152# Script try to send request each $wait_s_for_retry seconds until success
153to_try = True
154while to_try:
155 try:
156 to_launch_instance.launch_instance(instance_detail)
157 to_try = False
158 message = 'Success! Edit vnic to get public ip address'
159 logging.info(message)
160 telegram_notify(session, bot_api, chat_id, message)
161 # print(to_launch_instance.data)
162 session.close()
163 except oci.exceptions.ServiceError as e:
164 if e.status == 500:
165 # Out of host capacity.
166 message = f"{e.message} Retry in {wait_s_for_retry}s"
167 else:
168 message = f"{e} Retry in {wait_s_for_retry}s"
169 telegram_notify(session, bot_api, chat_id, message)
170 logging.info(message)
171 time.sleep(wait_s_for_retry)
172 except Exception as e:
173 message = f"{e} Retry in {wait_s_for_retry}s"
174 logging.info(message)
175 telegram_notify(session, bot_api, chat_id, message)
176 time.sleep(wait_s_for_retry)
177 except KeyboardInterrupt:
178 session.close()
179 sys.exit()