972457f416cff392755d7bb5b8f172ded17b6bed
4 # Copyright 2016 RIFT.IO Inc
6 # Licensed under the Apache License, Version 2.0 (the "License");
7 # you may not use this file except in compliance with the License.
8 # You may obtain a copy of the License at
10 # http://www.apache.org/licenses/LICENSE-2.0
12 # Unless required by applicable law or agreed to in writing, software
13 # distributed under the License is distributed on an "AS IS" BASIS,
14 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 # See the License for the specific language governing permissions and
16 # limitations under the License.
19 import rift
.rwcal
.openstack
as openstack_drv
29 logging
.basicConfig(level
=logging
.DEBUG
)
30 logger
= logging
.getLogger()
31 rwlog_handler
= rwlogger
.RwLogger(category
="rw-cal-log",
32 subcategory
="openstack",)
33 logger
.addHandler(rwlog_handler
)
34 #logger.setLevel(logging.DEBUG)
37 FILE_LOCK
= '/tmp/_openstack_prepare_vm.lock'
39 # This will create it if it does not exist already
40 self
.filename
= FileLock
.FILE_LOCK
43 # Bitwise OR fcntl.LOCK_NB if you need a non-blocking lock
45 logger
.info("<PID: %d> Attempting to acquire log." %os.getpid())
46 self
.handle
= open(self
.filename
, 'w')
47 fcntl
.flock(self
.handle
, fcntl
.LOCK_EX
)
48 logger
.info("<PID: %d> Lock successfully acquired." %os.getpid())
51 fcntl
.flock(self
.handle
, fcntl
.LOCK_UN
)
53 logger
.info("<PID: %d> Released lock." %os.getpid())
56 if self
.handle
and self
.handle
.closed
== False:
60 def allocate_floating_ip(drv
, argument
):
61 #### Allocate a floating_ip
63 available_ip
= [ ip
for ip
in drv
.nova_floating_ip_list() if ip
.instance_id
== None ]
65 if argument
.pool_name
:
66 ### Filter further based on IP address
67 available_ip
= [ ip
for ip
in available_ip
if ip
.pool
== argument
.pool_name
]
70 logger
.info("<PID: %d> No free floating_ips available. Allocating fresh from pool: %s" %(os
.getpid(), argument
.pool_name
))
71 pool_name
= argument
.pool_name
if argument
.pool_name
is not None else None
72 floating_ip
= drv
.nova_floating_ip_create(pool_name
)
74 floating_ip
= random
.choice(available_ip
)
75 logger
.info("<PID: %d> Selected floating_ip: %s from available free pool" %(os
.getpid(), floating_ip
))
79 except Exception as e
:
80 logger
.error("Floating IP Allocation Failed - %s", e
)
84 def handle_floating_ip_assignment(drv
, server
, argument
, management_ip
):
86 ### Try 3 time (<<<magic number>>>)
88 for attempt
in range(RETRY
):
91 floating_ip
= allocate_floating_ip(drv
, argument
)
92 logger
.info("Assigning the floating_ip: %s to VM: %s" %(floating_ip
, server
['name']))
93 drv
.nova_floating_ip_assign(argument
.server_id
,
96 logger
.info("Assigned floating_ip: %s to management_ip: %s" %(floating_ip
, management_ip
))
97 except Exception as e
:
98 logger
.error("Could not assign floating_ip: %s to VM: %s. Exception: %s" %(floating_ip
, server
['name'], str(e
)))
100 if attempt
== (RETRY
-1):
101 logger
.error("Max attempts %d reached for floating_ip allocation. Giving up" %attempt
)
104 logger
.error("Retrying floating ip allocation. Current retry count: %d" %attempt
)
110 def assign_floating_ip_address(drv
, argument
):
111 if not argument
.floating_ip
:
114 server
= drv
.nova_server_get(argument
.server_id
)
117 server
= drv
.nova_server_get(argument
.server_id
)
118 for network_name
,network_info
in server
['addresses'].items():
119 if network_info
and network_name
== argument
.mgmt_network
:
120 for n_info
in network_info
:
121 if 'OS-EXT-IPS:type' in n_info
and n_info
['OS-EXT-IPS:type'] == 'fixed':
122 management_ip
= n_info
['addr']
124 handle_floating_ip_assignment(drv
, server
, argument
, management_ip
)
126 except Exception as e
:
127 logger
.error("Exception in assign_floating_ip_address : %s", e
)
130 logger
.info("Waiting for management_ip to be assigned to server: %s" %(server
['name']))
133 logger
.info("No management_ip IP available to associate floating_ip for server: %s" %(server
['name']))
137 def create_port_metadata(drv
, argument
):
138 if argument
.port_metadata
== False:
141 ### Get Management Network ID
142 network_list
= drv
.neutron_network_list()
143 mgmt_network_id
= [net
['id'] for net
in network_list
if net
['name'] == argument
.mgmt_network
][0]
144 port_list
= [ port
for port
in drv
.neutron_port_list(**{'device_id': argument
.server_id
})
145 if port
['network_id'] != mgmt_network_id
]
148 meta_data
['rift-meta-ports'] = str(len(port_list
))
150 for port
in port_list
:
152 info
.append('"port_name":"'+port
['name']+'"')
153 if 'mac_address' in port
:
154 info
.append('"hw_addr":"'+port
['mac_address']+'"')
155 if 'network_id' in port
:
156 #info.append('"network_id":"'+port['network_id']+'"')
157 net_name
= [net
['name'] for net
in network_list
if net
['id'] == port
['network_id']]
159 info
.append('"network_name":"'+net_name
[0]+'"')
160 if 'fixed_ips' in port
:
161 ip_address
= port
['fixed_ips'][0]['ip_address']
162 info
.append('"ip":"'+ip_address
+'"')
164 meta_data
['rift-meta-port-'+str(port_id
)] = '{' + ','.join(info
) + '}'
167 nvconn
= drv
.nova_drv
._get
_nova
_connection
()
168 nvconn
.servers
.set_meta(argument
.server_id
, meta_data
)
170 def get_volume_id(server_vol_list
, name
):
171 if server_vol_list
is None:
174 for os_volume
in server_vol_list
:
176 " Device name is of format /dev/vda"
177 vol_name
= (os_volume
['device']).split('/')[2]
181 return os_volume
['volumeId']
183 def create_volume_metadata(drv
, argument
):
184 if argument
.vol_metadata
is None:
187 yaml_vol_str
= argument
.vol_metadata
.read()
188 yaml_vol_cfg
= yaml
.load(yaml_vol_str
)
190 srv_volume_list
= drv
.nova_volume_list(argument
.server_id
)
191 for volume
in yaml_vol_cfg
:
192 if 'custom_meta_data' not in volume
:
195 for vol_md_item
in volume
['custom_meta_data']:
196 if 'value' not in vol_md_item
:
198 vmd
[vol_md_item
['name']] = vol_md_item
['value']
201 vol_id
= get_volume_id(srv_volume_list
, volume
['name'])
203 logger
.error("Server %s Could not find volume %s" %(argument
.server_id
, volume
['name']))
205 drv
.cinder_volume_set_metadata(vol_id
, vmd
)
208 def prepare_vm_after_boot(drv
,argument
):
209 ### Important to call create_port_metadata before assign_floating_ip_address
210 ### since assign_floating_ip_address can wait thus delaying port_metadata creation
212 ### Wait for a max of 5 minute for server to come up -- Needs fine tuning
215 for i
in range(int(wait_time
/sleep_time
)):
216 server
= drv
.nova_server_get(argument
.server_id
)
217 if server
['status'] == 'ACTIVE':
218 logger
.info("Server %s to reached active state" %(server
['name']))
220 elif server
['status'] == 'BUILD':
221 logger
.info("Waiting for server: %s to build. Current state: %s" %(server
['name'], server
['status']))
222 time
.sleep(sleep_time
)
224 logger
.info("Server %s reached state: %s" %(server
['name'], server
['status']))
227 logger
.error("Server %s did not reach active state in %d seconds. Current state: %s" %(server
['name'], wait_time
, server
['status']))
229 #create_port_metadata(drv, argument)
230 create_volume_metadata(drv
, argument
)
232 assign_floating_ip_address(drv
, argument
)
233 except Exception as e
:
234 logger
.error("Exception in prepare_vm_after_boot : %s", e
)
242 parser
= argparse
.ArgumentParser(description
='Script to create openstack resources')
243 parser
.add_argument('--auth_url',
247 help='Keystone Auth URL')
249 parser
.add_argument('--username',
253 help = "Username for openstack installation")
255 parser
.add_argument('--password',
259 help = "Password for openstack installation")
261 parser
.add_argument('--tenant_name',
263 dest
= "tenant_name",
265 help = "Tenant name openstack installation")
267 parser
.add_argument('--user_domain',
269 dest
= "user_domain",
272 help = "User domain name for openstack installation")
274 parser
.add_argument('--project_domain',
276 dest
= "project_domain",
279 help = "Project domain name for openstack installation")
281 parser
.add_argument('--region',
284 default
= "RegionOne",
286 help = "Region name for openstack installation")
288 parser
.add_argument('--mgmt_network',
290 dest
= "mgmt_network",
292 help = "mgmt_network")
294 parser
.add_argument('--server_id',
298 help = "Server ID on which boot operations needs to be performed")
300 parser
.add_argument('--floating_ip',
301 action
= "store_true",
302 dest
= "floating_ip",
304 help = "Floating IP assignment required")
306 parser
.add_argument('--pool_name',
310 help = "Floating IP pool name")
313 parser
.add_argument('--port_metadata',
314 action
= "store_true",
315 dest
= "port_metadata",
317 help = "Create Port Metadata")
319 parser
.add_argument("--vol_metadata", type=argparse
.FileType('r'))
321 argument
= parser
.parse_args()
323 if not argument
.auth_url
:
324 logger
.error("ERROR: AuthURL is not configured")
327 logger
.info("Using AuthURL: %s" %(argument
.auth_url
))
329 if not argument
.username
:
330 logger
.error("ERROR: Username is not configured")
333 logger
.info("Using Username: %s" %(argument
.username
))
335 if not argument
.password
:
336 logger
.error("ERROR: Password is not configured")
339 logger
.info("Using Password: %s" %(argument
.password
))
341 if not argument
.tenant_name
:
342 logger
.error("ERROR: Tenant Name is not configured")
345 logger
.info("Using Tenant Name: %s" %(argument
.tenant_name
))
347 if not argument
.mgmt_network
:
348 logger
.error("ERROR: Management Network Name is not configured")
351 logger
.info("Using Management Network: %s" %(argument
.mgmt_network
))
353 if not argument
.server_id
:
354 logger
.error("ERROR: Server ID is not configured")
357 logger
.info("Using Server ID : %s" %(argument
.server_id
))
365 logger
.error("fork failed: %d (%s)\n" % (e
.errno
, e
.strerror
))
368 kwargs
= dict(username
= argument
.username
,
369 password
= argument
.password
,
370 auth_url
= argument
.auth_url
,
371 project
= argument
.tenant_name
,
372 mgmt_network
= argument
.mgmt_network
,
373 cert_validate
= False,
374 user_domain
= argument
.user_domain
,
375 project_domain
= argument
.project_domain
,
376 region
= argument
.region
)
378 drv
= openstack_drv
.OpenstackDriver(logger
= logger
, **kwargs
)
380 prepare_vm_after_boot(drv
, argument
)
381 except Exception as e
:
382 logger
.error("Exception in main of prepare_vm : %s", e
)
385 if __name__
== "__main__":
388 # Do not print anything in this script. This is a subprocess spawned by rwmain
389 # and the following print determines the success or failure of this script.
391 except Exception as e
:
392 logger
.error("Exception in prepare_vm : %s", e
)
393 # Do not print anything in this script. This is a subprocess spawned by rwmain
394 # and the following print determines the success or failure of this script.
395 print("False+" + str(e
),end
="")