import argparse
import sys, os, time
import rwlogger
+import yaml
+import random
+import fcntl
+
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger()
-
rwlog_handler = rwlogger.RwLogger(category="rw-cal-log",
subcategory="openstack",)
logger.addHandler(rwlog_handler)
#logger.setLevel(logging.DEBUG)
+class FileLock:
+ FILE_LOCK = '/tmp/_openstack_prepare_vm.lock'
+ def __init__(self):
+ # This will create it if it does not exist already
+ self.filename = FileLock.FILE_LOCK
+ self.handle = None
+
+ # Bitwise OR fcntl.LOCK_NB if you need a non-blocking lock
+ def acquire(self):
+ logger.info("<PID: %d> Attempting to acquire log." %os.getpid())
+ self.handle = open(self.filename, 'w')
+ fcntl.flock(self.handle, fcntl.LOCK_EX)
+ logger.info("<PID: %d> Lock successfully acquired." %os.getpid())
+
+ def release(self):
+ fcntl.flock(self.handle, fcntl.LOCK_UN)
+ self.handle.close()
+ logger.info("<PID: %d> Released lock." %os.getpid())
+
+ def __del__(self):
+ if self.handle and self.handle.closed == False:
+ self.handle.close()
+
+
+def allocate_floating_ip(drv, argument):
+ #### Allocate a floating_ip
+ try:
+ available_ip = [ ip for ip in drv.nova_floating_ip_list() if ip.instance_id == None ]
+
+ if argument.pool_name:
+ ### Filter further based on IP address
+ available_ip = [ ip for ip in available_ip if ip.pool == argument.pool_name ]
+
+ if not available_ip:
+ logger.info("<PID: %d> No free floating_ips available. Allocating fresh from pool: %s" %(os.getpid(), argument.pool_name))
+ pool_name = argument.pool_name if argument.pool_name is not None else None
+ floating_ip = drv.nova_floating_ip_create(pool_name)
+ else:
+ floating_ip = random.choice(available_ip)
+ logger.info("<PID: %d> Selected floating_ip: %s from available free pool" %(os.getpid(), floating_ip))
+ return floating_ip
+
+ except Exception as e:
+ logger.error("Floating IP Allocation Failed - %s", e)
+ return None
+
+
+def handle_floating_ip_assignment(drv, server, argument, management_ip):
+ lock = FileLock()
+ ### Try 3 time (<<<magic number>>>)
+ RETRY = 3
+ for attempt in range(RETRY):
+ try:
+ lock.acquire()
+ floating_ip = allocate_floating_ip(drv, argument)
+ logger.info("Assigning the floating_ip: %s to VM: %s" %(floating_ip, server['name']))
+ drv.nova_floating_ip_assign(argument.server_id,
+ floating_ip,
+ management_ip)
+ logger.info("Assigned floating_ip: %s to management_ip: %s" %(floating_ip, management_ip))
+ except Exception as e:
+ logger.error("Could not assign floating_ip: %s to VM: %s. Exception: %s" %(floating_ip, server['name'], str(e)))
+ lock.release()
+ if attempt == (RETRY -1):
+ logger.error("Max attempts %d reached for floating_ip allocation. Giving up" %attempt)
+ raise
+ else:
+ logger.error("Retrying floating ip allocation. Current retry count: %d" %attempt)
+ else:
+ lock.release()
+ return
+
+
def assign_floating_ip_address(drv, argument):
if not argument.floating_ip:
return
server = drv.nova_server_get(argument.server_id)
- logger.info("Assigning the floating_ip: %s to VM: %s" %(argument.floating_ip, server['name']))
-
+
for i in range(120):
server = drv.nova_server_get(argument.server_id)
for network_name,network_info in server['addresses'].items():
- if network_info:
- if network_name == argument.mgmt_network:
- for n_info in network_info:
- if 'OS-EXT-IPS:type' in n_info and n_info['OS-EXT-IPS:type'] == 'fixed':
- management_ip = n_info['addr']
- drv.nova_floating_ip_assign(argument.server_id,
- argument.floating_ip,
- management_ip)
- logger.info("Assigned floating_ip: %s to management_ip: %s" %(argument.floating_ip, management_ip))
- return
- logger.info("Waiting for management_ip to be assigned to server: %s" %(server['name']))
- time.sleep(1)
+ if network_info and network_name == argument.mgmt_network:
+ for n_info in network_info:
+ if 'OS-EXT-IPS:type' in n_info and n_info['OS-EXT-IPS:type'] == 'fixed':
+ management_ip = n_info['addr']
+ try:
+ handle_floating_ip_assignment(drv, server, argument, management_ip)
+ return
+ except Exception as e:
+ logger.error("Exception in assign_floating_ip_address : %s", e)
+ raise
+ else:
+ logger.info("Waiting for management_ip to be assigned to server: %s" %(server['name']))
+ time.sleep(1)
else:
logger.info("No management_ip IP available to associate floating_ip for server: %s" %(server['name']))
return
nvconn = drv.nova_drv._get_nova_connection()
nvconn.servers.set_meta(argument.server_id, meta_data)
+
+def get_volume_id(server_vol_list, name):
+ if server_vol_list is None:
+ return
+
+ for os_volume in server_vol_list:
+ try:
+ " Device name is of format /dev/vda"
+ vol_name = (os_volume['device']).split('/')[2]
+ except:
+ continue
+ if name == vol_name:
+ return os_volume['volumeId']
+def create_volume_metadata(drv, argument):
+ if argument.vol_metadata is None:
+ return
+
+ yaml_vol_str = argument.vol_metadata.read()
+ yaml_vol_cfg = yaml.load(yaml_vol_str)
+
+ srv_volume_list = drv.nova_volume_list(argument.server_id)
+ for volume in yaml_vol_cfg:
+ if 'custom_meta_data' not in volume:
+ continue
+ vmd = dict()
+ for vol_md_item in volume['custom_meta_data']:
+ if 'value' not in vol_md_item:
+ continue
+ vmd[vol_md_item['name']] = vol_md_item['value']
+
+ # Get volume id
+ vol_id = get_volume_id(srv_volume_list, volume['name'])
+ if vol_id is None:
+ logger.error("Server %s Could not find volume %s" %(argument.server_id, volume['name']))
+ sys.exit(3)
+ drv.cinder_volume_set_metadata(vol_id, vmd)
+
def prepare_vm_after_boot(drv,argument):
### Important to call create_port_metadata before assign_floating_ip_address
### since assign_floating_ip_address can wait thus delaying port_metadata creation
- ### Wait for 2 minute for server to come up -- Needs fine tuning
- wait_time = 120
- sleep_time = 1
+ ### Wait for a max of 5 minute for server to come up -- Needs fine tuning
+ wait_time = 500
+ sleep_time = 2
for i in range(int(wait_time/sleep_time)):
server = drv.nova_server_get(argument.server_id)
if server['status'] == 'ACTIVE':
else:
logger.error("Server %s did not reach active state in %d seconds. Current state: %s" %(server['name'], wait_time, server['status']))
sys.exit(4)
-
#create_port_metadata(drv, argument)
- assign_floating_ip_address(drv, argument)
+ create_volume_metadata(drv, argument)
+ try:
+ assign_floating_ip_address(drv, argument)
+ except Exception as e:
+ logger.error("Exception in prepare_vm_after_boot : %s", e)
+ raise
def main():
type = str,
help = "Tenant name openstack installation")
+ parser.add_argument('--user_domain',
+ action = "store",
+ dest = "user_domain",
+ default = None,
+ type = str,
+ help = "User domain name for openstack installation")
+
+ parser.add_argument('--project_domain',
+ action = "store",
+ dest = "project_domain",
+ default = None,
+ type = str,
+ help = "Project domain name for openstack installation")
+
+ parser.add_argument('--region',
+ action = "store",
+ dest = "region",
+ default = "RegionOne",
+ type = str,
+ help = "Region name for openstack installation")
+
parser.add_argument('--mgmt_network',
action = "store",
dest = "mgmt_network",
help = "Server ID on which boot operations needs to be performed")
parser.add_argument('--floating_ip',
- action = "store",
+ action = "store_true",
dest = "floating_ip",
+ default = False,
+ help = "Floating IP assignment required")
+
+ parser.add_argument('--pool_name',
+ action = "store",
+ dest = "pool_name",
type = str,
- help = "Floating IP to be assigned")
+ help = "Floating IP pool name")
+
parser.add_argument('--port_metadata',
action = "store_true",
default = False,
help = "Create Port Metadata")
+ parser.add_argument("--vol_metadata", type=argparse.FileType('r'))
+
argument = parser.parse_args()
if not argument.auth_url:
else:
logger.info("Using Server ID : %s" %(argument.server_id))
-
try:
pid = os.fork()
if pid > 0:
except OSError as e:
logger.error("fork failed: %d (%s)\n" % (e.errno, e.strerror))
sys.exit(2)
-
- drv = openstack_drv.OpenstackDriver(username = argument.username,
- password = argument.password,
- auth_url = argument.auth_url,
- tenant_name = argument.tenant_name,
- mgmt_network = argument.mgmt_network)
- prepare_vm_after_boot(drv, argument)
- sys.exit(0)
+
+ kwargs = dict(username = argument.username,
+ password = argument.password,
+ auth_url = argument.auth_url,
+ project = argument.tenant_name,
+ mgmt_network = argument.mgmt_network,
+ cert_validate = False,
+ user_domain = argument.user_domain,
+ project_domain = argument.project_domain,
+ region = argument.region)
+
+ drv = openstack_drv.OpenstackDriver(logger = logger, **kwargs)
+ try:
+ prepare_vm_after_boot(drv, argument)
+ except Exception as e:
+ logger.error("Exception in main of prepare_vm : %s", e)
+ raise
if __name__ == "__main__":
- main()
+ try:
+ main()
+ # Do not print anything in this script. This is a subprocess spawned by rwmain
+ # and the following print determines the success or failure of this script.
+ print("True",end="")
+ except Exception as e:
+ logger.error("Exception in prepare_vm : %s", e)
+ # Do not print anything in this script. This is a subprocess spawned by rwmain
+ # and the following print determines the success or failure of this script.
+ print("False+" + str(e),end="")
+ sys.exit(2)