예제 #1
0
def cisco_eox_query(request):
    """Manual query page against the Cisco EoX Version 5 API (if enabled)

    :param request:
    :return:
    """
    app_config = AppSettings()
    app_config.read_file()

    cisco_api_enabled = app_config.is_cisco_api_enabled()

    context = {"is_cisco_api_enabled": cisco_api_enabled}

    if request.method == "POST":
        # create a form instance and populate it with data from the request:
        if "sync_cisco_eox_states_now" in request.POST.keys():
            if "sync_cisco_eox_states_query" in request.POST.keys():
                query = request.POST['sync_cisco_eox_states_query']

                if query != "":
                    if len(query.split(" ")) == 1:
                        context['query_executed'] = query
                        try:
                            eox_api_update_records = update_cisco_eox_database(
                                api_query=query)

                        except ConnectionFailedException as ex:
                            eox_api_update_records = [
                                "Cannot contact Cisco API, error message:\n%s"
                                % ex
                            ]

                        except CiscoApiCallFailed as ex:
                            eox_api_update_records = [ex]

                        except Exception as ex:
                            logger.debug(
                                "execution failed due to unexpected exception",
                                exc_info=True)
                            eox_api_update_records = [
                                "execution failed: %s" % ex
                            ]

                        context['eox_api_update_records'] = json.dumps(
                            eox_api_update_records, indent=4, sort_keys=True)

                    else:
                        context['eox_api_update_records'] = "Invalid query '%s': not executed" % \
                                                            request.POST['sync_cisco_eox_states_query']
                else:
                    context['eox_api_update_records'] = [
                        "Please specify a valid query"
                    ]

            else:
                context[
                    'eox_api_update_records'] = "Query not executed, please select the \"execute it now\" checkbox."

    return render(request, "ciscoeox/cisco_eox_query.html", context=context)
예제 #2
0
    def load_client_credentials(self):
        logger.debug("load client credentials from configuration")
        app_settings = AppSettings()
        app_settings.read_file()

        # load client credentials
        self.client_id = app_settings.get_cisco_api_client_id()
        self.client_secret = app_settings.get_cisco_api_client_secret()
예제 #3
0
    def test_write_datetime_to_settings_file(self):
        self.clean_config_file()

        # create new AppSettings object
        settings = AppSettings()
        settings.create_defaults()

        # get a configuration value (default in the global section)
        now = datetime.now()
        value = now.isoformat()
        settings.set(
            key="cisco_eox_api_auto_sync_last_execution_time",
            section=AppSettings.CISCO_EOX_CRAWLER_SECTION,
            value=value
        )

        settings.write_file()

        read_value = settings.get_string(
            key="cisco_eox_api_auto_sync_last_execution_time",
            section=AppSettings.CISCO_EOX_CRAWLER_SECTION
        )
        self.assertEqual(value, read_value)
        self.assertEqual(now, parse_datetime(read_value))

        # cleanup
        self.clean_config_file()
예제 #4
0
def cisco_eox_query(request):
    """Manual query page against the Cisco EoX Version 5 API (if enabled)

    :param request:
    :return:
    """
    app_config = AppSettings()
    app_config.read_file()

    cisco_api_enabled = app_config.is_cisco_api_enabled()

    context = {
        "is_cisco_api_enabled": cisco_api_enabled
    }

    if request.method == "POST":
        # create a form instance and populate it with data from the request:
        if "sync_cisco_eox_states_now" in request.POST.keys():
            if "sync_cisco_eox_states_query" in request.POST.keys():
                query = request.POST['sync_cisco_eox_states_query']

                if query != "":
                    if len(query.split(" ")) == 1:
                        context['query_executed'] = query
                        try:
                            eox_api_update_records = update_cisco_eox_database(api_query=query)

                        except ConnectionFailedException as ex:
                            eox_api_update_records = ["Cannot contact Cisco API, error message:\n%s" % ex]

                        except CiscoApiCallFailed as ex:
                            eox_api_update_records = [ex]

                        except Exception as ex:
                            logger.debug("execution failed due to unexpected exception", exc_info=True)
                            eox_api_update_records = ["execution failed: %s" % ex]

                        context['eox_api_update_records'] = json.dumps(eox_api_update_records, indent=4, sort_keys=True)

                    else:
                        context['eox_api_update_records'] = "Invalid query '%s': not executed" % \
                                                            request.POST['sync_cisco_eox_states_query']
                else:
                    context['eox_api_update_records'] = ["Please specify a valid query"]

            else:
                context['eox_api_update_records'] = "Query not executed, please select the \"execute it now\" checkbox."

    return render(request, "ciscoeox/cisco_eox_query.html", context=context)
예제 #5
0
    def test_read_with_missing_file(self):
        """
        test the read function if no file exists
        """
        self.clean_config_file()

        # create new AppSettings object
        settings = AppSettings()
        self.assertFalse(os.path.exists(self.TEST_CONFIG_FILE))

        # read file specified in the settings
        settings.read_file()
        self.assertTrue(os.path.exists(self.TEST_CONFIG_FILE))

        # cleanup
        self.clean_config_file()
예제 #6
0
    def test_read_with_missing_file(self):
        """
        test the read function if no file exists
        """
        self.clean_config_file()

        # create new AppSettings object
        settings = AppSettings()
        self.assertFalse(os.path.exists(self.TEST_CONFIG_FILE))

        # read file specified in the settings
        settings.read_file()
        self.assertTrue(os.path.exists(self.TEST_CONFIG_FILE))

        # cleanup
        self.clean_config_file()
예제 #7
0
    def test_eox_update_call_with_sample_data(self):
        app_config = AppSettings()
        app_config.read_file()

        app_config.set_cisco_api_enabled(True)
        app_config.set_periodic_sync_enabled(True)
        app_config.write_file()

        eox_sample_response = os.path.join("app",
                                           "ciscoeox",
                                           "tests",
                                           "cisco_eox_sample_response.json")
        eox_db_json = json.loads(open(eox_sample_response).read())

        for record in eox_db_json['EOXRecord']:
            api_crawler.update_local_db_based_on_record(record, True)
예제 #8
0
def update_cisco_eox_database(api_query):
    """
    Synchronizes the local EoX data from the Cisco EoX API using the specified queries or the queries specified in the
    configuration when api_query is set to None
    :param api_query: single query that is send to the Cisco EoX API
    :return:
    """
    # load application settings and check, that the API is enabled
    app_settings = AppSettings()
    app_settings.read_file()

    if not app_settings.is_cisco_api_enabled():
        msg = "Cisco API access not enabled"
        logger.warn(msg)
        raise CiscoApiCallFailed(msg)

    blacklist = app_settings.get_product_blacklist_regex().split(";")
    create_missing = app_settings.is_auto_create_new_products()

    # start with Cisco EoX API queries
    logger.info("Query EoX database: %s" % api_query)
    query_results = query_cisco_eox_api(api_query, blacklist, create_missing)

    # filter empty result strings
    if len(query_results) == 0:
        query_results = [{
            "PID": None,
            "blacklist": False,
            "updated": False,
            "created": False,
            "message": "No product update required"
        }]

    return query_results
예제 #9
0
    def test_create_default_config(self):
        """
        test the create of the default configuration
        """
        self.clean_config_file()

        # create new AppSettings object and create defaults
        settings = AppSettings()
        settings.create_defaults()

        # verify result
        self.assertTrue(os.path.exists(self.TEST_CONFIG_FILE))

        # test dictionary (booleans are converted as string)
        self.assertEqual(json.dumps(settings.CONFIG_DEFAULTS, sort_keys=True),
                         json.dumps(settings.to_dictionary(), sort_keys=True))

        # cleanup
        self.clean_config_file()
    def test_trigger_manual_cisco_eox_synchronization(self):
        """
        Test if a Cisco EoX synchronization task is scheduled after
        :return:
        """
        app_config = AppSettings()
        app_config.read_file()

        app_config.set_cisco_api_enabled(True)
        app_config.set_periodic_sync_enabled(True)
        app_config.write_file()

        # schedule Cisco EoX API update
        url = reverse('cisco_api:start_cisco_eox_api_sync_now')
        self.client.login(username="******", password="******")
        resp = self.client.get(url)
        self.assertEqual(resp.status_code, 302)

        # verify that task ID is saved in the cache (set by the schedule call)
        task_id = cache.get("CISCO_EOX_API_SYN_IN_PROGRESS", "")
        self.assertNotEqual(task_id, "")
예제 #11
0
def login_required_if_login_only_mode(request):
    """
    Test if the login only mode is enabled. If this is the case, test if a user is authentication. If this is not the
    case, redirect to the login form.
    """
    login_only_mode = cache.get("LOGIN_ONLY_MODE_SETTING", None)

    if not login_only_mode:
        # key not in cache
        app_settings = AppSettings()
        app_settings.read_file()
        login_only_mode = app_settings.is_login_only_mode()

        # add setting to cache
        cache.set("LOGIN_ONLY_MODE_SETTING", login_only_mode, 60 * 60)

    if login_only_mode:
        if not request.user.is_authenticated():
            return True

    return False
예제 #12
0
    def test_create_default_config(self):
        """
        test the create of the default configuration
        """
        self.clean_config_file()

        # create new AppSettings object and create defaults
        settings = AppSettings()
        settings.create_defaults()

        # verify result
        self.assertTrue(os.path.exists(self.TEST_CONFIG_FILE))

        # test dictionary (booleans are converted as string)
        self.assertEqual(
            json.dumps(settings.CONFIG_DEFAULTS, sort_keys=True),
            json.dumps(settings.to_dictionary(), sort_keys=True)
        )

        # cleanup
        self.clean_config_file()
예제 #13
0
    def test_auto_create_new_products(self):
        self.clean_config_file()

        # create new AppSettings object
        settings = AppSettings()
        self.assertFalse(os.path.exists(self.TEST_CONFIG_FILE))
        settings.read_file()
        self.assertTrue(os.path.exists(self.TEST_CONFIG_FILE))

        # get values
        value = settings.is_auto_create_new_products()
        self.assertEqual(value, False)

        # set values
        settings.set_auto_create_new_products(True)
        settings.write_file()
        value = settings.is_auto_create_new_products()

        self.assertEqual(value, True)

        # cleanup
        self.clean_config_file()
예제 #14
0
    def load_client_credentials(self):
        logger.debug("load client credentials from configuration")
        app_settings = AppSettings()
        app_settings.read_file()

        # load client credentials
        self.client_id = app_settings.get_cisco_api_client_id()
        self.client_secret = app_settings.get_cisco_api_client_secret()
예제 #15
0
    def test_get_cisco_api_client_secret(self):
        self.clean_config_file()

        # create new AppSettings object
        settings = AppSettings()
        self.assertFalse(os.path.exists(self.TEST_CONFIG_FILE))
        settings.read_file()
        self.assertTrue(os.path.exists(self.TEST_CONFIG_FILE))

        # get values
        value = settings.get_cisco_api_client_secret()
        self.assertEqual(value, "PlsChgMe")

        # set values
        value = "test_secret"
        settings.set_cisco_api_client_secret(value)
        settings.write_file()
        value = settings.get_cisco_api_client_secret()

        self.assertEqual(value, value)

        # cleanup
        self.clean_config_file()
예제 #16
0
    def test_get_cisco_eox_queries_from_config(self):
        self.clean_config_file()

        # create new AppSettings object
        settings = AppSettings()
        self.assertFalse(os.path.exists(self.TEST_CONFIG_FILE))
        settings.read_file()
        self.assertTrue(os.path.exists(self.TEST_CONFIG_FILE))

        # get values
        value = settings.get_cisco_eox_api_queries()
        self.assertEqual(value, "")

        # set values
        queries = "test"
        settings.set_cisco_eox_api_queries(queries)
        settings.write_file()
        value = settings.get_cisco_eox_api_queries()

        self.assertEqual(value, queries)

        # cleanup
        self.clean_config_file()
예제 #17
0
    def test_get_product_blacklist_regex_from_config(self):
        self.clean_config_file()

        # create new AppSettings object
        settings = AppSettings()
        self.assertFalse(os.path.exists(self.TEST_CONFIG_FILE))
        settings.read_file()
        self.assertTrue(os.path.exists(self.TEST_CONFIG_FILE))

        # get values
        value = settings.get_product_blacklist_regex()
        self.assertEqual(value, "")

        # set values
        blacklist_entries = "test"
        settings.set_product_blacklist_regex(blacklist_entries)
        settings.write_file()
        value = settings.get_product_blacklist_regex()

        self.assertEqual(value, blacklist_entries)

        # cleanup
        self.clean_config_file()
예제 #18
0
    def test_auto_create_new_products(self):
        self.clean_config_file()

        # create new AppSettings object
        settings = AppSettings()
        self.assertFalse(os.path.exists(self.TEST_CONFIG_FILE))
        settings.read_file()
        self.assertTrue(os.path.exists(self.TEST_CONFIG_FILE))

        # get values
        value = settings.is_auto_create_new_products()
        self.assertEqual(value, False)

        # set values
        settings.set_auto_create_new_products(True)
        settings.write_file()
        value = settings.is_auto_create_new_products()

        self.assertEqual(value, True)

        # cleanup
        self.clean_config_file()
예제 #19
0
    def test_get_cisco_api_client_secret(self):
        self.clean_config_file()

        # create new AppSettings object
        settings = AppSettings()
        self.assertFalse(os.path.exists(self.TEST_CONFIG_FILE))
        settings.read_file()
        self.assertTrue(os.path.exists(self.TEST_CONFIG_FILE))

        # get values
        value = settings.get_cisco_api_client_secret()
        self.assertEqual(value, "PlsChgMe")

        # set values
        value = "test_secret"
        settings.set_cisco_api_client_secret(value)
        settings.write_file()
        value = settings.get_cisco_api_client_secret()

        self.assertEqual(value, value)

        # cleanup
        self.clean_config_file()
예제 #20
0
    def test_get_cisco_eox_queries_from_config(self):
        self.clean_config_file()

        # create new AppSettings object
        settings = AppSettings()
        self.assertFalse(os.path.exists(self.TEST_CONFIG_FILE))
        settings.read_file()
        self.assertTrue(os.path.exists(self.TEST_CONFIG_FILE))

        # get values
        value = settings.get_cisco_eox_api_queries()
        self.assertEqual(value, "")

        # set values
        queries = "test"
        settings.set_cisco_eox_api_queries(queries)
        settings.write_file()
        value = settings.get_cisco_eox_api_queries()

        self.assertEqual(value, queries)

        # cleanup
        self.clean_config_file()
예제 #21
0
    def test_get_product_blacklist_regex_from_config(self):
        self.clean_config_file()

        # create new AppSettings object
        settings = AppSettings()
        self.assertFalse(os.path.exists(self.TEST_CONFIG_FILE))
        settings.read_file()
        self.assertTrue(os.path.exists(self.TEST_CONFIG_FILE))

        # get values
        value = settings.get_product_blacklist_regex()
        self.assertEqual(value, "")

        # set values
        blacklist_entries = "test"
        settings.set_product_blacklist_regex(blacklist_entries)
        settings.write_file()
        value = settings.get_product_blacklist_regex()

        self.assertEqual(value, blacklist_entries)

        # cleanup
        self.clean_config_file()
예제 #22
0
    def test_write_datetime_to_settings_file(self):
        self.clean_config_file()

        # create new AppSettings object
        settings = AppSettings()
        settings.create_defaults()

        # get a configuration value (default in the global section)
        now = datetime.now()
        value = now.isoformat()
        settings.set(key="cisco_eox_api_auto_sync_last_execution_time",
                     section=AppSettings.CISCO_EOX_CRAWLER_SECTION,
                     value=value)

        settings.write_file()

        read_value = settings.get_string(
            key="cisco_eox_api_auto_sync_last_execution_time",
            section=AppSettings.CISCO_EOX_CRAWLER_SECTION)
        self.assertEqual(value, read_value)
        self.assertEqual(now, parse_datetime(read_value))

        # cleanup
        self.clean_config_file()
예제 #23
0
def change_configuration(request):
    """
    change configuration of the Product Database
    """
    app_config = AppSettings()
    app_config.read_file()

    if request.method == "POST":
        # create a form instance and populate it with data from the request:
        form = SettingsForm(request.POST)
        if form.is_valid():
            # set common settings
            app_config.set_login_only_mode(form.cleaned_data["login_only_mode"])

            # set the Cisco API configuration options
            api_enabled = form.cleaned_data["cisco_api_enabled"]

            if not api_enabled:
                # api is disabled, reset values to default
                app_config.set_cisco_api_enabled(api_enabled)
                app_config.set_cisco_api_client_id("PlsChgMe")
                app_config.set_cisco_api_client_secret("PlsChgMe")
                app_config.set_cisco_eox_api_auto_sync_enabled(False)
                app_config.set_auto_create_new_products(False)
                app_config.set_cisco_eox_api_queries("")
                app_config.set_product_blacklist_regex("")

            else:
                app_config.set_cisco_api_enabled(api_enabled)

                client_id = form.cleaned_data["cisco_api_client_id"] \
                    if form.cleaned_data["cisco_api_client_id"] != "" else "PlsChgMe"
                app_config.set_cisco_api_client_id(client_id)
                client_secret = form.cleaned_data["cisco_api_client_secret"] \
                    if form.cleaned_data["cisco_api_client_secret"] != "" else "PlsChgMe"
                app_config.set_cisco_api_client_secret(client_secret)

                if client_id != "PlsChgMe":
                    if settings.DEMO_MODE:
                        messages.success(request, "Successfully connected to the Cisco EoX API (Demo Mode)")
                    else:
                        result, message = test_cisco_eox_api_access(
                            form.cleaned_data["cisco_api_client_id"],
                            form.cleaned_data["cisco_api_client_secret"]
                        )

                        if result:
                            messages.success(request, "Successfully connected to the Cisco EoX API")

                        else:
                            messages.error(request, "Cannot contact the Cisco EoX API: %s" % message)

                else:
                    messages.info(
                        request,
                        "Please configure your Cisco API credentials within the Cisco API settings tab."
                    )

                app_config.set_cisco_eox_api_auto_sync_enabled(form.cleaned_data["eox_api_auto_sync_enabled"])
                app_config.set_auto_create_new_products(form.cleaned_data["eox_auto_sync_auto_create_elements"])
                app_config.set_cisco_eox_api_queries(form.cleaned_data["eox_api_queries"])
                app_config.set_product_blacklist_regex(form.cleaned_data["eox_api_blacklist"])

            app_config.write_file()

            # expire cached settings
            cache.delete("LOGIN_ONLY_MODE_SETTING")

            messages.success(request, "Settings saved successfully")
            return redirect(resolve_url("productdb_config:change_settings"))

    else:
        form = SettingsForm()
        form.fields['cisco_api_enabled'].initial = app_config.is_cisco_api_enabled()
        form.fields['login_only_mode'].initial = app_config.is_login_only_mode()
        form.fields['cisco_api_client_id'].initial = app_config.get_cisco_api_client_id()
        form.fields['cisco_api_client_secret'].initial = app_config.get_cisco_api_client_secret()
        form.fields['eox_api_auto_sync_enabled'].initial = app_config.is_cisco_eox_api_auto_sync_enabled()
        form.fields['eox_auto_sync_auto_create_elements'].initial = app_config.is_auto_create_new_products()
        form.fields['eox_api_queries'].initial = app_config.get_cisco_eox_api_queries()
        form.fields['eox_api_blacklist'].initial = app_config.get_product_blacklist_regex()

    context = {
        "form": form,
        "is_cisco_api_enabled": app_config.is_cisco_api_enabled(),
        "is_cisco_eox_api_auto_sync_enabled": app_config.is_cisco_eox_api_auto_sync_enabled()
    }
    return render(request, "config/change_configuration.html", context=context)
예제 #24
0
def test_app_settings():
    app_settings = AppSettings()
    assert app_settings
예제 #25
0
def execute_task_to_synchronize_cisco_eox_states(
        self, ignore_periodic_sync_flag=False):
    """
    This task synchronize the local database with the Cisco EoX API. It executes all configured queries and stores the
    results in the local database. There are two types of operation:
      * cisco_eox_api_auto_sync_auto_create_elements is set to true - will create any element which is not part of the
                                                                      blacklist and not in the database
      * cisco_eox_api_auto_sync_auto_create_elements is set to false - will only update entries, which are already
                                                                       included in the database

    :return:
    """
    app_config = AppSettings()
    app_config.read_file()
    run_task = app_config.is_cisco_eox_api_auto_sync_enabled()

    if ignore_periodic_sync_flag:
        run_task = True

    if run_task:
        logger.info("start sync with Cisco EoX API...")
        self.update_state(
            state=TaskState.PROCESSING,
            meta={"status_message": "sync with Cisco EoX API..."})

        # read queries from configuration
        queries = app_config.get_cisco_eox_api_queries().splitlines()
        if len(queries) == 0:
            result = {"status_message": "No Cisco EoX API queries configured."}

        # update the local database with the Cisco EoX API
        else:
            # test Cisco EoX API access
            success, _ = test_cisco_eox_api_access(
                app_config.get_cisco_api_client_id(),
                app_config.get_cisco_api_client_secret(), False)

            if not success:
                msg = "Cannot access the Cisco API. Please ensure that the server is connected to the internet " \
                      "and that the authentication settings are valid."
                logger.error(msg, exc_info=True)

                NotificationMessage.objects.create(
                    title="Synchronization with Cisco EoX API",
                    type=NotificationMessage.MESSAGE_ERROR,
                    summary_message=msg,
                    detailed_message=
                    "The synchronization with the Cisco EoX API was not started."
                )

                result = {"error_message": msg}

            else:
                try:
                    # execute query by query
                    notify_metrics = {"queries": {}}
                    counter = 0
                    for query in queries:
                        self.update_state(
                            state=TaskState.PROCESSING,
                            meta={
                                "status_message":
                                "send query <code>%s</code> to the Cisco EoX API (<strong>%d of "
                                "%d</strong>)..." %
                                (query, counter + 1, len(queries))
                            })

                        query_results = cisco_eox_api_crawler.update_cisco_eox_database(
                            query)

                        blist_counter = 0
                        update_counter = 0
                        create_counter = 0
                        for qres in query_results:
                            if qres["created"]:
                                create_counter += 1
                            elif qres["updated"]:
                                update_counter += 1
                            elif qres["blacklist"]:
                                blist_counter += 1

                        notify_metrics["queries"][query] = {
                            "amount": len(query_results),
                            "updated_entries": update_counter,
                            "created_entries": create_counter,
                            "blacklisted_entries": blist_counter,
                            "result_details": query_results
                        }

                        counter += 1

                    # create NotificationMessage
                    detailed_html = ""
                    blist_counter = 0
                    update_counter = 0
                    create_counter = 0
                    for query_key in notify_metrics["queries"].keys():
                        update_counter += notify_metrics["queries"][query_key][
                            "updated_entries"]
                        create_counter += notify_metrics["queries"][query_key][
                            "created_entries"]
                        blist_counter += notify_metrics["queries"][query_key][
                            "blacklisted_entries"]

                        # build detailed string
                        detailed_html += "<div style=\"text-align:left;\"><h3>Query: %s</h3>" % query_key

                        cond_1 = notify_metrics["queries"][query_key][
                            "updated_entries"] == 0
                        cond_1 = cond_1 and (notify_metrics["queries"]
                                             [query_key]["created_entries"]
                                             == 0)
                        cond_1 = cond_1 and (notify_metrics["queries"]
                                             [query_key]["blacklisted_entries"]
                                             == 0)

                        if cond_1:
                            detailed_html += "No changes required."

                        else:
                            detailed_html += "The following products are affected by this update:</p>"
                            detailed_html += "<ul>"

                            for qres in notify_metrics["queries"][query_key][
                                    "result_details"]:

                                msg = ""
                                if "message" in qres.keys():
                                    if qres["message"]:
                                        msg = qres["message"]

                                if qres["created"]:
                                    detailed_html += "<li>create the Product <code>%s</code> in the database" % (
                                        qres["PID"])
                                    if msg != "":
                                        detailed_html += "(%s)</li>" % msg
                                    else:
                                        detailed_html += "</li>"

                                elif qres["updated"]:
                                    detailed_html += "<li>update the Product data for <code>%s</code></li>" % (
                                        qres["PID"])
                                    if msg != "":
                                        detailed_html += "(%s)</li>" % msg
                                    else:
                                        detailed_html += "</li>"

                                elif qres["blacklist"]:
                                    detailed_html += "<li>Product data for <code>%s</code> ignored</li>" % (
                                        qres["PID"])
                                    if msg != "":
                                        detailed_html += "(%s)</li>" % msg
                                    else:
                                        detailed_html += "</li>"

                            detailed_html += "</ul>"

                        detailed_html += "</div>"

                    summary_html = "The synchronization was performed successfully. "

                    if update_counter == 1:
                        summary_html += "<strong>%d</strong> product was updated, " % update_counter
                    else:
                        summary_html += "<strong>%d</strong> products are updated, " % update_counter

                    if create_counter == 1:
                        summary_html += "<strong>%s</strong> product was added to the database and " % create_counter
                    else:
                        summary_html += "<strong>%s</strong> products are added to the database and " % create_counter

                    if blist_counter == 1:
                        summary_html += "<strong>%d</strong> product was ignored." % blist_counter
                    else:
                        summary_html += "<strong>%d</strong> products are ignored." % blist_counter

                    NotificationMessage.objects.create(
                        title="Synchronization with Cisco EoX API",
                        type=NotificationMessage.MESSAGE_SUCCESS,
                        summary_message=summary_html,
                        detailed_message=detailed_html)

                    result = {"status_message": detailed_html}

                    # if the task was executed eager, set state to SUCCESS (required for testing)
                    if self.request.is_eager:
                        self.update_state(
                            state=TaskState.SUCCESS,
                            meta={"status_message": detailed_html})

                except CredentialsNotFoundException as ex:
                    msg = "Invalid credentials for Cisco EoX API or insufficient access rights (%s)" % str(
                        ex)
                    logger.error(msg, exc_info=True)

                    NotificationMessage.objects.create(
                        title="Synchronization with Cisco EoX API",
                        type=NotificationMessage.MESSAGE_ERROR,
                        summary_message=msg,
                        detailed_message=
                        "The synchronization was performed partially.")

                    result = {"error_message": msg}

                except CiscoApiCallFailed as ex:
                    msg = "Server unreachable (%s)" % str(ex)
                    logger.error(msg, exc_info=True)

                    NotificationMessage.objects.create(
                        title="Synchronization with Cisco EoX API",
                        type=NotificationMessage.MESSAGE_ERROR,
                        summary_message=msg,
                        detailed_message=
                        "The synchronization was performed partially.")

                    result = {"error_message": msg}

    else:
        result = {"status_message": "task not enabled"}

    # remove in progress flag with the cache
    cache.delete("CISCO_EOX_API_SYN_IN_PROGRESS")

    return result
예제 #26
0
    def test_get_config_value(self):
        self.clean_config_file()

        # create new AppSettings object
        settings = AppSettings()
        settings.create_defaults()

        # get a configuration value (default in the global section)
        self.assertFalse(settings.get_boolean("cisco_api_enabled"))

        # get a configuration value (with an explicit option)
        self.assertEqual(
            "PlsChgMe",
            settings.get_string("client_id",
                                section=AppSettings.CISCO_API_SECTION))

        # get the default Cisco API enabled value
        self.assertFalse(settings.is_cisco_api_enabled())

        # set a new value
        settings.set_cisco_api_enabled(True)

        # set an invalid value
        with self.assertRaises(ValueError):
            settings.set_cisco_api_enabled("invalid value")

        # write results
        settings.write_file()

        # cleanup
        self.clean_config_file()
예제 #27
0
    def test_eox_update_call_with_special_character(self):
        """
        test, that no issue exists when the '%' sign is present in the ProductID
        :return:
        """
        app_config = AppSettings()
        app_config.read_file()

        app_config.set_cisco_api_enabled(True)
        app_config.set_periodic_sync_enabled(True)
        app_config.write_file()

        eox_db_record = """{
            "EndOfServiceContractRenewal": {
                "value": " ",
                "dateFormat": "YYYY-MM-DD"
            },
            "ProductIDDescription": "^IPX 8 CDP W/E1EC TO UNIVERSAL CDP (IPX 8/16/32)",
            "ProductBulletinNumber": "LEGACY_ESC_IPX_4",
            "LastDateOfSupport": {
                "value": "2003-07-01",
                "dateFormat": "YYYY-MM-DD"
            },
            "EOXInputValue": "SPA* ",
            "EOLProductID": "SPARE%",
            "UpdatedTimeStamp": {
                "value": "2015-08-23",
                "dateFormat": "YYYY-MM-DD"
            },
            "EOXInputType": "ShowEOXByPids",
            "EndOfRoutineFailureAnalysisDate": {
                "value": " ",
                "dateFormat": "YYYY-MM-DD"
            },
            "LinkToProductBulletinURL": "http://www.cisco.com/en/US/products/hw/tsd_products_support_end-of-sale_and_end-of-life_products_list.html",
            "EndOfSvcAttachDate": {
                "value": " ",
                "dateFormat": "YYYY-MM-DD"
            },
            "EndOfSaleDate": {
                "value": "1998-07-02",
                "dateFormat": "YYYY-MM-DD"
            },
            "EndOfSWMaintenanceReleases": {
                "value": " ",
                "dateFormat": "YYYY-MM-DD"
            },
            "EOXExternalAnnouncementDate": {
                "value": "1998-01-03",
                "dateFormat": "YYYY-MM-DD"
            },
            "EOXMigrationDetails": {
                "MigrationStrategy": " ",
                "MigrationProductId": " ",
                "MigrationProductInfoURL": " ",
                "PIDActiveFlag": "Y  ",
                "MigrationProductName": "See Product Bulletin",
                "MigrationInformation": " ",
                "MigrationOption": "Enter Product Name(s)"
            }
        }"""
        eox_db_json = json.loads(eox_db_record)
        api_crawler.update_local_db_based_on_record(eox_db_json, True)

        p = Product.objects.get(product_id="SPARE%")
예제 #28
0
def status(request):
    """
    Status page for the Product Database
    """
    app_config = AppSettings()
    app_config.read_file()

    is_cisco_api_enabled = app_config.is_cisco_api_enabled()
    context = {
        "is_cisco_api_enabled": is_cisco_api_enabled
    }

    if is_cisco_api_enabled:
        # test access (once every 30 minutes)
        cisco_eox_api_test_successful = cache.get("CISCO_EOC_API_TEST", False)

        # defaults, overwritten if an exception is thrown
        cisco_eox_api_available = True
        cisco_eox_api_message = "successful connected to the Cisco EoX API"

        if not cisco_eox_api_test_successful:
            try:
                test_cisco_eox_api_access(client_id=app_config.get_cisco_api_client_id(),
                                          client_secret=app_config.get_cisco_api_client_secret(),
                                          drop_credentials=False)
                cache.set("CISCO_EOC_API_TEST", True, 60 * 30)

            except Exception as ex:
                cisco_eox_api_available = True
                cisco_eox_api_message = str(ex)

        context["cisco_eox_api_available"] = cisco_eox_api_available
        context["cisco_eox_api_message"] = cisco_eox_api_message

    # determine worker status
    ws = WorkerState.objects.all()
    if ws.count() == 0:
        worker_status = """
            <div class="alert alert-danger" role="alert">
                <span class="fa fa-exclamation-circle"></span>
                <span class="sr-only">Error:</span>
                All backend worker offline, asynchronous and scheduled tasks are not executed.
            </div>"""
    else:
        alive_worker = False
        for w in ws:
            if w.is_alive():
                alive_worker = True
                break
        if alive_worker:
            worker_status = """
                <div class="alert alert-success" role="alert">
                    <span class="fa fa-info-circle"></span>
                    <span class="sr-only">Error:</span>
                    Backend worker found.
                </div>"""

        else:
            worker_status = """
                <div class="alert alert-warning" role="alert">
                    <span class="fa fa-exclamation-circle"></span>
                    <span class="sr-only">Error:</span>
                    Only unregistered backend worker found, asynchronous and scheduled tasks are not executed.
                    Please verify the state in the <a href="/productdb/admin">Django Admin</a> page.
                </div>"""

    context['worker_status'] = mark_safe(worker_status)

    return render(request, "config/status.html", context=context)
예제 #29
0
def execute_task_to_synchronize_cisco_eox_states(self, ignore_periodic_sync_flag=False):
    """
    This task synchronize the local database with the Cisco EoX API. It executes all configured queries and stores the
    results in the local database. There are two types of operation:
      * cisco_eox_api_auto_sync_auto_create_elements is set to true - will create any element which is not part of the
                                                                      blacklist and not in the database
      * cisco_eox_api_auto_sync_auto_create_elements is set to false - will only update entries, which are already
                                                                       included in the database

    :return:
    """
    app_config = AppSettings()
    app_config.read_file()
    run_task = app_config.is_cisco_eox_api_auto_sync_enabled()

    if ignore_periodic_sync_flag:
        run_task = True

    if run_task:
        logger.info("start sync with Cisco EoX API...")
        self.update_state(state=TaskState.PROCESSING, meta={
            "status_message": "sync with Cisco EoX API..."
        })

        # read queries from configuration
        queries = app_config.get_cisco_eox_api_queries().splitlines()
        if len(queries) == 0:
            result = {
                "status_message": "No Cisco EoX API queries configured."
            }

        # update the local database with the Cisco EoX API
        else:
            # test Cisco EoX API access
            success, _ = test_cisco_eox_api_access(
                app_config.get_cisco_api_client_id(),
                app_config.get_cisco_api_client_secret(),
                False
            )

            if not success:
                msg = "Cannot access the Cisco API. Please ensure that the server is connected to the internet " \
                      "and that the authentication settings are valid."
                logger.error(msg, exc_info=True)

                NotificationMessage.objects.create(
                    title="Synchronization with Cisco EoX API",
                    type=NotificationMessage.MESSAGE_ERROR,
                    summary_message=msg,
                    detailed_message="The synchronization with the Cisco EoX API was not started."
                )

                result = {
                    "error_message": msg
                }

            else:
                try:
                    # execute query by query
                    notify_metrics = {
                        "queries": {}
                    }
                    counter = 0
                    for query in queries:
                        self.update_state(state=TaskState.PROCESSING, meta={
                            "status_message": "send query <code>%s</code> to the Cisco EoX API (<strong>%d of "
                                              "%d</strong>)..." % (query, counter + 1, len(queries))
                        })

                        query_results = cisco_eox_api_crawler.update_cisco_eox_database(query)

                        blist_counter = 0
                        update_counter = 0
                        create_counter = 0
                        for qres in query_results:
                            if qres["created"]:
                                create_counter += 1
                            elif qres["updated"]:
                                update_counter += 1
                            elif qres["blacklist"]:
                                blist_counter += 1

                        notify_metrics["queries"][query] = {
                            "amount": len(query_results),
                            "updated_entries": update_counter,
                            "created_entries": create_counter,
                            "blacklisted_entries": blist_counter,
                            "result_details": query_results
                        }

                        counter += 1

                    # create NotificationMessage
                    detailed_html = ""
                    blist_counter = 0
                    update_counter = 0
                    create_counter = 0
                    for query_key in notify_metrics["queries"].keys():
                        update_counter += notify_metrics["queries"][query_key]["updated_entries"]
                        create_counter += notify_metrics["queries"][query_key]["created_entries"]
                        blist_counter += notify_metrics["queries"][query_key]["blacklisted_entries"]

                        # build detailed string
                        detailed_html += "<div style=\"text-align:left;\"><h3>Query: %s</h3>" % query_key

                        cond_1 = notify_metrics["queries"][query_key]["updated_entries"] == 0
                        cond_1 = cond_1 and (notify_metrics["queries"][query_key]["created_entries"] == 0)
                        cond_1 = cond_1 and (notify_metrics["queries"][query_key]["blacklisted_entries"] == 0)

                        if cond_1:
                            detailed_html += "No changes required."

                        else:
                            detailed_html += "The following products are affected by this update:</p>"
                            detailed_html += "<ul>"

                            for qres in notify_metrics["queries"][query_key]["result_details"]:

                                msg = ""
                                if "message" in qres.keys():
                                    if qres["message"]:
                                        msg = qres["message"]

                                if qres["created"]:
                                    detailed_html += "<li>create the Product <code>%s</code> in the database" % (
                                        qres["PID"]
                                    )
                                    if msg != "":
                                        detailed_html += "(%s)</li>" % msg
                                    else:
                                        detailed_html += "</li>"

                                elif qres["updated"]:
                                    detailed_html += "<li>update the Product data for <code>%s</code></li>" % (
                                        qres["PID"]
                                    )
                                    if msg != "":
                                        detailed_html += "(%s)</li>" % msg
                                    else:
                                        detailed_html += "</li>"

                                elif qres["blacklist"]:
                                    detailed_html += "<li>Product data for <code>%s</code> ignored</li>" % (
                                        qres["PID"]
                                    )
                                    if msg != "":
                                        detailed_html += "(%s)</li>" % msg
                                    else:
                                        detailed_html += "</li>"

                            detailed_html += "</ul>"

                        detailed_html += "</div>"

                    summary_html = "The synchronization was performed successfully. "

                    if update_counter == 1:
                        summary_html += "<strong>%d</strong> product was updated, " % update_counter
                    else:
                        summary_html += "<strong>%d</strong> products are updated, " % update_counter

                    if create_counter == 1:
                        summary_html += "<strong>%s</strong> product was added to the database and " % create_counter
                    else:
                        summary_html += "<strong>%s</strong> products are added to the database and " % create_counter

                    if blist_counter == 1:
                        summary_html += "<strong>%d</strong> product was ignored." % blist_counter
                    else:
                        summary_html += "<strong>%d</strong> products are ignored." % blist_counter

                    NotificationMessage.objects.create(
                        title="Synchronization with Cisco EoX API",
                        type=NotificationMessage.MESSAGE_SUCCESS,
                        summary_message=summary_html,
                        detailed_message=detailed_html
                    )

                    result = {
                        "status_message": detailed_html
                    }

                    # if the task was executed eager, set state to SUCCESS (required for testing)
                    if self.request.is_eager:
                        self.update_state(state=TaskState.SUCCESS, meta={
                            "status_message": detailed_html
                        })

                except CredentialsNotFoundException as ex:
                    msg = "Invalid credentials for Cisco EoX API or insufficient access rights (%s)" % str(ex)
                    logger.error(msg, exc_info=True)

                    NotificationMessage.objects.create(
                        title="Synchronization with Cisco EoX API",
                        type=NotificationMessage.MESSAGE_ERROR,
                        summary_message=msg,
                        detailed_message="The synchronization was performed partially."
                    )

                    result = {
                        "error_message": msg
                    }

                except CiscoApiCallFailed as ex:
                    msg = "Server unreachable (%s)" % str(ex)
                    logger.error(msg, exc_info=True)

                    NotificationMessage.objects.create(
                        title="Synchronization with Cisco EoX API",
                        type=NotificationMessage.MESSAGE_ERROR,
                        summary_message=msg,
                        detailed_message="The synchronization was performed partially."
                    )

                    result = {
                        "error_message": msg
                    }

    else:
        result = {
            "status_message": "task not enabled"
        }

    # remove in progress flag with the cache
    cache.delete("CISCO_EOX_API_SYN_IN_PROGRESS")

    return result
예제 #30
0
    def test_get_config_value(self):
        self.clean_config_file()

        # create new AppSettings object
        settings = AppSettings()
        settings.create_defaults()

        # get a configuration value (default in the global section)
        self.assertFalse(settings.get_boolean("cisco_api_enabled"))

        # get a configuration value (with an explicit option)
        self.assertEqual("PlsChgMe", settings.get_string("client_id", section=AppSettings.CISCO_API_SECTION))

        # get the default Cisco API enabled value
        self.assertFalse(settings.is_cisco_api_enabled())

        # set a new value
        settings.set_cisco_api_enabled(True)

        # set an invalid value
        with self.assertRaises(ValueError):
            settings.set_cisco_api_enabled("invalid value")

        # write results
        settings.write_file()

        # cleanup
        self.clean_config_file()