blob: be33d28bf10d8bc353f9c8f7e9c47c5083cff234 [file] [log] [blame]
Dmitriy Kruglov090cb192023-07-04 22:10:50 +02001import multiprocessing as mp
Dmitriy Kruglov6146cb42023-04-10 00:13:59 +02002import os
Dmitriy Kruglov090cb192023-07-04 22:10:50 +02003import random
Dmitriy Kruglov6146cb42023-04-10 00:13:59 +02004import sys
5from typing import Dict, Final, List
6
7import connection as conn
Dmitriy Kruglov6146cb42023-04-10 00:13:59 +02008from openstack.exceptions import ResourceFailure
9
10
11compute = conn.cloud.compute
12network = conn.cloud.network
13volume = conn.cloud.volume
14
15CLIENTS_COUNT: Final[int] = conn.FIO_CLIENTS_COUNT
16CLIENT_NAME_MASK: Final[str] = conn.FIO_CLIENT_NAME_MASK
Dmitriy Kruglov090cb192023-07-04 22:10:50 +020017AA_SERVER_GROUP_NAME: Final[str] = conn.FIO_AA_SERVER_GROUP_NAME
Dmitriy Kruglov6146cb42023-04-10 00:13:59 +020018UBUNTU_IMAGE_NAME: Final[str] = conn.UBUNTU_IMAGE_NAME
19
20VOL_NAME_MASK: Final[str] = conn.FIO_VOL_NAME_MASK
21VOL_SIZE: Final[int] = conn.FIO_VOL_SIZE
22VOL_TYPE: Final[str] = conn.FIO_VOL_TYPE
23VOL_MOUNTPOINT: Final[str] = conn.FIO_VOL_MOUNTPOINT
24
25FLAVOR_NAME: Final[str] = conn.FIO_FLAVOR_NAME
26FLAVOR_RAM: Final[int] = conn.FIO_FLAVOR_RAM
27FLAVOR_CPUS: Final[int] = conn.FIO_FLAVOR_CPUS
28FLAVOR_DISK: Final[int] = conn.FIO_FLAVOR_DISK
29
30NET_NAME: Final[str] = conn.FIO_NET_NAME
31ROUTER_NAME: Final[str] = conn.FIO_ROUTER_NAME
32FLOATING_NET_NAME = conn.FLOATING_NET_NAME
33SUBNET_NAME = conn.FIO_SUBNET_NAME
34SUBNET_RANGE = conn.FIO_SUBNET_RANGE
35MTU_SIZE = conn.MTU_SIZE
36NET_IPV4 = conn.NET_IPV4
37
38KEYPAIR_NAME: Final[str] = conn.FIO_KEYPAIR_NAME
39PRIVATE_KEYPAIR_FILE: Final[str] = conn.PRIVATE_KEYPAIR_FILE
40
41SG_NAME: Final[str] = conn.FIO_SG_NAME
42HV_SUFFIX: Final[str] = conn.HV_SUFFIX
43CLOUD_NAME: Final[str] = conn.CLOUD_NAME
Dmitriy Kruglov090cb192023-07-04 22:10:50 +020044CONCURRENCY: Final[int] = conn.CONCURRENCY
Dmitriy Kruglov6146cb42023-04-10 00:13:59 +020045
46NODES: Final[List[str]] = []
47SKIP_NODES: Final[List[str]] = []
48
49
50SG_ALLOW_ALL_RULES: Final[List[Dict]] = [
51 {
52 'remote_ip_prefix': '0.0.0.0/0',
53 'protocol': 'icmp',
54 'port_range_max': None,
55 'port_range_min': None,
56 'ethertype': 'IPv4'
57 },
58 {
59 'remote_ip_prefix': '0.0.0.0/0',
60 'protocol': 'tcp',
61 'port_range_max': 65535,
62 'port_range_min': 1,
63 'ethertype': 'IPv4'
64 },
65 {
66 'remote_ip_prefix': '0.0.0.0/0',
67 'protocol': 'udp',
68 'port_range_max': 65535,
69 'port_range_min': 1,
70 'ethertype': 'IPv4'
71 }
72]
73
74
Dmitriy Kruglov090cb192023-07-04 22:10:50 +020075def create_fio_client(
76 image_id: str, flavor_id: str, networks: List,
77 key_name: str, security_groups: List, server_group_id: str
78) -> None:
79 rand_name = str(random.randint(1, 0x7fffffff))
80 vm_name = f"{CLIENT_NAME_MASK}-{rand_name}"
81
82 vm = compute.create_server(
83 name=vm_name,
84 image_id=image_id,
85 flavor_id=flavor_id,
86 networks=networks,
87 key_name=key_name,
88 security_groups=security_groups,
89 scheduler_hints={'group': server_group_id})
90 try:
91 vm = compute.wait_for_server(vm, wait=180)
92 print(f"Fio client '{vm.name}' is created on '{vm.compute_host}' node")
93 # Stop and exit if any of the servers creation failed (for any reason)
94 except ResourceFailure as e:
95 print(
96 f"Fio client '{vm.name}' creation failed with '{e.message}'"
97 " error.")
98 conn.delete_server(vm)
99 sys.exit(0)
100
101 # Create a volume of the given type
102 vol_name = f"{VOL_NAME_MASK}-{rand_name}"
103 vol = volume.create_volume(
104 name=vol_name, size=VOL_SIZE, volume_type=VOL_TYPE)
105 try:
106 vol = volume.wait_for_status(vol, status='available')
107 print(f"Volume '{vol.name}' is created")
108 # Delete a volume if its creation failed and switch to next
109 # fio client VM
110 except ResourceFailure as e:
111 print(
112 f"Volume '{vol.name}' creation failed with '{e.message}' "
113 "error.")
114 conn.delete_volume(vol)
115
116 # Attach the volume to the fio client
Ievgeniia Zadorozhnaa33b29a2023-08-29 18:19:47 +0300117 compute.create_volume_attachment(vm, volume_id=vol.id)
Dmitriy Kruglov090cb192023-07-04 22:10:50 +0200118 try:
119 vol = volume.wait_for_status(vol, status='in-use')
120 print(f"Volume '{vol.name}' is attached to '{vm.name}' fio client")
121 # Delete a volume if attachment failed and switch to next
122 # fio client VM
123 except ResourceFailure as e:
124 print(
125 f"Volume '{vol.name}' attachment failed with '{e.message}' "
126 "error.")
127 conn.delete_volume(vol)
Dmitriy Kruglov6146cb42023-04-10 00:13:59 +0200128
129
130if __name__ == "__main__":
131 # Check if any fio servers already exist on the cloud
132 servers = compute.servers(details=False, name=CLIENT_NAME_MASK)
133 srvrs = list(servers)
134 if srvrs:
135 names = [s.name for s in srvrs]
136 print("The following servers already exist in the cloud:")
137 print(*names, sep='\n')
138 sys.exit(0)
139
140 # Create fio sg if needed
Ievgeniia Zadorozhna09f06c22023-08-29 19:39:27 +0300141 project_id = conn.cloud.current_project_id
Dmitriy Kruglov090cb192023-07-04 22:10:50 +0200142 sg = network.find_security_group(SG_NAME, project_id=project_id)
Dmitriy Kruglov6146cb42023-04-10 00:13:59 +0200143 if not sg:
144 sg = network.create_security_group(name=SG_NAME)
145 # Add 'allow-all' kind of rules to the security group
146 pairs = [
147 (r, d) for r in SG_ALLOW_ALL_RULES for d in ('ingress', 'egress')]
148 for (rule, direction) in pairs:
149 network.create_security_group_rule(
150 security_group_id=sg.id, direction=direction, **rule)
151
152 # Create fio keypair if needed
153 kp = compute.find_keypair(KEYPAIR_NAME)
154 if not kp:
155 kp = compute.create_keypair(name=KEYPAIR_NAME)
156 with open(PRIVATE_KEYPAIR_FILE, 'w') as f:
157 f.write("{}".format(kp.private_key))
158
159 os.chmod(PRIVATE_KEYPAIR_FILE, 0o400)
160
161 # Create fio flavor if needed
162 flavor = compute.find_flavor(FLAVOR_NAME)
163 if not flavor:
164 flavor = compute.create_flavor(
165 name=FLAVOR_NAME, ram=FLAVOR_RAM,
166 vcpus=FLAVOR_CPUS, disk=FLAVOR_DISK)
167
168 # Set image property to enable virtio-net multique in created servers
169 img = compute.find_image(UBUNTU_IMAGE_NAME)
170 compute.set_image_metadata(img.id, hw_vif_multiqueue_enabled='true')
171
172 # Create fio router if needed
173 fip_net = network.find_network(FLOATING_NET_NAME)
174 router = network.find_router(ROUTER_NAME)
175 if not router:
176 router = network.create_router(
177 name=ROUTER_NAME, external_gateway_info={'network_id': fip_net.id})
178
179 # Create fio net/subnet if needed
180 fio_net = network.find_network(NET_NAME)
181 if not fio_net:
182 fio_net = network.create_network(
183 name=NET_NAME,
184 availability_zone_hints=['nova'],
185 # mtu=MTU_SIZE,
186 shared=False,
187 port_security_enabled=True)
188 fio_subnet = network.create_subnet(
189 name=SUBNET_NAME,
190 network_id=fio_net.id,
191 cidr=SUBNET_RANGE,
192 ip_version=NET_IPV4)
193 # Add fio net to fio router
194 fio_net_port = network.add_interface_to_router(
195 router.id, subnet_id=fio_subnet.id)
196
Dmitriy Kruglov090cb192023-07-04 22:10:50 +0200197 # Create fio server group with anti-affinity scheduling policy
Ievgeniia Zadorozhnaa33b29a2023-08-29 18:19:47 +0300198 server_group = conn.find_server_group(AA_SERVER_GROUP_NAME)
Dmitriy Kruglov090cb192023-07-04 22:10:50 +0200199 if not server_group:
200 server_group = compute.create_server_group(
201 name=AA_SERVER_GROUP_NAME, policies=['soft-anti-affinity'])
Dmitriy Kruglov6146cb42023-04-10 00:13:59 +0200202
Dmitriy Kruglov090cb192023-07-04 22:10:50 +0200203 vm_kwargs = dict(
204 image_id=img.id,
205 flavor_id=flavor.id,
206 networks=[{'uuid': fio_net.id}],
207 key_name=KEYPAIR_NAME,
208 security_groups=[{'name': SG_NAME}],
209 server_group_id=server_group.id)
Dmitriy Kruglov6146cb42023-04-10 00:13:59 +0200210
Dmitriy Kruglov090cb192023-07-04 22:10:50 +0200211 # Create fio client VMs in parallel in batches of CONCURRENCY size
212 with mp.Pool(processes=CONCURRENCY) as pool:
213 results = [
214 pool.apply_async(create_fio_client, kwds=vm_kwargs)
215 for _ in range(CLIENTS_COUNT)]
216 # Wait for batch of fio client VMs to be created
217 _ = [r.get() for r in results]