diff --git a/assets/js/common/ChartsDisabledBox/ChartsDisabledBox.jsx b/assets/js/common/ChartsDisabledBox/ChartsDisabledBox.jsx new file mode 100644 index 0000000000..b73c181f39 --- /dev/null +++ b/assets/js/common/ChartsDisabledBox/ChartsDisabledBox.jsx @@ -0,0 +1,16 @@ +import React from 'react'; + +function ChartsDisabledBox() { + return ( +
+

+ Charts are disabled, please check documentation for further details +

+
+ ); +} + +export default ChartsDisabledBox; diff --git a/assets/js/common/ChartsDisabledBox/ChartsDisabledBox.stories.jsx b/assets/js/common/ChartsDisabledBox/ChartsDisabledBox.stories.jsx new file mode 100644 index 0000000000..552d28194a --- /dev/null +++ b/assets/js/common/ChartsDisabledBox/ChartsDisabledBox.stories.jsx @@ -0,0 +1,10 @@ +import ChartsDisabledBox from '.'; + +export default { + title: 'Components/ChartsDisabledBox', + component: ChartsDisabledBox, +}; + +export const Default = { + args: {}, +}; diff --git a/assets/js/common/ChartsDisabledBox/index.js b/assets/js/common/ChartsDisabledBox/index.js new file mode 100644 index 0000000000..2c32433abb --- /dev/null +++ b/assets/js/common/ChartsDisabledBox/index.js @@ -0,0 +1,3 @@ +import ChartsDisabledBox from './ChartsDisabledBox'; + +export default ChartsDisabledBox; diff --git a/assets/js/common/ChartsFeatureWrapper/ChartsFeatureWrapper.jsx b/assets/js/common/ChartsFeatureWrapper/ChartsFeatureWrapper.jsx new file mode 100644 index 0000000000..61dff666a6 --- /dev/null +++ b/assets/js/common/ChartsFeatureWrapper/ChartsFeatureWrapper.jsx @@ -0,0 +1,10 @@ +import React from 'react'; +import ChartsDisabledBox from '@common/ChartsDisabledBox'; + +function ChartsFeatureWrapper({ children }) { + // eslint-disable-next-line no-undef + if (!config.chartsEnabled) return ; + return children; +} + +export default ChartsFeatureWrapper; diff --git a/assets/js/common/ChartsFeatureWrapper/ChartsFeatureWrapper.test.jsx b/assets/js/common/ChartsFeatureWrapper/ChartsFeatureWrapper.test.jsx new file mode 100644 index 0000000000..962858b086 --- /dev/null +++ b/assets/js/common/ChartsFeatureWrapper/ChartsFeatureWrapper.test.jsx @@ -0,0 +1,31 @@ +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import '@testing-library/jest-dom'; +import ChartsFeatureWrapper from './ChartsFeatureWrapper'; + +describe('ChartFeatureWrapper', () => { + afterEach(() => { + global.config = { chartsEnabled: false }; + }); + + it('should render ChartDisabledBox if the chart feature is disabled', () => { + global.config = { chartsEnabled: false }; + + render(); + expect(screen.getByTestId('chart-disabled-box')).toHaveTextContent( + 'disabled' + ); + }); + + it('should render children if the chart feature is enabled', () => { + global.config = { chartsEnabled: true }; + + render( + + {' '} +
child
{' '} +
+ ); + expect(screen.getByTestId('child')).toHaveTextContent('child'); + }); +}); diff --git a/assets/js/common/ChartsFeatureWrapper/index.js b/assets/js/common/ChartsFeatureWrapper/index.js new file mode 100644 index 0000000000..fcebbd70d7 --- /dev/null +++ b/assets/js/common/ChartsFeatureWrapper/index.js @@ -0,0 +1,3 @@ +import ChartsFeatureWrapper from './ChartsFeatureWrapper'; + +export default ChartsFeatureWrapper; diff --git a/assets/js/pages/HostDetailsPage/HostDetails.jsx b/assets/js/pages/HostDetailsPage/HostDetails.jsx index 4c5d48f6da..f570a24aa6 100644 --- a/assets/js/pages/HostDetailsPage/HostDetails.jsx +++ b/assets/js/pages/HostDetailsPage/HostDetails.jsx @@ -12,6 +12,8 @@ import PageHeader from '@common/PageHeader'; import Table from '@common/Table'; import Tooltip from '@common/Tooltip'; import WarningBanner from '@common/Banners/WarningBanner'; +import ChartsFeatureWrapper from '@common/ChartsFeatureWrapper'; + import { subHours } from 'date-fns'; import SuseLogo from '@static/suse_logo.svg'; @@ -209,24 +211,26 @@ function HostDetails({ /> -
- `${value}%`} - startInterval={subHours(timeNow, 3)} - /> -
-
- formatBytes(value, 3)} - /> -
+ +
+ `${value}%`} + startInterval={subHours(timeNow, 3)} + /> +
+
+ formatBytes(value, 3)} + /> +
+

Provider details

diff --git a/config/config.exs b/config/config.exs index 0fa50e12cc..7df3a68b99 100644 --- a/config/config.exs +++ b/config/config.exs @@ -141,7 +141,9 @@ config :trento, Trento.Infrastructure.Prometheus, config :trento, Trento.Infrastructure.Prometheus.PrometheusApi, url: "http://localhost:9090" -config :trento, Trento.Charts, host_data_fetcher: Trento.Infrastructure.Prometheus.PrometheusApi +config :trento, Trento.Charts, + enabled: true, + host_data_fetcher: Trento.Infrastructure.Prometheus.PrometheusApi config :trento, uuid_namespace: "fb92284e-aa5e-47f6-a883-bf9469e7a0dc", diff --git a/config/runtime.exs b/config/runtime.exs index 148e55a672..fa251f7da0 100644 --- a/config/runtime.exs +++ b/config/runtime.exs @@ -83,6 +83,8 @@ if config_env() in [:prod, :demo] do config :trento, Trento.Infrastructure.Prometheus.PrometheusApi, url: System.get_env("PROMETHEUS_URL") || "http://localhost:9090" + config :trento, Trento.Charts, enabled: System.get_env("CHARTS_ENABLED", "true") == "true" + # ## Using releases # # If you are doing OTP releases, you need to instruct Phoenix diff --git a/lib/trento_web/controllers/page_controller.ex b/lib/trento_web/controllers/page_controller.ex index e0020274ba..535d5a93ee 100644 --- a/lib/trento_web/controllers/page_controller.ex +++ b/lib/trento_web/controllers/page_controller.ex @@ -3,11 +3,12 @@ defmodule TrentoWeb.PageController do def index(conn, _params) do check_service_base_url = Application.fetch_env!(:trento, :checks_service)[:base_url] - + charts_enabled = Application.fetch_env!(:trento, Trento.Charts)[:enabled] deregistration_debounce = Application.fetch_env!(:trento, :deregistration_debounce) render(conn, "index.html", check_service_base_url: check_service_base_url, + charts_enabled: charts_enabled, deregistration_debounce: deregistration_debounce ) end diff --git a/lib/trento_web/plugs/charts_disabled_plug.ex b/lib/trento_web/plugs/charts_disabled_plug.ex new file mode 100644 index 0000000000..4612ddd27b --- /dev/null +++ b/lib/trento_web/plugs/charts_disabled_plug.ex @@ -0,0 +1,33 @@ +defmodule TrentoWeb.Plugs.ChartsDisabledPlug do + @moduledoc """ + This plug acts as a barrier for the charts endpoint, return 501 for all the requests. + + The endpoints are accessible only if the ":trento, Trento.Charts, enabled" configuration entry is properly set. + + The plug itself is mounted only when the charts are disabled in the configuration. + """ + @behaviour Plug + + alias TrentoWeb.ErrorView + + import Plug.Conn + + @impl true + def init(opts), do: opts + + @impl true + @spec call(Plug.Conn.t(), any) :: Plug.Conn.t() + def call(conn, _) do + conn + |> put_resp_content_type("application/json") + |> resp( + 501, + Jason.encode!( + ErrorView.render("501.json", %{ + reason: "Charts endpoints are disabled, check the documentation for further details" + }) + ) + ) + |> halt() + end +end diff --git a/lib/trento_web/plugs/unplug/predicates/charts_disabled.ex b/lib/trento_web/plugs/unplug/predicates/charts_disabled.ex new file mode 100644 index 0000000000..710cce6eec --- /dev/null +++ b/lib/trento_web/plugs/unplug/predicates/charts_disabled.ex @@ -0,0 +1,8 @@ +defmodule TrentoWeb.Plugs.Unplug.Predicates.ChartsDisabled do + @moduledoc false + + @behaviour Unplug.Predicate + + @impl true + def call(_, _), do: !Application.fetch_env!(:trento, Trento.Charts)[:enabled] +end diff --git a/lib/trento_web/router.ex b/lib/trento_web/router.ex index e5494eaf5c..bd8656d373 100644 --- a/lib/trento_web/router.ex +++ b/lib/trento_web/router.ex @@ -43,6 +43,12 @@ defmodule TrentoWeb.Router do error_handler: TrentoWeb.Plugs.ApiAuthErrorHandler} end + pipeline :charts_feature do + plug Unplug, + if: TrentoWeb.Plugs.Unplug.Predicates.ChartsDisabled, + do: TrentoWeb.Plugs.ChartsDisabledPlug + end + scope "/" do pipe_through :browser @@ -140,8 +146,12 @@ defmodule TrentoWeb.Router do get "/hosts/:id/exporters_status", PrometheusController, :exporters_status - get "/charts/hosts/:id/cpu", ChartController, :host_cpu - get "/charts/hosts/:id/memory", ChartController, :host_memory + scope "/charts" do + pipe_through :charts_feature + + get "/hosts/:id/cpu", ChartController, :host_cpu + get "/hosts/:id/memory", ChartController, :host_memory + end end scope "/v2", TrentoWeb.V2 do diff --git a/lib/trento_web/templates/page/index.html.heex b/lib/trento_web/templates/page/index.html.heex index b1f7755b62..173931cd3a 100644 --- a/lib/trento_web/templates/page/index.html.heex +++ b/lib/trento_web/templates/page/index.html.heex @@ -4,6 +4,7 @@ const config = { checksServiceBaseUrl: '<%= @check_service_base_url %>', deregistrationDebounce: <%= @deregistration_debounce %>, + chartsEnabled: <%= @charts_enabled %>, }; diff --git a/lib/trento_web/views/error_view.ex b/lib/trento_web/views/error_view.ex index 7ef91f6b59..a5cafa281f 100644 --- a/lib/trento_web/views/error_view.ex +++ b/lib/trento_web/views/error_view.ex @@ -74,6 +74,17 @@ defmodule TrentoWeb.ErrorView do } end + def render("501.json", %{reason: reason}) do + %{ + errors: [ + %{ + title: "Not implemented", + detail: reason + } + ] + } + end + def template_not_found(template, _assigns) do %{ errors: [ diff --git a/test/trento_web/plugs/unplug/predicates/charts_disabled.exs b/test/trento_web/plugs/unplug/predicates/charts_disabled.exs new file mode 100644 index 0000000000..1380e70bd2 --- /dev/null +++ b/test/trento_web/plugs/unplug/predicates/charts_disabled.exs @@ -0,0 +1,22 @@ +defmodule TrentoWeb.Plugs.Unplug.Predicates.ChartsDisabledTest do + use TrentoWeb.ConnCase, async: true + use Plug.Test + + alias TrentoWeb.Plugs.ChartsDisabledPlug + + test "should return 501 when called" do + conn = conn(:get, "/foo") + + conn = ChartsDisabledPlug.call(conn, []) + + assert %{ + "errors" => [ + %{ + "detail" => + "Charts endpoints are disabled, check the documentation for further details", + "title" => "Not implemented" + } + ] + } = json_response(conn, 501) + end +end