Esempio n. 1
0
 def post(self):
     """ Add a device """
     json_data = request.get_json()
     supported_platforms = ['eos', 'junos', 'ios', 'iosxr', 'nxos', 'nxos_ssh']
     data = {}
     errors = []
     data, errors = Device.validate(**json_data)
     if errors != []:
         return empty_result(status='error', data=errors), 400
     with sqla_session() as session:
         instance: Device = session.query(Device).filter(Device.hostname ==
                                                         data['hostname']).one_or_none()
         if instance:
             errors.append('Device already exists')
             return empty_result(status='error', data=errors), 400
         if 'platform' not in data or data['platform'] not in supported_platforms:
             errors.append("Device platform not specified or not known (must be any of: {})".
                           format(', '.join(supported_platforms)))
             return empty_result(status='error', data=errors), 400
         if data['device_type'] in ['DIST', 'CORE']:
             if 'management_ip' not in data or not data['management_ip']:
                 data['management_ip'] = cnaas_nms.confpush.underlay.find_free_mgmt_lo_ip(session)
             if 'infra_ip' not in data or not data['infra_ip']:
                 data['infra_ip'] = cnaas_nms.confpush.underlay.find_free_infra_ip(session)
         new_device = Device.device_create(**data)
         session.add(new_device)
         session.flush()
         return empty_result(status='success', data={"added_device": new_device.as_dict()}), 200
Esempio n. 2
0
    def get(self, hostname: str):
        """ Get device configuration """
        result = empty_result()
        result['data'] = {'config': None}
        if not Device.valid_hostname(hostname):
            return empty_result(status='error',
                                data=f"Invalid hostname specified"), 400

        try:
            config, template_vars = cnaas_nms.confpush.sync_devices.generate_only(
                hostname)
            result['data']['config'] = {
                'hostname': hostname,
                'generated_config': config,
                'available_variables': template_vars
            }
        except Exception as e:
            logger.exception(
                f"Exception while generating config for device {hostname}")
            return empty_result(
                status='error',
                data="Exception while generating config for device {}: {} {}".
                format(hostname, type(e), str(e))), 500

        return result
Esempio n. 3
0
    def post(self) -> tuple:
        """ Download new firmware """
        json_data = request.get_json()

        kwargs = dict()

        if 'url' not in json_data:
            return empty_result(status='error',
                                data='Missing parameter url')

        if 'sha1' not in json_data:
            return empty_result(status='error',
                                data='Missing parameter sha1')

        if 'verify_tls' not in json_data:
            return empty_result(status='error',
                                data='Missing parameter verify_tls')

        kwargs['url'] = json_data['url']
        kwargs['sha1'] = json_data['sha1']
        kwargs['verify_tls'] = json_data['verify_tls']

        scheduler = Scheduler()
        job_id = scheduler.add_onetime_job(
            'cnaas_nms.api.firmware:get_firmware',
            when=1,
            scheduled_by=get_jwt_identity(),
            kwargs=kwargs)
        res = empty_result(data='Scheduled job to download firmware')
        res['job_id'] = job_id

        return res
Esempio n. 4
0
    def get(self):
        """ Get settings """
        args = request.args
        hostname = None
        device_type = None
        model = None
        if 'hostname' in args:
            if Device.valid_hostname(args['hostname']):
                hostname = args['hostname']
            else:
                return empty_result('error', "Invalid hostname specified"), 400
            with sqla_session() as session:
                dev: Device = session.query(Device).\
                    filter(Device.hostname == hostname).one_or_none()
                if dev:
                    device_type = dev.device_type
                    model = dev.model
                else:
                    return empty_result('error', "Hostname not found in database"), 400
        if 'device_type' in args:
            if DeviceType.has_name(args['device_type'].upper()):
                device_type = DeviceType[args['device_type'].upper()]
            else:
                return empty_result('error', "Invalid device type specified"), 400

        try:
            settings, settings_origin = get_settings(hostname, device_type, model)
        except Exception as e:
            return empty_result('error', "Error getting settings: {}".format(str(e))), 400

        return empty_result(data={'settings': settings, 'settings_origin': settings_origin})
Esempio n. 5
0
 def get(self, repo):
     """ Get repository information """
     try:
         repo_type = RepoType[str(repo).upper()]
     except:
         return empty_result('error', "Invalid repository type"), 400
     return empty_result('success', get_repo_status(repo_type))
Esempio n. 6
0
    def delete(self, device_id):
        """ Delete device from ID """
        json_data = request.get_json()

        if json_data and 'factory_default' in json_data:
            if isinstance(json_data['factory_default'], bool) and json_data['factory_default'] is True:
                scheduler = Scheduler()
                job_id = scheduler.add_onetime_job(
                    'cnaas_nms.confpush.erase:device_erase',
                    when=1,
                    scheduled_by=get_jwt_identity(),
                    kwargs={'device_id': device_id})
                return empty_result(data='Scheduled job {} to factory default device'.format(job_id))
        else:
            with sqla_session() as session:
                dev: Device = session.query(Device).filter(Device.id == device_id).one_or_none()
                if not dev:
                    return empty_result('error', "Device not found"), 404
                try:
                    session.delete(dev)
                    session.commit()
                except IntegrityError as e:
                    session.rollback()
                    return empty_result(
                        status='error',
                        data="Could not remove device because existing references: {}".format(e))
                except Exception as e:
                    session.rollback()
                    return empty_result(
                        status='error',
                        data="Could not remove device: {}".format(e))
                return empty_result(status="success", data={"deleted_device": dev.as_dict()}), 200
Esempio n. 7
0
    def put(self, hostname):
        """Bounce selected interfaces by appling bounce-down/bounce-up template"""
        json_data = request.get_json()

        if 'bounce_interfaces' in json_data and isinstance(json_data['bounce_interfaces'], list):
            interfaces: List[str] = json_data['bounce_interfaces']
            try:
                bounce_success = bounce_interfaces(hostname, interfaces)
            except ValueError as e:
                return empty_result(status='error', data=str(e)), 400
            except Exception as e:
                return empty_result(status='error', data=str(e)), 500

            if bounce_success:
                return empty_result(
                    status='success',
                    data="Bounced interfaces: {}".format(', '.join(interfaces))
                )
            else:
                return empty_result(
                    status='success',
                    data="No error, but no interfaces changed state: {}".
                         format(', '.join(interfaces))
                )
        else:
            return empty_result(status='error', data="Unknown action"), 400
Esempio n. 8
0
    def post(self):
        """ Discover device """
        json_data = request.get_json()

        if 'ztp_mac' not in json_data:
            return empty_result(status='error',
                                data="POST data must include 'ztp_mac'"), 400
        if 'dhcp_ip' not in json_data:
            return empty_result(status='error',
                                data="POST data must include 'dhcp_ip'"), 400
        ztp_mac = json_data['ztp_mac']
        dhcp_ip = json_data['dhcp_ip']

        job_id = cnaas_nms.confpush.init_device.schedule_discover_device(
            ztp_mac=ztp_mac,
            dhcp_ip=dhcp_ip,
            iteration=1,
            scheduled_by=get_jwt_identity())

        logger.debug(
            f"Discover device for ztp_mac {ztp_mac} scheduled as ID {job_id}")

        res = empty_result(
            data=f"Scheduled job to discover device for ztp_mac {ztp_mac}")
        res['job_id'] = job_id

        return res
Esempio n. 9
0
 def get(self, job_id):
     """ Get job information by ID """
     with sqla_session() as session:
         job = session.query(Job).filter(Job.id == job_id).one_or_none()
         if job:
             return empty_result(data={'jobs': [job.as_dict()]})
         else:
             return empty_result(status='error', data="No job with id {} found".format(job_id)), 400
Esempio n. 10
0
 def get(self, id):
     job = Jobtracker()
     try:
         job.load(id)
     except Exception as e:
         return empty_result(status='error', data=str(e)), 400
     result = empty_result(data={'jobs': [job.to_dict(json_serializable=True)]})
     return result
Esempio n. 11
0
 def post(self):
     json_data = request.get_json()
     syntax_dict, syntax_dict_origin = merge_dict_origin({}, json_data, {}, 'API POST data')
     try:
         ret = check_settings_syntax(syntax_dict, syntax_dict_origin)
     except SettingsSyntaxError as e:
         return empty_result(status='error', data=str(e)), 400
     else:
         return empty_result(status='success', data=ret)
Esempio n. 12
0
 def delete(self, device_id):
     with sqla_session() as session:
         instance = session.query(Device).filter(
             Device.id == device_id).one_or_none()
         if instance:
             session.delete(instance)
             session.commit()
             return empty_result(), 200
         else:
             return empty_result('error', "Device not found"), 404
Esempio n. 13
0
    def post(self, hostname: str):
        """Restore configuration to previous version"""
        json_data = request.get_json()
        apply_kwargs = {'hostname': hostname}
        config = None
        if not Device.valid_hostname(hostname):
            return empty_result(status='error',
                                data=f"Invalid hostname specified"), 400

        if 'job_id' in json_data:
            try:
                job_id = int(json_data['job_id'])
            except Exception:
                return empty_result('error', "job_id must be an integer"), 400
        else:
            return empty_result('error', "job_id must be specified"), 400

        with sqla_session() as session:
            try:
                prev_config_result = Job.get_previous_config(session,
                                                             hostname,
                                                             job_id=job_id)
                failed = prev_config_result['failed']
                if not failed and 'config' in prev_config_result:
                    config = prev_config_result['config']
            except JobNotFoundError as e:
                return empty_result('error', str(e)), 404
            except InvalidJobError as e:
                return empty_result('error', str(e)), 500
            except Exception as e:
                return empty_result('error',
                                    "Unhandled exception: {}".format(e)), 500

        if failed:
            return empty_result(
                'error', "The specified job_id has a failed status"), 400

        if not config:
            return empty_result('error', "No config found in this job"), 500

        if 'dry_run' in json_data and isinstance(json_data['dry_run'], bool) \
                and not json_data['dry_run']:
            apply_kwargs['dry_run'] = False
        else:
            apply_kwargs['dry_run'] = True

        apply_kwargs['config'] = config

        scheduler = Scheduler()
        job_id = scheduler.add_onetime_job(
            'cnaas_nms.confpush.sync_devices:apply_config',
            when=1,
            scheduled_by=get_jwt_identity(),
            kwargs=apply_kwargs,
        )

        res = empty_result(data=f"Scheduled job to restore {hostname}")
        res['job_id'] = job_id

        return res, 200
Esempio n. 14
0
    def post(self):
        json_data = request.get_json()
        kwargs: dict = {}
        if 'hostname' in json_data:
            hostname = str(json_data['hostname'])
            if not Device.valid_hostname(hostname):
                return empty_result(
                    status='error',
                    data=f"Hostname '{hostname}' is not a valid hostname"), 400
            with sqla_session() as session:
                dev: Device = session.query(Device).\
                    filter(Device.hostname == hostname).one_or_none()
                if not dev or dev.state != DeviceState.MANAGED:
                    return empty_result(
                        status='error',
                        data=
                        f"Hostname '{hostname}' not found or is not a managed device"
                    ), 400
            kwargs['hostname'] = hostname
            what = hostname
        elif 'device_type' in json_data:
            if DeviceType.has_name(str(json_data['device_type']).upper()):
                kwargs['device_type'] = str(json_data['device_type']).upper()
            else:
                return empty_result(
                    status='error',
                    data=
                    f"Invalid device type '{json_data['device_type']}' specified"
                ), 400
            what = f"{json_data['device_type']} devices"
        elif 'all' in json_data and isinstance(json_data['all'],
                                               bool) and json_data['all']:
            what = "all devices"
        else:
            return empty_result(
                status='error',
                data=f"No devices to synchronize was specified"), 400

        if 'dry_run' in json_data and isinstance(json_data['dry_run'], bool) \
                and not json_data['dry_run']:
            kwargs['dry_run'] = False
        if 'force' in json_data and isinstance(json_data['force'], bool):
            kwargs['force'] = json_data['force']

        scheduler = Scheduler()
        job_id = scheduler.add_onetime_job(
            'cnaas_nms.confpush.sync_devices:sync_devices',
            when=1,
            kwargs=kwargs)

        res = empty_result(data=f"Scheduled job to synchronize {what}")
        res['job_id'] = job_id

        return res
Esempio n. 15
0
 def get(self, device_id):
     result = empty_result()
     result['data'] = {'devices': []}
     with sqla_session() as session:
         instance = session.query(Device).filter(
             Device.id == device_id).one_or_none()
         if instance:
             result['data']['devices'].append(instance.as_dict())
         else:
             return empty_result('error', "Device not found"), 404
     return result
Esempio n. 16
0
 def delete(self, mgmtdomain_id):
     with sqla_session() as session:
         instance = session.query(Mgmtdomain).\
             filter(Mgmtdomain.id == mgmtdomain_id).one_or_none()
         if instance:
             session.delete(instance)
             session.commit()
             return empty_result(), 204
         else:
             return empty_result('error',
                                 "Management domain not found"), 404
Esempio n. 17
0
 def get(self, hostname):
     """ Get a device from hostname """
     result = empty_result()
     result['data'] = {'devices': []}
     with sqla_session() as session:
         instance = session.query(Device).filter(Device.hostname == hostname).one_or_none()
         if instance:
             result['data']['devices'].append(instance.as_dict())
         else:
             return empty_result('error', "Device not found"), 404
     return result
Esempio n. 18
0
 def get(self) -> tuple:
     """ Get firmwares """
     try:
         res = requests.get(get_httpd_url(),
                            verify=verify_tls())
         json_data = json.loads(res.content)['data']
     except Exception as e:
         logger.exception(f"Exception when getting images: {e}")
         return empty_result(status='error',
                             data='Could not get files'), 404
     return empty_result(status='success', data=json_data)
Esempio n. 19
0
 def get(self, mgmtdomain_id):
     result = empty_result()
     result['data'] = {'mgmtdomains': []}
     with sqla_session() as session:
         instance = session.query(Mgmtdomain).\
             filter(Mgmtdomain.id == mgmtdomain_id).one_or_none()
         if instance:
             result['data']['mgmtdomains'].append(instance.as_dict())
         else:
             return empty_result('error',
                                 "Management domain not found"), 404
     return result
Esempio n. 20
0
 def put(self):
     """ Modify plugins """
     json_data = request.get_json()
     if 'action' in json_data:
         if str(json_data['action']).upper() == 'SELFTEST':
             pmh = PluginManagerHandler()
             res = pmh.pm.hook.selftest()
             return empty_result('success', {'result': res})
         else:
             return empty_result('error', "Unknown action specified"), 400
     else:
         return empty_result('error', "No action specified"), 400
Esempio n. 21
0
    def delete(self):
        """ Remove job locks """
        json_data = request.get_json()
        if 'name' not in json_data or not json_data['name']:
            return empty_result('error', "No lock name specified"), 400

        with sqla_session() as session:
            lock = session.query(Joblock).filter(Joblock.name == json_data['name']).one_or_none()
            if lock:
                session.delete(lock)
            else:
                return empty_result('error', "No such lock found in database"), 404

        return empty_result('success', data={'name': json_data['name'], 'status': 'deleted'})
Esempio n. 22
0
    def put(self, device_id):
        """ Modify device from ID """
        json_data = request.get_json()
        with sqla_session() as session:
            dev: Device = session.query(Device).filter(
                Device.id == device_id).one_or_none()

            if not dev:
                return empty_result(status='error', data=f"No device with id {device_id}")

            errors = dev.device_update(**json_data)
            if errors:
                return empty_result(status='error', data=errors), 404
            return empty_result(status='success', data={"updated_device": dev.as_dict()}), 200
Esempio n. 23
0
    def put(self, repo):
        """ Modify repository """
        json_data = request.get_json()
        try:
            repo_type = RepoType[str(repo).upper()]
        except:
            return empty_result('error', "Invalid repository type"), 400

        if 'action' in json_data:
            if str(json_data['action']).upper() == 'REFRESH':
                # TODO: consider doing as scheduled job?
                try:
                    res = refresh_repo(repo_type, get_jwt_identity())
                    return empty_result('success', res)
                except VerifyPathException as e:
                    return empty_result(
                        'error',
                        "Repository structure is invalid ({}): {}".format(
                            type(e).__name__, str(e))), 400
                except JoblockError as e:
                    return empty_result(
                        'error',
                        "Another job is locking configuration of devices, try again later ({})"
                        .format(str(e))), 503
                except SettingsSyntaxError as e:
                    return empty_result(
                        'error',
                        "Syntax error in repository: {}".format(str(e))), 400
                except Exception as e:
                    return empty_result(
                        'error', "Error in repository: {}".format(str(e))), 500
            else:
                return empty_result('error', "Invalid action"), 400
        else:
            return empty_result('error', "No action specified"), 400
Esempio n. 24
0
 def get(self):
     """ List all plugins """
     try:
         pmh = PluginManagerHandler()
         plugindata = pmh.get_plugindata()
         plugin_module_names = pmh.get_plugins()
     except Exception as e:
         return empty_result('error',
                             "Error retrieving plugins {}".format(str(e)))
     else:
         return empty_result('success', {
             'loaded_plugins': plugin_module_names,
             'plugindata': plugindata
         })
Esempio n. 25
0
    def put(self, hostname):
        """Take a map of interfaces and associated values to update.
        Example:
            {"interfaces": {"Ethernet1": {"configtype": "ACCESS_AUTO"}}}
        """
        json_data = request.get_json()
        data = {}
        errors = []

        with sqla_session() as session:
            dev: Device = session.query(Device).filter(
                Device.hostname == hostname).one_or_none()
            if not dev:
                return empty_result('error', "Device not found"), 404

            updated = False
            if 'interfaces' in json_data and isinstance(
                    json_data['interfaces'], dict):
                for if_name, if_dict in json_data['interfaces'].items():
                    if not isinstance(if_dict, dict):
                        errors.append(
                            "Each interface must have a dict with data to update"
                        )
                        continue
                    intf = session.query(Interface).filter(Interface.device == dev).\
                        filter(Interface.name == if_name).one_or_none()
                    if not intf:
                        errors.append(f"Interface {if_name} not found")
                        continue

                    if 'configtype' in if_dict:
                        configtype = if_dict['configtype'].upper()
                        if InterfaceConfigType.has_name(configtype):
                            intf.configtype = InterfaceConfigType[configtype]
                            updated = True
                            data[if_name] = {'configtype': configtype}
                        else:
                            errors.append(
                                f"Invalid configtype received: {configtype}")
            if updated:
                dev.synchronized = False

        if errors:
            if data:
                ret = {'errors': errors, 'updated': data}
            else:
                ret = {'errors': errors}
            return empty_result(status='error', data=ret), 400
        else:
            return empty_result(status='success', data={'updated': data})
Esempio n. 26
0
 def get(self):
     """ Get all management domains """
     result = empty_result()
     result['data'] = {'mgmtdomains': []}
     filter_exp = None
     with sqla_session() as session:
         query = session.query(Mgmtdomain)
         try:
             query = build_filter(Mgmtdomain, query).limit(limit_results())
         except Exception as e:
             return empty_result(status='error',
                                 data="Unable to filter mgmtdomains: {}".format(e)), 400
         for instance in query:
             result['data']['mgmtdomains'].append(instance.as_dict())
     return result
Esempio n. 27
0
 def post(self):
     json_data = request.get_json()
     data = {}
     errors = []
     data, errors = Device.validate(**json_data)
     if errors != []:
         return empty_result(status='error', data=errors), 404
     with sqla_session() as session:
         instance: Device = session.query(Device).filter(
             Device.hostname == data['hostname']).one_or_none()
         if instance is not None:
             errors.append('Device already exists')
             return errors
     Device.device_add(**json_data)
     return empty_result(status='success'), 200
Esempio n. 28
0
 def get(self, hostname):
     result = empty_result()
     result['data'] = {'interfaces': []}
     with sqla_session() as session:
         dev = session.query(Device).filter(
             Device.hostname == hostname).one_or_none()
         if not dev:
             return empty_result('error', "Device not found"), 404
         result['data']['hostname'] = dev.hostname
         intfs = session.query(Interface).filter(
             Interface.device == dev).all()
         intf: Interface
         for intf in intfs:
             result['data']['interfaces'].append(intf.as_dict())
     return result
Esempio n. 29
0
    def put(self, job_id):
        json_data = request.get_json()
        if 'action' not in json_data:
            return empty_result(status='error',
                                data="Action must be specified"), 400

        with sqla_session() as session:
            job = session.query(Job).filter(Job.id == job_id).one_or_none()
            if not job:
                return empty_result(
                    status='error',
                    data="No job with id {} found".format(job_id)), 400
            job_status = job.status

        action = str(json_data['action']).upper()
        if action == 'ABORT':
            allowed_jobstates = [JobStatus.SCHEDULED, JobStatus.RUNNING]
            if job_status not in allowed_jobstates:
                return empty_result(
                    status='error',
                    data="Job id {} is in state {}, must be {} to abort".
                    format(job_id, job_status,
                           (" or ".join([x.name
                                         for x in allowed_jobstates])))), 400
            abort_reason = "Aborted via API call"
            if 'abort_reason' in json_data and isinstance(
                    json_data['abort_reason'], str):
                abort_reason = json_data['abort_reason'][:255]

            abort_reason += " (aborted by {})".format(get_jwt_identity())

            if job_status == JobStatus.SCHEDULED:
                scheduler = Scheduler()
                scheduler.remove_scheduled_job(job_id=job_id,
                                               abort_message=abort_reason)
                time.sleep(2)
            elif job_status == JobStatus.RUNNING:
                with sqla_session() as session:
                    job = session.query(Job).filter(
                        Job.id == job_id).one_or_none()
                    job.status = JobStatus.ABORTING

            with sqla_session() as session:
                job = session.query(Job).filter(Job.id == job_id).one_or_none()
                return empty_result(data={"jobs": [job.as_dict()]})
        else:
            return empty_result(status='error',
                                data="Unknown action: {}".format(action)), 400
Esempio n. 30
0
 def get(self):
     result = {'linknet': []}
     with sqla_session() as session:
         query = session.query(Linknet)
         for instance in query:
             result['linknet'].append(instance.as_dict())
     return empty_result(status='success', data=result)