diff --git a/infra-vmaas/.github/workflows/create-snapshot.yaml b/infra-vmaas/.github/workflows/create-snapshot.yaml new file mode 100644 index 0000000..e69de29 diff --git a/infra-vmaas/.github/workflows/create-vms.yaml b/infra-vmaas/.github/workflows/create-vms.yaml new file mode 100644 index 0000000..3e9a2f1 --- /dev/null +++ b/infra-vmaas/.github/workflows/create-vms.yaml @@ -0,0 +1,2 @@ +# creates VM based on start time +# triggerd manually, scheduled \ No newline at end of file diff --git a/infra-vmaas/.github/workflows/delete-vms.yaml b/infra-vmaas/.github/workflows/delete-vms.yaml new file mode 100644 index 0000000..c70fc5d --- /dev/null +++ b/infra-vmaas/.github/workflows/delete-vms.yaml @@ -0,0 +1,3 @@ +# only allow to be run after approaval from approaval group + +# destroys VM diff --git a/infra-vmaas/README.md b/infra-vmaas/README.md new file mode 100644 index 0000000..ff35c69 --- /dev/null +++ b/infra-vmaas/README.md @@ -0,0 +1,22 @@ +# IONOS VMaaS +[ionos_vmaas](https://github.com/hpi-schul-cloud/) is a tool to manage our VM we have to provide in the dbildungsplattform context. +This tool can +- create a VM +- delete a VM +- create a snapshots +- delete a snapshot +- create a list of all VMs in a Datacenter ... + +## Prerequisites +* An account to IONOS datacenter +* Python 3.6++ +* A terminal shell in a Linux operated environment + +## Installation +* Run 'pip3 install -r requirements.txt' to install the required Python packages. +* ´´´ pip install git+https://github.com/ionos-cloud/sdk-python.git ´´´ + + +## Configuration + + diff --git a/infra-vmaas/python-sdk/create-a-server.py b/infra-vmaas/python-sdk/create-a-server.py new file mode 100644 index 0000000..d98e95d --- /dev/null +++ b/infra-vmaas/python-sdk/create-a-server.py @@ -0,0 +1,252 @@ +# https://docs.ionos.com/python-sdk/ +import os +from typing import List +import ionoscloud +from ionoscloud.rest import ApiException +from pprint import pprint +import csv +from csv import DictWriter +import time +import requests + + + +# this config with a token or username/password made it possible to deploy, but it made problems with Anisble and Terraform +# configuration = ionoscloud.Configuration(token=os.getenv("VMAAS_IONOS_TOKEN")) +configuration = ionoscloud.Configuration( + username=os.getenv("DBP_IONOS_USERNAME"), + password=os.getenv("DBP_IONOS_PASSWORD")) + +header_list =header_list = ['uuid','tenant','datacenter_id','datacenter_location','datacenter_name','image_id','ipblock_name','ipblock_ips','ipblock_name','ipblock_size','lan_id','lan_name','nic_id','nic_name','server_cores','server_id','server_name','server_ram','server_type','volume_id','volume_name','volume_size','volume_type','volume_size'] + +# VARS + +# Hard +datacenter_description = "This is a datacenter to place the VMs" +img_filter_str = "ubuntu-22.04-server-cloudimg" +lan_public = True + +with open('vm_file_start.csv', newline='') as vm_file: + reader = csv.DictReader(vm_file) + for row in reader: + if row['uuid'] == "abcd": + vm_obj = row + # - und + + server_name = str("vm-" + row['uuid'] + "-" + row['tenant']) + datacenter_location = row['datacenter_location'] + server_type = row['server_type'] + +# Datacenter Name has to be changed +vm_obj['datacenter_name'] = 'AimeesTest' +vm_obj['datacenter_location'] = datacenter_location +vm_obj['server_name'] = server_name +vm_obj['lan_name'] = str(server_name + '-lan') +vm_obj['nic_name'] = str(server_name + '-nic') +vm_obj['volume_name'] = str(server_name + '-root-volume') +vm_obj['volume_type'] = 'HDD' +vm_obj['ipblock_name'] = str(server_name + '-ipblock-name') +vm_obj['ipblock_size'] = 1 + +# from OS Envs +ssh_keys = [os.getenv("VMAAS_PUBLIC_SSH_KEY")] + + +# test for ssh key existence Error Code +if ssh_keys == '': + raise ValueError('ssh key is not send. Make sure you provide a VMAAS_PUBLIC_SSH_KEY ENV') + +# set server tpe +if vm_obj['server_type'] == 'type_a': + vm_obj['server_cores'] = 1 + vm_obj['server_ram'] = 1024 + vm_obj['volume_size'] = 50 +else: + raise ValueError('server type is not type_a; No other server type defined; Ram etc counld not be set') + + +print(vm_obj) + + +print("*****Get Datacenters ID*****") +with ionoscloud.ApiClient(configuration) as api_client: + api_instance = ionoscloud.DataCentersApi(api_client) + try: + api_response = api_instance.datacenters_get() + datacenters: List[ionoscloud.Datacenter] = api_instance.datacenters_get(depth=1).items + for datacenter in datacenters: + if (vm_obj['datacenter_name'] == datacenter.properties.name): + id: str = datacenter.id + datacenter_id = id + except ApiException as e: + pprint('Exception when calling DataCentersApi.datacenters_get: %s\n' % e) + +print("datacenter_id: " + datacenter_id) +vm_obj['datacenter_id'] = datacenter_id + + +print("*****Create an ipblock ans return ipblocks_ips*****") +with ionoscloud.ApiClient(configuration) as api_client: + api_instance = ionoscloud.IPBlocksApi(api_client) + try: + ipblocks: List[ionoscloud.IpBlock] = api_instance.ipblocks_get(depth=3).items + ipblock_exists = False + for ipblock in ipblocks: + if ipblock.properties.name == vm_obj['ipblock_name']: + ipblock_exists = True + print("ipblock with name: " + vm_obj['ipblock_name'] + " already existend") + if ipblock_exists == False: + # test return code + print("ipblock with name: " + vm_obj['ipblock_name'] + " will be created") + properties=ionoscloud.IpBlockProperties(name=vm_obj['ipblock_name'], location=vm_obj['datacenter_location'], size=1) + ipblock = ionoscloud.IpBlock(properties=properties) + print(api_instance.ipblocks_post(ipblock)) + for ipblock in ipblocks: + if (vm_obj['ipblock_name'] == ipblock.properties.name): + vm_obj['ipblock_ips']= ipblock.properties.ips + except ApiException as e: + print('Exception when calling IPBlocksApi.ipblocks_get: %s\n' % e) + + +print("*****Get Image Id *****") +with ionoscloud.ApiClient(configuration) as api_client: + api_instance = ionoscloud.ImagesApi(api_client) + try: + images: List[ionoscloud.Image] = api_instance.images_get(depth=3).items + for image in images: + id: ionoscloud.ImageProperties = image.id + properties: ionoscloud.ImageProperties = image.properties + if(img_filter_str in properties.name and datacenter_location in properties.location): + vm_obj['image_id'] = id + print(vm_obj['image_id']) + except ApiException as e: + print('Exception when calling ImagesApi.images_get: %s\n' % e) + + +print("*****Create a Lan and get lan_id*****") +with ionoscloud.ApiClient(configuration) as api_client: + api_instance = ionoscloud.LANsApi(api_client) + try: + lans: List[ionoscloud.Lan] = api_instance.datacenters_lans_get(vm_obj['datacenter_id'], depth=3).items + lan_exists = False + for lan in lans: + if lan.properties.name == vm_obj['lan_name']: + lan_exists = True + print("Lan with name: " + vm_obj['lan_name'] + " already existend") + if lan_exists == False: + print("Lan with name: " + vm_obj['lan_name'] + " will be created") + properties = ionoscloud.LanPropertiesPost(name=vm_obj['lan_name'], public=lan_public) + lan = ionoscloud.LanPost(properties=properties) + api_instance.datacenters_lans_post(vm_obj['datacenter_id'], lan) + for lan in lans: + if (vm_obj['lan_name'] == lan.properties.name): + vm_obj['lan_id']= lan.id + except ApiException as e: + print('Exception when calling LANsApi.datacenters_lans_post: %s\n' % e) + +print('*****Create a Server and get server_id*****') +with ionoscloud.ApiClient(configuration) as api_client: + api_instance = ionoscloud.ServersApi(api_client) + properties = ionoscloud.ServerProperties(name=vm_obj['server_name'], cores=vm_obj['server_cores'], ram=vm_obj['server_ram']) + server = ionoscloud.Server(properties=properties) + try: + servers: List[ionoscloud.Server] =api_instance.datacenters_servers_get(vm_obj['datacenter_id'], depth=3).items + server_exists = False + for server in servers: + if server.properties.name == vm_obj['server_name']: + server_exists = True + print("Server with name: " + vm_obj['server_name'] + " already existend") + if server_exists == False: + print("Server with name: " + vm_obj['server_name'] + " will be created") + properties = ionoscloud.ServerProperties(name=vm_obj['server_name'], cores=vm_obj['server_cores'], ram=vm_obj['server_ram']) + server = ionoscloud.Server(properties=properties) + api_instance.datacenters_servers_post(vm_obj['datacenter_id'], server) + for server in servers: + if (vm_obj['server_name'] == server.properties.name): + vm_obj['server_id']= server.id + except ApiException as e: + print('Exception when calling ServersApi.datacenters_servers_post: %s\n' % e) + + +print("*****Create a Volume*****") +with ionoscloud.ApiClient(configuration) as api_client: + api_instance = ionoscloud.VolumesApi(api_client) + properties = ionoscloud.VolumeProperties(name=vm_obj['volume_name'], size=vm_obj['volume_size'], type=vm_obj['volume_type'], image=vm_obj['image_id'], ssh_keys=ssh_keys) + volume = ionoscloud.Volume(properties=properties) + try: + volumes: List[ionoscloud.Volume] =api_instance.datacenters_volumes_get(datacenter_id, depth=3).items + volume_exists = False + for volume in volumes: + if volume.properties.name == vm_obj['volume_name']: + volume_exists = True + print("Volume with name: " + vm_obj['volume_name'] + " already existend") + if volume_exists == False: + print("Volume with name: " + vm_obj['volume_name'] + " will be created") + properties = ionoscloud.VolumeProperties(name=vm_obj['volume_name'], size=vm_obj['volume_size'], type=vm_obj['volume_type'], image=vm_obj['image_id'], ssh_keys=ssh_keys) + volume = ionoscloud.Volume(properties=properties) + api_instance.datacenters_volumes_post(vm_obj['datacenter_id'], volume) + attach_volume = True + for volume in volumes: + if (vm_obj['volume_name'] == volume.properties.name): + vm_obj['volume_id']= volume.id + except ApiException as e: + print('Exception when calling VolumesApi.datacenters_volumes_post: %s\n' % e) + + + +# this needs improvement +# state can not be shown right after +time.sleep(15) +volume_ready = False +print("*****Check readiness of Volume*****") +while volume_ready is not True: + with ionoscloud.ApiClient(configuration) as api_client: + api_instance = ionoscloud.VolumesApi(api_client) + volume: ionoscloud.Volume = api_instance.datacenters_volumes_find_by_id(vm_obj['datacenter_id'], vm_obj['volume_id']) + if volume.metadata.state == "AVAILABLE": + volume_ready = True + print("Volume is in an available state") + else: + print("Waiting for volume to be ready for attachment") + time.sleep(10) + + + +print("*****Attach a Volume*****") +with ionoscloud.ApiClient(configuration) as api_client: + api_instance = ionoscloud.ServersApi(api_client) + volume = ionoscloud.Volume(id=vm_obj['volume_id']) + try: + api_instance.datacenters_servers_volumes_post(vm_obj['datacenter_id'], vm_obj['server_id'], volume=volume) + except ApiException as e: + print('Exception when calling ServersApi.datacenters_servers_volumes_post: %s\n' % e) + +print("*****Create a nic and get nic_id*****") +with ionoscloud.ApiClient(configuration) as api_client: + api_instance = ionoscloud.NetworkInterfacesApi(api_client) + try: + nics: List[ionoscloud.Nic] =api_instance.datacenters_servers_nics_get(vm_obj['datacenter_id'], vm_obj['server_id'], depth=3).items + nic_exists = False + for nic in nics: + if nic.properties.name == vm_obj['nic_name']: + nic_exists = True + print("nic with name: " + vm_obj['nic_name'] + " already existend") + if nic_exists == False: + print("nic with name: " + vm_obj['nic_name'] + " will be created") + properties = ionoscloud.NicProperties(name=vm_obj['nic_name'], ips=list(vm_obj['ipblock_ips']), lan=vm_obj['lan_id'] ) + nic = ionoscloud.Nic(properties=properties) + api_instance.datacenters_servers_nics_post(vm_obj['datacenter_id'], vm_obj['server_id'], nic) + attach_volume = True + for nic in nics: + if (vm_obj['nic_name'] == nic.properties.name): + vm_obj['nic_id']= nic.id + except ApiException as e: + print('Exception when calling NetworkInterfacesApi.datacenters_servers_nics_post: %s\n' % e) + +print(vm_obj) + +# server_id has not been put in the csv file properly once, may need further testing +with open('vm_file_filled.csv', 'a') as vm_file: + dictwriter_object = DictWriter(vm_file, fieldnames=header_list) + dictwriter_object.writerow(vm_obj) + + diff --git a/infra-vmaas/python-sdk/create-a-snapshot.py b/infra-vmaas/python-sdk/create-a-snapshot.py new file mode 100644 index 0000000..659e2ab --- /dev/null +++ b/infra-vmaas/python-sdk/create-a-snapshot.py @@ -0,0 +1,27 @@ +# https://docs.ionos.com/python-sdk/ +import os +from typing import List +import ionoscloud +from ionoscloud.rest import ApiException +import csv + +# need to have a ssh key in your envs +configuration = ionoscloud.Configuration( + username=os.getenv("DBP_IONOS_USERNAME"), + password=os.getenv("DBP_IONOS_PASSWORD")) + +with open('vm_file_filled.csv', newline='') as vm_file: + # needs to filter specific line + for i in csv.DictReader(vm_file): + vm_obj = (dict(i)) +print(vm_obj) + +with ionoscloud.ApiClient(configuration) as api_client: + api_instance = ionoscloud.VolumesApi(api_client) + try: + api_instance.datacenters_volumes_create_snapshot_post(vm_obj['datacenter_id'], vm_obj['volume_id']) + except ApiException as e: + print('Exception when calling VolumesApi.datacenters_volumes_create_snapshot_post: %s\n' % e) + + +# save snapshot id \ No newline at end of file diff --git a/infra-vmaas/python-sdk/delete-a-server.py b/infra-vmaas/python-sdk/delete-a-server.py new file mode 100644 index 0000000..d581916 --- /dev/null +++ b/infra-vmaas/python-sdk/delete-a-server.py @@ -0,0 +1,83 @@ +# https://docs.ionos.com/python-sdk/ +import os +from typing import List +import ionoscloud +from ionoscloud.rest import ApiException +import csv + +# need to have a ssh key in your envs +configuration = ionoscloud.Configuration( + username=os.getenv("DBP_IONOS_USERNAME"), + password=os.getenv("DBP_IONOS_PASSWORD")) + +with open('vm_file_filled.csv', newline='') as vm_file: + # needs to filter specific line + for i in csv.DictReader(vm_file): + vm_obj = (dict(i)) +print(vm_obj) + +print("*****Delete Nic*****") +with ionoscloud.ApiClient(configuration) as api_client: + api_instance = ionoscloud.NetworkInterfacesApi(api_client) + try: + nics: List[ionoscloud.Nic] =api_instance.datacenters_servers_nics_get(vm_obj['datacenter_id'], vm_obj['server_id'], depth=3).items + print(nics) + for nic in nics: + properties: ionoscloud.NicProperties = nic.properties + if(vm_obj['nic_name'] == properties.name): + api_instance.datacenters_servers_nics_delete(vm_obj['datacenter_id'], vm_obj['server_id'], vm_obj['nic_id']) + except ApiException as e: + print('Exception when calling NetworkInterfacesApi.datacenters_servers_nics_post: %s\n' % e) + +# Dont have to detach volume first, works fine +print("*****Delete a Volume*****") +with ionoscloud.ApiClient(configuration) as api_client: + api_instance = ionoscloud.VolumesApi(api_client) + try: + print(api_instance.datacenters_volumes_delete(vm_obj['datacenter_id'], vm_obj['volume_id'])) + except ApiException as e: + print('Exception when calling VolumesApi.datacenters_volumes_post: %s\n' % e) + + +print("*****Delete a Server*****") +with ionoscloud.ApiClient(configuration) as api_client: + api_instance = ionoscloud.ServersApi(api_client) + try: + api_instance.datacenters_servers_delete(vm_obj['datacenter_id'], vm_obj['server_id']) + except ApiException as e: + print('Exception when calling ServersApi.datacenters_servers_delete: %s\n' % e) + +# this again needs some time +# sleep or something wiser should be used + +print("*****Delete Lan*****") +with ionoscloud.ApiClient(configuration) as api_client: + api_instance = ionoscloud.LANsApi(api_client) + try: + lans: List[ionoscloud.Lan] = api_instance.datacenters_lans_get(vm_obj['datacenter_id'], depth=3).items + for lan in lans: + id = lan.id + properties: ionoscloud.LanProperties = lan.properties + if( vm_obj['lan_name'] in properties.name): + lan_id = id + api_instance.datacenters_lans_delete(vm_obj['datacenter_id'], lan_id) + except ApiException as e: + print('Exception when calling LANsApi.datacenters_lans_delete: %s\n' % e) + + +print("***** Delete Ipblock *****") +with ionoscloud.ApiClient(configuration) as api_client: + api_instance = ionoscloud.IPBlocksApi(api_client) + try: + ipblocks: List[ionoscloud.IpBlock] = api_instance.ipblocks_get(depth=3).items + for ipblock in ipblocks: + if (vm_obj['ipblock_name'] == ipblock.properties.name): + ipblock_id = ipblock.id + api_instance.ipblocks_delete(ipblock_id) + except ApiException as e: + print('Exception when calling IPBlocksApi.ipblocks_delete: %s\n' % e) + + +# delete/adjust entry in csv + + diff --git a/infra-vmaas/python-sdk/delete-a-snapshot.py b/infra-vmaas/python-sdk/delete-a-snapshot.py new file mode 100644 index 0000000..23a63fb --- /dev/null +++ b/infra-vmaas/python-sdk/delete-a-snapshot.py @@ -0,0 +1,29 @@ +# https://docs.ionos.com/python-sdk/ +import os +from typing import List +import ionoscloud +from ionoscloud.rest import ApiException +import csv + +# need to have a ssh key in your envs +configuration = ionoscloud.Configuration( + username=os.getenv("DBP_IONOS_USERNAME"), + password=os.getenv("DBP_IONOS_PASSWORD")) + +with open('vm_file_filled.csv', newline='') as vm_file: + # needs to filter specific line + for i in csv.DictReader(vm_file): + vm_obj = (dict(i)) +print(vm_obj) + + +# not tested yet +with ionoscloud.ApiClient(configuration) as api_client: + api_instance = ionoscloud.VolumesApi(api_client) + try: + api_instance.snapshots_delete(vm_obj['snapshot_id']) + except ApiException as e: + print('Exception when calling VolumesApi.datacenters_volumes_create_snapshot_post: %s\n' % e) + + +# delet csv entry completely \ No newline at end of file diff --git a/infra-vmaas/python-sdk/setup.py b/infra-vmaas/python-sdk/setup.py new file mode 100644 index 0000000..777dbc7 --- /dev/null +++ b/infra-vmaas/python-sdk/setup.py @@ -0,0 +1,24 @@ +#Easily download, build, install, upgrade, and uninstall Python packages +import setuptools + +with open("README.md", "r") as fh: + long_description = fh.read() + +setuptools.setup( + name="vmaas", + version="1.0", + author="SRE-Team", + author_email="devops@dbildungscloud.com", + description="Files to run our VMaaS", + long_description=long_description, + long_description_content_type="text/markdown", + url="https://github.com/", + packages=setuptools.find_packages(), + install_requires=['ionoscloud'], + scripts=['sct.py'], + classifiers=[ + "Programming Language :: Python :: 3", + "Operating System :: OS Independent", + ], + python_requires='>=3.6', +) \ No newline at end of file diff --git a/infra-vmaas/python-sdk/vm_file_start.csv b/infra-vmaas/python-sdk/vm_file_start.csv new file mode 100644 index 0000000..2bbe742 --- /dev/null +++ b/infra-vmaas/python-sdk/vm_file_start.csv @@ -0,0 +1,2 @@ +uuid,tenant,datacenter_id,datacenter_location,datacenter_name,image_id,ipblock_name,ipblock_ips,ipblock_name,ipblock_size,lan_id,lan_name,nic_id,nic_name,server_cores,server_id,server_name,server_ram,server_type,volume_id,volume_name,volume_size,volume_type,volume_size +abcd,bw,,de/txl,,,,,,,,,,,,,,,type_a,,,,, diff --git a/infra-vmaas/python-sdk/write_initial_csv.py b/infra-vmaas/python-sdk/write_initial_csv.py new file mode 100644 index 0000000..fafb854 --- /dev/null +++ b/infra-vmaas/python-sdk/write_initial_csv.py @@ -0,0 +1,14 @@ +import csv + +# values like snapshot id, start time, end time not implemented yet + +header_list = ['uuid','tenant','datacenter_id','datacenter_location','datacenter_name','image_id','ipblock_name','ipblock_ips','ipblock_name','ipblock_size','lan_id','lan_name','nic_id','nic_name','server_cores','server_id','server_name','server_ram','server_type','volume_id','volume_name','volume_size','volume_type','volume_size'] +header = header_list + +with open('vm_file_start.csv', 'w', newline='') as csvfile: + fieldnames = header_list + writer = csv.DictWriter(csvfile, fieldnames=fieldnames) + writer.writeheader() + writer.writerow({'uuid': 'abcd', 'tenant': 'bw', 'datacenter_location' : 'de/txl', 'server_type': 'type_a'}) + + diff --git a/infra-vmaas/requirements.txt b/infra-vmaas/requirements.txt new file mode 100644 index 0000000..eca3c1f --- /dev/null +++ b/infra-vmaas/requirements.txt @@ -0,0 +1 @@ +ionoscloud==6.1.4 \ No newline at end of file