예제 #1
0
    def prepare(self):
        """
        Run the preparation sequence required to start a salt-api daemon.

        If sub-classed, don't **ever** forget to run:

            super(YourSubClass, self).prepare()
        """
        super().prepare()

        try:
            if self.config["verify_env"]:
                logfile = self.options.api_logfile
                if logfile is not None:
                    # Logfile is not using Syslog, verify
                    with salt.utils.files.set_umask(0o027):
                        verify_log_files([logfile], self.config["user"])
        except OSError as err:
            log.exception("Failed to prepare salt environment")
            self.shutdown(err.errno)

        self.setup_logfile_logger()
        verify_log(self.config)
        log.info("Setting up the Salt API")
        self.api = salt.client.netapi.NetapiClient(self.config)
        self.daemonize_if_required()
        self.set_pidfile()
예제 #2
0
 def test_verify_log_files(self):
     path = os.path.join(self.tmpdir, 'foo', 'bar.log')
     self.assertFalse(os.path.exists(path))
     verify_log_files([path], getpass.getuser())
     self.assertTrue(os.path.exists(path))
예제 #3
0
 def test_verify_log_files_file_scheme(self):
     verify_log_files(['file://{}'], getpass.getuser())
     self.assertFalse(os.path.isdir(os.path.join(os.getcwd(), 'file:')))
예제 #4
0
 def test_verify_log_files_tcp_scheme(self):
     verify_log_files(['udp://foo'], getpass.getuser())
     self.assertFalse(os.path.isdir(os.path.join(os.getcwd(), 'tcp:')))
예제 #5
0
 def test_verify_log_files_udp_scheme(self):
     verify_log_files(["udp://foo"], getpass.getuser())
     self.assertFalse(os.path.isdir(os.path.join(os.getcwd(), "udp:")))
예제 #6
0
    def run(self):
        """
        Execute the salt-cloud command line
        """
        # Parse shell arguments
        self.parse_args()

        salt_master_user = self.config.get("user")
        if salt_master_user is None:
            salt_master_user = salt.utils.user.get_user()

        if not check_user(salt_master_user):
            self.error(
                "If salt-cloud is running on a master machine, salt-cloud "
                "needs to run as the same user as the salt-master, '{0}'. "
                "If salt-cloud is not running on a salt-master, the "
                "appropriate write permissions must be granted to '{1}'. "
                "Please run salt-cloud as root, '{0}', or change "
                "permissions for '{1}'.".format(salt_master_user,
                                                syspaths.CONFIG_DIR))

        try:
            if self.config["verify_env"]:
                verify_env(
                    [os.path.dirname(self.config["conf_file"])],
                    salt_master_user,
                    root_dir=self.config["root_dir"],
                )
                logfile = self.config["log_file"]
                if logfile is not None:
                    # Logfile is not using Syslog, verify
                    verify_log_files([logfile], salt_master_user)
        except (IOError, OSError) as err:
            log.error("Error while verifying the environment: %s", err)
            sys.exit(err.errno)

        # Setup log file logging
        self.setup_logfile_logger()
        verify_log(self.config)

        if self.options.update_bootstrap:
            ret = salt.utils.cloud.update_bootstrap(self.config)
            salt.output.display_output(ret,
                                       self.options.output,
                                       opts=self.config)
            self.exit(salt.defaults.exitcodes.EX_OK)

        log.info("salt-cloud starting")
        try:
            mapper = salt.cloud.Map(self.config)
        except SaltCloudSystemExit as exc:
            self.handle_exception(exc.args, exc)
        except SaltCloudException as exc:
            msg = "There was an error generating the mapper."
            self.handle_exception(msg, exc)

        names = self.config.get("names", None)
        if names is not None:
            filtered_rendered_map = {}
            for map_profile in mapper.rendered_map:
                filtered_map_profile = {}
                for name in mapper.rendered_map[map_profile]:
                    if name in names:
                        filtered_map_profile[name] = mapper.rendered_map[
                            map_profile][name]
                if filtered_map_profile:
                    filtered_rendered_map[map_profile] = filtered_map_profile
            mapper.rendered_map = filtered_rendered_map

        ret = {}

        if self.selected_query_option is not None:
            if self.selected_query_option == "list_providers":
                # pylint: disable=broad-except
                try:
                    ret = mapper.provider_list()
                except (
                        SaltCloudException,
                        Exception,
                ) as exc:
                    msg = "There was an error listing providers: {0}"
                    self.handle_exception(msg, exc)
                # pylint: enable=broad-except

            elif self.selected_query_option == "list_profiles":
                provider = self.options.list_profiles
                # pylint: disable=broad-except
                try:
                    ret = mapper.profile_list(provider)
                except (
                        SaltCloudException,
                        Exception,
                ) as exc:
                    msg = "There was an error listing profiles: {0}"
                    self.handle_exception(msg, exc)
                # pylint: enable=broad-except

            elif self.config.get("map", None):
                log.info("Applying map from '%s'.", self.config["map"])
                # pylint: disable=broad-except
                try:
                    ret = mapper.interpolated_map(
                        query=self.selected_query_option)
                except (
                        SaltCloudException,
                        Exception,
                ) as exc:
                    msg = "There was an error with a custom map: {0}"
                    self.handle_exception(msg, exc)
                # pylint: enable=broad-except
            else:
                # pylint: disable=broad-except
                try:
                    ret = mapper.map_providers_parallel(
                        query=self.selected_query_option)
                except (
                        SaltCloudException,
                        Exception,
                ) as exc:
                    msg = "There was an error with a map: {0}"
                    self.handle_exception(msg, exc)
                # pylint: enable=broad-except

        elif self.options.list_locations is not None:
            # pylint: disable=broad-except
            try:
                ret = mapper.location_list(self.options.list_locations)
            except (
                    SaltCloudException,
                    Exception,
            ) as exc:
                msg = "There was an error listing locations: {0}"
                self.handle_exception(msg, exc)
            # pylint: enable=broad-except

        elif self.options.list_images is not None:
            # pylint: disable=broad-except
            try:
                ret = mapper.image_list(self.options.list_images)
            except (
                    SaltCloudException,
                    Exception,
            ) as exc:
                msg = "There was an error listing images: {0}"
                self.handle_exception(msg, exc)
            # pylint: enable=broad-except

        elif self.options.list_sizes is not None:
            # pylint: disable=broad-except
            try:
                ret = mapper.size_list(self.options.list_sizes)
            except (
                    SaltCloudException,
                    Exception,
            ) as exc:
                msg = "There was an error listing sizes: {0}"
                self.handle_exception(msg, exc)
            # pylint: enable=broad-except

        elif self.options.destroy and (self.config.get("names", None)
                                       or self.config.get("map", None)):
            map_file = self.config.get("map", None)
            names = self.config.get("names", ())
            if map_file is not None:
                if names != ():
                    msg = (
                        "Supplying a mapfile, '{0}', in addition to instance names {1} "
                        "with the '--destroy' or '-d' function is not supported. "
                        "Please choose to delete either the entire map file or individual "
                        "instances.".format(map_file, names))
                    self.handle_exception(msg, SaltCloudSystemExit)

                log.info("Applying map from '%s'.", map_file)
                matching = mapper.delete_map(query="list_nodes")
            else:
                matching = mapper.get_running_by_names(
                    names, profile=self.options.profile)

            if not matching:
                print("No machines were found to be destroyed")
                self.exit(salt.defaults.exitcodes.EX_OK)

            msg = "The following virtual machines are set to be destroyed:\n"
            names = set()
            for alias, drivers in six.iteritems(matching):
                msg += "  {0}:\n".format(alias)
                for driver, vms in six.iteritems(drivers):
                    msg += "    {0}:\n".format(driver)
                    for name in vms:
                        msg += "      {0}\n".format(name)
                        names.add(name)
            # pylint: disable=broad-except
            try:
                if self.print_confirm(msg):
                    ret = mapper.destroy(names, cached=True)
            except (
                    SaltCloudException,
                    Exception,
            ) as exc:
                msg = "There was an error destroying machines: {0}"
                self.handle_exception(msg, exc)
            # pylint: enable=broad-except

        elif self.options.action and (self.config.get("names", None)
                                      or self.config.get("map", None)):
            if self.config.get("map", None):
                log.info("Applying map from '%s'.", self.config["map"])
                try:
                    names = mapper.get_vmnames_by_action(self.options.action)
                except SaltCloudException as exc:
                    msg = "There was an error actioning virtual machines."
                    self.handle_exception(msg, exc)
            else:
                names = self.config.get("names", None)

            kwargs = {}
            machines = []
            msg = (
                "The following virtual machines are set to be actioned with "
                '"{0}":\n'.format(self.options.action))
            for name in names:
                if "=" in name:
                    # This is obviously not a machine name, treat it as a kwarg
                    key, value = name.split("=", 1)
                    kwargs[key] = value
                else:
                    msg += "  {0}\n".format(name)
                    machines.append(name)
            names = machines

            # pylint: disable=broad-except
            try:
                if self.print_confirm(msg):
                    ret = mapper.do_action(names, kwargs)
            except (
                    SaltCloudException,
                    Exception,
            ) as exc:
                msg = "There was an error actioning machines: {0}"
                self.handle_exception(msg, exc)
            # pylint: enable=broad-except

        elif self.options.function:
            kwargs = {}
            args = self.args[:]
            for arg in args[:]:
                if "=" in arg:
                    key, value = arg.split("=", 1)
                    kwargs[key] = value
                    args.remove(arg)

            if args:
                self.error(
                    "Any arguments passed to --function need to be passed "
                    "as kwargs. Ex: image=ami-54cf5c3d. Remaining "
                    "arguments: {0}".format(args))
            # pylint: disable=broad-except
            try:
                ret = mapper.do_function(self.function_provider,
                                         self.function_name, kwargs)
            except (
                    SaltCloudException,
                    Exception,
            ) as exc:
                msg = "There was an error running the function: {0}"
                self.handle_exception(msg, exc)
            # pylint: enable=broad-except

        elif self.options.profile and self.config.get("names", False):
            # pylint: disable=broad-except
            try:
                ret = mapper.run_profile(self.options.profile,
                                         self.config.get("names"))
            except (
                    SaltCloudException,
                    Exception,
            ) as exc:
                msg = "There was a profile error: {0}"
                self.handle_exception(msg, exc)
            # pylint: enable=broad-except

        elif self.options.set_password:
            username = self.credential_username
            provider_name = "salt.cloud.provider.{0}".format(
                self.credential_provider)
            # TODO: check if provider is configured
            # set the password
            salt.utils.cloud.store_password_in_keyring(provider_name, username)
        elif self.config.get("map",
                             None) and self.selected_query_option is None:
            if not mapper.rendered_map:
                sys.stderr.write("No nodes defined in this map")
                self.exit(salt.defaults.exitcodes.EX_GENERIC)
            # pylint: disable=broad-except
            try:
                ret = {}
                run_map = True

                log.info("Applying map from '%s'.", self.config["map"])
                dmap = mapper.map_data()

                msg = ""
                if "errors" in dmap:
                    # display profile errors
                    msg += "Found the following errors:\n"
                    for profile_name, error in six.iteritems(dmap["errors"]):
                        msg += "  {0}: {1}\n".format(profile_name, error)
                    sys.stderr.write(msg)
                    sys.stderr.flush()

                msg = ""
                if "existing" in dmap:
                    msg += "The following virtual machines already exist:\n"
                    for name in dmap["existing"]:
                        msg += "  {0}\n".format(name)

                if dmap["create"]:
                    msg += "The following virtual machines are set to be " "created:\n"
                    for name in dmap["create"]:
                        msg += "  {0}\n".format(name)

                if "destroy" in dmap:
                    msg += ("The following virtual machines are set to be "
                            "destroyed:\n")
                    for name in dmap["destroy"]:
                        msg += "  {0}\n".format(name)

                if not dmap["create"] and not dmap.get("destroy", None):
                    if not dmap.get("existing", None):
                        # nothing to create or destroy & nothing exists
                        print(msg)
                        self.exit(1)
                    else:
                        # nothing to create or destroy, print existing
                        run_map = False

                if run_map:
                    if self.print_confirm(msg):
                        ret = mapper.run_map(dmap)

                    if self.config.get("parallel", False) is False:
                        log.info("Complete")

                if dmap.get("existing", None):
                    for name in dmap["existing"]:
                        if "ec2" in dmap["existing"][name]["provider"]:
                            msg = "Instance already exists, or is terminated and has the same name."
                        else:
                            msg = "Already running."
                        ret[name] = {"Message": msg}

            except (
                    SaltCloudException,
                    Exception,
            ) as exc:
                msg = "There was a query error: {0}"
                self.handle_exception(msg, exc)
            # pylint: enable=broad-except

        elif self.options.bootstrap:
            host = self.options.bootstrap
            if self.args and "=" not in self.args[0]:
                minion_id = self.args.pop(0)
            else:
                minion_id = host

            vm_ = {
                "driver": "",
                "ssh_host": host,
                "name": minion_id,
            }
            args = self.args[:]
            for arg in args[:]:
                if "=" in arg:
                    key, value = arg.split("=", 1)
                    vm_[key] = value
                    args.remove(arg)

            if args:
                self.error(
                    "Any arguments passed to --bootstrap need to be passed as "
                    "kwargs. Ex: ssh_username=larry. Remaining arguments: {0}".
                    format(args))

            # pylint: disable=broad-except
            try:
                ret = salt.utils.cloud.bootstrap(vm_, self.config)
            except (
                    SaltCloudException,
                    Exception,
            ) as exc:
                msg = "There was an error bootstrapping the minion: {0}"
                self.handle_exception(msg, exc)
            # pylint: enable=broad-except

        else:
            self.error("Nothing was done. Using the proper arguments?")

        salt.output.display_output(ret, self.options.output, opts=self.config)
        self.exit(salt.defaults.exitcodes.EX_OK)
예제 #7
0
파일: cli.py 프로젝트: zyuhu/salt
    def run(self):
        '''
        Execute the salt-cloud command line
        '''
        # Parse shell arguments
        self.parse_args()

        salt_master_user = self.config.get('user')
        if salt_master_user is None:
            salt_master_user = salt.utils.user.get_user()

        if not check_user(salt_master_user):
            self.error(
                'If salt-cloud is running on a master machine, salt-cloud '
                'needs to run as the same user as the salt-master, \'{0}\'. '
                'If salt-cloud is not running on a salt-master, the '
                'appropriate write permissions must be granted to \'{1}\'. '
                'Please run salt-cloud as root, \'{0}\', or change '
                'permissions for \'{1}\'.'.format(salt_master_user,
                                                  syspaths.CONFIG_DIR))

        try:
            if self.config['verify_env']:
                verify_env(
                    [os.path.dirname(self.config['conf_file'])],
                    salt_master_user,
                    root_dir=self.config['root_dir'],
                )
                logfile = self.config['log_file']
                if logfile is not None:
                    # Logfile is not using Syslog, verify
                    verify_log_files([logfile], salt_master_user)
        except (IOError, OSError) as err:
            log.error('Error while verifying the environment: %s', err)
            sys.exit(err.errno)

        # Setup log file logging
        self.setup_logfile_logger()
        verify_log(self.config)

        if self.options.update_bootstrap:
            ret = salt.utils.cloud.update_bootstrap(self.config)
            salt.output.display_output(ret,
                                       self.options.output,
                                       opts=self.config)
            self.exit(salt.defaults.exitcodes.EX_OK)

        log.info('salt-cloud starting')
        try:
            mapper = salt.cloud.Map(self.config)
        except SaltCloudSystemExit as exc:
            self.handle_exception(exc.args, exc)
        except SaltCloudException as exc:
            msg = 'There was an error generating the mapper.'
            self.handle_exception(msg, exc)

        names = self.config.get('names', None)
        if names is not None:
            filtered_rendered_map = {}
            for map_profile in mapper.rendered_map:
                filtered_map_profile = {}
                for name in mapper.rendered_map[map_profile]:
                    if name in names:
                        filtered_map_profile[name] = mapper.rendered_map[
                            map_profile][name]
                if filtered_map_profile:
                    filtered_rendered_map[map_profile] = filtered_map_profile
            mapper.rendered_map = filtered_rendered_map

        ret = {}

        if self.selected_query_option is not None:
            if self.selected_query_option == 'list_providers':
                try:
                    ret = mapper.provider_list()
                except (SaltCloudException, Exception) as exc:
                    msg = 'There was an error listing providers: {0}'
                    self.handle_exception(msg, exc)

            elif self.selected_query_option == 'list_profiles':
                provider = self.options.list_profiles
                try:
                    ret = mapper.profile_list(provider)
                except (SaltCloudException, Exception) as exc:
                    msg = 'There was an error listing profiles: {0}'
                    self.handle_exception(msg, exc)

            elif self.config.get('map', None):
                log.info('Applying map from \'%s\'.', self.config['map'])
                try:
                    ret = mapper.interpolated_map(
                        query=self.selected_query_option)
                except (SaltCloudException, Exception) as exc:
                    msg = 'There was an error with a custom map: {0}'
                    self.handle_exception(msg, exc)
            else:
                try:
                    ret = mapper.map_providers_parallel(
                        query=self.selected_query_option)
                except (SaltCloudException, Exception) as exc:
                    msg = 'There was an error with a map: {0}'
                    self.handle_exception(msg, exc)

        elif self.options.list_locations is not None:
            try:
                ret = mapper.location_list(self.options.list_locations)
            except (SaltCloudException, Exception) as exc:
                msg = 'There was an error listing locations: {0}'
                self.handle_exception(msg, exc)

        elif self.options.list_images is not None:
            try:
                ret = mapper.image_list(self.options.list_images)
            except (SaltCloudException, Exception) as exc:
                msg = 'There was an error listing images: {0}'
                self.handle_exception(msg, exc)

        elif self.options.list_sizes is not None:
            try:
                ret = mapper.size_list(self.options.list_sizes)
            except (SaltCloudException, Exception) as exc:
                msg = 'There was an error listing sizes: {0}'
                self.handle_exception(msg, exc)

        elif self.options.destroy and (self.config.get('names', None)
                                       or self.config.get('map', None)):
            map_file = self.config.get('map', None)
            names = self.config.get('names', ())
            if map_file is not None:
                if names != ():
                    msg = 'Supplying a mapfile, \'{0}\', in addition to instance names {1} ' \
                          'with the \'--destroy\' or \'-d\' function is not supported. ' \
                          'Please choose to delete either the entire map file or individual ' \
                          'instances.'.format(map_file, names)
                    self.handle_exception(msg, SaltCloudSystemExit)

                log.info('Applying map from \'%s\'.', map_file)
                matching = mapper.delete_map(query='list_nodes')
            else:
                matching = mapper.get_running_by_names(
                    names, profile=self.options.profile)

            if not matching:
                print('No machines were found to be destroyed')
                self.exit(salt.defaults.exitcodes.EX_OK)

            msg = 'The following virtual machines are set to be destroyed:\n'
            names = set()
            for alias, drivers in six.iteritems(matching):
                msg += '  {0}:\n'.format(alias)
                for driver, vms in six.iteritems(drivers):
                    msg += '    {0}:\n'.format(driver)
                    for name in vms:
                        msg += '      {0}\n'.format(name)
                        names.add(name)
            try:
                if self.print_confirm(msg):
                    ret = mapper.destroy(names, cached=True)
            except (SaltCloudException, Exception) as exc:
                msg = 'There was an error destroying machines: {0}'
                self.handle_exception(msg, exc)

        elif self.options.action and (self.config.get('names', None)
                                      or self.config.get('map', None)):
            if self.config.get('map', None):
                log.info('Applying map from \'%s\'.', self.config['map'])
                try:
                    names = mapper.get_vmnames_by_action(self.options.action)
                except SaltCloudException as exc:
                    msg = 'There was an error actioning virtual machines.'
                    self.handle_exception(msg, exc)
            else:
                names = self.config.get('names', None)

            kwargs = {}
            machines = []
            msg = (
                'The following virtual machines are set to be actioned with '
                '"{0}":\n'.format(self.options.action))
            for name in names:
                if '=' in name:
                    # This is obviously not a machine name, treat it as a kwarg
                    key, value = name.split('=', 1)
                    kwargs[key] = value
                else:
                    msg += '  {0}\n'.format(name)
                    machines.append(name)
            names = machines

            try:
                if self.print_confirm(msg):
                    ret = mapper.do_action(names, kwargs)
            except (SaltCloudException, Exception) as exc:
                msg = 'There was an error actioning machines: {0}'
                self.handle_exception(msg, exc)

        elif self.options.function:
            kwargs = {}
            args = self.args[:]
            for arg in args[:]:
                if '=' in arg:
                    key, value = arg.split('=', 1)
                    kwargs[key] = value
                    args.remove(arg)

            if args:
                self.error(
                    'Any arguments passed to --function need to be passed '
                    'as kwargs. Ex: image=ami-54cf5c3d. Remaining '
                    'arguments: {0}'.format(args))
            try:
                ret = mapper.do_function(self.function_provider,
                                         self.function_name, kwargs)
            except (SaltCloudException, Exception) as exc:
                msg = 'There was an error running the function: {0}'
                self.handle_exception(msg, exc)

        elif self.options.profile and self.config.get('names', False):
            try:
                ret = mapper.run_profile(self.options.profile,
                                         self.config.get('names'))
            except (SaltCloudException, Exception) as exc:
                msg = 'There was a profile error: {0}'
                self.handle_exception(msg, exc)

        elif self.options.set_password:
            username = self.credential_username
            provider_name = "salt.cloud.provider.{0}".format(
                self.credential_provider)
            # TODO: check if provider is configured
            # set the password
            salt.utils.cloud.store_password_in_keyring(provider_name, username)
        elif self.config.get('map', None) and \
                self.selected_query_option is None:
            if not mapper.rendered_map:
                sys.stderr.write('No nodes defined in this map')
                self.exit(salt.defaults.exitcodes.EX_GENERIC)
            try:
                ret = {}
                run_map = True

                log.info('Applying map from \'%s\'.', self.config['map'])
                dmap = mapper.map_data()

                msg = ''
                if 'errors' in dmap:
                    # display profile errors
                    msg += 'Found the following errors:\n'
                    for profile_name, error in six.iteritems(dmap['errors']):
                        msg += '  {0}: {1}\n'.format(profile_name, error)
                    sys.stderr.write(msg)
                    sys.stderr.flush()

                msg = ''
                if 'existing' in dmap:
                    msg += ('The following virtual machines already exist:\n')
                    for name in dmap['existing']:
                        msg += '  {0}\n'.format(name)

                if dmap['create']:
                    msg += ('The following virtual machines are set to be '
                            'created:\n')
                    for name in dmap['create']:
                        msg += '  {0}\n'.format(name)

                if 'destroy' in dmap:
                    msg += ('The following virtual machines are set to be '
                            'destroyed:\n')
                    for name in dmap['destroy']:
                        msg += '  {0}\n'.format(name)

                if not dmap['create'] and not dmap.get('destroy', None):
                    if not dmap.get('existing', None):
                        # nothing to create or destroy & nothing exists
                        print(msg)
                        self.exit(1)
                    else:
                        # nothing to create or destroy, print existing
                        run_map = False

                if run_map:
                    if self.print_confirm(msg):
                        ret = mapper.run_map(dmap)

                    if self.config.get('parallel', False) is False:
                        log.info('Complete')

                if dmap.get('existing', None):
                    for name in dmap['existing']:
                        if 'ec2' in dmap['existing'][name]['provider']:
                            msg = 'Instance already exists, or is terminated and has the same name.'
                        else:
                            msg = 'Already running.'
                        ret[name] = {'Message': msg}

            except (SaltCloudException, Exception) as exc:
                msg = 'There was a query error: {0}'
                self.handle_exception(msg, exc)

        elif self.options.bootstrap:
            host = self.options.bootstrap
            if self.args and '=' not in self.args[0]:
                minion_id = self.args.pop(0)
            else:
                minion_id = host

            vm_ = {
                'driver': '',
                'ssh_host': host,
                'name': minion_id,
            }
            args = self.args[:]
            for arg in args[:]:
                if '=' in arg:
                    key, value = arg.split('=', 1)
                    vm_[key] = value
                    args.remove(arg)

            if args:
                self.error(
                    'Any arguments passed to --bootstrap need to be passed as '
                    'kwargs. Ex: ssh_username=larry. Remaining arguments: {0}'.
                    format(args))

            try:
                ret = salt.utils.cloud.bootstrap(vm_, self.config)
            except (SaltCloudException, Exception) as exc:
                msg = 'There was an error bootstrapping the minion: {0}'
                self.handle_exception(msg, exc)

        else:
            self.error('Nothing was done. Using the proper arguments?')

        salt.output.display_output(ret, self.options.output, opts=self.config)
        self.exit(salt.defaults.exitcodes.EX_OK)