blob: ab4502dc34836e379ec02b416aaad66cd949d0b1 [file] [log] [blame]
Dmitriy Kruglovd3b2bb92023-12-07 13:26:31 +01001import base64
Dmitriy Kruglov5e3ee1d2024-06-09 11:59:00 +02002import concurrent.futures as cex
Dmitriy Kruglov6146cb42023-04-10 00:13:59 +02003import os
Dmitriy Kruglov090cb192023-07-04 22:10:50 +02004import random
Dmitriy Kruglov6146cb42023-04-10 00:13:59 +02005import sys
6from typing import Dict, Final, List
7
8import connection as conn
Dmitriy Kruglov6146cb42023-04-10 00:13:59 +02009from openstack.exceptions import ResourceFailure
Dmitriy Kruglovd3b2bb92023-12-07 13:26:31 +010010from oslo_utils import encodeutils
Dmitriy Kruglov6146cb42023-04-10 00:13:59 +020011
12
13compute = conn.cloud.compute
14network = conn.cloud.network
15volume = conn.cloud.volume
16
17CLIENTS_COUNT: Final[int] = conn.FIO_CLIENTS_COUNT
18CLIENT_NAME_MASK: Final[str] = conn.FIO_CLIENT_NAME_MASK
Dmitriy Kruglov090cb192023-07-04 22:10:50 +020019AA_SERVER_GROUP_NAME: Final[str] = conn.FIO_AA_SERVER_GROUP_NAME
Dmitriy Kruglov6146cb42023-04-10 00:13:59 +020020UBUNTU_IMAGE_NAME: Final[str] = conn.UBUNTU_IMAGE_NAME
21
22VOL_NAME_MASK: Final[str] = conn.FIO_VOL_NAME_MASK
23VOL_SIZE: Final[int] = conn.FIO_VOL_SIZE
24VOL_TYPE: Final[str] = conn.FIO_VOL_TYPE
25VOL_MOUNTPOINT: Final[str] = conn.FIO_VOL_MOUNTPOINT
26
27FLAVOR_NAME: Final[str] = conn.FIO_FLAVOR_NAME
28FLAVOR_RAM: Final[int] = conn.FIO_FLAVOR_RAM
29FLAVOR_CPUS: Final[int] = conn.FIO_FLAVOR_CPUS
30FLAVOR_DISK: Final[int] = conn.FIO_FLAVOR_DISK
31
32NET_NAME: Final[str] = conn.FIO_NET_NAME
33ROUTER_NAME: Final[str] = conn.FIO_ROUTER_NAME
34FLOATING_NET_NAME = conn.FLOATING_NET_NAME
35SUBNET_NAME = conn.FIO_SUBNET_NAME
36SUBNET_RANGE = conn.FIO_SUBNET_RANGE
37MTU_SIZE = conn.MTU_SIZE
38NET_IPV4 = conn.NET_IPV4
39
40KEYPAIR_NAME: Final[str] = conn.FIO_KEYPAIR_NAME
41PRIVATE_KEYPAIR_FILE: Final[str] = conn.PRIVATE_KEYPAIR_FILE
42
43SG_NAME: Final[str] = conn.FIO_SG_NAME
44HV_SUFFIX: Final[str] = conn.HV_SUFFIX
45CLOUD_NAME: Final[str] = conn.CLOUD_NAME
Dmitriy Kruglov090cb192023-07-04 22:10:50 +020046CONCURRENCY: Final[int] = conn.CONCURRENCY
Dmitriy Kruglov6146cb42023-04-10 00:13:59 +020047
48NODES: Final[List[str]] = []
49SKIP_NODES: Final[List[str]] = []
50
51
52SG_ALLOW_ALL_RULES: Final[List[Dict]] = [
53 {
54 'remote_ip_prefix': '0.0.0.0/0',
55 'protocol': 'icmp',
56 'port_range_max': None,
57 'port_range_min': None,
58 'ethertype': 'IPv4'
59 },
60 {
61 'remote_ip_prefix': '0.0.0.0/0',
62 'protocol': 'tcp',
63 'port_range_max': 65535,
64 'port_range_min': 1,
65 'ethertype': 'IPv4'
66 },
67 {
68 'remote_ip_prefix': '0.0.0.0/0',
69 'protocol': 'udp',
70 'port_range_max': 65535,
71 'port_range_min': 1,
72 'ethertype': 'IPv4'
73 }
74]
75
76
Dmitriy Kruglov090cb192023-07-04 22:10:50 +020077def create_fio_client(
78 image_id: str, flavor_id: str, networks: List,
Dmitriy Kruglovd3b2bb92023-12-07 13:26:31 +010079 key_name: str, security_groups: List, server_group_id: str,
80 user_data: str
Dmitriy Kruglov090cb192023-07-04 22:10:50 +020081) -> None:
82 rand_name = str(random.randint(1, 0x7fffffff))
83 vm_name = f"{CLIENT_NAME_MASK}-{rand_name}"
84
Dmitriy Kruglovd3b2bb92023-12-07 13:26:31 +010085 kwargs = {}
86 if user_data:
87 kwargs['user_data'] = user_data
Dmitriy Kruglov090cb192023-07-04 22:10:50 +020088 vm = compute.create_server(
89 name=vm_name,
90 image_id=image_id,
91 flavor_id=flavor_id,
92 networks=networks,
93 key_name=key_name,
94 security_groups=security_groups,
Dmitriy Kruglovd3b2bb92023-12-07 13:26:31 +010095 scheduler_hints={'group': server_group_id},
96 **kwargs)
Dmitriy Kruglov090cb192023-07-04 22:10:50 +020097 try:
98 vm = compute.wait_for_server(vm, wait=180)
99 print(f"Fio client '{vm.name}' is created on '{vm.compute_host}' node")
100 # Stop and exit if any of the servers creation failed (for any reason)
101 except ResourceFailure as e:
102 print(
103 f"Fio client '{vm.name}' creation failed with '{e.message}'"
104 " error.")
105 conn.delete_server(vm)
106 sys.exit(0)
107
108 # Create a volume of the given type
109 vol_name = f"{VOL_NAME_MASK}-{rand_name}"
110 vol = volume.create_volume(
111 name=vol_name, size=VOL_SIZE, volume_type=VOL_TYPE)
112 try:
113 vol = volume.wait_for_status(vol, status='available')
114 print(f"Volume '{vol.name}' is created")
115 # Delete a volume if its creation failed and switch to next
116 # fio client VM
117 except ResourceFailure as e:
118 print(
119 f"Volume '{vol.name}' creation failed with '{e.message}' "
120 "error.")
121 conn.delete_volume(vol)
122
123 # Attach the volume to the fio client
124 compute.create_volume_attachment(vm, volume=vol)
125 try:
126 vol = volume.wait_for_status(vol, status='in-use')
127 print(f"Volume '{vol.name}' is attached to '{vm.name}' fio client")
128 # Delete a volume if attachment failed and switch to next
129 # fio client VM
130 except ResourceFailure as e:
131 print(
132 f"Volume '{vol.name}' attachment failed with '{e.message}' "
133 "error.")
134 conn.delete_volume(vol)
Dmitriy Kruglov6146cb42023-04-10 00:13:59 +0200135
136
137if __name__ == "__main__":
138 # Check if any fio servers already exist on the cloud
139 servers = compute.servers(details=False, name=CLIENT_NAME_MASK)
140 srvrs = list(servers)
141 if srvrs:
142 names = [s.name for s in srvrs]
143 print("The following servers already exist in the cloud:")
144 print(*names, sep='\n')
145 sys.exit(0)
146
147 # Create fio sg if needed
Ievgeniia Zadorozhna09f06c22023-08-29 19:39:27 +0300148 project_id = conn.cloud.current_project_id
Dmitriy Kruglov090cb192023-07-04 22:10:50 +0200149 sg = network.find_security_group(SG_NAME, project_id=project_id)
Dmitriy Kruglov6146cb42023-04-10 00:13:59 +0200150 if not sg:
151 sg = network.create_security_group(name=SG_NAME)
152 # Add 'allow-all' kind of rules to the security group
153 pairs = [
154 (r, d) for r in SG_ALLOW_ALL_RULES for d in ('ingress', 'egress')]
155 for (rule, direction) in pairs:
156 network.create_security_group_rule(
157 security_group_id=sg.id, direction=direction, **rule)
158
159 # Create fio keypair if needed
160 kp = compute.find_keypair(KEYPAIR_NAME)
161 if not kp:
162 kp = compute.create_keypair(name=KEYPAIR_NAME)
163 with open(PRIVATE_KEYPAIR_FILE, 'w') as f:
164 f.write("{}".format(kp.private_key))
165
166 os.chmod(PRIVATE_KEYPAIR_FILE, 0o400)
167
168 # Create fio flavor if needed
169 flavor = compute.find_flavor(FLAVOR_NAME)
170 if not flavor:
171 flavor = compute.create_flavor(
172 name=FLAVOR_NAME, ram=FLAVOR_RAM,
173 vcpus=FLAVOR_CPUS, disk=FLAVOR_DISK)
174
175 # Set image property to enable virtio-net multique in created servers
176 img = compute.find_image(UBUNTU_IMAGE_NAME)
177 compute.set_image_metadata(img.id, hw_vif_multiqueue_enabled='true')
178
179 # Create fio router if needed
180 fip_net = network.find_network(FLOATING_NET_NAME)
181 router = network.find_router(ROUTER_NAME)
182 if not router:
183 router = network.create_router(
184 name=ROUTER_NAME, external_gateway_info={'network_id': fip_net.id})
185
186 # Create fio net/subnet if needed
187 fio_net = network.find_network(NET_NAME)
188 if not fio_net:
189 fio_net = network.create_network(
190 name=NET_NAME,
191 availability_zone_hints=['nova'],
192 # mtu=MTU_SIZE,
193 shared=False,
194 port_security_enabled=True)
195 fio_subnet = network.create_subnet(
196 name=SUBNET_NAME,
197 network_id=fio_net.id,
198 cidr=SUBNET_RANGE,
199 ip_version=NET_IPV4)
200 # Add fio net to fio router
201 fio_net_port = network.add_interface_to_router(
202 router.id, subnet_id=fio_subnet.id)
203
Dmitriy Kruglov090cb192023-07-04 22:10:50 +0200204 # Create fio server group with anti-affinity scheduling policy
205 server_group = compute.find_server_group(
206 AA_SERVER_GROUP_NAME, all_projects=True)
207 if not server_group:
208 server_group = compute.create_server_group(
209 name=AA_SERVER_GROUP_NAME, policies=['soft-anti-affinity'])
Dmitriy Kruglov6146cb42023-04-10 00:13:59 +0200210
Dmitriy Kruglovd3b2bb92023-12-07 13:26:31 +0100211 # Prepare user data for fio client VMs
212 udata = None
213 with open('user_data.sh', 'r') as script:
214 f = encodeutils.safe_encode(script.read().encode('utf-8'))
215 udata = base64.b64encode(f).decode('utf-8')
216
Dmitriy Kruglov090cb192023-07-04 22:10:50 +0200217 vm_kwargs = dict(
218 image_id=img.id,
219 flavor_id=flavor.id,
220 networks=[{'uuid': fio_net.id}],
221 key_name=KEYPAIR_NAME,
222 security_groups=[{'name': SG_NAME}],
Dmitriy Kruglovd3b2bb92023-12-07 13:26:31 +0100223 server_group_id=server_group.id,
224 user_data=udata)
Dmitriy Kruglov6146cb42023-04-10 00:13:59 +0200225
Dmitriy Kruglov090cb192023-07-04 22:10:50 +0200226 # Create fio client VMs in parallel in batches of CONCURRENCY size
Dmitriy Kruglov5e3ee1d2024-06-09 11:59:00 +0200227 with cex.ThreadPoolExecutor(max_workers=CONCURRENCY) as executor:
228 futures = [executor.submit(create_fio_client, **vm_kwargs) for _ in range(CLIENTS_COUNT)]
Dmitriy Kruglov090cb192023-07-04 22:10:50 +0200229 # Wait for batch of fio client VMs to be created
Dmitriy Kruglov5e3ee1d2024-06-09 11:59:00 +0200230 _ = [future.result() for future in futures]