Esempio n. 1
0
def api_create_custom_command_profiles(request):
    """
    POST:
    http://localhost:5000/api/v1/custom_command_profiles

    BODY:
    [{
      "profile_name": "Profile_1",
      "command_list": ["show inventory"]
    },{
      "profile_name": "Profile_2",
      "command_list": ["show platform"]
    }]
    """

    rows = []
    db_session = DBSession()
    error_found = False

    json_list = convert_json_request_to_list(request)

    for data in json_list:
        row = dict()
        try:
            validate_required_keys_in_dict(data, [KEY_PROFILE_NAME])

            profile_name = get_acceptable_string(data[KEY_PROFILE_NAME])
            row[KEY_PROFILE_NAME] = profile_name

            if profile_name is None or len(profile_name) == 0:
                raise ValueError("Invalid custom command profile name '{}'.".format(data[KEY_PROFILE_NAME]))

            validate_acceptable_keys_in_dict(data, [KEY_PROFILE_NAME, KEY_COMMAND_LIST])

            command_list = convert_value_to_list(data, KEY_COMMAND_LIST)
            command_list = None if command_list is None else ','.join(command_list)

            custom_command_profile = get_custom_command_profile(db_session, profile_name)
            if custom_command_profile is not None and command_list is None:
                command_list = custom_command_profile.command_list

            create_or_update_custom_command_profile(db_session=db_session,
                                                    profile_name=profile_name,
                                                    command_list=command_list,
                                                    created_by=g.api_user.username,
                                                    custom_command_profile=custom_command_profile)
            row[RESPONSE_STATUS] = APIStatus.SUCCESS

        except Exception as e:
            row[RESPONSE_STATUS] = APIStatus.FAILED
            row[RESPONSE_STATUS_MESSAGE] = e.message
            error_found = True

        rows.append(row)

    return jsonify(**{RESPONSE_ENVELOPE: {'custom_command_profile_list': rows}}), \
                  (HTTP_OK if not error_found else HTTP_MULTI_STATUS_ERROR)
Esempio n. 2
0
def api_create_regions(request):
    """
    POST:
    http://localhost:5000/api/v1/regions

    BODY:
    [{
      "name": "Region_1"
      "server_repository": ["Repository1", "Repository2"]

    },{
      "name": "Region_2"
    }]
    """
    rows = []
    db_session = DBSession()
    error_found = False

    json_list = convert_json_request_to_list(request)

    for data in json_list:
        row = dict()
        try:
            validate_required_keys_in_dict(data, [KEY_REGION_NAME])

            region_name = get_acceptable_string(data[KEY_REGION_NAME])
            row[KEY_REGION_NAME] = region_name

            if region_name is None or len(region_name) == 0:
                raise ValueError("'{}' is an invalid region name.".format(data[KEY_REGION_NAME]))

            validate_acceptable_keys_in_dict(data, [KEY_REGION_NAME, KEY_SERVER_REPOSITORIES])

            # If the server_repositories is not in the json, it will return None
            server_repositories = convert_value_to_list(data, KEY_SERVER_REPOSITORIES)

            region = get_region(db_session, region_name)
            if region is not None and server_repositories is None:
                server_repositories = get_region_server_name_list(region)

            create_or_update_region(db_session=db_session,
                                    region_name=region_name,
                                    server_repositories=None if server_repositories is None else ','.join(server_repositories),
                                    created_by=g.api_user.username,
                                    region=region)

            row[RESPONSE_STATUS] = APIStatus.SUCCESS

        except Exception as e:
            row[RESPONSE_STATUS] = APIStatus.FAILED
            row[RESPONSE_STATUS_MESSAGE] = e.message
            error_found = True

        rows.append(row)

    return jsonify(**{RESPONSE_ENVELOPE: {'region_list': rows}}), (HTTP_OK if not error_found else HTTP_MULTI_STATUS_ERROR)
Esempio n. 3
0
def api_create_server_repositories(request):
    """
    [{
        "hostname": "Repository_1",
        "server_type": "TFTP",
        "tftp_server_path": "223.255.254.245",
        "home_directory": "/auto/tftp-sjc-users1"
    },{
        "hostname": "Repository_2",
        "server_type": "FTP",
        "server_address": "172.27.153.150",
        "home_directory": "/tftpboot"
    },{
        "hostname": "Repository_3",
        "server_type": "SFTP",
        "server_address": "nb-server3",
        "home_directory": "/auto/tftp-vista"
    }]
    """
    rows = []
    db_session = DBSession()
    error_found = False

    json_list = convert_json_request_to_list(request)
    for data in json_list:
        row = dict()
        try:
            validate_required_keys_in_dict(data, [KEY_HOSTNAME, KEY_SERVER_TYPE])

            hostname = get_acceptable_string(data[KEY_HOSTNAME])
            row[KEY_HOSTNAME] = hostname

            if len(hostname) == 0:
                raise ValueError("Server repository name '{}' is not valid.".format(data[KEY_HOSTNAME]))

            server_type = data.get(KEY_SERVER_TYPE)
            if server_type not in [ServerType.TFTP_SERVER, ServerType.FTP_SERVER, ServerType.SFTP_SERVER,
                                   ServerType.LOCAL_SERVER, ServerType.SCP_SERVER]:
                raise ValueError("'{}' is not a supported server type.".format(server_type))

            row[KEY_SERVER_TYPE] = server_type

            validate_required_keys_in_dict(data, required_keys_dict[server_type])
            validate_acceptable_keys_in_dict(data, acceptable_keys_dict[server_type])

            server = get_server(db_session, hostname)
            if server is None:
                # These are the required fields for a new server repository creation.
                validate_required_keys_in_dict(data, required_keys_dict.get(server_type))

            server_url = data.get(server_url_dict[server_type])
            server_url = server_url if server_url is not None else \
                (None if server is None else server.server_url)

            server_directory = data.get(server_directory_dict[server_type])
            server_directory = server_directory if server_directory is not None else \
                (None if server is None else server.server_directory)

            vrf = data.get(KEY_VRF) if data.get(KEY_VRF) is not None else \
                (None if server is None else server.vrf)

            username = data.get(KEY_USERNAME) if data.get(KEY_USERNAME) is not None else \
                (None if server is None else server.username)

            password = data.get(KEY_PASSWORD) if data.get(KEY_PASSWORD) is not None else \
                (None if server is None else server.password)

            destination_on_host = data.get(KEY_DESTINATION_ON_HOST) if data.get(KEY_DESTINATION_ON_HOST) is not None else \
                (None if server is None else server.destination_on_host)

            create_or_update_server_repository(db_session,
                                               hostname=hostname,
                                               server_type=server_type,
                                               server_url=server_url,
                                               username=username,
                                               password=password,
                                               vrf=vrf,
                                               server_directory=server_directory,
                                               destination_on_host=destination_on_host,
                                               created_by=g.api_user.username,
                                               server=get_server(db_session, hostname))

            row[RESPONSE_STATUS] = APIStatus.SUCCESS
        except Exception as e:
            row[RESPONSE_STATUS] = APIStatus.FAILED
            row[RESPONSE_STATUS_MESSAGE] = e.message
            error_found = True

        rows.append(row)

    return jsonify(**{RESPONSE_ENVELOPE: {'server_repository_list': rows}}), (HTTP_OK if not error_found else HTTP_MULTI_STATUS_ERROR)
Esempio n. 4
0
def api_create_hosts(request):
    """
    POST: http://localhost:5000/api/v1/hosts
    BODY:
        [ {'hostname': 'My Host 1',
           'region': 'SJ Labs',
           'roles': 'PE',
           'connection_type': 'telnet',
           'host_or_ip': '172.28.98.2',
           'username': '******',
           'password': '******',
           'enable_password': '******',
           'location': 'building 20'
           } ]

    RETURN:
        {"api_response": {
            "host_list": [ {"status": "SUCCESS", "hostname": "My Host 1"},
                           {"status": "SUCCESS", "hostname": "My Host 2"} ]

            }
        }
    """
    rows = []
    db_session = DBSession()
    error_found = False

    # Pre-fetched information to speed up bulk host creation.
    region_dict = get_region_name_to_id_dict(db_session)
    jump_host_dict = get_jump_host_name_to_id_dict(db_session)
    software_profile_dict = get_software_profile_name_to_id_dict(db_session)

    json_list = convert_json_request_to_list(request)

    for data in json_list:
        row = dict()
        try:
            validate_required_keys_in_dict(data, [KEY_HOSTNAME])

            hostname = get_acceptable_string(data.get(KEY_HOSTNAME))
            row[KEY_HOSTNAME] = hostname

            if hostname is None or len(hostname) == 0:
                raise ValueError("'{}' is an invalid hostname.".format(
                    data.get(KEY_HOSTNAME)))

            validate_acceptable_keys_in_dict(data, [
                KEY_HOSTNAME, KEY_REGION, KEY_LOCATION, KEY_ROLES,
                KEY_SOFTWARE_PROFILE, KEY_CONNECTION_TYPE, KEY_TS_OR_IP,
                KEY_PORT_NUMBER, KEY_USERNAME, KEY_PASSWORD,
                KEY_ENABLE_PASSWORD, KEY_JUMP_HOST
            ])

            host = get_host(db_session, hostname)
            if host is None:
                # These are the required fields for a new host creation.
                validate_required_keys_in_dict(
                    data, [KEY_REGION, KEY_CONNECTION_TYPE, KEY_TS_OR_IP])

            value = get_id_from_value('Region', region_dict, data, KEY_REGION)
            region_id = value if value is not None else \
                (None if host is None else host.region_id)

            value = get_id_from_value('Jump host', jump_host_dict, data,
                                      KEY_JUMP_HOST)
            jump_host_id = value if value is not None else \
                (None if host is None else host.connection_param[0].jump_host_id)

            value = get_id_from_value('Software profile',
                                      software_profile_dict, data,
                                      KEY_SOFTWARE_PROFILE)
            software_profile_id = value if value is not None else \
                (None if host is None else host.software_profile_id)

            connection_type = data.get(KEY_CONNECTION_TYPE)
            if connection_type is not None:
                if connection_type not in [
                        ConnectionType.SSH, ConnectionType.TELNET
                ]:
                    raise ValueError(
                        'Connection Type must be either telnet or ssh')
            else:
                connection_type = None if host is None else host.connection_param[
                    0].connection_type

            roles = convert_value_to_list(data, KEY_ROLES)
            roles = ','.join(roles) if roles is not None else \
                (None if host is None else host.roles)

            host_or_ip = convert_value_to_list(data, KEY_TS_OR_IP)
            host_or_ip = ','.join(host_or_ip) if host_or_ip is not None else \
                (None if host is None else host.connection_param[0].host_or_ip)

            port_number = convert_value_to_list(data, KEY_PORT_NUMBER)
            port_number = ','.join(str(p) for p in port_number) if port_number is not None else \
                (None if host is None else host.connection_param[0].port_number)

            location = data.get(KEY_LOCATION) if data.get(KEY_LOCATION ) is not None else \
                (None if host is None else host.location)

            username = data.get(KEY_USERNAME) if data.get(KEY_USERNAME) is not None else \
                (None if host is None else host.connection_param[0].username)

            password = data.get(KEY_PASSWORD) if data.get(KEY_PASSWORD) is not None else \
                (None if host is None else host.connection_param[0].password)

            enable_password = data.get(KEY_ENABLE_PASSWORD) if data.get(KEY_ENABLE_PASSWORD) is not None else \
                (None if host is None else host.connection_param[0].enable_password)

            create_or_update_host(db_session=db_session,
                                  hostname=hostname,
                                  region_id=region_id,
                                  location=location,
                                  roles=roles,
                                  software_profile_id=software_profile_id,
                                  connection_type=connection_type,
                                  host_or_ip=host_or_ip,
                                  username=username,
                                  password=password,
                                  enable_password=enable_password,
                                  port_number=port_number,
                                  jump_host_id=jump_host_id,
                                  created_by=g.api_user.username,
                                  host=host)

            row[RESPONSE_STATUS] = APIStatus.SUCCESS

        except Exception as e:
            row[RESPONSE_STATUS] = APIStatus.FAILED
            row[RESPONSE_STATUS_MESSAGE] = e.message
            error_found = True

        rows.append(row)

    # end loop

    return jsonify(**{RESPONSE_ENVELOPE: {
        'host_list': rows
    }}), (HTTP_OK if not error_found else HTTP_MULTI_STATUS_ERROR)
Esempio n. 5
0
def api_create_jump_hosts(request):
    """
    POST:
    http://localhost:5000/api/v1/jump_hosts

    BODY:
    [{
      "hostname": "Jump_Host_1",
      "connection_type": "telnet",
      "host_or_ip": "1.1.1.1",
      "port_number": 5000,
      "username": "******",
      "password": "******"
    },{
      "hostname": "Jump_Host_2",
      "connection_type": "ssh",
      "host_or_ip": "my-server",
      "username": "******",
      "password": "******"

    }]
    """
    rows = []
    db_session = DBSession()
    error_found = False

    json_list = convert_json_request_to_list(request)

    for data in json_list:
        row = dict()
        try:
            validate_required_keys_in_dict(data, [KEY_HOSTNAME])

            hostname = get_acceptable_string(data[KEY_HOSTNAME])
            row[KEY_HOSTNAME] = hostname

            if len(hostname) == 0:
                raise ValueError("'{}' is an invalid jump hostname.".format(
                    data[KEY_HOSTNAME]))

            validate_acceptable_keys_in_dict(data, [
                KEY_HOSTNAME, KEY_CONNECTION_TYPE, KEY_HOST_OR_IP,
                KEY_PORT_NUMBER, KEY_USERNAME, KEY_PASSWORD
            ])

            jump_host = get_jump_host(db_session, hostname)
            if jump_host is None:
                # These are the required fields for a new jump host creation.
                validate_required_keys_in_dict(
                    data, [KEY_CONNECTION_TYPE, KEY_HOST_OR_IP])

            connection_type = data.get(KEY_CONNECTION_TYPE)
            if connection_type is not None:
                if connection_type not in [
                        ConnectionType.SSH, ConnectionType.TELNET
                ]:
                    raise ValueError(
                        'Connection Type must be either telnet or ssh')
            else:
                connection_type = None if jump_host is None else jump_host.connection_type

            host_or_ip = data.get(KEY_HOST_OR_IP) if data.get(KEY_HOST_OR_IP) is not None else \
                (None if jump_host is None else jump_host.host_or_ip)

            port_number = data.get(KEY_PORT_NUMBER) if data.get(KEY_PORT_NUMBER) is not None else \
                (None if jump_host is None else jump_host.port_number)

            username = data.get(KEY_USERNAME) if data.get(KEY_USERNAME) is not None else \
                (None if jump_host is None else jump_host.username)

            password = data.get(KEY_PASSWORD) if data.get(KEY_PASSWORD) is not None else \
                (None if jump_host is None else jump_host.password)

            create_or_update_jump_host(db_session,
                                       hostname=hostname,
                                       connection_type=connection_type,
                                       host_or_ip=host_or_ip,
                                       port_number=port_number,
                                       username=username,
                                       password=password,
                                       created_by=g.api_user.username,
                                       jumphost=jump_host)

            row[RESPONSE_STATUS] = APIStatus.SUCCESS

        except Exception as e:
            row[RESPONSE_STATUS] = APIStatus.FAILED
            row[RESPONSE_STATUS_MESSAGE] = e.message
            error_found = True

        rows.append(row)

    return jsonify(**{RESPONSE_ENVELOPE: {
        'jump_host_list': rows
    }}), (HTTP_OK if not error_found else HTTP_MULTI_STATUS_ERROR)
Esempio n. 6
0
def api_create_regions(request):
    """
    POST:
    http://localhost:5000/api/v1/regions

    BODY:
    [{
      "name": "Region_1"
      "server_repository": ["Repository1", "Repository2"]

    },{
      "name": "Region_2"
    }]
    """
    rows = []
    db_session = DBSession()
    error_found = False

    json_list = convert_json_request_to_list(request)

    for data in json_list:
        row = dict()
        try:
            validate_required_keys_in_dict(data, [KEY_REGION_NAME])

            region_name = get_acceptable_string(data[KEY_REGION_NAME])
            row[KEY_REGION_NAME] = region_name

            if region_name is None or len(region_name) == 0:
                raise ValueError("'{}' is an invalid region name.".format(
                    data[KEY_REGION_NAME]))

            validate_acceptable_keys_in_dict(
                data, [KEY_REGION_NAME, KEY_SERVER_REPOSITORIES])

            # If the server_repositories is not in the json, it will return None
            server_repositories = convert_value_to_list(
                data, KEY_SERVER_REPOSITORIES)

            region = get_region(db_session, region_name)
            if region is not None and server_repositories is None:
                server_repositories = get_region_server_name_list(region)

            create_or_update_region(
                db_session=db_session,
                region_name=region_name,
                server_repositories=None if server_repositories is None else
                ','.join(server_repositories),
                created_by=g.api_user.username,
                region=region)

            row[RESPONSE_STATUS] = APIStatus.SUCCESS

        except Exception as e:
            row[RESPONSE_STATUS] = APIStatus.FAILED
            row[RESPONSE_STATUS_MESSAGE] = e.message
            error_found = True

        rows.append(row)

    return jsonify(**{RESPONSE_ENVELOPE: {
        'region_list': rows
    }}), (HTTP_OK if not error_found else HTTP_MULTI_STATUS_ERROR)
Esempio n. 7
0
def api_create_install_request(request):
    """
    Install Action: Pre-Upgrade, Post-Upgrade, and Commit

        POST: http://localhost:5000/api/v1/install
        BODY:
            [ {'hostname': 'My Host',
               'install_action': 'Post-Upgrade',
               'scheduled_time': '05-02-2016 08:00 AM',
               'command_profile': 'Edge Devices',
               'dependency': 'Add'} ]

    Install Action: Add
        BODY:
            [ {'hostname': 'My Host',
               'install_action': 'Add',
               'scheduled_time': '05-02-2016 08:00 AM',
               'server_repository': 'My FTP Server',
               'software_packages': ['asr9k-px-5.3.3.CSCuz05961.pie, asr9k-px-5.3.3.CSCux89921.pie],
               'dependency': 'Pre-Upgrade'} ]

    Install Action: Activate, Remove, Deactivate
        BODY:
            [ {'hostname': 'My Host',
               'install_action': 'Activate',
               'scheduled_time': '05-02-2016 08:00 AM',
               'software_packages': ['asr9k-px-5.3.3.CSCuz05961.pie, asr9k-px-5.3.3.CSCux89921.pie]
               'dependency': '101'} ]


        RETURN:
            {"api_response": {
                "install_job_list": [ {"status": "SUCCESS", "hostname": "My Host", "id": 101},
                                      {"status": "FAILED", "hostname": "My Host 2", "status_message": "Unable to locate host"} ]

                }
            }
    """
    rows = []
    error_found = False
    db_session = DBSession()
    custom_command_profile_dict = get_custom_command_profile_name_to_id_dict(db_session)
    # ----------------------------  first phase is to attempt the data validation ---------------------------- #

    entries = []
    json_list = convert_json_request_to_list(request)

    for data in json_list:
        row = dict()
        try:
            validate_required_keys_in_dict(data, [KEY_INSTALL_ACTION])

            install_action = data[KEY_INSTALL_ACTION]
            if install_action not in supported_install_actions:
                raise ValueError("'{}' is an invalid install action.".format(install_action))

            validate_acceptable_keys_in_dict(data, acceptable_keys)
            validate_required_keys_in_dict(data, required_keys_dict[install_action])

            hostname = data[KEY_HOSTNAME]
            host = get_host(db_session, hostname)
            if host is None:
                raise ValueError("'{}' is an invalid hostname.".format(data[KEY_HOSTNAME]))

            if KEY_SERVER_REPOSITORY in data.keys():
                server = get_server(db_session, data[KEY_SERVER_REPOSITORY])
                if server is None:
                    raise ValueError("'{}' is an invalid server repository.".format(data[KEY_SERVER_REPOSITORY]))

            if KEY_CUSTOM_COMMAND_PROFILE in data.keys():
                custom_command_profile_names = convert_value_to_list(data, KEY_CUSTOM_COMMAND_PROFILE)
                for custom_command_profile_name in custom_command_profile_names:
                    custom_command_profile_id = custom_command_profile_dict.get(custom_command_profile_name)
                    if custom_command_profile_id is None:
                        raise ValueError("'{}' is an invalid custom command profile.".format(custom_command_profile_name))

            if KEY_SOFTWARE_PACKAGES in data.keys() and is_empty(data[KEY_SOFTWARE_PACKAGES]):
                raise ValueError("Software packages when specified cannot be empty.")

            # Check time fields and validate their values
            if KEY_SCHEDULED_TIME not in data.keys():
                row[KEY_UTC_SCHEDULED_TIME] = datetime.utcnow()
            elif KEY_UTC_OFFSET not in data.keys():
                raise ValueError("Missing utc_offset. If scheduled_time is submitted, utc_offset is also required.")
            elif not verify_utc_offset(data[KEY_UTC_OFFSET]):
                raise ValueError("Invalid utc_offset: Must be in '<+|->dd:dd' format and be between -12:00 and +14:00.")
            else:
                try:
                    time = datetime.strptime(data[KEY_SCHEDULED_TIME], "%m-%d-%Y %I:%M %p")
                    row[KEY_UTC_SCHEDULED_TIME] = get_utc_time(time, data[KEY_UTC_OFFSET])
                except ValueError:
                    raise ValueError("Invalid scheduled_time: {} must be in 'mm-dd-yyyy hh:mm AM|PM' format.".
                                     format(data[KEY_SCHEDULED_TIME]))

            # Handle duplicate entry.  It is defined by the hostname and install_action pair.
            if (hostname, install_action) not in entries:
                entries.append((hostname, install_action))
            else:
                raise ValueError("More than one entry with the same hostname: '{}' and install_action: '{}'. "
                                 "Remove any duplicate and resubmit.".format(hostname, install_action))

        except Exception as e:
            row[RESPONSE_STATUS] = APIStatus.FAILED
            row[RESPONSE_STATUS_MESSAGE] = e.message
            error_found = True

        # Add the original key value pairs to the new array.
        for key in data.keys():
            row[key] = data[key]

        rows.append(row)

    # End of loop

    if error_found:
        for row in rows:
            if RESPONSE_STATUS not in row.keys():
                row[RESPONSE_STATUS] = APIStatus.FAILED
                row[RESPONSE_STATUS_MESSAGE] = 'Not submitted. Check other jobs for error message.'

            if KEY_UTC_SCHEDULED_TIME in row.keys():
                row.pop(KEY_UTC_SCHEDULED_TIME)

        return jsonify(**{RESPONSE_ENVELOPE: {KEY_INSTALL_JOB_LIST: rows}}), HTTP_BAD_REQUEST

    # ----------------------------  Second phase is to attempt the job creation ---------------------------- #

    sorted_list = sorted(rows, cmp=get_key)

    rows = []
    error_found = False
    implicit_dependency_list = {}

    for install_request in sorted_list:
        row = dict()
        try:
            hostname = install_request[KEY_HOSTNAME]
            install_action = install_request[KEY_INSTALL_ACTION]

            row[KEY_INSTALL_ACTION] = install_action
            row[KEY_HOSTNAME] = hostname

            host_id = get_host(db_session, hostname).id
            utc_scheduled_time = install_request[KEY_UTC_SCHEDULED_TIME].strftime("%m/%d/%Y %I:%M %p")

            server_id = -1
            if KEY_SERVER_REPOSITORY in install_request.keys():
                server = get_server(db_session, install_request[KEY_SERVER_REPOSITORY])
                if server is not None:
                    server_id = server.id

            server_directory = ''
            if KEY_SERVER_DIRECTORY in install_request.keys():
                server_directory = install_request[KEY_SERVER_DIRECTORY]

            software_packages = []
            if KEY_SOFTWARE_PACKAGES in install_request.keys():
                software_packages = install_request[KEY_SOFTWARE_PACKAGES]

            custom_command_profile_ids = []
            if KEY_CUSTOM_COMMAND_PROFILE in install_request.keys():
                custom_command_profile_names = convert_value_to_list(install_request, KEY_CUSTOM_COMMAND_PROFILE)
                for custom_command_profile_name in custom_command_profile_names:
                    custom_command_profile_id = custom_command_profile_dict.get(custom_command_profile_name)
                    if custom_command_profile_id is not None:
                        custom_command_profile_ids.append(str(custom_command_profile_id))

            install_job = create_or_update_install_job(db_session,
                                                       host_id=host_id,
                                                       install_action=install_action,
                                                       scheduled_time=utc_scheduled_time,
                                                       software_packages=software_packages,
                                                       server_id=server_id,
                                                       server_directory=server_directory,
                                                       custom_command_profile_ids=custom_command_profile_ids,
                                                       dependency=get_dependency_id(db_session, implicit_dependency_list, install_request, host_id),
                                                       created_by=g.api_user.username)

            row[KEY_ID] = install_job.id

            if install_action in ordered_install_actions:
                if hostname not in implicit_dependency_list:
                    implicit_dependency_list[hostname] = []

                implicit_dependency_list[hostname].append((install_job.id, install_action, install_request[KEY_UTC_SCHEDULED_TIME]))

            row[RESPONSE_STATUS] = APIStatus.SUCCESS

        except Exception as e:
            row[RESPONSE_STATUS] = APIStatus.FAILED
            row[RESPONSE_STATUS_MESSAGE] = e.message
            row[RESPONSE_TRACE] = traceback.format_exc()
            error_found = True

        rows.append(row)

    return jsonify(**{RESPONSE_ENVELOPE: {KEY_INSTALL_JOB_LIST: rows}}), (HTTP_OK if not error_found else HTTP_MULTI_STATUS_ERROR)
Esempio n. 8
0
def api_create_server_repositories(request):
    """
    [{
        "hostname": "Repository_1",
        "server_type": "TFTP",
        "tftp_server_path": "223.255.254.245",
        "home_directory": "/auto/tftp-sjc-users1"
    },{
        "hostname": "Repository_2",
        "server_type": "FTP",
        "server_address": "172.27.153.150",
        "home_directory": "/tftpboot"
    },{
        "hostname": "Repository_3",
        "server_type": "SFTP",
        "server_address": "nb-server3",
        "home_directory": "/auto/tftp-vista"
    }]
    """
    rows = []
    db_session = DBSession()
    error_found = False

    json_list = convert_json_request_to_list(request)
    for data in json_list:
        row = dict()
        try:
            validate_required_keys_in_dict(data,
                                           [KEY_HOSTNAME, KEY_SERVER_TYPE])

            hostname = get_acceptable_string(data[KEY_HOSTNAME])
            row[KEY_HOSTNAME] = hostname

            if len(hostname) == 0:
                raise ValueError(
                    "Server repository name '{}' is not valid.".format(
                        data[KEY_HOSTNAME]))

            server_type = data.get(KEY_SERVER_TYPE)
            if server_type not in [
                    ServerType.TFTP_SERVER, ServerType.FTP_SERVER,
                    ServerType.SFTP_SERVER, ServerType.LOCAL_SERVER,
                    ServerType.SCP_SERVER
            ]:
                raise ValueError(
                    "'{}' is not a supported server type.".format(server_type))

            row[KEY_SERVER_TYPE] = server_type

            validate_required_keys_in_dict(data,
                                           required_keys_dict[server_type])
            validate_acceptable_keys_in_dict(data,
                                             acceptable_keys_dict[server_type])

            server = get_server(db_session, hostname)
            if server is None:
                # These are the required fields for a new server repository creation.
                validate_required_keys_in_dict(
                    data, required_keys_dict.get(server_type))

            server_url = data.get(server_url_dict[server_type])
            server_url = server_url if server_url is not None else \
                (None if server is None else server.server_url)

            server_directory = data.get(server_directory_dict[server_type])
            server_directory = server_directory if server_directory is not None else \
                (None if server is None else server.server_directory)

            vrf = data.get(KEY_VRF) if data.get(KEY_VRF) is not None else \
                (None if server is None else server.vrf)

            username = data.get(KEY_USERNAME) if data.get(KEY_USERNAME) is not None else \
                (None if server is None else server.username)

            password = data.get(KEY_PASSWORD) if data.get(KEY_PASSWORD) is not None else \
                (None if server is None else server.password)

            destination_on_host = data.get(KEY_DESTINATION_ON_HOST) if data.get(KEY_DESTINATION_ON_HOST) is not None else \
                (None if server is None else server.destination_on_host)

            create_or_update_server_repository(
                db_session,
                hostname=hostname,
                server_type=server_type,
                server_url=server_url,
                username=username,
                password=password,
                vrf=vrf,
                server_directory=server_directory,
                destination_on_host=destination_on_host,
                created_by=g.api_user.username,
                server=get_server(db_session, hostname))

            row[RESPONSE_STATUS] = APIStatus.SUCCESS
        except Exception as e:
            row[RESPONSE_STATUS] = APIStatus.FAILED
            row[RESPONSE_STATUS_MESSAGE] = e.message
            error_found = True

        rows.append(row)

    return jsonify(**{RESPONSE_ENVELOPE: {
        'server_repository_list': rows
    }}), (HTTP_OK if not error_found else HTTP_MULTI_STATUS_ERROR)
Esempio n. 9
0
def api_create_install_request(request):
    """
    Install Action: Pre-Upgrade, Post-Upgrade, and Commit

        POST: http://localhost:5000/api/v1/install
        BODY:
            [ {'hostname': 'My Host',
               'install_action': 'Post-Upgrade',
               'scheduled_time': '05-02-2016 08:00 AM',
               'command_profile': 'Edge Devices',
               'dependency': 'Add'} ]

    Install Action: Add
        BODY:
            [ {'hostname': 'My Host',
               'install_action': 'Add',
               'scheduled_time': '05-02-2016 08:00 AM',
               'server_repository': 'My FTP Server',
               'software_packages': ['asr9k-px-5.3.3.CSCuz05961.pie, asr9k-px-5.3.3.CSCux89921.pie],
               'dependency': 'Pre-Upgrade'} ]

    Install Action: Activate, Remove, Deactivate
        BODY:
            [ {'hostname': 'My Host',
               'install_action': 'Activate',
               'scheduled_time': '05-02-2016 08:00 AM',
               'software_packages': ['asr9k-px-5.3.3.CSCuz05961.pie, asr9k-px-5.3.3.CSCux89921.pie]
               'dependency': '101'} ]


        RETURN:
            {"api_response": {
                "install_job_list": [ {"status": "SUCCESS", "hostname": "My Host", "id": 101},
                                      {"status": "FAILED", "hostname": "My Host 2", "status_message": "Unable to locate host"} ]

                }
            }
    """
    rows = []
    error_found = False
    db_session = DBSession()
    custom_command_profile_dict = get_custom_command_profile_name_to_id_dict(
        db_session)
    # ----------------------------  first phase is to attempt the data validation ---------------------------- #

    entries = []
    json_list = convert_json_request_to_list(request)

    for data in json_list:
        row = dict()
        try:
            validate_required_keys_in_dict(data, [KEY_INSTALL_ACTION])

            install_action = data[KEY_INSTALL_ACTION]
            if install_action not in supported_install_actions:
                raise ValueError("'{}' is an invalid install action.".format(
                    install_action))

            validate_acceptable_keys_in_dict(data, acceptable_keys)
            validate_required_keys_in_dict(data,
                                           required_keys_dict[install_action])

            hostname = data[KEY_HOSTNAME]
            host = get_host(db_session, hostname)
            if host is None:
                raise ValueError("'{}' is an invalid hostname.".format(
                    data[KEY_HOSTNAME]))

            if KEY_SERVER_REPOSITORY in data.keys():
                server = get_server(db_session, data[KEY_SERVER_REPOSITORY])
                if server is None:
                    raise ValueError(
                        "'{}' is an invalid server repository.".format(
                            data[KEY_SERVER_REPOSITORY]))

            if KEY_CUSTOM_COMMAND_PROFILE in data.keys():
                custom_command_profile_names = convert_value_to_list(
                    data, KEY_CUSTOM_COMMAND_PROFILE)
                for custom_command_profile_name in custom_command_profile_names:
                    custom_command_profile_id = custom_command_profile_dict.get(
                        custom_command_profile_name)
                    if custom_command_profile_id is None:
                        raise ValueError(
                            "'{}' is an invalid custom command profile.".
                            format(custom_command_profile_name))

            if KEY_SOFTWARE_PACKAGES in data.keys() and is_empty(
                    data[KEY_SOFTWARE_PACKAGES]):
                raise ValueError(
                    "Software packages when specified cannot be empty.")

            # Check time fields and validate their values
            if KEY_SCHEDULED_TIME not in data.keys():
                row[KEY_UTC_SCHEDULED_TIME] = datetime.utcnow()
            elif KEY_UTC_OFFSET not in data.keys():
                raise ValueError(
                    "Missing utc_offset. If scheduled_time is submitted, utc_offset is also required."
                )
            elif not verify_utc_offset(data[KEY_UTC_OFFSET]):
                raise ValueError(
                    "Invalid utc_offset: Must be in '<+|->dd:dd' format and be between -12:00 and +14:00."
                )
            else:
                try:
                    time = datetime.strptime(data[KEY_SCHEDULED_TIME],
                                             "%m-%d-%Y %I:%M %p")
                    row[KEY_UTC_SCHEDULED_TIME] = get_utc_time(
                        time, data[KEY_UTC_OFFSET])
                except ValueError:
                    raise ValueError(
                        "Invalid scheduled_time: {} must be in 'mm-dd-yyyy hh:mm AM|PM' format."
                        .format(data[KEY_SCHEDULED_TIME]))

            # Handle duplicate entry.  It is defined by the hostname and install_action pair.
            if (hostname, install_action) not in entries:
                entries.append((hostname, install_action))
            else:
                raise ValueError(
                    "More than one entry with the same hostname: '{}' and install_action: '{}'. "
                    "Remove any duplicate and resubmit.".format(
                        hostname, install_action))

        except Exception as e:
            row[RESPONSE_STATUS] = APIStatus.FAILED
            row[RESPONSE_STATUS_MESSAGE] = e.message
            error_found = True

        # Add the original key value pairs to the new array.
        for key in data.keys():
            row[key] = data[key]

        rows.append(row)

    # End of loop

    if error_found:
        for row in rows:
            if RESPONSE_STATUS not in row.keys():
                row[RESPONSE_STATUS] = APIStatus.FAILED
                row[RESPONSE_STATUS_MESSAGE] = 'Not submitted. Check other jobs for error message.'

            if KEY_UTC_SCHEDULED_TIME in row.keys():
                row.pop(KEY_UTC_SCHEDULED_TIME)

        return jsonify(**{RESPONSE_ENVELOPE: {
            KEY_INSTALL_JOB_LIST: rows
        }}), HTTP_BAD_REQUEST

    # ----------------------------  Second phase is to attempt the job creation ---------------------------- #

    sorted_list = sorted(rows, cmp=get_key)

    rows = []
    error_found = False
    implicit_dependency_list = {}

    for install_request in sorted_list:
        row = dict()
        try:
            hostname = install_request[KEY_HOSTNAME]
            install_action = install_request[KEY_INSTALL_ACTION]

            row[KEY_INSTALL_ACTION] = install_action
            row[KEY_HOSTNAME] = hostname

            host_id = get_host(db_session, hostname).id
            utc_scheduled_time = install_request[
                KEY_UTC_SCHEDULED_TIME].strftime("%m/%d/%Y %I:%M %p")

            server_id = -1
            if KEY_SERVER_REPOSITORY in install_request.keys():
                server = get_server(db_session,
                                    install_request[KEY_SERVER_REPOSITORY])
                if server is not None:
                    server_id = server.id

            server_directory = ''
            if KEY_SERVER_DIRECTORY in install_request.keys():
                server_directory = install_request[KEY_SERVER_DIRECTORY]

            software_packages = []
            if KEY_SOFTWARE_PACKAGES in install_request.keys():
                software_packages = install_request[KEY_SOFTWARE_PACKAGES]

            custom_command_profile_ids = []
            if KEY_CUSTOM_COMMAND_PROFILE in install_request.keys():
                custom_command_profile_names = convert_value_to_list(
                    install_request, KEY_CUSTOM_COMMAND_PROFILE)
                for custom_command_profile_name in custom_command_profile_names:
                    custom_command_profile_id = custom_command_profile_dict.get(
                        custom_command_profile_name)
                    if custom_command_profile_id is not None:
                        custom_command_profile_ids.append(
                            str(custom_command_profile_id))

            install_job = create_or_update_install_job(
                db_session,
                host_id=host_id,
                install_action=install_action,
                scheduled_time=utc_scheduled_time,
                software_packages=software_packages,
                server_id=server_id,
                server_directory=server_directory,
                custom_command_profile_ids=custom_command_profile_ids,
                dependency=get_dependency_id(db_session,
                                             implicit_dependency_list,
                                             install_request, host_id),
                created_by=g.api_user.username)

            row[KEY_ID] = install_job.id

            if install_action in ordered_install_actions:
                if hostname not in implicit_dependency_list:
                    implicit_dependency_list[hostname] = []

                implicit_dependency_list[hostname].append(
                    (install_job.id, install_action,
                     install_request[KEY_UTC_SCHEDULED_TIME]))

            row[RESPONSE_STATUS] = APIStatus.SUCCESS

        except Exception as e:
            row[RESPONSE_STATUS] = APIStatus.FAILED
            row[RESPONSE_STATUS_MESSAGE] = e.message
            row[RESPONSE_TRACE] = traceback.format_exc()
            error_found = True

        rows.append(row)

    return jsonify(**{RESPONSE_ENVELOPE: {
        KEY_INSTALL_JOB_LIST: rows
    }}), (HTTP_OK if not error_found else HTTP_MULTI_STATUS_ERROR)