Exemple #1
0
def server_edit(hostname):
    db_session = DBSession()

    server = get_server(db_session, hostname)
    if server is None:
        abort(404)

    form = ServerForm(request.form)

    if request.method == 'POST' and form.validate():
        if not can_edit(current_user):
            abort(401)

        if hostname != form.hostname.data and get_server(
                db_session, form.hostname.data) is not None:
            return render_template('server/edit.html',
                                   form=form,
                                   duplicate_error=True)

        create_or_update_server_repository(
            db_session=db_session,
            hostname=form.hostname.data,
            server_type=form.server_type.data,
            server_url=form.server_url.data,
            username=form.username.data,
            password=form.password.data
            if len(form.password.data) > 0 else server.password,
            vrf=form.vrf.data
            if form.server_type.data == ServerType.TFTP_SERVER
            or form.server_type.data == ServerType.FTP_SERVER else '',
            server_directory=form.server_directory.data,
            destination_on_host=form.destination_on_host.data,
            created_by=current_user.username,
            server=server)

        return redirect(url_for('home'))
    else:
        # Assign the values to form fields
        form.hostname.data = server.hostname
        form.server_type.data = server.server_type
        form.server_url.data = server.server_url
        form.username.data = server.username
        form.vrf.data = server.vrf
        form.server_directory.data = server.server_directory
        form.destination_on_host.data = server.destination_on_host

        if not is_empty(server.password):
            form.password_placeholder = 'Use Password on File'
        else:
            form.password_placeholder = 'No Password Specified'

        return render_template('server/edit.html', form=form)
def api_get_server_repositories(request):

    validate_url_parameters(request, [KEY_HOSTNAME])

    rows = []
    db_session = DBSession()

    hostname = request.args.get(KEY_HOSTNAME)
    if hostname:
        server = get_server(db_session, hostname)
        if server is None:
            raise ValueError("Server repository '{}' does not exist in the database.".format(hostname))

        servers = [server]
    else:
        servers = get_server_list(db_session)

    for server in servers:
        if server is not None:
            row = dict()
            row[KEY_HOSTNAME] = server.hostname
            row[KEY_SERVER_TYPE] = server.server_type

            for req in params_dict[server.server_type]:
                row[req] = server.__getattribute__(req) if server.__getattribute__(req) is not None else ''

            row[server_url_dict[server.server_type]] = server.server_url

            if not is_empty(server_directory_dict[server.server_type]):
                row[server_directory_dict[server.server_type]] = server.server_directory

            rows.append(row)

    return jsonify(**{RESPONSE_ENVELOPE: {'server_repository_list': rows}})
Exemple #3
0
def server_create():
    if not can_create(current_user):
        abort(401)

    form = ServerForm(request.form)

    if request.method == 'POST' and form.validate():
        db_session = DBSession()
        server = get_server(db_session, form.hostname.data)
        if server is not None:
            return render_template('server/edit.html',
                                   form=form,
                                   duplicate_error=True)

        create_or_update_server_repository(
            db_session=db_session,
            hostname=form.hostname.data,
            server_type=form.server_type.data,
            server_url=form.server_url.data,
            username=form.username.data,
            password=form.password.data,
            vrf=form.vrf.data
            if form.server_type.data == ServerType.TFTP_SERVER
            or form.server_type.data == ServerType.FTP_SERVER else '',
            server_directory=form.server_directory.data,
            destination_on_host=form.destination_on_host.data,
            created_by=current_user.username)

        return redirect(url_for('home'))

    return render_template('server/edit.html', form=form)
Exemple #4
0
def get_penguins(cpps=None, server=None, shape=None):
    servers = common.get_json("servers")
    shapes = common.get_json("shapes")
    try:
        cpps = common.get_cpps(servers, cpps)
        server = common.get_server(servers, cpps, server)
        shape = get_shape(shapes, shape)
    except (KeyboardInterrupt, EOFError):
        raise common.LoginError()
    logger = logging.getLogger()
    logger.addHandler(logging.NullHandler())
    clients_offsets = [(common.get_client(servers, cpps, server, logger),
                        int(offset["x"]), int(offset["y"]))
                       for offset in shape["offsets"]]
    return cpps, server, shape, clients_offsets
def api_get_server_repositories(request):

    validate_url_parameters(request, [KEY_HOSTNAME])

    rows = []
    db_session = DBSession()

    hostname = request.args.get(KEY_HOSTNAME)
    if hostname:
        server = get_server(db_session, hostname)
        if server is None:
            raise ValueError(
                "Server repository '{}' does not exist in the database.".
                format(hostname))

        servers = [server]
    else:
        servers = get_server_list(db_session)

    for server in servers:
        if server is not None:
            row = dict()
            row[KEY_HOSTNAME] = server.hostname
            row[KEY_SERVER_TYPE] = server.server_type

            for req in params_dict[server.server_type]:
                row[req] = server.__getattribute__(
                    req) if server.__getattribute__(req) is not None else ''

            row[server_url_dict[server.server_type]] = server.server_url

            if not is_empty(server_directory_dict[server.server_type]):
                row[server_directory_dict[
                    server.server_type]] = server.server_directory

            rows.append(row)

    return jsonify(**{RESPONSE_ENVELOPE: {'server_repository_list': rows}})
Exemple #6
0
def check_server_reachability():
    if not can_check_reachability(current_user):
        abort(401)

    hostname = request.args.get('hostname')
    server_type = request.args.get('server_type')
    server_url = request.args.get('server_url')
    username = request.args.get('username')
    password = request.args.get('password')
    server_directory = request.args.get('server_directory')

    server = Server(hostname=hostname,
                    server_type=server_type,
                    server_url=server_url,
                    username=username,
                    password=password,
                    server_directory=server_directory)
    # The form is in the edit mode and the user clicks Validate Reachability
    # If there is no password specified, try get it from the database.
    if (server_type == ServerType.FTP_SERVER
            or server_type == ServerType.SFTP_SERVER
            or server_type == ServerType.SCP_SERVER) and password == '':

        db_session = DBSession()
        server_in_db = get_server(db_session, hostname)
        if server_in_db is not None:
            server.password = server_in_db.password

    server_impl = get_server_impl(server)

    is_reachable, error = server_impl.check_reachability()

    if is_reachable:
        return jsonify({'status': 'OK'})
    else:
        return jsonify({'status': error})
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)
Exemple #8
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)
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)
Exemple #10
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)