blob: d04b67be62d1e310ba9e21c9f0c2520f9993a5b8 [file] [log] [blame]
Dmitriy Kruglov6146cb42023-04-10 00:13:59 +02001import os
2import sys
3from typing import Dict, Final, List
4
5import connection as conn
6import openstack
7from openstack.exceptions import ResourceFailure
8
9
10compute = conn.cloud.compute
11network = conn.cloud.network
12volume = conn.cloud.volume
13
14CLIENTS_COUNT: Final[int] = conn.FIO_CLIENTS_COUNT
15CLIENT_NAME_MASK: Final[str] = conn.FIO_CLIENT_NAME_MASK
16UBUNTU_IMAGE_NAME: Final[str] = conn.UBUNTU_IMAGE_NAME
17
18VOL_NAME_MASK: Final[str] = conn.FIO_VOL_NAME_MASK
19VOL_SIZE: Final[int] = conn.FIO_VOL_SIZE
20VOL_TYPE: Final[str] = conn.FIO_VOL_TYPE
21VOL_MOUNTPOINT: Final[str] = conn.FIO_VOL_MOUNTPOINT
22
23FLAVOR_NAME: Final[str] = conn.FIO_FLAVOR_NAME
24FLAVOR_RAM: Final[int] = conn.FIO_FLAVOR_RAM
25FLAVOR_CPUS: Final[int] = conn.FIO_FLAVOR_CPUS
26FLAVOR_DISK: Final[int] = conn.FIO_FLAVOR_DISK
27
28NET_NAME: Final[str] = conn.FIO_NET_NAME
29ROUTER_NAME: Final[str] = conn.FIO_ROUTER_NAME
30FLOATING_NET_NAME = conn.FLOATING_NET_NAME
31SUBNET_NAME = conn.FIO_SUBNET_NAME
32SUBNET_RANGE = conn.FIO_SUBNET_RANGE
33MTU_SIZE = conn.MTU_SIZE
34NET_IPV4 = conn.NET_IPV4
35
36KEYPAIR_NAME: Final[str] = conn.FIO_KEYPAIR_NAME
37PRIVATE_KEYPAIR_FILE: Final[str] = conn.PRIVATE_KEYPAIR_FILE
38
39SG_NAME: Final[str] = conn.FIO_SG_NAME
40HV_SUFFIX: Final[str] = conn.HV_SUFFIX
41CLOUD_NAME: Final[str] = conn.CLOUD_NAME
42
43NODES: Final[List[str]] = []
44SKIP_NODES: Final[List[str]] = []
45
46
47SG_ALLOW_ALL_RULES: Final[List[Dict]] = [
48 {
49 'remote_ip_prefix': '0.0.0.0/0',
50 'protocol': 'icmp',
51 'port_range_max': None,
52 'port_range_min': None,
53 'ethertype': 'IPv4'
54 },
55 {
56 'remote_ip_prefix': '0.0.0.0/0',
57 'protocol': 'tcp',
58 'port_range_max': 65535,
59 'port_range_min': 1,
60 'ethertype': 'IPv4'
61 },
62 {
63 'remote_ip_prefix': '0.0.0.0/0',
64 'protocol': 'udp',
65 'port_range_max': 65535,
66 'port_range_min': 1,
67 'ethertype': 'IPv4'
68 }
69]
70
71
72def create_server(
73 name, image_id, flavor_id, networks,
74 key_name, security_groups, availability_zone
75) -> openstack.connection.Connection:
76 srv = compute.create_server(
77 name=name, image_id=image_id, flavor_id=flavor_id, networks=networks,
78 key_name=key_name, security_groups=security_groups,
79 availability_zone=availability_zone)
80 return srv
81
82
83if __name__ == "__main__":
84 # Check if any fio servers already exist on the cloud
85 servers = compute.servers(details=False, name=CLIENT_NAME_MASK)
86 srvrs = list(servers)
87 if srvrs:
88 names = [s.name for s in srvrs]
89 print("The following servers already exist in the cloud:")
90 print(*names, sep='\n')
91 sys.exit(0)
92
93 # Create fio sg if needed
94 sg = network.find_security_group(SG_NAME)
95 if not sg:
96 sg = network.create_security_group(name=SG_NAME)
97 # Add 'allow-all' kind of rules to the security group
98 pairs = [
99 (r, d) for r in SG_ALLOW_ALL_RULES for d in ('ingress', 'egress')]
100 for (rule, direction) in pairs:
101 network.create_security_group_rule(
102 security_group_id=sg.id, direction=direction, **rule)
103
104 # Create fio keypair if needed
105 kp = compute.find_keypair(KEYPAIR_NAME)
106 if not kp:
107 kp = compute.create_keypair(name=KEYPAIR_NAME)
108 with open(PRIVATE_KEYPAIR_FILE, 'w') as f:
109 f.write("{}".format(kp.private_key))
110
111 os.chmod(PRIVATE_KEYPAIR_FILE, 0o400)
112
113 # Create fio flavor if needed
114 flavor = compute.find_flavor(FLAVOR_NAME)
115 if not flavor:
116 flavor = compute.create_flavor(
117 name=FLAVOR_NAME, ram=FLAVOR_RAM,
118 vcpus=FLAVOR_CPUS, disk=FLAVOR_DISK)
119
120 # Set image property to enable virtio-net multique in created servers
121 img = compute.find_image(UBUNTU_IMAGE_NAME)
122 compute.set_image_metadata(img.id, hw_vif_multiqueue_enabled='true')
123
124 # Create fio router if needed
125 fip_net = network.find_network(FLOATING_NET_NAME)
126 router = network.find_router(ROUTER_NAME)
127 if not router:
128 router = network.create_router(
129 name=ROUTER_NAME, external_gateway_info={'network_id': fip_net.id})
130
131 # Create fio net/subnet if needed
132 fio_net = network.find_network(NET_NAME)
133 if not fio_net:
134 fio_net = network.create_network(
135 name=NET_NAME,
136 availability_zone_hints=['nova'],
137 # mtu=MTU_SIZE,
138 shared=False,
139 port_security_enabled=True)
140 fio_subnet = network.create_subnet(
141 name=SUBNET_NAME,
142 network_id=fio_net.id,
143 cidr=SUBNET_RANGE,
144 ip_version=NET_IPV4)
145 # Add fio net to fio router
146 fio_net_port = network.add_interface_to_router(
147 router.id, subnet_id=fio_subnet.id)
148
149 # Get list of running computes with enabled 'nova-compute' service
150 cmp_services = compute.services(binary='nova-compute')
151 computes = [s for s in cmp_services if
152 s.host in NODES and
153 s.host not in SKIP_NODES and
154 s.state == 'up' and s.status == 'enabled']
155
156 # Prepare list of hypervisors to be used for running fio servers
157 hypervisors = []
158 computes_num = len(computes)
159 for i in range(CLIENTS_COUNT):
160 hypervisors.append(
161 ".".join([computes[i % computes_num].host, HV_SUFFIX]))
162
163 # Create <CLIENTS_COUNT> clients, attached to fio private network
164 vms = []
165 for i in range(CLIENTS_COUNT):
166 name = f"{CLIENT_NAME_MASK}{i}"
167 az = f"::{hypervisors[i]}"
168 flavor_id = flavor.id
169 vm = create_server(
170 name=name,
171 image_id=img.id,
172 flavor_id=flavor_id,
173 networks=[{'uuid': fio_net.id}],
174 key_name=KEYPAIR_NAME,
175 security_groups=[{'name': SG_NAME}],
176 availability_zone=az)
177 try:
178 vm = compute.wait_for_server(vm, wait=180)
179 node = hypervisors[i].split('.')[0]
180 print(f"Fio client VM '{vm.name}' is created on '{node}' node")
181 # Stop and exit if any of the servers creation failed (for any reason)
182 except ResourceFailure as e:
183 print(
184 f"Fio client VM '{vm.name}' creation failed with '{e.message}'"
185 " error.")
186 conn.delete_server(vm)
187 sys.exit(0)
188 vms.append(vm)
189
190 # Create a volume of the given type
191 vol_name = f"{VOL_NAME_MASK}{i}"
192 vol = volume.create_volume(
193 name=vol_name, size=VOL_SIZE, volume_type=VOL_TYPE)
194 try:
195 vol = volume.wait_for_status(vol, status='available')
196 print(f"Volume '{vol.name}' is created")
197 # Delete a volume if its creation failed and switch to next
198 # fio client VM
199 except ResourceFailure as e:
200 print(
201 f"Volume '{vol.name}' creation failed with '{e.message}' "
202 "error.")
203 conn.delete_volume(vol)
204 continue
205
206 # Attach the volume to the fio client
207 compute.create_volume_attachment(vm, volume=vol)
208 try:
209 vol = volume.wait_for_status(vol, status='in-use')
210 print(f"Volume '{vol.name}' is attached to '{vm.name}' fio client")
211 # Delete a volume if attachment failed and switch to next
212 # fio client VM
213 except ResourceFailure as e:
214 print(
215 f"Volume '{vol.name}' attachment failed with '{e.message}' "
216 "error.")
217 conn.delete_volume(vol)
218 continue