You can use a custom Python script to create a restricted vCenter Server user, with optional flags to create a vCenter Server role and apply snapshot, failover, and failback privileges.
This script allows you to create a vCenter Server user with restricted roles that contain the minimum set of privileges required by the Cyber Recovery connector to perform snapshot replication, failover, and failback operations. Run this script from the Cyber Recovery connector VM command line.
Prerequisites
- GOVC installed on the system where you run this script. You can download GOVC here: https://github.com/vmware/govmomi/tree/master/govc#readme.
- Set the GOVC_PATH variable in the script to the path to the 'govc' executable on the system where you run this script. The default is /usr/local/bin/govc.
- Administrator user account and password from the vCenter Server where you are creating this user. You must pass these credentials when you run the script.
Usage
Create a vCenter Server user and role with a minimum set of privileges needed by the Cyber Recovery connector. Optional commands appear inside square brackets [ ].
vcdr-create-vcenter-user.py [-h]
Options:
Option | Description |
---|---|
-h, --help |
Displays a list of commands and options. |
--vcenter VCENTER |
IP address of the vCenter Server where you create this user. |
--admin-username admin-username |
Username of a user withvCenter Server Administrator privileges. User must have vCenter Server Adminstrator privileges before you run the CLI commands. If not supplied, the script prompts you for this username. |
- [-admin-password admin-password] |
Password of a user withvCenter Server Administrator privileges. If not supplied, the script prompts you for this password. Make sure the password you choose for this user adheres to the VMware vSphere password policy requirements. |
--new-username new-username |
Use name for the new user. |
[--new-password new-password] |
Password for the new user. |
--vcenter-role vcenter-role |
Name of new or existing vCenter Server role to assign to the new user. You can apply --snapshot-privs and/or --failback-privs to this role. |
[--keep-existing-privs] |
Keep existing privileges on the provided role. Using this option ensures that you do not unecessarily remove privileges from the provided role. |
[--create-role-only] |
Create role with necessary privileges, but do not create a user account or assign permissions. |
[--snapshot-privs] |
This option adds snapshot and failover privileges to the user role. |
[--failback-privs] |
This option adds snapshot, failover, and failback privileges to the user role. |
Example
The following example shows how to use the CLI to create a vCenter Server role called vcdr-dkup-role and assign the role snapshot and failover privileges (but no failback). This command then creates a vCenter Server user named [email protected], and globally assigns this new user the new role.
connector-name>> vcdr-create-vcenter-user.py --vcenter 192.0.170.23 --admin-username [email protected] --new-username [email protected] --vcenter-role vcdr-bkup-role --snapshot-privs
Script
#!/usr/bin/env python """ Copyright 2021 VMware, Inc. All rights reserved. ========================== IMPORT! READ THE FOLLOWING ========================== This script can be downloaded and used by customers to create a vCenter user, role, and permission for use with vCenter registration with the VMware Cloud Disaster Recover (VCDR) product. REQUIREMENTS - Set the GOVC_PATH variable, below, to the path to the 'govc' executable on the system where this script will run. The default is '/usr/local/bin/govc'. - GOVC GOVC must be installed in order for this script to work. https://github.com/vmware/govmomi/tree/master/govc#readme EXAMPLE $ vcdr-create-vcenter-user.py --vcenter 10.80.15.23 --admin-username [email protected] \ --new-username [email protected] --vcenter-role vcdr-bkup-role --snapshot-privs The above will create a vCenter role called vcdr-dkup-role with the privileges necessary to perform VM backup (i.e., it will not work for failback). It will also create a vCenter user called [email protected]. Finally, it will globally assign this new user the above role. USAGE $ vcdr-create-vcenter-user.py --help usage: vcdr-create-vcenter-user.py [-h] --vcenter VCENTER --admin-username admin-username --new-username new-username [--admin-password admin-password] [--new-password new-password] --vcenter-role vcenter-role [--keep-existing-privs] [--create-role-only] [--snapshot-privs | --failback-privs] Create vCenter user/role/permission with minimal privileges for use with VCDR. optional arguments: -h, --help show this help message and exit --vcenter VCENTER vCenter IP on which to create/update user --admin-username admin-username Admin username at desired vCenter --new-username new-username New username to be created in the desired vCenter --admin-password admin-password Admin password at desired vCenter (will be prompted if not provided) --new-password new-password New password for the new user in the desired vCenter (will be prompted if not provided) --vcenter-role vcenter-role Name of new or existing vCenter role to associate to the new user --keep-existing-privs Keep existing privileges on provided role (i.e., do not prune unnecessary privileges from provided role) --create-role-only Create role with necessary privileges but do not create a user account or assign permissions --snapshot-privs Create a user with privileges necessary to snapshot VMs and failover (the default) --failback-privs Create a user with privileges necessary to snapshot VMs, failover, and failback MISC This script cannot be used to create/update localos users (i.e., the created VCDR user account must be of the form 'name@domain', e.g., '[email protected]'). This script has been tested with python3. """ __author__ = "VMware, Inc" from getpass import getpass import json import logging import os import subprocess import time logger = logging.getLogger(__name__) logger.setLevel(logging.DEBUG) GOVC_PATH = '/usr/local/bin/govc' LOG_FILE = '/var/tmp/vcdr-create-vcenter-user' VCDR_SNAPSHOT_PRIVS = [ 'Datastore.Browse', 'Datastore.FileManagement', 'Global.DisableMethods', 'Global.EnableMethods', 'System.Anonymous', 'System.Read', 'System.View', 'VirtualMachine.Config.ChangeTracking', 'VirtualMachine.Config.DiskLease', 'VirtualMachine.Config.QueryUnownedFiles', 'VirtualMachine.Config.ReloadFromPath', 'VirtualMachine.Provisioning.DiskRandomRead', 'VirtualMachine.Provisioning.GetVmFiles', 'VirtualMachine.Provisioning.ReadCustSpecs', 'VirtualMachine.State.CreateSnapshot', 'VirtualMachine.State.RemoveSnapshot' ] VCDR_FAILBACK_PRIVS = VCDR_SNAPSHOT_PRIVS + [ 'Datastore.AllocateSpace', 'Datastore.Config', 'Datastore.DeleteFile', 'Datastore.UpdateVirtualMachineFiles', 'Datastore.UpdateVirtualMachineMetadata', 'Global.CancelTask', 'Global.GlobalTag', 'Global.Licenses', 'Global.ManageCustomFields', 'Global.SetCustomField', 'InventoryService.Tagging.AttachTag', 'Network.Assign', 'Resource.AssignVAppToPool', 'Resource.AssignVMToPool', 'Sessions.GlobalMessage', 'Sessions.ValidateSession', 'VirtualMachine.Config.AddExistingDisk', 'VirtualMachine.Config.AddNewDisk', 'VirtualMachine.Config.AddRemoveDevice', 'VirtualMachine.Config.AdvancedConfig', 'VirtualMachine.Config.CPUCount', 'VirtualMachine.Config.DiskExtend', 'VirtualMachine.Config.EditDevice', 'VirtualMachine.Config.HostUSBDevice', 'VirtualMachine.Config.ManagedBy', 'VirtualMachine.Config.Memory', 'VirtualMachine.Config.MksControl', 'VirtualMachine.Config.QueryFTCompatibility', 'VirtualMachine.Config.RawDevice', 'VirtualMachine.Config.RemoveDisk', 'VirtualMachine.Config.Rename', 'VirtualMachine.Config.ResetGuestInfo', 'VirtualMachine.Config.Resource', 'VirtualMachine.Config.Settings', 'VirtualMachine.Config.SwapPlacement', 'VirtualMachine.GuestOperations.Execute', 'VirtualMachine.GuestOperations.Modify', 'VirtualMachine.GuestOperations.Query', 'VirtualMachine.Interact.Backup', 'VirtualMachine.Interact.DeviceConnection', 'VirtualMachine.Interact.GuestControl', 'VirtualMachine.Interact.PowerOff', 'VirtualMachine.Interact.PowerOn', 'VirtualMachine.Interact.SetCDMedia', 'VirtualMachine.Interact.SetFloppyMedia', 'VirtualMachine.Interact.ToolsInstall', 'VirtualMachine.Inventory.Create', 'VirtualMachine.Inventory.CreateFromExisting', 'VirtualMachine.Inventory.Move', 'VirtualMachine.Inventory.Register', 'VirtualMachine.Inventory.Unregister', 'VirtualMachine.Provisioning.Customize', 'VirtualMachine.Provisioning.DiskRandomAccess', 'VirtualMachine.Provisioning.FileRandomAccess', 'VirtualMachine.Provisioning.MarkAsVM', 'VirtualMachine.Provisioning.ModifyCustSpecs', 'VirtualMachine.Provisioning.PromoteDisks', 'VirtualMachine.State.RevertToSnapshot' ] VCDR_LWD_PRIVS = [ 'vSphereDataProtection.Protection', 'Host.Config.NetService', 'vSphereDataProtection.Recovery', 'System.Read', 'System.Anonymous', 'Host.Config.Storage', ] class GOVC(object): def __init__(self, vc_url, vc_username, vc_password, verify_server_cert=False, exit_on_cmd_failure=True): """ The govc URL scheme defaults to https and the URL path defaults to /sdk. This means that: 1. 'host' is equivalent to 'https://<host>/sdk'. 2. 'username:password@host' is equivalent to 'https://<username:password@host>/sdk'. # pragma: allowlist secret :param vc_url: URL of ESXi or vCenter instance to connect to :param vc_username: vCenter or ESXi admin user's username :param vc_password: vCenter or ESXi admin user's password :param verify_server_cert: Verify vCenter or ESXi server certificate :return: None """ self.vc_url = vc_url self.vc_username = vc_username self.vc_password = vc_password self.verify_server_cert = verify_server_cert self.exit_on_cmd_failure = exit_on_cmd_failure self.set_envs() def _run_govc_cli(self, cmd_args, timeout, json=False): """ Run command. :param cmd_args: List of command line args :param json: Enable JSON output :param timeout: command timeout in secs :return: command output """ cmd = [GOVC_PATH] cmd.extend(cmd_args) if json: cmd.insert(2, '-json') wait = 0 logger.debug('Run command %s.', cmd) p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) while p.poll() is None and wait < timeout: wait += 1 time.sleep(1) if p.poll() is None: p.kill() rc = 124 else: rc = p.returncode stdout, stderr = p.communicate() if rc != 0: if rc == 124: stderr = 'timed out after {} secs, {}'.format(timeout, stderr) logger.error('%s failed, rc: %d, stdout: %s, stderr: %s', cmd, rc, stdout, stderr) if self.exit_on_cmd_failure: exit(rc) else: raise subprocess.CalledProcessError(rc, cmd, output=stdout+stderr) logger.info(stdout) return stdout.strip() def set_envs(self): """ Set govc login environment variables. While using '-u https://user:pass@host/sdk' from the govc command line, # pragma: allowlist secret there is a bug if the username or the password includes special characters. Using environment variables instead confirmed works. """ os.environ['GOVC_URL'] = self.vc_url os.environ['GOVC_USERNAME'] = self.vc_username os.environ['GOVC_PASSWORD'] = self.vc_password os.environ['GOVC_INSECURE'] = 'false' if self.verify_server_cert else 'true' logger.debug('govc envs: %s', {k: v for k, v in os.environ.items() if k.startswith('GOVC') and k != 'GOVC_PASSWORD'}) def ssogroup_create(self, name, description=None, timeout=15, json=False, **kwargs): """ Create SSO group. :param name: SSO group name :param description: SSO group description :param timeout: command timeout in secs :param json: Enable JSON output :return: Command output """ kwargs.clear() cmd_args = ['sso.group.create'] if description: cmd_args.extend(['-d', description]) cmd_args.append(name) return self._run_govc_cli(cmd_args, timeout=timeout, json=json) def ssogroup_ls(self, timeout=15, json=False, **kwargs): """ List SSO groups. :param timeout: command timeout in secs :param json: Enable JSON output :return: SSO groups """ kwargs.clear() cmd_args = ['sso.group.ls'] return self._run_govc_cli(cmd_args, timeout=timeout, json=json) def ssogroup_rm(self, name, timeout=15, json=False, **kwargs): """ Remove SSO group. :param name: SSO group name :param timeout: command timeout in secs :param json: Enable JSON output :return: Command output """ kwargs.clear() cmd_args = ['sso.group.rm', name] return self._run_govc_cli(cmd_args, timeout=timeout, json=json) def ssogroup_update(self, name, description='', add_user=None, remove_user=None, timeout=15, json=False, **kwargs): """ Update SSO group. :param name: SSO group name :param description: SSO group description :param add_user: Add user to group :param remove_user: Remove user from group :param description: SSO group description :param timeout: command timeout in secs :param json: Enable JSON output :return: Command output """ kwargs.clear() cmd_args = ['sso.group.update'] if description: cmd_args.extend(['-d', description]) if add_user is not None: cmd_args.extend(['-a', add_user]) if remove_user is not None: cmd_args.extend(['-r', remove_user]) cmd_args.append(name) return self._run_govc_cli(cmd_args, timeout=timeout, json=json) def ssouser_create(self, name, password=None, description=None, solution=False, act_as_user=True, role='Administrator', certificate=None, timeout=15, json=False, **kwargs): """ Create SSO user. :param name: SSO user name :param password: SSO person user password :param description: SSO user description :param solution: Whether is solution user :param act_as_user: ActAsUser role for solution user WSTrust :param role: Role for solution user (RegularUser|Administrator) :param certificate: Certificate for solution user :param timeout: command timeout in secs :param json: Enable JSON output :return: Command output """ kwargs.clear() cmd_args = ['sso.user.create'] if description: cmd_args.extend(['-d', description]) if solution: assert certificate, 'Solution user certificate is required!' assert role in ['RegularUser', 'Administrator'], ( 'Invalid solution user role: {}!'.format(role)) if act_as_user: cmd_args.append('-A') cmd_args.extend(['-R', role, '-C', certificate]) else: # Person user. assert password, 'SSO user password is required!' cmd_args.extend(['-p', password]) cmd_args.append(name) return self._run_govc_cli(cmd_args, timeout=timeout, json=json) def ssouser_id(self, name=None, timeout=15, json=False, **kwargs): """ Get SSO user and group IDs. :param name: SSO user name :param timeout: command timeout in secs :param json: Enable JSON output :return: SSO user and group IDs """ kwargs.clear() cmd_args = ['sso.user.id'] if name is not None: cmd_args.append(name) return self._run_govc_cli(cmd_args, timeout=timeout, json=json) def ssouser_ls(self, solution=False, timeout=15, json=False, **kwargs): """ List SSO users. :param solution: List solution users :param timeout: command timeout in secs :param json: Enable JSON output :return: SSO users """ kwargs.clear() cmd_args = ['sso.user.ls'] if solution: cmd_args.append('-s') return self._run_govc_cli(cmd_args, timeout=timeout, json=json) def ssouser_rm(self, name, timeout=15, json=False, **kwargs): """ Remove SSO user. :param name: SSO user name :param timeout: command timeout in secs :param json: Enable JSON output :return: SSO user and group IDs :return: Command output """ kwargs.clear() cmd_args = ['sso.user.rm', name] return self._run_govc_cli(cmd_args, timeout=timeout, json=json) def ssouser_update(self, name, password=None, description=None, solution=False, act_as_user=True, role=None, certificate=None, timeout=15, json=False, **kwargs): """ Update SSO user. :param name: SSO user name :param password: SSO person user password :param description: SSO user description :param solution: Whether is solution user :param act_as_user: ActAsUser role for solution user WSTrust :param role: Role for solution user (RegularUser|Administrator) :param certificate: Certificate for solution user :param timeout: command timeout in secs :param json: Enable JSON output :return: Command output """ kwargs.clear() cmd_args = ['sso.user.update'] if description is not None: cmd_args.extend(['-d', description]) if solution: if act_as_user: cmd_args.append('-A') if role is not None: assert role in ['RegularUser', 'Administrator'], ( 'Invalid solution user role: {}!'.format(role)) cmd_args.extend(['-R', role]) if certificate is not None: cmd_args.extend(['-C', '{}'.format(certificate)]) else: if password is not None: cmd_args.extend(['-p', password]) cmd_args.append(name) return self._run_govc_cli(cmd_args, timeout=timeout, json=json) def get_sso_user_privileges(self, username, timeout=15, **kwargs): """ Get privileges associated with an SSO user :param name: SSO user name :param timeout: command timeout in secs :return: List of privileges """ kwargs.clear() permission_cmd_args = ['permissions.ls'] permission_output = self._run_govc_cli(permission_cmd_args, timeout=timeout) privileges_list = [] normalized_user = username.lower() for line in permission_output.splitlines()[1:]: line_split = line.split('/') #formatted [role, entity, username, propogate] user = line_split[1].split()[0].lower() # user formatted either <user> or <domain>\\<user> user_split = user.split("\\") role = line_split[0].strip() constructed_user = user_split[1] + "@" + user_split[0] if len(user_split) == 2 else user if normalized_user == constructed_user: role_cmd_args = ['role.ls', role] privileges_list.extend(self._run_govc_cli(role_cmd_args, timeout=timeout).split()) break return privileges_list def set_sso_user_privileges(self, username, role, entity='/', timeout=15, **kwargs): """ Attach a role to a user :param username: SSO user name :param role: Role to attach to SSO user :param entity: Entity to attach privileges on, default root :param timeout: command timeout in secs """ kwargs.clear() permission_cmd_args = ["permissions.set"] permission_cmd_args.extend(['-principal', username]) permission_cmd_args.extend(['-role', role]) permission_cmd_args.extend(['-propagate=true']) permission_cmd_args.extend([entity]) self._run_govc_cli(permission_cmd_args, timeout=timeout) def role_ls(self, role=None, json=False, timeout=15, **kwargs): """ Get information about roles. Lists names of all roles if a role is not provided. :param role: name of role to get information about :param timeout: command timeout in secs """ kwargs.clear() role_cmd_args = ["role.ls"] if role: role_cmd_args.append(role) return self._run_govc_cli(role_cmd_args, timeout=timeout, json=json) def role_create(self, role, privileges, timeout=15, **kwargs): """ Get information about roles. Lists names of all roles if a role is not provided. :param role: name of role to get information about :param privileges: list of privileges to attach to role :param timeout: command timeout in secs """ kwargs.clear() role_cmd_args = ["role.create"] role_cmd_args.append(role) role_cmd_args.extend(privileges) return self._run_govc_cli(role_cmd_args, timeout=timeout) def role_update(self, role, privileges_to_add=None, privileges_to_remove=None, timeout=15, **kwargs): """ Get information about roles. Lists names of all roles if a role is not provided. :param role: name of role to get information about :param privileges_to_add: list of privileges to attach to role :param privileges_to_remove: list of privileges to remove :param timeout: command timeout in secs """ kwargs.clear() role_cmd_args = ["role.update"] if privileges_to_add: role_cmd_args.append("-a") role_cmd_args.append(role) role_cmd_args.extend(privileges_to_add) if privileges_to_remove: role_cmd_args.append("-r") role_cmd_args.append(role) role_cmd_args.extend(privileges_to_remove) return self._run_govc_cli(role_cmd_args, timeout=timeout) class vcdr_create_vcenter_user(object): def _get_password(self, account=None, retype=False): ''' Prompt for a password. ''' prompt = 'Retype password' if retype else 'Password' if account is not None: prompt += ' for account %s' % account prompt += ': ' while True: password = getpass(prompt=prompt) if password: return password def _get_username_and_domain(self, user): username = user domain = None if '@' in user: username, domain = user.split('@', 1) return username, domain def _get_user(self, govc_channel, user): username, domain = self._get_username_and_domain(user) users = govc_channel.ssouser_ls(json=True) if users: users = json.loads(users) for user in users: if user['Id']['Name'] == username and user['Id']['Domain'] == domain: return user return None def _get_role(self, govc_channel, role_name): try: role = govc_channel.role_ls(role_name, json=True) return json.loads(role) if role else None except: # Unable to find role. pass return None def handle_vcdr_create_vcenter_user(self, vcenter, adminUsername, newUsername, adminPassword=None, newPassword=None, vcenterRole=None, vcenterEntity=None, snapshotPrivs=False, failbackPrivs=True, keepExistingPrivs=False, createRoleOnly=False): """ @param vcenter: vCenter IP to create new user on @param adminUsername: Admin username at desired vCenter @param newUsername: New username to be created in the desired vCenter @param adminPassword: Admin password at desired vCenter @param newPassword: New password to be attached to the new user in the desired vCenter @param vcenterRole: Name of the vCenter role to attach to the new user @param vcenterEntity: VCenter entity path to give the new user privileges on, by default root @param snapshotPrivs: Associate privileges necessary for snapshotting and failover with the role @param failbackPrivs: Associate privileges necessary for snapshotting, failover, and failback with the role @param keepExistingPrivs: Keep existing privileges on provided role (i.e., do not prune unnecessary privileges from provided role) @param createRoleOnly: Create role with necessary privileges but do not create a user account or assign permissions """ try: if adminPassword is None: adminPassword = self._get_password(account=adminUsername) if newPassword is None: while True: newPassword = self._get_password(account=newUsername) newPassword2 = self._get_password(account=newUsername, retype=True) if newPassword == newPassword2: break print('Passwords do not match.') govc_channel = GOVC(vcenter, adminUsername, adminPassword, exit_on_cmd_failure=False) except: msg = u'Unable to establish connection with vCenter {} with username {}'.format(vcenter, adminUsername) logging.exception(msg) print(msg) return # Decide which privileges we care about. TODO: select based on CLI. if failbackPrivs: target_privs = VCDR_FAILBACK_PRIVS else: target_privs = VCDR_SNAPSHOT_PRIVS # Check the privileges of the Admin, and assign only the permissible privileges. admin_role = self._get_role(govc_channel, 'Admin') target_privs = list(set(admin_role['Privilege']) & set(target_privs + VCDR_LWD_PRIVS)) # Create user if it doesn't already exist. if not createRoleOnly: existing_user = False try: existing_user = self._get_user(govc_channel, newUsername) newUsernameWithOutDomain, _ = self._get_username_and_domain(newUsername) if not existing_user: govc_channel.ssouser_create(newUsernameWithOutDomain, newPassword) else: govc_channel.ssouser_update(newUsernameWithOutDomain, newPassword) except: msg = u'Unable to {} user {} on vCenter {}'.format("update" if existing_user else "create", newUsername, vcenter) logging.exception(msg) print(msg) return # Create role if it doesn't already exist and add appropriate privs. try: existing_role = self._get_role(govc_channel, vcenterRole) if existing_role: govc_channel.role_update(vcenterRole, privileges_to_add=target_privs) else: govc_channel.role_create(vcenterRole, target_privs) except: msg = u'Unable to create/update role {} on vCenter {}'.format(vcenterRole, vcenter) logging.exception(msg) print(msg) return # Remove extraneous privs from role. if not keepExistingPrivs: try: role = self._get_role(govc_channel, vcenterRole) privs = role['Privilege'] extra_privs = list(set(privs) - set(target_privs)) if extra_privs: govc_channel.role_update(vcenterRole, privileges_to_remove=extra_privs) except: msg = u'Unable to remove extraneous privs from role {} on vCenter {}'.format(vcenterRole, vcenter) logging.exception(msg) print(msg) return # Update the permissions. if not createRoleOnly: try: vcenterEntity = vcenterEntity or '/' govc_channel.set_sso_user_privileges(newUsername, vcenterRole, vcenterEntity) except: msg = u'Unable to create permission on {} for {}/{} on vCenter {}'.format(vcenterEntity, newUsername, vcenterRole, vcenter) logging.exception(msg) print(msg) return return if __name__ == '__main__': import argparse logging.basicConfig(level=logging.DEBUG, filename=LOG_FILE, filemode='a') logging.info('Starting script') parser = argparse.ArgumentParser(description='Create vCenter user/role/permission with minimal privileges for use with VCDR.') parser.add_argument('--vcenter', required=True, help='vCenter IP on which to create/update user') parser.add_argument('--admin-username', required=True, metavar='admin-username', help='Admin username at desired vCenter') parser.add_argument('--new-username', required=True, metavar='new-username', help='New username to be created in the desired vCenter') parser.add_argument('--admin-password', metavar='admin-password', help='Admin password at desired vCenter (will be prompted if not provided)') parser.add_argument('--new-password', metavar='new-password', help='New password for the new user in the desired vCenter (will be prompted if not provided)') parser.add_argument('--vcenter-role', required=True, metavar='vcenter-role', help='Name of new or existing vCenter role to associate to the new user') parser.add_argument('--keep-existing-privs', action='store_true', help='Keep existing privileges on provided role (i.e., do not prune unnecessary privileges from provided role)') parser.add_argument('--create-role-only', action='store_true', help='Create role with necessary privileges but do not create a user account or assign permissions') group = parser.add_mutually_exclusive_group() group.add_argument('--snapshot-privs', action='store_true', help='Create a user with privileges necessary to snapshot VMs and failover (the default)') group.add_argument('--failback-privs', action='store_true', help='Create a user with privileges necessary to snapshot VMs, failover, and failback') args = vars(parser.parse_args()) vcenter = args.get('vcenter') admin_username = args.get('admin_username') new_username = args.get('new_username') admin_password = args.get('admin_password') new_password = args.get('new_password') vcenter_role = args.get('vcenter_role') vcenter_entity = '/' snapshot_privs = args.get('snapshot_privs') failback_privs = args.get('failback_privs') keep_existing_privs= args.get('keep_existing_privs', False) create_role_only = args.get('create_role_only', False) worker = vcdr_create_vcenter_user() worker.handle_vcdr_create_vcenter_user(vcenter, admin_username, new_username, adminPassword=admin_password, newPassword=new_password, vcenterRole=vcenter_role, vcenterEntity=vcenter_entity, snapshotPrivs=snapshot_privs, failbackPrivs=failback_privs, keepExistingPrivs=keep_existing_privs, createRoleOnly=create_role_only) logging.info('Ending script') exit(0)