def ensure_required_plugins_are_installed(): """ Ensure the required Vagrant plugins are installed :return None: """ for plugin in REQUIRED_VAGRANT_PLUGINS: log.info("Ensuring Vagrant plugin {} is installed".format(plugin)) ensure_installed = "vagrant plugin list | grep {} || " \ "vagrant plugin install {}".format(plugin, plugin) run_local_command(ensure_installed, shell=True)
def run_vagrant_up(directory): """ Run 'up' on the hypernode vagrant :param str directory: Directory to start the vagrant in :return None: """ log.info("Running 'vagrant up' in the hypernode-vagrant " "checkout directory. This can take a while.") start_vagrant = 'cd {} && vagrant up'.format(directory) run_local_command(start_vagrant, shell=True)
def destroy_hypernode_vagrant(checkout_directory): """ Destroy a hypernode-vagrant :param str checkout_directory: Path to the hypernode-vagrant checkout to destroy :return None: """ log.info("Destroying Vagrant") vagrant_destroy_command = "cd {} && vagrant destroy -f".format( checkout_directory) run_local_command(vagrant_destroy_command, shell=True)
def test_run_local_command_does_not_write_to_stdout_in_case_of_nonzero_exit_in_python2_but_no_stdout(self): if not is_python_3(): self.check_output.side_effect = CalledProcessError( 1, cmd='echo 1', output=None ) with self.assertRaises(CalledProcessError): run_local_command(['echo', '1']) self.assertFalse(self.write_output_to_stdout.called)
def test_run_local_command_only_writes_stdout_to_stdout_in_case_of_nonzero_exit_in_python3_but_no_stderr(self): if is_python_3(): self.check_output.side_effect = CalledProcessError( 1, cmd='echo 1', output='stdout', stderr=None ) with self.assertRaises(CalledProcessError): run_local_command(['echo', '1']) self.write_output_to_stdout.assert_called_once_with('stdout')
def destroy_hypernode_vagrant(checkout_directory): """ Destroy a hypernode-vagrant :param str checkout_directory: Path to the hypernode-vagrant checkout to destroy :return None: """ log.info("Destroying Vagrant") vagrant_destroy_command = "cd {} && vagrant destroy -f".format( checkout_directory ) run_local_command(vagrant_destroy_command, shell=True)
def test_run_local_command_also_writes_stdout_to_stdout_in_case_of_nonzero_exit_in_python2(self): if not is_python_3(): self.check_output.side_effect = CalledProcessError( 1, cmd='echo 1', output='stdout', # No stderr in CalledProcessError in Python 2 ) with self.assertRaises(CalledProcessError): run_local_command(['echo', '1']) self.write_output_to_stdout.assert_called_once_with('stdout')
def run_vagrant_up(directory): """ Run 'up' on the hypernode vagrant :param str directory: Directory to start the vagrant in :return None: """ log.info( "Running 'vagrant up' in the hypernode-vagrant " "checkout directory. This can take a while." ) start_vagrant = 'cd {} && vagrant up'.format(directory) run_local_command(start_vagrant, shell=True)
def run_vagrant_up(directory, no_provision=False): """ Run 'up' on the hypernode vagrant :param str directory: Directory to start the vagrant in :param bool no_provision: Pass --no-provision to vagrant up :return None: """ log.info("Running 'vagrant up' in the hypernode-vagrant " "checkout directory. This can take a while.") start_vagrant = 'cd {} && vagrant up'.format(directory) if no_provision: start_vagrant += ' --no-provision' run_local_command(start_vagrant, shell=True)
def ensure_hypernode_vagrant_checkout(directory): """ Ensure there is a hypernode-vagrant checkout in the specified directory :param str directory: Directory to specify the checkout in :return None: """ if is_hypernode_vagrant_directory(directory): log.info("Found existing Vagrant file in directory") else: log.info("Cloning hypernode-vagrant") clone_command = [ 'git', 'clone', HYPERNODE_VAGRANT_REPOSITORY, directory ] run_local_command(clone_command)
def test_run_local_command_also_writes_stderr_and_stdout_to_stdout_in_case_of_nonzero_exit_in_python3(self): if is_python_3(): self.check_output.side_effect = CalledProcessError( 1, cmd='echo 1', output='stdout', stderr='stderr' ) with self.assertRaises(CalledProcessError): run_local_command(['echo', '1']) expected_calls = [ call('stdout'), call('stderr') ] # For loop instead of assertEqual(s) or assertCountEqual(s) because # that is both Python 2 and 3 compatible. for expected_call in expected_calls: self.assertIn(expected_call, self.write_output_to_stdout.mock_calls)
def test_run_local_command_does_not_decode_output_if_python_2_because_it_is_already_a_string(self): self.is_python_3.return_value = False ret = run_local_command(['echo', '1']) self.assertFalse(self.check_output.return_value.decode.called) self.assertEqual(ret, self.check_output.return_value)
def upload_project_to_vagrant(project_path, vagrant_info): """ Upload the project to the vagrant :param str project_path: The path on the host to upload :param dict vagrant_info: The vagrant ssh-config connection details :return None: """ log.info("Uploading project {} to /data/web/public on the vagrant.." "".format(project_path)) upload_project_command = "rsync -avz --delete " \ "-e 'ssh -p {Port} -i {IdentityFile} " \ "-oStrictHostKeyChecking=no " \ "-oUserKnownHostsFile=/dev/null' " \ "{project_path}/* root@{HostName}:{upload_path}" \ "".format(project_path=project_path, upload_path=UPLOAD_PATH, **vagrant_info) run_local_command(upload_project_command, shell=True)
def run_command_in_vagrant(command_to_run, vagrant_info, ssh_user=HYPERNODE_VAGRANT_DEFAULT_USER): """ Run a command in the remote vagrant :param str command_to_run: The command to run :param dict vagrant_info: The vagrant ssh-config connection details :param str ssh_user: The SSH user to run the command as :return None: """ log.info("Running command in the vagrant environment") ssh_wrapper_command = wrap_ssh_call( vagrant_info, ssh_user=ssh_user, command_to_run=command_to_run ) try: run_local_command(ssh_wrapper_command, shell=True) except CalledProcessError as e: log.info("Running command in Vagrant exited nonzero") write_output_to_stdout(e.output)
def run_command_in_vagrant(command_to_run, vagrant_info, ssh_user=HYPERNODE_VAGRANT_DEFAULT_USER): """ Run a command in the remote vagrant :param str command_to_run: The command to run :param dict vagrant_info: The vagrant ssh-config connection details :param str ssh_user: The SSH user to run the command as :return None: """ log.info("Running command in the vagrant environment") ssh_wrapper_command = wrap_ssh_call(vagrant_info, ssh_user=ssh_user, command_to_run=command_to_run) try: run_local_command(ssh_wrapper_command, shell=True) except CalledProcessError as e: log.info("Running command in Vagrant exited nonzero") write_output_to_stdout(e.output)
def ensure_hypernode_vagrant_checkout(directory): """ Ensure there is a hypernode-vagrant checkout in the specified directory :param str directory: Directory to specify the checkout in :return None: """ if is_hypernode_vagrant_directory(directory): log.info("Found existing Vagrant file in directory") else: log.info("Cloning hypernode-vagrant") clone_command = [ 'git', 'clone', HYPERNODE_VAGRANT_REPOSITORY, directory ] run_local_command(clone_command) check_call( "cd {} && git checkout " "copy-empty-webroot-files-as-root-then-chown".format(directory), shell=True)
def get_networking_information_from_vagrant(directory): """ Return a dict with networking information from the running Vagrant in the specified directory :param str directory: Directory to get the networking information from :return dict vagrant_ssh_config: Parsed vagrant ssh-config output """ get_attribute = "cd {directory} && " \ "vagrant ssh-config | " \ "grep {attribute} | " \ "awk '{{print $NF}}'" get_attribute_from_vagrant = partial(get_attribute.format, directory=directory) vagrant_ssh_config = { attribute: run_local_command(get_attribute_from_vagrant(attribute=attribute), shell=True).strip() for attribute in ('HostName', 'Port', 'IdentityFile') } log.info("Retrieved networking info from {}: {}" "".format(directory, vagrant_ssh_config)) return vagrant_ssh_config
def get_networking_information_from_vagrant(directory): """ Return a dict with networking information from the running Vagrant in the specified directory :param str directory: Directory to get the networking information from :return dict vagrant_ssh_config: Parsed vagrant ssh-config output """ get_attribute = "cd {directory} && " \ "vagrant ssh-config | " \ "grep {attribute} | " \ "awk '{{print $NF}}'" get_attribute_from_vagrant = partial( get_attribute.format, directory=directory ) vagrant_ssh_config = { attribute: run_local_command( get_attribute_from_vagrant(attribute=attribute), shell=True ).strip() for attribute in ('HostName', 'Port', 'IdentityFile') } log.info("Retrieved networking info from {}: {}" "".format(directory, vagrant_ssh_config)) return vagrant_ssh_config
def test_run_local_command_decodes_output_if_python_3(self): ret = run_local_command(['echo', '1']) self.check_output.return_value.decode.assert_called_once_with('utf-8') self.assertEqual(ret, self.check_output.return_value.decode.return_value)
def test_run_local_command_writes_output_to_stdout(self): run_local_command(['echo', '1']) self.write_output_to_stdout.assert_called_once_with( self.check_output.return_value )
def test_run_local_command_checks_output_of_shell_command(self): run_local_command('echo 1 | xargs', shell=True) self.check_output.assert_called_once_with( 'echo 1 | xargs', shell=True )
def test_run_local_command_checks_output_of_specified_command(self): run_local_command(['echo', '1']) self.check_output.assert_called_once_with( ['echo', '1'], shell=False )