diff --git a/css/style.css b/css/style.css new file mode 100644 index 0000000..b0c664c --- /dev/null +++ b/css/style.css @@ -0,0 +1,3 @@ +h1, h2, h3 { + color: #ffffff !important; +} \ No newline at end of file diff --git a/docs/css/style.css b/docs/css/style.css new file mode 100644 index 0000000..b0c664c --- /dev/null +++ b/docs/css/style.css @@ -0,0 +1,3 @@ +h1, h2, h3 { + color: #ffffff !important; +} \ No newline at end of file diff --git a/docs/docs/api/dashboard.md b/docs/docs/api/dashboard.md new file mode 100644 index 0000000..f12b838 --- /dev/null +++ b/docs/docs/api/dashboard.md @@ -0,0 +1,212 @@ +# Dashboard + +Without any doubt, this is the principal resource of Perses. + +A `Dashboard` belongs to a `Project`. See the [project documentation](./project.md) to see how to create a project. + +It is defined like this: + +```yaml +kind: "Dashboard" +metadata: + name: + project: +spec: +``` + +## Dashboard specification + +```yaml +# Metadata.name has some restrictions. For example, you can't use space here. +# `display` allows to provide a rich name and a description for your dashboard. +[ display: ] + +# `datasources` is a map where the key is the reference of the datasource. The value is the actual datasource definition. +# A datasource can be referenced by the different panels and/or variables. +datasources: + [ : ] + +# `variables` is the list of dashboard variables. A variable can be referenced by the different panels and/or by other variables. +variables: + - [ ] + +# `panels` is a map where the key is the reference of the panel. The value is the actual panel definition that describes +# the kind of chart this panel is using. A panel can only hold one chart. +panels: + [ : ] + +# `layouts` is the list of layouts. A layout describes how to display the list of panels. +# Indeed, in Perses the definition of a panel is uncorrelated from the definition of where to position it. +layouts: + - + +# `duration` is the default time range to use on the initial load of the dashboard. +[ duration: ] + +# `refreshInterval` is the default refresh interval to use on the initial load of the dashboard. +[ refreshInterval: ] +``` + +A dashboard in its minimal definition only requires a panel and a layout. + +### Display specification + +This is the way to provide a rich name and a description for your dashboard. There is no restriction about the type of +characters you can use here. + +```yaml +# The new name of the dashboard. If set, it will replace `metadata.name` in the dashboard title in the UI. +# Note that it cannot be used when you are querying the API. Only `metadata.name` can be used to reference the dashboard. +# This is just for display purpose. +[ name: ] + +# The description of the dashboard. +[ description: ] +``` + +### Datasource specification + +See the [datasource](./datasource.md) documentation. + +### Variable specification + +See the [variable](./variable.md) documentation. + +### Panel specification + +```yaml +kind: "Panel" +spec: + display: + + # `plugin` is where you define the chart type to use. + # The chart type chosen should match one of the chart plugins known to the Perses instance. + plugin: + + # `queries` is the list of queries to be executed by the panel. The available types of query are conditioned by the type of chart & the type of datasource used. + queries: + - [ ] +``` + +#### Panel Plugin specification + +```yaml +# `kind` is the plugin type of the panel. For example, `TimeSeriesChart`. +kind: + +# `spec` is the actual definition of the panel plugin. Each `kind` comes with its own `spec`. +spec: +``` + +See the [Panel plugins](../plugins/panels.md) documentation to know more about the different panels supported by Perses. + +#### Query specification + +```yaml +# kind` is the type of the query. For the moment we only support `TimeSeriesQuery`. +kind: +spec: + plugin: +``` + +##### Query Plugin specification + +```yaml +# `kind` is the plugin type matching the type of query. For example, `PrometheusTimeSeriesQuery` for the query type `TimeSeriesQuery`. +kind: + +# `spec` is the actual definition of the query. Each `kind` comes with its own `spec`. +spec: +``` + +Perses supports only Prometheus for the `TimeSeriesQuery` for the moment. +Please look at the [Prometheus documentation](../plugins/prometheus.md#datasource) to know the spec for the `PrometheusTimeSeriesQuery`. + +### Layout specification + +```yaml +kind: "Grid" +spec: + [ display: ] + items: + [ - ] +``` + +Example: + +```yaml +kind: "Grid" +spec: + display: + title: "Row 1" + collapse: + open: true + items: + - x: 0 + y: 0 + width: 2 + height: 3 + content: + "$ref": "#/spec/panels/statRAM" + - x: 0 + y: 4 + width: 2 + height: 3 + content: + $ref": "#/spec/panels/statTotalRAM" +``` + +### Grid Display specification + +```yaml +title: +collapse: + open: +``` + +### Grid Item specification + +```yaml +x: +y: +width: +height: +content: + "$ref": +``` + +## API definition + +### Get a list of `Dashboard` + +```bash +GET /api/v1/projects//dasbhoards +``` + +URL query parameters: + +- name = `` : filters the list of dashboards based on their name (prefix match). + +### Get a single `Dashboard` + +```bash +GET /api/v1/projects//dasbhoards/ +``` + +### Create a single `Dashboard` + +```bash +POST /api/v1/projects//dashboards +``` + +### Update a single `Dashboard` + +```bash +PUT /api/v1/projects//dasbhoards/ +``` + +### Delete a single `Dashboard` + +```bash +DELETE /api/v1/projects//dasbhoards/ +``` \ No newline at end of file diff --git a/docs/docs/api/datasource.md b/docs/docs/api/datasource.md new file mode 100644 index 0000000..c58563a --- /dev/null +++ b/docs/docs/api/datasource.md @@ -0,0 +1,218 @@ +# Datasource + +## Choose a scope + +There are three different scopes in which you can define a datasource, depending on how much you want it to be shared. + +- for common use cases, use higher scopes to reuse the same datasource on multiple dashboards +- for more specific needs, use lower scopes to restrict the datasource availability to a specific set of (or even a single) dashboard(s). + +### Dashboard level + +We have extended the dashboard spec to include a list of datasources: + +```typescript +interface DashboardSpec { + // ... existing dashboard spec ... + datasources: Record; +} +``` + +Of course, the scope of such definition is the dashboard where it is defined. +It cannot be used outside the dashboard. + +### Project level + +In case you would like to share a datasource across different dashboards in the **same** project, you will need to +create a `Datasource`. + +```yaml +kind: "Datasource" +metadata: + name: + project: +spec: +``` + +### Global level + +When we talk about scope and user permission in a REST API, the easiest way is to associate one permission per endpoint. +If we want to provide a datasource shared by all projects, then it makes sense to have a different object that is +living outside a project. + +That’s why we have another resource called `GlobalDatasource` + +```yaml +kind: "GlobalDatasource" +metadata: + name: +spec: +``` + +## Datasource specification + +```yaml +[ display: ] + +# If true, then it's the default datasource for the type defined in the plugin. +[ default: | default = false ] + +# The definition of the plugin datasource +plugin: +``` + +### Plugin definition + +```yaml +# The type of the datasource. For example, `PrometheusDatasource` +kind: + +# The actual definition of the datasource. It will depend on the type defined in the previous field `kind` +spec: +``` + +We are supporting only prometheus as a datasource for the moment. +Please look at the [documentation](../plugins/prometheus.md#datasource) to know the spec for the Prometheus datasource. + +### Selecting / Referencing a Datasource + +In the panels, you will be able to select a datasource. Like proposed in the first draft, the selector will be like +this: + +```typescript +interface DatasourceSelector { + kind: string; + // name is the unique name of the datasource to use + // If name is omitted, that effectively means "use the default datasource for this kind". + name?: string; +} +``` + +The priority order is `"Local datasource in the dashboard" > "Project datasource" > "Global datasource"`. + +So if by any chance you have a local datasource that is named exactly like a Project datasource, or a Global datasource, +we will consider that the user intentionally wanted to override the upper datasource. We will use the one with the +smallest scope. + +### How to use the Perses' proxy + +As described before, you can provide a proxy configuration that will be used by the Perses server to redirect any +queries to the datasource. + +It means in the case of the Prometheus datasource, +if the field `directUrl` is not set then the FE needs to use the Perses server to contact the datasource. + +For that, the FE will have to determinate which URL should be used to contact the Perses server based on what kind of +datasource is used. + +* datasource is at project scope. + + ``` + var datasource; + if datasource.kind == 'Datasource'; then + url= '/proxy/projects' + datasource.metadata.project + '/datasources/' + datasource.metadata.name + ``` + +* datasource is at global scope. + + ``` + var datasource; + if datasource.kind == 'GlobalDatasource'; then + url= '/proxy/globaldatasources/' + datasource.metadata.name + ``` + +## API definition + +### `Datasource` + +#### Get a list of `Datasource` + +```bash +GET /api/v1/projects//datasources +``` + +URL query parameters: + +- kind = `` : should be used to filter the list of datasources with a specific kind +- default = `` : should be used to filter the list of datasources to only have the default one. You should have + one default datasource per kind +- name = `` : should be used to filter the list of datasources based on the prefix name. + +Example: + +The following query should return an empty list or a list containing a single Prometheus datasource. + +```bash +GET /api/v1/projects//datasources?kind=Prometheus&default=true +``` + +#### Get a single `Datasource` + +```bash +GET /api/v1/projects//datasources/ +``` + +#### Create a single `Datasource` + +```bash +POST /api/v1/projects//datasources +``` + +#### Update a single `Datasource` + +```bash +PUT /api/v1/projects//datasources/ +``` + +#### Delete a single `Datasource` + +```bash +DELETE /api/v1/projects//datasources/ +``` + +### `GlobalDatasource` + +#### Get a list of `GlobalDatasource` + +```bash +GET /api/v1/globaldatasources +``` + +URL query parameters: + +- kind = `` : should be used to filter the list of datasource with a specific kind +- default = `` : should be used to filter the list of datasource to only have the default one. You should have + one default datasource per kind +- name = `` : should be used to filter the list of datasource based on the prefix name. + +Example: + +The following query should return an empty list or a list containing a single Prometheus datasource. + +```bash +GET /api/v1/globaldatasources?kind=Prometheus&default=true +``` + +#### Get a single `GlobalDatasource` + +```bash +GET /api/v1/globaldatasources/ +``` + +#### Create a single `GlobalDatasource` + +```bash +POST /api/v1/globaldatasources +``` + +#### Update a single `GlobalDatasource` + +```bash +PUT /api/v1/globaldatasources/ +``` + +#### Delete a single `GlobalDatasource` + +```bash +DELETE /api/v1/globaldatasources/ +``` \ No newline at end of file diff --git a/docs/docs/api/ephemeral-dashboard.md b/docs/docs/api/ephemeral-dashboard.md new file mode 100644 index 0000000..ea3fe87 --- /dev/null +++ b/docs/docs/api/ephemeral-dashboard.md @@ -0,0 +1,60 @@ +# Ephemeral Dashboard + +It's a dashboard but with a TTL. That means after a defined duration, the dashboard will be removed from the database. + +We are providing this resource mainly to create a dashboard preview from a pull request. + +```yaml +kind: "EphemeralDashboard" +metadata: + name: + project: +spec: +``` + +See the next section to get details about the ``. + +## Ephemeral Dashboard specification + +It's a merge with the [dashboard_spec](./dashboard.md#dashboard-specification) and an additional field `ttl`. + +```yaml +ttl: + +``` + +## API definition + +### Get a list of `EphemeralDashboard` + +```bash +GET /api/v1/projects//ephemeraldashboards +``` + +URL query parameters: + +- name = `` : filters the list of ephemeral dashboards based on their name (prefix match). + +### Get a single `EphemeralDashboard` + +```bash +GET /api/v1/projects//ephemeraldashboards/ +``` + +### Create a single `EphemeralDashboard` + +```bash +POST /api/v1/projects//ephemeraldashboards +``` + +### Update a single `EphemeralDashboard` + +```bash +PUT /api/v1/projects//ephemeraldashboards/ +``` + +### Delete a single `EphemeralDashboard` + +```bash +DELETE /api/v1/projects//ephemeraldashboards/ +``` \ No newline at end of file diff --git a/docs/docs/api/index.md b/docs/docs/api/index.md new file mode 100644 index 0000000..58b7639 --- /dev/null +++ b/docs/docs/api/index.md @@ -0,0 +1,63 @@ +# Reference + +This section will give you an insight on every resource supported by the Perses API. While it can give you some +explanations about the purpose of each resource, this documentation is mainly for users that would like to interact +directly with the API and manipulate the resources without using the UI. + +On the different documentations, you will find the definition of each resource in the yaml format. +Brackets indicate that a parameter is optional. + +Generic placeholders are defined as follows: + +* ``: a boolean that can take the values `true` or `false` +* ``: a duration matching the regular + expression `((([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?|0)`, + e.g. `1d`, `1h30m`, `5m`, `10s` +* ``: a valid path in the current working directory +* ``: a valid URL path +* ``: an integer value +* ``: a regular string that is a secret, such as a password +* ``: a regular string + +## Table of contents + +1. [Project](./project.md) +1. [Dashboard](./dashboard.md) + 1. [Specification](./dashboard.md#dashboard-specification) + 1. [API definition](./dashboard.md#api-definition) +1. [Datasource](./datasource.md) + 1. [Choose a scope](./datasource.md#choose-a-scope) + 1. [Specification](./datasource.md#datasource-specification) + 1. [API definition](./datasource.md#api-definition) +1. [EphemeralDashboard](./ephemeral-dashboard.md) + 1. [Specification](./ephemeral-dashboard.md#ephemeral-dashboard-specification) + 1. [API definition](./ephemeral-dashboard.md#api-definition) +1. [Secret](./secret.md) + 1. [Specification](./secret.md#secret-specification) + 1. [API definition](./secret.md#api-definition) +1. [User](./user.md) + 1. [Specification](./user.md#user-specification) + 1. [API definition](./user.md#api-definition) +1. [Variable](./variable.md) + 1. [Choose a scope](./variable.md#choose-a-scope) + 1. [Specification](./variable.md#variable-specification) + 1. [API definition](./variable.md#api-definition) +1. [Role](./role.md) + 1. [Choose a scope](./datasource.md#choose-a-scope) + 1. [Specification](./role.md#role-specification) + 1. [API definition](./role.md#api-definition) +1. [RoleBinding](./rolebinding.md) + 1. [Choose a scope](./rolebinding.md#choose-a-scope) + 1. [Specification](./rolebinding.md#rolebinding-specification) + 1. [API definition](./rolebinding.md#api-definition) +1. Plugins + 1. [Panels](../plugins/panels.md) + 1. [BarChart](../plugins/panels.md#barchart) + 1. [GaugeChart](../plugins/panels.md#gaugechart) + 1. [Markdown](../plugins/panels.md#markdown) + 1. [StatChart](../plugins/panels.md#statchart) + 1. [TimeSeriesChart](../plugins/panels.md#timeserieschart) + 1. [Prometheus](../plugins/prometheus.md) + 1. [Datasource](../plugins/prometheus.md#datasource) + 1. [Query](../plugins/prometheus.md#query) + 1. [Variable](../plugins/prometheus.md#variable) \ No newline at end of file diff --git a/docs/docs/api/project.md b/docs/docs/api/project.md new file mode 100644 index 0000000..4897cab --- /dev/null +++ b/docs/docs/api/project.md @@ -0,0 +1,50 @@ +# Project + +A project can be defined as a workspace. It's the place where users will spend most of their time creating dashboards, +variables and datasources. + +**You need to own a project if you want to create a dashboard** + +Creating a project is as simple as providing a name: + +```yaml +kind: "Project" +metadata: + name: +``` + +## API definition + +### Get a list of `Project` + +```bash +GET /api/v1/projects +``` + +URL query parameters: + +- name = `` : filters the list of projects based on their names (prefix). + +### Get a single `Project` + +```bash +GET /api/v1/projects/ +``` + +### Create a single `Project` + +```bash +POST /api/v1/projects +``` + +### Update a single `Project` + +```bash +PUT /api/v1/projects/ +``` + +### Delete a single `Project` + +```bash +DELETE /api/v1/projects/ +``` \ No newline at end of file diff --git a/docs/docs/api/role.md b/docs/docs/api/role.md new file mode 100644 index 0000000..77134fd --- /dev/null +++ b/docs/docs/api/role.md @@ -0,0 +1,149 @@ +# Role + +A `Role` defines a set of permissions within a particular project. When you create a `Role` you need to specify the project it belongs in. +`GlobalRole`, by contrast, is not limited to a project scope. + +## Choose a scope + +There are two different scopes in which you can define a Role, depending on how much you want it to be shared. + +- for global scope, use `GlobalRole` +- for project scope, use `Role` + +### Project level + +In case you would like to set permissions at Project level, you will need to create a `Role`. + +```yaml +kind: "Role" +metadata: + name: + project: +spec: +``` + +### Global level + +In case you would like to set permissions at Global level , you will need to create a `GlobalRole`. + +```yaml +kind: "GlobalRole" +metadata: + name: +spec: +``` + +## Role specification + +```yaml +# List of permissions owned by the role +permissions: + - +``` + +### Permission specification + +```yaml +# Types of actions the permission grant access +actions: + - + +# The list of kind targeted by the permission. For example: `Datasource`, `Dashboard`, ... +# With Role, you can't target global kinds +scopes: + - +``` + +### More info about authorization + +Please look at the [documentation](../design-docs//authorization.md) to know more about permissions and roles. + +## API definition + +### `Role` + +#### Get a list of `Role` + +```bash +GET /api/v1/projects//roles +``` + +URL query parameters: + +- name = `` : should be used to filter the list of Roles based on the prefix name. + +Example: + +The following query should return an empty list or a list containing roles. + +```bash +GET /api/v1/projects//roles?name=owner +``` + +#### Get a single `Role` + +```bash +GET /api/v1/projects//roles/ +``` + +#### Create a single `Role` + +```bash +POST /api/v1/projects//roles +``` + +#### Update a single `Role` + +```bash +PUT /api/v1/projects//roles/ +``` + +#### Delete a single `Role` + +```bash +DELETE /api/v1/projects//roles/ +``` + +### `GlobalRole` + +#### Get a list of `GlobalRole` + +```bash +GET /api/v1/globalroles +``` + +URL query parameters: + +- name = `` : should be used to filter the list of Role based on the prefix name. + +Example: + +The following query should return an empty list or a list containing global roles. + +```bash +GET /api/v1/globalRoles?name=admin +``` + +#### Get a single `GlobalRole` + +```bash +GET /api/v1/globalroles/ +``` + +#### Create a single `GlobalRole` + +```bash +POST /api/v1/globalroles +``` + +#### Update a single `GlobalRole` + +```bash +PUT /api/v1/globalroles/ +``` + +#### Delete a single `GlobalRole` + +```bash +DELETE /api/v1/globalroles/ +``` \ No newline at end of file diff --git a/docs/docs/api/rolebinding.md b/docs/docs/api/rolebinding.md new file mode 100644 index 0000000..7afae8d --- /dev/null +++ b/docs/docs/api/rolebinding.md @@ -0,0 +1,150 @@ +# Role Binding + +A role binding grants the permissions defined in a role to a user or set of users. +It holds a list of subjects (users or teams) and a reference to the role being granted. A `RoleBinding` grants permissions within a specific project whereas a `GlobalRoleBinding` grants that access global-wide. + +A `RoleBinding` may reference any `Role` in the same project. Similarly, a `GlobalRoleBinding` can reference any `GlobalRole`. + +## Choose a scope + +There are two different scopes in which you can define a RoleBinding, depending on the role scope. + +- for GlobalRole, use GlobalRoleBinding +- for Role, use RoleBinding + +### Project level + +In case you would like to set a role binding for a Role, you will need to create a `RoleBinding`. + +```yaml +kind: "RoleBinding" +metadata: + name: + project: +spec: +``` + +### Global level + +In case you would like to set a role binding for a GlobalRole , you will need to create a `GlobalRoleBinding`. + +```yaml +kind: "GlobalRoleBinding" +metadata: + name: +spec: +``` + +## RoleBinding specification + +```yaml +# Name of the Role or GlobalRole concerned by the role binding (metadata.name) +role: +# Subjects that will inherit permissions from the role +subjects: + - +``` + +### Subject specification + +```yaml +# The type of the subject. For example: `User` +kind: + +# The name of the subject (metadata.name) +name: +``` + +### More info about authorization + +Please look at the [documentation](../design-docs/authorization.md) to know more about permissions and role bindings. + +## API definition + +### `RoleBinding` + +#### Get a list of `RoleBinding` + +```bash +GET /api/v1/projects//rolebindings +``` + +URL query parameters: + +- name = `` : should be used to filter the list of RoleBindings based on the prefix name. + +Example: + +The following query should return an empty list or a list containing roleBindings. + +```bash +GET /api/v1/projects//rolebindings?name=ownerRB +``` + +#### Get a single `RoleBinding` + +```bash +GET /api/v1/projects//rolebindings/ +``` + +#### Create a single `RoleBinding` + +```bash +POST /api/v1/projects//rolebindings +``` + +#### Update a single `RoleBinding` + +```bash +PUT /api/v1/projects//rolebindings/ +``` + +#### Delete a single `RoleBinding` + +```bash +DELETE /api/v1/projects//rolebindings/ +``` + +### `GlobalRoleBinding` + +#### Get a list of `GlobalRoleBinding` + +```bash +GET /api/v1/globalrolebindings +``` + +URL query parameters: + +- name = `` : should be used to filter the list of RoleBinding based on the prefix name. + +Example: + +The following query should return an empty list or a list containing global rolebindings. + +```bash +GET /api/v1/globalRoleBindings?name=adminRB +``` + +#### Get a single `GlobalRoleBinding` + +```bash +GET /api/v1/globalrolebindings/ +``` + +#### Create a single `GlobalRoleBinding` + +```bash +POST /api/v1/globalrolebindings +``` + +#### Update a single `GlobalRoleBinding` + +```bash +PUT /api/v1/globalrolebindings/ +``` + +#### Delete a single `GlobalRoleBinding` + +```bash +DELETE /api/v1/globalrolebindings/ +``` \ No newline at end of file diff --git a/docs/docs/api/secret.md b/docs/docs/api/secret.md new file mode 100644 index 0000000..8a94144 --- /dev/null +++ b/docs/docs/api/secret.md @@ -0,0 +1,174 @@ +# Secret + +When defining a datasource, you will probably need to provide a basic authentication, a certificate, or a token to be +used when the Perses backend will contact your Datasource. + +We have two different objects to store sensitive data: `GlobalSecret` and `Secret`. +You should use one or the other depending on which object your datasource corresponds to. + +- To store sensitive data for a `GlobalDatasource`, you need to create a `GlobalSecret`. +- For a `Datasource` object or a datasource defined directly in a dashboard, you need to create a `Secret`. `GlobalSecret` cannot be used here. + +A `Secret` is defined like that: + +```yaml +kind: "Secret" +metadata: + project: + name: +spec: +``` + +And a `GlobalSecret`: + +```yaml +kind: "GlobalSecret" +metadata: + name: +spec: +``` + +See the next section to get details about the `` + +## Secret specification + +```yaml +[ basicAuth: ] + +# The HTTP authorization credentials for the targets. +# Basic Auth and authorization are mutually exclusive. Use one or the other not both at the same time. +[ authorization: ] + +# Config used to connect to the targets. +[ tlsConfig: ] +``` + +### Basic Auth specification + +```yaml +username: +[ password: ] +[ passwordFile: ] +``` + +### Authorization specification + +```yaml +[ type: | default = "Bearer" ] + +# The HTTP credentials like a Bearer token +[ credentials: ] +[ credentialsFile: ] +``` + +### TLS Config specification + +```yaml +# CA certificate to validate API server certificate with. At most one of ca and ca_file is allowed. +[ ca: ] +[ caFile: ] + +# Certificate and key for client cert authentication to the server. +# At most one of cert and cert_file is allowed. +# At most one of key and key_file is allowed. +[ cert: ] +[ certFile: ] +[ key: ] +[ keyFile: ] + +# ServerName extension to indicate the name of the server. +# https://tools.ietf.org/html/rfc4366#section-3.1 +[ serverName: ] + +# Disable validation of the server certificate. +[ insecureSkipVerify: | default = false ] +``` + +### Example + +```yaml +kind: "Secret" +metadata: + project: + name: +spec: + authorization: + type: "Bearer" + credentials: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c" + tlsConfig: + insecureSkipVerify: false +``` + +## API definition + +### `Secret` + +#### Get a list of `Secret` + +```bash +GET /api/v1/projects//secrets +``` + +URL query parameters: + +- name = `` : filters the list of secrets based on their names (prefix). + +#### Get a single `Secret` + +```bash +GET /api/v1/projects//secrets/ +``` + +#### Create a single `Secret` + +```bash +POST /api/v1/projects//secrets +``` + +#### Update a single `Secret` + +```bash +PUT /api/v1/projects//secrets/ +``` + +#### Delete a single `Secret` + +```bash +DELETE /api/v1/projects//secrets/ +``` + +### Global `Secret` + +#### Get a list of global `Secret` + +```bash +GET /api/v1/globalsecrets +``` + +URL query parameters: + +- name = `` : filters the list of global secrets based on their names (prefix). + +#### Get a single global `Secret` + +```bash +GET /api/v1/globalsecrets/ +``` + +#### Create a single global `Secret` + +```bash +POST /api/v1/globalsecrets +``` + +#### Update a single global `Secret` + +```bash +PUT /api/v1/globalsecrets/ +``` + +#### Delete a single global `Secret` + +```bash +DELETE /api/v1/globalsecrets/ +``` \ No newline at end of file diff --git a/docs/docs/api/user.md b/docs/docs/api/user.md new file mode 100644 index 0000000..e8071f9 --- /dev/null +++ b/docs/docs/api/user.md @@ -0,0 +1,75 @@ +# User + +For the moment, user is a way to create an account and then get a write access to a project you created. + +## User Specification + +```yaml +kind: "User" +metadata: + # User name for login + name: +spec: + [ firstName: ] + [ lastName: ] + + # Password when provided is hashed and salted before going to the database + # Password is optional because depending on the Perses configuration, you might be able to login with external + # authentication provider or not be able to create a user at all. + # It can happen when the Perses server relies on a ldap database for authentication. + [ nativeProvider: [ password: ]] + + # Save the context of the oauth provider used if the user has been created from an external OIDC or OAuth + # authentication provider. + oauthProviders: + - [ ] +``` + +### OAuth Provider specification + +```yaml +# Identifying the provider +issuer: + +# Email of the user in the provider +email: + +# Identifying the user in the provider +subject: +``` + +## API definition + +### Get a list of `User` + +```bash +GET /api/v1/users +``` + +URL query parameters: + +- name = `` : filters the list of users based on their login name (prefix). + +### Get a single `User` + +```bash +GET /api/v1/users/ +``` + +### Create a single `User` + +```bash +POST /api/v1/users +``` + +### Update a single `User` + +```bash +PUT /api/v1/users/ +``` + +### Delete a single `User` + +```bash +DELETE /api/v1/users/ +``` \ No newline at end of file diff --git a/docs/docs/api/variable.md b/docs/docs/api/variable.md new file mode 100644 index 0000000..e795af5 --- /dev/null +++ b/docs/docs/api/variable.md @@ -0,0 +1,238 @@ +# Variable + +## Choose a scope + +There are three different scopes in which you can define a variable, depending on how much you want it to be shared. + +- for common use cases, use higher scopes to reuse the same variable on multiple dashboards +- for more specific needs, use lower scopes to restrict the variable availability to a specific set of (or even a + single) dashboard(s). + +### Dashboard level + +That's the usual level to define a variable. + +```typescript +interface DashboardSpec { + // ... existing dashboard spec ... + variables: VariableSpec[]; +} +``` + +### Project level + +In case you would like to share a variable across different dashboards in the **same** project, you will need to +create a `Variable`. + +```yaml +kind: "Variable" +metadata: + name: + project: +spec: +``` + +### Global level + +When we talk about scope and user permission in a REST API, the easiest way is to associate one permission per endpoint. +If we want to provide a variable shared by all projects, then it makes sense to have a different object that is +living outside a project. + +That’s why we have another resource called `GlobalVariable` + +```yaml +kind: "GlobalVariable" +metadata: + name: +spec: +``` + +## Variable specification + +We are supporting two different types of variables: `TextVariable` and `ListVariable`. + +### TextVariable + +```yaml +kind: "TextVariable" +spec: +``` + +#### Text Variable specification + +```yaml +# It is a mandatory attribute when you are defining a variable directly in a dashboard. +# If you are creating a GlobalVariable or a Variable, you don't have to use this attribute as it is replaced by metadata.name. +# This is the unique name of the variable that can be used in another variable or in the different dashboard to use +[ name: ] + +[ display: ] +value: +[ constant: | default = false ] +``` + +#### Example + +```yaml +kind: "Variable" # Alternatively, "GlobalVariable" +metadata: + name: "text" + project: "perses" +spec: + kind: "TextVariable" + spec: + value: "my text" +``` + +Or in case you are defining the variable in a dashboard + +```yaml +variables: + - kind: "TextVariable" + spec: + name: "text" + value: "my text" +``` + +### ListVariable + +```yaml +kind: "ListVariable" +spec: +``` + +#### List Variable specification + +```yaml +# It is a mandatory attribute when you are defining a variable directly in a dashboard. +# If you are creating a GlobalVariable or a Variable, you don't have to use this attribute as it is replaced by metadata.name. +# This is the unique name of the variable that can be used in another variable or in the different dashboard to use +[ name: ] + +[ display: ] + +# It's a value from the list to be selected by default +# It can be a single value or a list. +[ defaultValue: | ] + +# Whether to append the "All" value that allows selecting all available values at once. +[ allowAllValue: | default = false ] + +# Whether to allow multi-selection of values. +[ allMultiple: | default = false ] + +# It is a custom value that will be used if allowAllValue is true and if then `all` is selected +[ customAllValue: ] + +# CapturingRegexp is the regexp used to catch and filter the result of the query. +# If empty, then nothing is filtered. This is the equivalent of setting capturingRegexp with (.*) +[ capturingRegexp: ] + +# The method to apply when rendering the list of values +[ sort: | default = "none" ] + +# The definition of the plugin variable +plugin: +``` + +#### Display specification + +```yaml +# The new name of the variable. If set, it will replace `metadata.name` in the variable title in the UI. +# Note that it cannot be used when you are querying the API. Only `metadata.name` can be used to reference the variable. +# This is just for display purpose. +[ name: ] + +# The description of the variable +[ description: ] + +# If true, the variable won't be displayed above the dashboard. +[ hidden: | default = false ] +``` + +#### Plugin definition + +```yaml +# The type of the variable. For example, `PrometheusPromQLVariable` +kind: + +# The actual definition of the variable. It will depend on the type defined in the previous field `kind` +spec: +``` + +We are supporting only prometheus for the variables for the moment. +Please take a look at the [documentation](../plugins/prometheus.md#variable) to know the spec for the Prometheus variable. + +## API Definition + +### `Variable` + +#### Get a list of `Variable` + +```bash +GET /api/v1/projects//variables +``` + +URL query parameters: + +- name = `` : filters the list of variables based on their name (prefix match). + +#### Get a single `Variable` + +```bash +GET /api/v1/projects//variables/ +``` + +#### Create a single `Variable` + +```bash +POST /api/v1/projects//variables +``` + +#### Update a single `Variable` + +```bash +PUT /api/v1/projects//variables/ +``` + +#### Delete a single `Variable` + +```bash +DELETE /api/v1/projects//variables/ +``` + +### `GlobalVariable` + +#### Get a list of `GlobalVariable` + +```bash +GET /api/v1/globalvariables +``` + +URL query parameters: + +- name = `` : filters the list of variables based on their name (prefix match). + +#### Get a single `GlobalVariable` + +```bash +GET /api/v1/globalvariables/ +``` + +#### Create a single `GlobalVariable` + +```bash +POST /api/v1/globalvariables +``` + +#### Update a single `GlobalVariable` + +```bash +PUT /api/v1/globalvariables/ +``` + +#### Delete a single `GlobalVariable` + +```bash +DELETE /api/v1/globalvariables/ +``` \ No newline at end of file diff --git a/docs/docs/authentication.md b/docs/docs/authentication.md new file mode 100644 index 0000000..3570687 --- /dev/null +++ b/docs/docs/authentication.md @@ -0,0 +1,26 @@ +Perses has various authentication flows configurable. You can choose to authenticate from a native provider that will allow you to create some users, or else rely on an external [identity provider](https://perses.dev/docs/perses/v0.47.0/design-docs/authentication.md/#external-oidcoauth-providers){target=_blank}. + +In both cases + +* each new user will be saved in the Perses database. +* at login time, a Perses session (access_token/refresh_token) will be created + +Please note that the number of identity providers is not limited. + +```yaml title="foo" +authentication: + providers: + # Enable or not the native Perses identity provider + enable_native: true/false + # Register one or several OIDC provider(s) + oidc: [] + # Register one or several OAuth provider(s) + oauth: [] +``` + +## Native provider + +In case a native provider is used, the users and their password are stored in the Perses database. + +Login is done through http POST on `/api/auth/providers/native/login`. + diff --git a/docs/docs/dac/cue.md b/docs/docs/dac/cue.md new file mode 100644 index 0000000..a78e7e4 --- /dev/null +++ b/docs/docs/dac/cue.md @@ -0,0 +1 @@ +DAC Page \ No newline at end of file diff --git a/docs/docs/dac/cue/dashboardbuilder.md b/docs/docs/dac/cue/dashboardbuilder.md new file mode 100644 index 0000000..325ee0d --- /dev/null +++ b/docs/docs/dac/cue/dashboardbuilder.md @@ -0,0 +1,88 @@ +The Dashboard builder helps creating dashboards in the format expected by Perses. + +## Usage + +```cue +package myDaC + +import ( + dashboardBuilder "github.com/perses/perses/cue/dac-utils/dashboard" +) + +dashboardBuilder & {} // input parameters expected +``` + +## Parameters + +| Parameter | Type | Description | +|----------------|----------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------| +| `#name` | string | The name of the dashboard. | +| `#display` | [Display](../../api/dashboard.md#display-specification) | Display object to tune the display name and description. | +| `#project` | string | The project to which the dashboard belongs. | +| `#variables` | [...[VariableSpec](../../api/variable.md#dashboard-level)] | An array of variables defined for the dashboard. | +| `#panelGroups` | map[string]: { layout: [Layout](../../api/dashboard.md#layout-specification), panels: map[string]: [Panel](../../api/dashboard.md#panel-specification) } | A map where each key is a panel group name, and the value is an object containing layout and panels for that group. | + +## Example + +```cue +package myDaC + +import ( + dashboardBuilder "github.com/perses/perses/cue/dac-utils/dashboard" + panelGroupsBuilder "github.com/perses/perses/cue/dac-utils/panelgroups" + panelBuilder "github.com/perses/perses/cue/dac-utils/prometheus/panel" + varGroupBuilder "github.com/perses/perses/cue/dac-utils/variable/group" + textVarBuilder "github.com/perses/perses/cue/dac-utils/variable/text" + labelValuesVarBuilder "github.com/perses/perses/cue/dac-utils/prometheus/variable/labelvalues" + timeseriesChart "github.com/perses/perses/cue/schemas/panels/time-series:model" + promQuery "github.com/perses/perses/cue/schemas/queries/prometheus:model" +) + +dashboardBuilder & { + #name: "ContainersMonitoring" + #project: "MyProject" + #variables: {varGroupBuilder & { + #input: [ + textVarBuilder & { + #name: "prometheus" + #value: "platform" + #constant: true + }, + labelValuesVarBuilder & { + #name: "stack" + #display: name: "PaaS" + #metric: "thanos_build_info" + #label: "stack" + #datasourceName: "promDemo" + } + ] + }}.variables + #panelGroups: panelGroupsBuilder & { + #input: [ + { + #title: "Resource usage" + #cols: 3 + #panels: [ + panelBuilder & { + spec: { + display: name: "Container CPU" + plugin: timeseriesChart + queries: [ + { + kind: "TimeSeriesQuery" + spec: plugin: promQuery & { + spec: query: "sum by (container) (container_cpu_usage_seconds)" + } + }, + ] + } + } + ] + }, + ] + } +} +``` + +As you can see, other builders are used in conjunction with the dashboard builder to facilitate further the coding. +Please refer to their respective documentation for more information about each. \ No newline at end of file diff --git a/docs/docs/dac/cue/filterbuilder.md b/docs/docs/dac/cue/filterbuilder.md new file mode 100644 index 0000000..9258f3c --- /dev/null +++ b/docs/docs/dac/cue/filterbuilder.md @@ -0,0 +1,61 @@ +The Filter builder helps generating a filter, a.k.a a labels matcher expression. + +## Usage + +```cue +package myDaC + +import ( + promFilterBuilder "github.com/perses/perses/cue/dac-utils/prometheus/filter" +) + +promFilterBuilder & {} // input parameters expected +``` + +## Parameters + +| Parameter | Type | Mandatory/Optional | Default | Description | +|-----------|-----------------|--------------------|---------|-------------------------------------------------------------------| +| `#input` | [...varBuilder] | Mandatory | | The list of variables builders from which to generate the filter. | + +## Output + +| Field | Type | Description | +|----------|--------|------------------------------------------------------------------------------------------------------------------------------------------------| +| `filter` | string | A labels matcher expression, that covers all the variables previously passed. E.g `{namespace="$namespace",pod="$pod",container="$container"}` | + +## Example + +```cue +package myDaC + +import ( + promFilterBuilder "github.com/perses/perses/cue/dac-utils/prometheus/filter" + textVarBuilder "github.com/perses/perses/cue/dac-utils/variable/text" + promQLVarBuilder "github.com/perses/perses/cue/dac-utils/prometheus/variable/promql" + labelValuesVarBuilder "github.com/perses/perses/cue/dac-utils/prometheus/variable/labelvalues" +) + +{promFilterBuilder & { + #input: [ + textVarBuilder & { + #name: "prometheus" + #value: "platform" + #constant: true + }, + labelValuesVarBuilder & { + #name: "stack" + #display: name: "PaaS" + #metric: "thanos_build_info" + #label: "stack" + #datasourceName: "promDemo" + }, + promQLVarBuilder & { + #name: "namespace" + #metric: "kube_namespace_labels" + #allowMultiple: true + #datasourceName: "promDemo" + } + ] +}}.filter +``` \ No newline at end of file diff --git a/docs/docs/dac/cue/index.md b/docs/docs/dac/cue/index.md new file mode 100644 index 0000000..a55acc5 --- /dev/null +++ b/docs/docs/dac/cue/index.md @@ -0,0 +1,216 @@ +# CUE SDK for Dashboard-as-Code + +!!! info "Getting started with Dashboard as code" + + To get started with Dashboard-as-Code in Perses, have a look at the [DaC user guide](../../user-guides/dashboard-as-code.md) first. + +This section provides detailed information about the CUE SDK to develop dashboards as code in Perses. +It's focusing on explaining how to use the different builders provided by the SDK, that you should rely on to simplify the coding. +Besides, you can always manipulate directly the base datamodel of the Perses dashboard, but this is less convenient. + +See the dedicated pages for each builder: + +* [Dashboard Builder](dashboardbuilder.md) +* [Panel Groups Builder](panelgroupsbuilder.md) + +## Variable Related builders: +* [Variable Group Builder](variablegroupbuilder.md) +* [Static List Variable Builder](staticlistvariablebuilder.md) +* [Text Variable Builder](textvariablebuilder.md) + +## Prometheus Related builders: +* [Filter Builder](filterbuilder.md) +* [Panel Builder](prometheuspanelbuilder.md) + * Variable-related builders: + * [Label Names Variable](labelnamesvariablebuilder.md) + * [Label Values Variable](labelvaluesvariablebuilder.md) + * [PromQL Variable](promqlvariablebuilder.md) + +## Useful patterns + +This section provides additional tips & tricks to help you develop dashboards as code: + +### Declare intermediary objects for reusability + +For code organization & to allow reuse/imports of definitions, it's often interesting to declare things like panels, variables etc. upfront and to pass them afterwards to the dashboard object. + +Example: + +```cue +package myDaC + +import ( + dashboardBuilder "github.com/perses/perses/cue/dac-utils/dashboard" + panelGroupsBuilder "github.com/perses/perses/cue/dac-utils/panelgroups" + panelBuilder "github.com/perses/perses/cue/dac-utils/prometheus/panel" + varGroupBuilder "github.com/perses/perses/cue/dac-utils/variable/group" + promQLVarBuilder "github.com/perses/perses/cue/dac-utils/prometheus/variable/promql" + promFilterBuilder "github.com/perses/perses/cue/dac-utils/prometheus/filter" + timeseriesChart "github.com/perses/perses/cue/schemas/panels/time-series:model" + promQuery "github.com/perses/perses/cue/schemas/queries/prometheus:model" +) + +#myVarsBuilder: varGroupBuilder & { + #input: [ + promQLVarBuilder & { + #name: "namespace" + #metric: "kube_namespace_labels" + #allowMultiple: true + #datasourceName: "promDemo" + }, + promQLVarBuilder & { + #name: "pod" + #metric: "kube_pod_info" + #allowAllValue: true + #allowMultiple: true + #datasourceName: "promDemo" + }, + ] +} + +#filter: { promFilterBuilder & #myVarsBuilder }.filter + +#cpuPanel: panelBuilder & { + spec: { + display: name: "Container CPU" + plugin: timeseriesChart + queries: [ + { + kind: "TimeSeriesQuery" + spec: plugin: promQuery & { + spec: query: "sum (container_cpu_usage_seconds{\(#filter)})" + } + }, + ] + } +} + +dashboardBuilder & { + #name: "ContainersMonitoring" + #project: "MyProject" + #variables: #myVarsBuilder.variables + #panelGroups: panelGroupsBuilder & { + #input: [ + { + #title: "Resource usage" + #cols: 3 + #panels: [ + #cpuPanel, + ] + }, + ] + } +} +``` + +Once your code is organized this way, you can even split the different definitions in different files. This avoids e.g to have one very big file when you have a dashboard with lots of panels. + +### Multiple variable groups + +If you want 2 independant groups of variables on the same dashboard like "C depends on B that depends on A" and "F depends on E that depends on D", use 2 times the variable group builder independantly, then concat the lists. + +Example: + +```cue +package myDaC + +import ( + "list" + dashboardBuilder "github.com/perses/perses/cue/dac-utils/dashboard" + panelGroupsBuilder "github.com/perses/perses/cue/dac-utils/panelgroups" + panelBuilder "github.com/perses/perses/cue/dac-utils/prometheus/panel" + varGroupBuilder "github.com/perses/perses/cue/dac-utils/variable/group" + promQLVarBuilder "github.com/perses/perses/cue/dac-utils/prometheus/variable/promql" + promFilterBuilder "github.com/perses/perses/cue/dac-utils/prometheus/filter" + timeseriesChart "github.com/perses/perses/cue/schemas/panels/time-series:model" + promQuery "github.com/perses/perses/cue/schemas/queries/prometheus:model" +) + +#myCloudVarsBuilder: varGroupBuilder & { + #input: [ + promQLVarBuilder & { + #name: "namespace" + #metric: "kube_namespace_labels" + #allowMultiple: true + #datasourceName: "promDemo" + }, + promQLVarBuilder & { + #name: "pod" + #metric: "kube_pod_info" + #allowAllValue: true + #allowMultiple: true + #datasourceName: "promDemo" + } + ] +} + +#cloudFilter: { promFilterBuilder & #myCloudVarsBuilder }.filter + +#myVMVarsBuilder: varGroupBuilder & { + #input: [ + promQLVarBuilder & { + #name: "datacenter" + #metric: "node_uname_info" + #allowMultiple: true + #datasourceName: "promDemo" + }, + promQLVarBuilder & { + #name: "hostname" + #metric: "node_uname_info" + #allowAllValue: true + #allowMultiple: true + #datasourceName: "promDemo" + } + ] +} + +#vmFilter: { promFilterBuilder & #myVMVarsBuilder }.filter + +#containerCPUPanel: panelBuilder & { + spec: { + display: name: "Container CPU" + plugin: timeseriesChart + queries: [ + { + kind: "TimeSeriesQuery" + spec: plugin: promQuery & { + spec: query: "sum (container_cpu_usage_seconds{\(#cloudFilter)})" + } + }, + ] + } +} + +#vmCPUPanel: panelBuilder & { + spec: { + display: name: "VM CPU" + plugin: timeseriesChart + queries: [ + { + kind: "TimeSeriesQuery" + spec: plugin: promQuery & { + spec: query: "sum (node_memory_MemTotal_bytes{\(#vmFilter)})" + } + }, + ] + } +} + +dashboardBuilder & { + #name: "ContainersMonitoring" + #project: "MyProject" + #variables: list.Concat([#myCloudVarsBuilder.variables, #myVMVarsBuilder.variables]) + #panelGroups: panelGroupsBuilder & { + #input: [ + { + #title: "Resource usage" + #cols: 3 + #panels: [ + #containerCPUPanel, + #vmCPUPanel, + ] + }, + ] + } +} +``` \ No newline at end of file diff --git a/docs/docs/dac/cue/labelnamesvariablebuilder.md b/docs/docs/dac/cue/labelnamesvariablebuilder.md new file mode 100644 index 0000000..8dae93f --- /dev/null +++ b/docs/docs/dac/cue/labelnamesvariablebuilder.md @@ -0,0 +1,50 @@ +The Label Names Variable builder helps creating prometheus label names variables in the format expected by Perses. + +## Usage + +```cue +package myDaC + +import ( + labelNamesVarBuilder "github.com/perses/perses/cue/dac-utils/prometheus/variable/labelnames" +) + +labelNamesVarBuilder & {} // input parameters expected +``` + +## Parameters + +| Parameter | Type | Mandatory/Optional | Default | Description | +|--------------------|-----------------------------------------------------------------|--------------------|---------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `#name` | string | Mandatory | | The name of this variable. | +| `#display` | [Display](../../../api/variable#display-specification) | Optional | | Display object to tune the display name, description and visibility (show/hide). | +| `#allowAllValue` | boolean | Optional | false | Whether to append the "All" value to the list. | +| `#allowMultiple` | boolean | Optional | false | Whether to allow multi-selection of values. | +| `#customAllValue` | string | Optional | | Custom value that will be used if `#allowAllValue` is true and if `All` is selected. | +| `#capturingRegexp` | string | Optional | | Regexp used to catch and filter the results of the query. If empty, then nothing is filtered (equivalent of setting it to `(.*)`). | +| `#sort` | [Sort](../../../api/variable#list-variable-specification) | Optional | | Sort method to apply when rendering the list of values. | +| `#datasourceName` | string | Mandatory | | The name of the datasource to query. | +| `#metric` | string | Optional | | The name of the source metric to be used. /!\ Mandatory if you want to rely on the standard query pattern, thus didn't provide a value to the `#query` parameter. | +| `#query` | string | Optional | | Custom query to be used for this variable. /!\ Mandatory if you didn't provide a value to the `#metric` parameter. | + +## Output + +| Field | Type | Description | +|------------|----------------------------------------------------------------|-----------------------------------------------------------| +| `variable` | [Variable](../../../api/variable#variable-specification) | The final variable object, to be passed to the dashboard. | + +## Example + +```cue +package myDaC + +import ( + labelNamesVarBuilder "github.com/perses/perses/cue/dac-utils/prometheus/variable/labelnames" +) + +{labelNamesVarBuilder & { + #name: "namespaceLabels" + #metric: "kube_namespace_labels" + #datasourceName: "promDemo" +}}.variable +``` \ No newline at end of file diff --git a/docs/docs/dac/cue/labelvaluesvariablebuilder.md b/docs/docs/dac/cue/labelvaluesvariablebuilder.md new file mode 100644 index 0000000..0f8f99a --- /dev/null +++ b/docs/docs/dac/cue/labelvaluesvariablebuilder.md @@ -0,0 +1,53 @@ +The Label Values Variable builder helps creating prometheus label values variables in the format expected by Perses. + +## Usage + +```cue +package myDaC + +import ( + labelValuesVarBuilder "github.com/perses/perses/cue/dac-utils/prometheus/variable/labelvalues" +) + +labelValuesVarBuilder & {} // input parameters expected +``` + +## Parameters + +| Parameter | Type | Mandatory/Optional | Default | Description | +|--------------------|-----------------------------------------------------------------|--------------------|---------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `#name` | string | Mandatory | | The name of this variable. | +| `#display` | [Display](../../../api/variable#display-specification) | Optional | | Display object to tune the display name, description and visibility (show/hide). | +| `#allowAllValue` | boolean | Optional | false | Whether to append the "All" value to the list. | +| `#allowMultiple` | boolean | Optional | false | Whether to allow multi-selection of values. | +| `#customAllValue` | string | Optional | | Custom value that will be used if `#allowAllValue` is true and if `All` is selected. | +| `#capturingRegexp` | string | Optional | | Regexp used to catch and filter the results of the query. If empty, then nothing is filtered (equivalent of setting it to `(.*)`). | +| `#sort` | [Sort](../../../api/variable#list-variable-specification) | Optional | | Sort method to apply when rendering the list of values. | +| `#datasourceName` | string | Mandatory | | The name of the datasource to query. | +| `#metric` | string | Optional | | The name of the source metric to be used. /!\ Mandatory if you want to rely on the standard query pattern, thus didn't provide a value to the `#query` parameter. | +| `#label` | string | Mandatory | to `name` parameter | The label from which to retrieve the list of values. /!\ The [filter library](filterbuilder.md) does NOT rely on this parameter to build the corresponding matcher, only `#name` is used. | +| `#query` | string | Optional | | Custom query to be used for this variable. /!\ Mandatory if you didn't provide a value to the `#metric` parameter. | + +## Output + +| Field | Type | Description | +|------------|----------------------------------------------------------------|-----------------------------------------------------------| +| `variable` | [Variable](../../../api/variable#variable-specification) | The final variable object, to be passed to the dashboard. | + +## Example + +```cue +package myDaC + +import ( + labelValuesVarBuilder "github.com/perses/perses/cue/dac-utils/prometheus/variable/labelvalues" +) + +{labelValuesVarBuilder & { + #name: "stack" + #display: name: "PaaS" + #metric: "thanos_build_info" + #label: "stack" + #datasourceName: "promDemo" +}}.variable +``` \ No newline at end of file diff --git a/docs/docs/dac/cue/panelbuilder.md b/docs/docs/dac/cue/panelbuilder.md new file mode 100644 index 0000000..f94d88e --- /dev/null +++ b/docs/docs/dac/cue/panelbuilder.md @@ -0,0 +1,59 @@ +The Prometheus Panel builder helps creating panels in the format expected by Perses. + +## Usage + +```cue +package myDaC + +import ( + panelBuilder "github.com/perses/perses/cue/dac-utils/prometheus/panel" +) + +panelBuilder & {} // input parameters expected +``` + +## Parameters + +| Parameter | Type | Mandatory/Optional | Default | Description | +|-----------------|------------------------------------------------------------|--------------------|---------|------------------------------------------------------------| +| `#clause` | `"by"` \| `"without"` \| `""` | Optional | `""` | The aggregation clause for this panel's queries. | +| `#clauseLabels` | [...string] | Optional | [] | The labels on which to aggregate for this panel's queries. | +| `spec` | [PanelSpec](../../../api/dashboard.md#panel-specification) | Mandatory | | A PanelSpec object | + +the panel spec object can use the following string fields provided by the builder, via interpolation: + +| Field | Type | Description | +|---------|--------|-----------------------------------------------------------------------------------------------------| +| `#aggr` | string | Aggregation clause built from the provided `#clause` and `#clauseLabels`. E.g `by (namespace, pod)` | + +## Example + +```cue +package myDaC + +import ( + panelBuilder "github.com/perses/perses/cue/dac-utils/prometheus/panel" + timeseriesChart "github.com/perses/perses/cue/schemas/panels/time-series:model" + promQuery "github.com/perses/perses/cue/schemas/queries/prometheus:model" +) + +#cpuPanel: this=panelBuilder & { + #clause: "by" + #clauseLabels: ["container"] + + spec: { + display: name: "Container CPU" + plugin: timeseriesChart + queries: [ + { + kind: "TimeSeriesQuery" + spec: plugin: promQuery & { + spec: query: "sum \(this.#aggr) (container_cpu_usage_seconds{})" + } + }, + ] + } +} + +#cpuPanel +``` \ No newline at end of file diff --git a/docs/docs/dac/cue/panelgroupsbuilder.md b/docs/docs/dac/cue/panelgroupsbuilder.md new file mode 100644 index 0000000..5a2f915 --- /dev/null +++ b/docs/docs/dac/cue/panelgroupsbuilder.md @@ -0,0 +1,65 @@ +The Panel Groups builder helps creating panel groups easily. + +## Usage + +```cue +package myDaC + +import ( + panelGroupsBuilder "github.com/perses/perses/cue/dac-utils/panelgroups" +) + +panelGroupsBuilder & {} // input parameter expected +``` + +## Parameters + +| Parameter | Type | Description | +|-----------|------------------------|---------------------------------------------------------------------| +| `#input` | [...panelGroupBuilder] | Each array element provides the information to build a panel group. | + +### panelGroupBuilder parameters + +| Parameter | Type | Default | Description | +|-----------|----------------------------------------------------------|---------|-------------------------------------------------------| +| `#panels` | [...[Panel](../../api/dashboard.md#panel-specification)] | | An array of panels to be included in the panel group. | +| `#title` | string | | The title of the panel group. | +| `#cols` | >0 & <=24 | | The number of columns in the grid layout. | +| `#height` | number | 6 | The height for all panels in the grid | + +## Example + +```cue +package myDaC + +import ( + panelGroupsBuilder "github.com/perses/perses/cue/dac-utils/panelgroups" +) + +#memoryPanel: {} // v1.#Panel object +#cpuPanel: {} // v1.#Panel object + +panelGroupsBuilder & { + #input: [ + { + #title: "Resource usage" + #cols: 3 + #panels: [ + #memoryPanel, + #cpuPanel, + ] + }, + { + #title: "Resource usage bis" + #cols: 1 + #height: 4 + #panels: [ + #cpuPanel, + #memoryPanel, + ] + }, + ] +} +``` + +To build panels please refer to the [Prometheus Panel builder](prometheuspanelbuilder.md) \ No newline at end of file diff --git a/docs/docs/dac/cue/prometheuspanelbuilder.md b/docs/docs/dac/cue/prometheuspanelbuilder.md new file mode 100644 index 0000000..353df68 --- /dev/null +++ b/docs/docs/dac/cue/prometheuspanelbuilder.md @@ -0,0 +1,59 @@ +The Prometheus Panel builder helps creating panels in the format expected by Perses. + +## Usage + +```cue +package myDaC + +import ( + panelBuilder "github.com/perses/perses/cue/dac-utils/prometheus/panel" +) + +panelBuilder & {} // input parameters expected +``` + +## Parameters + +| Parameter | Type | Mandatory/Optional | Default | Description | +|-----------------|------------------------------------------------------------|--------------------|---------|------------------------------------------------------------| +| `#clause` | `"by"` \| `"without"` \| `""` | Optional | `""` | The aggregation clause for this panel's queries. | +| `#clauseLabels` | [...string] | Optional | [] | The labels on which to aggregate for this panel's queries. | +| `spec` | [PanelSpec](../../../api/dashboard#panel-specification) | Mandatory | | A PanelSpec object | + +the panel spec object can use the following string fields provided by the builder, via interpolation: + +| Field | Type | Description | +|---------|--------|-----------------------------------------------------------------------------------------------------| +| `#aggr` | string | Aggregation clause built from the provided `#clause` and `#clauseLabels`. E.g `by (namespace, pod)` | + +## Example + +```cue +package myDaC + +import ( + panelBuilder "github.com/perses/perses/cue/dac-utils/prometheus/panel" + timeseriesChart "github.com/perses/perses/cue/schemas/panels/time-series:model" + promQuery "github.com/perses/perses/cue/schemas/queries/prometheus:model" +) + +#cpuPanel: this=panelBuilder & { + #clause: "by" + #clauseLabels: ["container"] + + spec: { + display: name: "Container CPU" + plugin: timeseriesChart + queries: [ + { + kind: "TimeSeriesQuery" + spec: plugin: promQuery & { + spec: query: "sum \(this.#aggr) (container_cpu_usage_seconds{})" + } + }, + ] + } +} + +#cpuPanel +``` \ No newline at end of file diff --git a/docs/docs/dac/cue/promqlvariablebuilder.md b/docs/docs/dac/cue/promqlvariablebuilder.md new file mode 100644 index 0000000..6c5bbc1 --- /dev/null +++ b/docs/docs/dac/cue/promqlvariablebuilder.md @@ -0,0 +1,53 @@ +The PromQL Variable builder helps creating prometheus promQL variables in the format expected by Perses. + +## Usage + +```cue +package myDaC + +import ( + promQLVarBuilder "github.com/perses/perses/cue/dac-utils/prometheus/variable/promql" +) + +promQLVarBuilder & {} // input parameters expected +``` + +## Parameters + +| Parameter | Type | Mandatory/Optional | Default | Description | +|--------------------|-----------------------------------------------------------------|--------------------|---------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `#name` | string | Mandatory | | The name of this variable. | +| `#display` | [Display](../../../api/variable#display-specification) | Optional | | Display object to tune the display name, description and visibility (show/hide). | +| `#allowAllValue` | boolean | Optional | false | Whether to append the "All" value to the list. | +| `#allowMultiple` | boolean | Optional | false | Whether to allow multi-selection of values. | +| `#customAllValue` | string | Optional | | Custom value that will be used if `#allowAllValue` is true and if `All` is selected. | +| `#capturingRegexp` | string | Optional | | Regexp used to catch and filter the results of the query. If empty, then nothing is filtered (equivalent of setting it to `(.*)`). | +| `#sort` | [Sort](../../../api/variable#list-variable-specification) | Optional | | Sort method to apply when rendering the list of values. | +| `#datasourceName` | string | Mandatory | | The name of the datasource to query. | +| `#metric` | string | Optional | | The name of the source metric to be used. /!\ Mandatory if you want to rely on the standard query pattern, thus didn't provide a value to the `#query` parameter. | +| `#label` | string | Mandatory | to `name` parameter | The label from which to retrieve the list of values. /!\ The [filter library](filterbuilder.md) does NOT rely on this parameter to build the corresponding matcher, only `#name` is used. | +| `#query` | string | Optional | | Custom query to be used for this variable. /!\ Mandatory if you didn't provide a value to the `#metric` parameter. | + +## Output + +| Field | Type | Description | +|------------|----------------------------------------------------------------|-----------------------------------------------------------| +| `variable` | [Variable](../../../api/variable#variable-specification) | The final variable object, to be passed to the dashboard. | + +## Example + +```cue +package myDaC + +import ( + promQLVarBuilder "github.com/perses/perses/cue/dac-utils/prometheus/variable/promql" +) + +{promQLVarBuilder & { + #name: "container" + #metric: "kube_pod_container_info" + #allowAllValue: true + #allowMultiple: true + #datasourceName: "promDemo" +}}.variable +``` \ No newline at end of file diff --git a/docs/docs/dac/cue/staticlistvariablebuilder.md b/docs/docs/dac/cue/staticlistvariablebuilder.md new file mode 100644 index 0000000..64f9f1b --- /dev/null +++ b/docs/docs/dac/cue/staticlistvariablebuilder.md @@ -0,0 +1,47 @@ +The Static List Variable builder helps creating static list variables in the format expected by Perses. + +## Usage + +```cue +package myDaC + +import ( + staticListVarBuilder "github.com/perses/perses/cue/dac-utils/variable/staticlist" +) + +staticListVarBuilder & {} // input parameters expected +``` + +## Parameters + +| Parameter | Type | Mandatory/Optional | Default | Description | +|--------------------|--------------------------------------------------------------|--------------------|---------|------------------------------------------------------------------------------------------------------------------------------------| +| `#name` | string | Mandatory | | The name of this variable. | +| `#display` | [Display](../../../api/variable#display-specification) | Optional | | Display object to tune the display name, description and visibility (show/hide). | +| `#allowAllValue` | boolean | Optional | false | Whether to append the "All" value to the list. | +| `#allowMultiple` | boolean | Optional | false | Whether to allow multi-selection of values. | +| `#customAllValue` | string | Optional | | Custom value that will be used if `#allowAllValue` is true and if `All` is selected. | +| `#capturingRegexp` | string | Optional | | Regexp used to catch and filter the results of the query. If empty, then nothing is filtered (equivalent of setting it to `(.*)`). | +| `#sort` | [Sort](../../../api/variable#list-variable-specification) | Optional | | Sort method to apply when rendering the list of values. | +| `#values` | [...(string \| { value: string, label?: string })] | Mandatory | | The value of this variable. | + +## Output + +| Field | Type | Description | +|------------|-------------------------------------------------------------|-----------------------------------------------------------| +| `variable` | [Variable](../../../api/variable#variable-specification) | The final variable object, to be passed to the dashboard. | + +## Example + +```cue +package myDaC + +import ( + staticListVarBuilder "github.com/perses/perses/cue/dac-utils/variable/staticlist" +) + +{staticListVarBuilder & { + #name: "prometheus" + #values: ["one", "two", {value: "three", label: "THREE" }] +}}.variable +``` \ No newline at end of file diff --git a/docs/docs/dac/cue/textvariablebuilder.md b/docs/docs/dac/cue/textvariablebuilder.md new file mode 100644 index 0000000..e106bb2 --- /dev/null +++ b/docs/docs/dac/cue/textvariablebuilder.md @@ -0,0 +1,44 @@ +The Text Variable builder helps creating text variables in the format expected by Perses. + +## Usage + +```cue +package myDaC + +import ( + textVarBuilder "github.com/perses/perses/cue/dac-utils/variable/text" +) + +textVarBuilder & {} // input parameters expected +``` + +## Parameters + +| Parameter | Type | Mandatory/Optional | Default | Description | +|-------------|-----------------------------------------------------------|--------------------|---------|----------------------------------------------------------------------------------| +| `#name` | string | Mandatory | | The name of this variable. | +| `#display` | [Display](../../../api/variable#display-specification) | Optional | | Display object to tune the display name, description and visibility (show/hide). | +| `#value` | string | Mandatory | | The value of this variable. | +| `#constant` | bool | Mandatory | false | Whether this variable is a constant. | + +## Output + +| Field | Type | Description | +|------------|-------------------------------------------------------------|-----------------------------------------------------------| +| `variable` | [Variable](../../../api/variable#variable-specification) | The final variable object, to be passed to the dashboard. | + +## Example + +```cue +package myDaC + +import ( + textVarBuilder "github.com/perses/perses/cue/dac-utils/variable/text" +) + +{textVarBuilder & { + #name: "prometheus" + #value: "platform" + #constant: true +}}.variable +``` \ No newline at end of file diff --git a/docs/docs/dac/cue/variablegroupbuilder.md b/docs/docs/dac/cue/variablegroupbuilder.md new file mode 100644 index 0000000..6a110a3 --- /dev/null +++ b/docs/docs/dac/cue/variablegroupbuilder.md @@ -0,0 +1,64 @@ +The Variable Group builder takes care of generating a pattern that we often see in dashboards: when you have e.g 3 variables A, B and C, it's quite common to "bind" them together so that B depends on A, and C depends on B + A. + +## Usage + +```cue +package myDaC + +import ( + varGroupBuilder "github.com/perses/perses/cue/dac-utils/variable/group" +) + +varGroupBuilder & {} // input parameters expected +``` + +## Parameters + +| Parameter | Type | Mandatory/Optional | Default | Description | +|-----------|-----------------|--------------------|---------|--------------------------------------| +| `#input` | [...varBuilder] | Mandatory | | The list of variables to be grouped. | + +Technically the array could contain any kind of object, still it is meant to receive variables builder entries that are going to do something with the dependencies appended by the Variable Group builder. +You can also pass to it variables for which the notion of dependencies don't/can't apply (like text variables or static lists) but that will still be used as dependencies for the following variables. + +## Output + +| Field | Type | Description | +|-------------|------------------------------------------------------------------|---------------------------------------------------------------------| +| `variables` | [...[Variable](../../../api/variable#variable-specification)] | The final list of variables objects, to be passed to the dashboard. | + +## Example + +```cue +package myDaC + +import ( + varGroupBuilder "github.com/perses/perses/cue/dac-utils/variable/group" + textVarBuilder "github.com/perses/perses/cue/dac-utils/variable/text" + promQLVarBuilder "github.com/perses/perses/cue/dac-utils/prometheus/variable/promql" + labelValuesVarBuilder "github.com/perses/perses/cue/dac-utils/prometheus/variable/labelvalues" +) + +{varGroupBuilder & { + #input: [ + textVarBuilder & { + #name: "prometheus" + #value: "platform" + #constant: true + }, + labelValuesVarBuilder & { + #name: "stack" + #display: name: "PaaS" + #metric: "thanos_build_info" + #label: "stack" + #datasourceName: "promDemo" + }, + promQLVarBuilder & { + #name: "namespace" + #metric: "kube_namespace_labels" + #allowMultiple: true + #datasourceName: "promDemo" + } + ] +}}.variables +``` \ No newline at end of file diff --git a/docs/docs/dac/go.md b/docs/docs/dac/go.md new file mode 100644 index 0000000..30404ce --- /dev/null +++ b/docs/docs/dac/go.md @@ -0,0 +1 @@ +TODO \ No newline at end of file diff --git a/docs/docs/dac/go/barpanelbuilder.md b/docs/docs/dac/go/barpanelbuilder.md new file mode 100644 index 0000000..66f17aa --- /dev/null +++ b/docs/docs/dac/go/barpanelbuilder.md @@ -0,0 +1,88 @@ +## Constructor + +```golang +import "github.com/perses/perses/go-sdk/panel/bar" + +var options []bar.Option +bar.Chart(options...) +``` + +Need a list of options. + +## Default options + +- Calculation(): last + +## Available options + +### Calculation + +```golang +import "github.com/perses/perses/go-sdk/common" +import "github.com/perses/perses/go-sdk/panel/bar" + +bar.Calculation(common.Last) +``` + +Define the chart calculation. + +### Format + +```golang +import "github.com/perses/perses/go-sdk/common" +import "github.com/perses/perses/go-sdk/panel/bar" + +bar.Format(common.Format{...}) +``` + +Define the chart format. + +### SortingBy + +```golang +import "github.com/perses/perses/go-sdk/panel/bar" + +bar.SortingBy(bar.AscSort) +``` + +Define the chart sorting. + +### WithMode + +```golang +import "github.com/perses/perses/go-sdk/panel/bar" + +bar.WithMode(bar.PercentageMode) +``` + +Define the chart mode. + +## Example + +```golang +package main + +import ( + "github.com/perses/perses/go-sdk/common" + "github.com/perses/perses/go-sdk/dashboard" + panelgroup "github.com/perses/perses/go-sdk/panel-group" + "github.com/perses/perses/go-sdk/panel/bar" +) + +func main() { + dashboard.New("Example Dashboard", + dashboard.AddPanelGroup("Resource usage", + panelgroup.AddPanel("Container memory", + bar.Chart( + bar.Calculation(common.LastCalculation), + bar.Format(common.Format{ + Unit: common.BytesUnit, + }), + bar.SortingBy(bar.AscSort), + bar.WithMode(bar.PercentageMode), + ), + ), + ), + ) +} +``` \ No newline at end of file diff --git a/docs/docs/dac/go/dashboardbuilder.md b/docs/docs/dac/go/dashboardbuilder.md new file mode 100644 index 0000000..b3adaf7 --- /dev/null +++ b/docs/docs/dac/go/dashboardbuilder.md @@ -0,0 +1,157 @@ +## Constructor + +```golang +import "github.com/perses/perses/go-sdk/dashboard" + +var options []dashboard.Option +dashboard.New("my Super Dashboard", options...) +``` + +Need to provide the name of the dashboard and a list of options. + +## Default options + +- [Name()](#name): with the name provided in the constructor +- [Duration()](#duration): one hour + +## Available options + +### Name + +```golang +import "github.com/perses/perses/go-sdk/dashboard" + +dashboard.Name("My Super Dashboard") +``` + +Define the dashboard metadata name and display name. + +### ProjectName + +```golang +import "github.com/perses/perses/go-sdk/dashboard" + +dashboard.ProjectName("MySuperProject") +``` + +Define the dashboard project name in metadata. + +### Duration + +```golang +import "time" +import "github.com/perses/perses/go-sdk/dashboard" + +dashboard.Duration(2*time.Hour) +``` + +Define the dashboard duration. + +### RefreshInterval + +```golang +import "time" +import "github.com/perses/perses/go-sdk/dashboard" + +dashboard.RefreshInterval(15*time.minutes) +``` + +Define the dashboard refresh interval. + +### AddPanelGroup + +```golang +import "github.com/perses/perses/go-sdk/dashboard" +import "github.com/perses/perses/go-sdk/panel-group" + +var panelGroupOptions []panelgroup.Option +dashboard.AddPanelGroup("My Super Panel Group", panelGroupOptions...) +``` + +Add a panel group to the dashboard. More info at [Panel Group](./panel-group.md). + +### AddDatasource + +```golang +import "github.com/perses/perses/go-sdk/dashboard" +import "github.com/perses/perses/go-sdk/datasource" + +var datasourceOptions []datasource.Option +dashboard.AddDatasource("MySuperDatasourceName", datasourceOptions...) +``` + +Add a local datasource to the dashboard. More info at [Datasource](./datasource.md). + +### AddVariable + +```golang +import "github.com/perses/perses/go-sdk/dashboard" +import "github.com/perses/perses/go-sdk/variable" + +var variableOptions []variable.Option +dashboard.AddVariable("MySuperVariableName", variableOptions...) +``` + +Add a local variable to the dashboard. More info at [Variable](./variable.md). + +### AddVariableGroup + +```golang +import "github.com/perses/perses/go-sdk/dashboard" +import "github.com/perses/perses/go-sdk/variable-group" + +var variableGroupOptions []variablegroup.Option +dashboard.AddVariableGroup(variableGroupOptions...) +``` + +Add a group of variables to the dashboard. More info at [Variable Group](./variable-group.md). + +## Example + +```golang +package main + +import ( + "time" + + "github.com/perses/perses/go-sdk/dashboard" + "github.com/perses/perses/go-sdk/panel-group" + "github.com/perses/perses/go-sdk/panel/markdown" + + promDs "github.com/perses/perses/go-sdk/prometheus/datasource" + labelValuesVar "github.com/perses/perses/go-sdk/prometheus/variable/label-values" + listVar "github.com/perses/perses/go-sdk/variable/list-variable" +) + +func main() { + dashboard.New("Example Dashboard", + dashboard.ProjectName("MyProject"), + dashboard.RefreshInterval(1*time.Minute), + dashboard.Duration(24*time.Hour), + + // VARIABLES + dashboard.AddVariable("stack", + listVar.List( + labelValuesVar.PrometheusLabelValues("stack", + labelValuesVar.Matchers("thanos_build_info{}"), + labelValuesVar.Datasource("promDemo"), + ), + listVar.DisplayName("PaaS"), + ), + ), + + // ROWS + dashboard.AddPanelGroup("Info", + panelgroup.PanelsPerLine(3), + + // PANELS + panelgroup.AddPanel("Contact", + markdown.Markdown("Dashboard owner: [John Doe](mailto:zzz)"), + ), + ), + + // DATASOURCES + dashboard.AddDatasource("promDemo", promDs.Prometheus(promDs.HTTPProxy("#####"))), + ) +} +``` \ No newline at end of file diff --git a/docs/docs/dac/go/datasourcebuilder.md b/docs/docs/dac/go/datasourcebuilder.md new file mode 100644 index 0000000..d455515 --- /dev/null +++ b/docs/docs/dac/go/datasourcebuilder.md @@ -0,0 +1,76 @@ +## Constructor + +```golang +import "github.com/perses/perses/go-sdk/datasource" + +var options []datasource.Option +datasource.New("My Super Datasource", options...) +``` + +Need to provide the name of the datasource and a list of options. + +## Default options + +- [Name()](#name): with the name provided in the constructor. + +## Available options + +### Name + +```golang +import "github.com/perses/perses/go-sdk/datasource" + +datasource.Name("My Super Datasource") +``` + +Define the datasource metadata name + display name. + +### ProjectName + +```golang +import "github.com/perses/perses/go-sdk/datasource" + +datasource.ProjectName("MySuperProject") +``` + +Define the datasource project name in metadata. + +### Default + +```golang +import "github.com/perses/perses/go-sdk/datasource" + +datasource.Default(true) +``` + +Set if datasource is a default datasource. + +## Datasource Plugin Options + +### Prometheus Datasource + +```golang +import promDs "github.com/perses/perses/go-sdk/prometheus/datasource" + +promDs.Prometheus(promDsOptions...) +``` + +Set Prometheus plugin for the datasource. More info at [Prometheus Datasource](./prometheus/datasource.md). + +## Example + +```golang +package main + +import ( + "github.com/perses/perses/go-sdk/dashboard" + + promDs "github.com/perses/perses/go-sdk/prometheus/datasource" +) + +func main() { + dashboard.New("ExampleDashboard", + dashboard.AddDatasource("prometheusDemo", promDs.Prometheus(promDs.DirectURL("https://prometheus.demo.do.prometheus.io/"))), + ) +} +``` \ No newline at end of file diff --git a/docs/docs/dac/go/guagepanelbuilder.md b/docs/docs/dac/go/guagepanelbuilder.md new file mode 100644 index 0000000..fcf5027 --- /dev/null +++ b/docs/docs/dac/go/guagepanelbuilder.md @@ -0,0 +1,88 @@ +## Constructor + +```golang +import "github.com/perses/perses/go-sdk/panel/gauge" + +var options []gauge.Option +gauge.Chart(options...) +``` + +Need a list of options. + +## Default options + +- Calculation(): last + +## Available options + +### Calculation + +```golang +import "github.com/perses/perses/go-sdk/common" +import "github.com/perses/perses/go-sdk/panel/gauge" + +gauge.Calculation(common.Last) +``` + +Define the chart calculation. + +### Format + +```golang +import "github.com/perses/perses/go-sdk/common" +import "github.com/perses/perses/go-sdk/panel/gauge" + +gauge.Format(common.Format{...}) +``` + +Define the chart format. + +### Thresholds + +```golang +import "github.com/perses/perses/go-sdk/common" +import "github.com/perses/perses/go-sdk/panel/gauge" + +gauge.Thresholds(common.Thresholds{...}) +``` + +Define chart thresholds. + +### Max + +```golang +import "github.com/perses/perses/go-sdk/panel/gauge" + +gauge.Max(20) +``` + +Define the chart max value. + +## Example + +```golang +package main + +import ( + "github.com/perses/perses/go-sdk/common" + "github.com/perses/perses/go-sdk/dashboard" + panelgroup "github.com/perses/perses/go-sdk/panel-group" + "github.com/perses/perses/go-sdk/panel/gauge" +) + +func main() { + dashboard.New("Example Dashboard", + dashboard.AddPanelGroup("Resource usage", + panelgroup.AddPanel("Container memory", + gauge.Chart( + gauge.Calculation(common.LastCalculation), + gauge.Format(common.Format{ + Unit: common.BytesUnit, + }), + gauge.Max(20), + ), + ), + ), + ) +} +``` \ No newline at end of file diff --git a/docs/docs/dac/go/httpbuilder.md b/docs/docs/dac/go/httpbuilder.md new file mode 100644 index 0000000..66c80c9 --- /dev/null +++ b/docs/docs/dac/go/httpbuilder.md @@ -0,0 +1,99 @@ +## Constructor + +```golang +import "github.com/perses/perses/go-sdk/http" + +var options []http.Option +http.New("http://mysuperurl.com", options...) +``` + +Need to provide an url and a list of options. + +## Default options + +- URL(): with the url provided in the constructor + +## Available options + +### URL + +```golang +import "github.com/perses/perses/go-sdk/http" + +http.URL("http://mysuperurl.com") +``` + +Define the url of the http proxy. + +### AllowedEndpoints + +```golang +import "github.com/perses/perses/go-sdk/http" + +var endpoints []http.AllowedEndpoint +http.AllowedEndpoints(endpoints...) +``` + +Define the proxy allowed endpoints. + +### AddAllowedEndpoint + +```golang +import "github.com/perses/perses/go-sdk/http" + +http.Thresholds("GET", "/api/v1/labels") +``` + +Add an allowed endpoint to the http proxy. + +### Headers + +```golang +import "github.com/perses/perses/go-sdk/http" + +var headers := make(map[string]string) +http.WithSparkline(headers) +``` + +Define the headers of the http proxy. + +### AddHeader + +```golang +import "github.com/perses/perses/go-sdk/http" + +http.AddHeader("Authorization", "Bearer test") +``` + +Add a header to the http proxy. + +### Secret + +```golang +import "github.com/perses/perses/go-sdk/http" + +http.Secret("secretName") +``` + +Define the secret name to use for the http proxy. + +## Example + +```golang +package main + +import ( + "github.com/perses/perses/go-sdk/dashboard" + "github.com/perses/perses/go-sdk/http" + + promDs "github.com/perses/perses/go-sdk/prometheus/datasource" +) + +func main() { + dashboard.New("Example Dashboard", + dashboard.AddDatasource("prometheusDemo", promDs.Prometheus( + promDs.HTTPProxy("https://prometheus.demo.do.prometheus.io/", http.AddHeader("Authorization", "Bearer test")), + )), + ) +} +``` \ No newline at end of file diff --git a/docs/docs/dac/go/index.md b/docs/docs/dac/go/index.md new file mode 100644 index 0000000..b01b8e0 --- /dev/null +++ b/docs/docs/dac/go/index.md @@ -0,0 +1,32 @@ +# Go SDK for Dashboard-as-Code + +!!! info "Getting started with Dashboard as code" + + To get started with Dashboard-as-Code in Perses, have a look at the [DaC user guide](../../user-guides/dashboard-as-code.md) first. + +This section provides detailed information about the Go SDK to develop dashboards as code in Perses. +It's focusing on explaining how to use the different builders provided by the SDK. + +See the dedicated pages for each builder: + +* [Dashboard](./dashboardbuilder.md) +* [Datasource](./datasourcebuilder.md) +* [Panel](./panel.md) + * [Bar](./panel/bar.md) + * [Gauge](./panel/gauge.md) + * [Markdown](./panel/markdown.md) + * [Stat](./panel/stat.md) + * [Time Series](./panel/time-series.md) +* [Panel Group](./panel-group.md) +* [Query](./query.md) +* [Variable](./variable.md) +* [Variable Group](./variable-group.md) + +## Prometheus Related builders: + +- [Datasource](./prometheus/datasource.md) +- [Query](./prometheus/query.md) + - Variable-related builders: + - [Label Names Variable](./prometheus/variable/label-names.md) + - [Label Values Variable](./prometheus/variable/label-values.md) + - [PromQL Variable](./prometheus/variable/promql.md) \ No newline at end of file diff --git a/docs/docs/dac/go/labelnamesvariablebuilder.md b/docs/docs/dac/go/labelnamesvariablebuilder.md new file mode 100644 index 0000000..a80fe54 --- /dev/null +++ b/docs/docs/dac/go/labelnamesvariablebuilder.md @@ -0,0 +1,81 @@ +## Constructor + +```golang +import "github.com/perses/perses/go-sdk/prometheus/label-names" + +var options []labelnames.Option +labelnames.PrometheusLabelNames(options...) +``` + +Need a list of options. + +## Default options + +- None + +## Available options + +### Matchers + +```golang +import "github.com/perses/perses/go-sdk/prometheus/label-names" + +var matchers []string +labelnames.Matchers(matchers...) +``` + +Define matchers filtering the result. + +### AddMatcher + +```golang +import "github.com/perses/perses/go-sdk/prometheus/label-names" + +labelnames.AddMatcher("my_super_matcher") +``` + +Define a matcher filtering the result. + +### Datasource + +```golang +import "github.com/perses/perses/go-sdk/prometheus/label-names" + +labelnames.Datasource("datasourceName") +``` + +Define the datasource where the expression will be executed. + +### Filter + +```golang +import "github.com/perses/perses/go-sdk/variable" + +variable.Filter(variables...) +``` + +Mainly used by Mainly used by [variable group](../../variable-group.md).. It will filter the current variable with the provided variables. +The filter will be applied only if matchers don't have curly brackets. + +## Example + +```golang +package main + +import ( + "github.com/perses/perses/go-sdk/dashboard" + labelnames "github.com/perses/perses/go-sdk/prometheus/variable/label-names" + listvariable "github.com/perses/perses/go-sdk/variable/list-variable" +) + +func main() { + dashboard.New("Example Dashboard", + dashboard.AddVariable("namespaceLabels", listvariable.List( + labelnames.PrometheusLabelNames( + labelnames.Matchers("kube_namespace_labels{stack=\"$stack\",prometheus=\"$prometheus\",prometheus_namespace=\"$prometheus_namespace\",namespace=\"$namespace\"}"), + labelnames.Datasource("prometheusDemo"), + ), + )), + ) +} +``` \ No newline at end of file diff --git a/docs/docs/dac/go/labelvaluesvariablebuilder.md b/docs/docs/dac/go/labelvaluesvariablebuilder.md new file mode 100644 index 0000000..e268821 --- /dev/null +++ b/docs/docs/dac/go/labelvaluesvariablebuilder.md @@ -0,0 +1,94 @@ +## Constructor + +```golang +import "github.com/perses/perses/go-sdk/prometheus/label-values" + +var options []labelvalues.Option +labelvalues.PrometheusLabelValues("my_super_label_name", options...) +``` + +Need to provide a label name and a list of options. + +## Default options + +- [LabelName()](#labelname): with the label name provided in the constructor. + +## Available options + +### LabelName + +```golang +import "github.com/perses/perses/go-sdk/prometheus/label-values" + +labelvalues.LabelName("my_super_label_name") +``` + +Define the label name where value will be retrieved. + +### Matchers + +```golang +import "github.com/perses/perses/go-sdk/prometheus/label-values" + +var matchers []string +labelvalues.Matchers(matchers...) +``` + +Define matchers filtering the result. + +### AddMatcher + +```golang +import "github.com/perses/perses/go-sdk/prometheus/label-values" + +labelvalues.AddMatcher("my_super_matcher") +``` + +Define a matcher filtering the result. + +### Datasource + +```golang +import "github.com/perses/perses/go-sdk/prometheus/label-values" + +labelvalues.Datasource("datasourceValue") +``` + +Define the datasource where the expression will be executed. + +### Filter + +```golang +import "github.com/perses/perses/go-sdk/variable" + +variable.Filter(variables...) +``` + +Mainly used by [variable group](../../variable-group.md). It will filter the current variable with the provided variables. +The filter will be applied only if matchers don't have curly brackets. + +## Example + +```golang +package main + +import ( + "github.com/perses/perses/go-sdk/dashboard" + labelvalues "github.com/perses/perses/go-sdk/prometheus/variable/label-values" + listvariable "github.com/perses/perses/go-sdk/variable/list-variable" +) + +func main() { + dashboard.New("Example Dashboard", + dashboard.AddVariable("stack", + listvariable.List( + labelvalues.PrometheusLabelValues("stack", + labelvalues.Matchers("thanos_build_info{}"), + labelvalues.Datasource("prometheusDemo"), + ), + listvariable.DisplayName("PaaS"), + ), + ), + ) +} +``` \ No newline at end of file diff --git a/docs/docs/dac/go/markdownpanelbuilder.md b/docs/docs/dac/go/markdownpanelbuilder.md new file mode 100644 index 0000000..03a2c03 --- /dev/null +++ b/docs/docs/dac/go/markdownpanelbuilder.md @@ -0,0 +1,65 @@ +## Constructor + +```golang +import "github.com/perses/perses/go-sdk/panel/markdown" + +var options []markdown.Option +markdown.Markdown("My super markdown **text**", options...) +``` + +Need to provide a text and a list of options. + +## Default options + +- Text(): with the text provided in the constructor + +## Available options + +### Text + +```golang +import "github.com/perses/perses/go-sdk/panel/markdown" + +markdown.Text("My super markdown **text**") +``` + +Define the markdown text of the panel. + +### NewLine + +```golang +import "github.com/perses/perses/go-sdk/panel/markdown" + +markdown.NewLine("my super new line text") +``` + +Add a new line to the markdown text. + +## Example + +```golang +package main + +import ( + "github.com/perses/perses/go-sdk/dashboard" + panelgroup "github.com/perses/perses/go-sdk/panel-group" + "github.com/perses/perses/go-sdk/panel/markdown" +) + +func main() { + dashboard.New("Example Dashboard", + dashboard.AddPanelGroup("Resource usage", + panelgroup.AddPanel("Container memory", + markdown.Markdown("This is a markdown panel", + markdown.NewLine("This is a new line"), + markdown.NewLine("This is a new line"), + markdown.NewLine("This is a new line"), + markdown.NewLine("This is a new line"), + markdown.NewLine("This is a new line"), + markdown.NewLine("This is a new line"), + ), + ), + ), + ) +} +``` \ No newline at end of file diff --git a/docs/docs/dac/go/panelbuilder.md b/docs/docs/dac/go/panelbuilder.md new file mode 100644 index 0000000..e955775 --- /dev/null +++ b/docs/docs/dac/go/panelbuilder.md @@ -0,0 +1,132 @@ +## Constructor + +```golang +import "github.com/perses/perses/go-sdk/panel" + +var options []panel.Option +panel.New("My Super Panel", options...) +``` + +Need to provide the name of the panel and a list of options. + +## Default options + +- [Title()](#title): with the title provided in the constructor. + +## Available options + +### Title + +```golang +import "github.com/perses/perses/go-sdk/panel" + +panel.Name("My Super Panel") +``` + +Define the panel title. + +### Description + +```golang +import "github.com/perses/perses/go-sdk/panel" + +panel.Description("My Super Panel") +``` + +Define the panel description. + +### AddQuery + +```golang +import "github.com/perses/perses/go-sdk/panel" + +var queryOptions []query.Option +panel.AddQuery(queryOptions...) +``` + +Define the panel query. More info at [Query](./query.md). + +## Panel Plugin Options + +### Bar Panel + +```golang +import "github.com/perses/perses/go-sdk/panel/bar" + +var barOptions []bar.Option +bar.Chart(barOptions...) +``` + +Define the panel chart. More info at [Bar Panel](./panel/bar.md). + +### Gauge Panel + +```golang +import "github.com/perses/perses/go-sdk/panel/gauge" + +var gaugeOptions []gauge.Option +gauge.Chart(gaugeOptions...) +``` + +Define the panel chart. More info at [Gauge Panel](./panel/gauge.md). + +### Markdown Panel + +```golang +import "github.com/perses/perses/go-sdk/panel/markdown" + +var markdownOptions []markdown.Option +markdown.Chart(markdownOptions...) +``` + +Define the panel chart. More info at [Markdown Panel](./panel/markdown.md). + +### Stat Panel + +```golang +import "github.com/perses/perses/go-sdk/panel/stat" + +var statOptions []stat.Option +stat.Chart(statOptions...) +``` + +Define the panel chart. More info at [Stat Panel](./panel/stat.md). + +### Time Series Panel + +```golang +import "github.com/perses/perses/go-sdk/panel/time-series" + +var timeSeriesOptions []timeseries.Option +timeseries.Chart(timeSeriesOptions...) +``` + +Define the panel chart. More info at [Time Series Panel](./panel/time-series.md). + +## Example + +```golang +package main + +import ( + "github.com/perses/perses/go-sdk/dashboard" + "github.com/perses/perses/go-sdk/panel" + panelgroup "github.com/perses/perses/go-sdk/panel-group" + timeseries "github.com/perses/perses/go-sdk/panel/time-series" + "github.com/perses/perses/go-sdk/prometheus/query" +) + +func main() { + dashboard.New("Example Dashboard", + dashboard.AddPanelGroup("Resource usage", + panelgroup.AddPanel("Container memory", + panel.Description("This is a super panel"), + timeseries.Chart(), + panel.AddQuery( + query.PromQL("max by (container) (container_memory_rss{stack=\"$stack\",prometheus=\"$prometheus\",prometheus_namespace=\"$prometheus_namespace\",namespace=\"$namespace\",pod=\"$pod\",container=\"$container\"})"), + ), + ), + ), + ) +} +``` \ No newline at end of file diff --git a/docs/docs/dac/go/panelgroupbuilder.md b/docs/docs/dac/go/panelgroupbuilder.md new file mode 100644 index 0000000..6ed1bd4 --- /dev/null +++ b/docs/docs/dac/go/panelgroupbuilder.md @@ -0,0 +1,112 @@ +## Constructor + +```golang +import "github.com/perses/perses/go-sdk/panel-group" + +var options []panelgroup.Option +panelgroup.New("My Panel Group Title", options...) +``` + +Need to provide a title and a list of options. + +## Default options + +- [Title()](#title): with the title provided in the constructor. +- [PanelWidth()](#panelwidth): 12 +- [PanelHeight()](#panelheight): 6 +- [Collapsed()](#collapsed): true + +## Available options + +### Title + +```golang +import "github.com/perses/perses/go-sdk/panel-group" + +panelgroup.Title("My Panel Group Title") +``` + +Define the panel group title. + +### PanelWidth + +```golang +import "github.com/perses/perses/go-sdk/panel-group" + +panelgroup.PanelWidth(6) +``` + +Define the panel width. The value must be between 1 and 24. + +### PanelsPerLine + +```golang +import "github.com/perses/perses/go-sdk/panel-group" + +panelgroup.PanelsPerLine(4) +``` + +Helper for defining panel width instead of PanelWidth. The value must be between 1 and 24. + +### PanelHeight + +```golang +import "github.com/perses/perses/go-sdk/panel-group" + +panelgroup.PanelHeight(6) +``` + +Define the panel height. The value must be between 1 and 24. + +### Collapsed + +```golang +import "github.com/perses/perses/go-sdk/panel-group" + +panelgroup.Collapsed(true) +``` + +Define if the panel group is collapsed or not when the dashboard is loaded. +Collapsed panel group are lazy loaded when they are opened. + +### AddPanel + +```golang +import "github.com/perses/perses/go-sdk/panel-group" +import "github.com/perses/perses/go-sdk/panel" + +var panelOptions []panel.Option +panelgroup.AddPanel("MySuperPanelName", panelOptions...) +``` + +Add a panel to the group, the panel will be placed depending on the ordering of in the group. +More info about the panel can be found [here](panel.md). + +## Example + +```golang +package main + +import ( + "github.com/perses/perses/go-sdk/dashboard" + "github.com/perses/perses/go-sdk/panel" + panelgroup "github.com/perses/perses/go-sdk/panel-group" + timeseries "github.com/perses/perses/go-sdk/panel/time-series" + "github.com/perses/perses/go-sdk/prometheus/query" +) + +func main() { + dashboard.New("Example Dashboard", + dashboard.AddPanelGroup("Resource usage", + panelgroup.Collapsed(false), + panelgroup.PanelsPerLine(1), + panelgroup.AddPanel("Container memory", + timeseries.Chart(), + panel.AddQuery( + query.PromQL("max by (container) (container_memory_rss{stack=\"$stack\",prometheus=\"$prometheus\",prometheus_namespace=\"$prometheus_namespace\",namespace=\"$namespace\",pod=\"$pod\",container=\"$container\"})"), + ), + ), + ), + ) +} +``` \ No newline at end of file diff --git a/docs/docs/dac/go/prometheusdatasourcebuilder.md b/docs/docs/dac/go/prometheusdatasourcebuilder.md new file mode 100644 index 0000000..dd330f5 --- /dev/null +++ b/docs/docs/dac/go/prometheusdatasourcebuilder.md @@ -0,0 +1,54 @@ +## Constructor + +```golang +import "github.com/perses/perses/go-sdk/prometheus/datasource" + +var options []datasource.Option +datasource.Prometheus(options...) +``` + +Need a list of options. At least direct URL or proxy URL, in order to work. + +## Default options + +- None + +## Available options + +#### Direct URL + +```golang +import "github.com/perses/perses/go-sdk/prometheus/datasource" + +datasource.DirectURL("https://prometheus.demo.do.prometheus.io") +``` + +Set Prometheus plugin for the datasource with a direct URL. + +#### Proxy + +```golang +import "github.com/perses/perses/go-sdk/prometheus/datasource" + +datasource.HTTPProxy("https://current-domain-name.io", httpProxyOptions...) +``` + +Set Prometheus plugin for the datasource with a proxy URL, useful for bypassing. More info at [HTTP Builder](httpbuilder.md). + +## Example + +```golang +package main + +import ( + "github.com/perses/perses/go-sdk/dashboard" + + promDs "github.com/perses/perses/go-sdk/prometheus/datasource" +) + +func main() { + dashboard.New("Example Dashboard", + dashboard.AddDatasource("prometheusDemo", promDs.Prometheus(promDs.DirectURL("https://prometheus.demo.do.prometheus.io/"))), + ) +} +``` \ No newline at end of file diff --git a/docs/docs/dac/go/prometheusquerybuilder.md b/docs/docs/dac/go/prometheusquerybuilder.md new file mode 100644 index 0000000..76f58db --- /dev/null +++ b/docs/docs/dac/go/prometheusquerybuilder.md @@ -0,0 +1,98 @@ +## Constructor + +```golang +import "github.com/perses/perses/go-sdk/prometheus/query" + +var options []query.Option +query.PromQL("max by (container) (container_memory_rss{})", options...) +``` + +Need to provide the PromQL expression and a list of options. + +## Default options + +- [Expr()](#expr): with the expression provided in the constructor. + +## Available options + +#### Expr + +```golang +import "github.com/perses/perses/go-sdk/prometheus/query" + +query.Expr("max by (container) (container_memory_rss{})") +``` + +Define query expression. + +#### Datasource + +```golang +import "github.com/perses/perses/go-sdk/prometheus/query" + +query.Datasource("MySuperDatasource") +``` + +Define the datasource the query will use. + +#### SeriesNameFormat + +```golang +import "github.com/perses/perses/go-sdk/prometheus/query" + +query.SeriesNameFormat("") // TODO: check +``` + +Define query series name format. + +#### MinStep + +```golang +import "time" +import "github.com/perses/perses/go-sdk/prometheus/query" + +query.MinStep(5*time.Minute) +``` + +Define query min step. + +#### Resolution + +```golang +import "github.com/perses/perses/go-sdk/prometheus/query" + +query.Resolution(3600) +``` + +Define query resolution. + +## Example + +```golang +package main + +import ( + "time" + + "github.com/perses/perses/go-sdk/dashboard" + "github.com/perses/perses/go-sdk/panel" + panelgroup "github.com/perses/perses/go-sdk/panel-group" + timeseries "github.com/perses/perses/go-sdk/panel/time-series" + "github.com/perses/perses/go-sdk/prometheus/query" +) + +func main() { + dashboard.New("Example Dashboard", + dashboard.AddPanelGroup("Resource usage", + panelgroup.AddPanel("Container memory", + timeseries.Chart(), + panel.AddQuery( + query.PromQL("max by (container) (container_memory_rss{stack=\"$stack\",prometheus=\"$prometheus\",prometheus_namespace=\"$prometheus_namespace\",namespace=\"$namespace\",pod=\"$pod\",container=\"$container\"})", + query.MinStep(time.Minute), + ), + ), + ), + ), + ) +} +``` \ No newline at end of file diff --git a/docs/docs/dac/go/promqlvariablebuilder.md b/docs/docs/dac/go/promqlvariablebuilder.md new file mode 100644 index 0000000..9db0929 --- /dev/null +++ b/docs/docs/dac/go/promqlvariablebuilder.md @@ -0,0 +1,70 @@ +## Constructor + +```golang +import "github.com/perses/perses/go-sdk/prometheus/promql" + +var options []promql.Option +promql.PrometheusPromQL("group by (namespace) (kube_namespace_labels{}", options...) +``` + +Need to provide the name of the variable and a list of options. + +## Default options + +- [Expr()](#expr): with the expr provided in the constructor. + +## Available options + +### Expr + +```golang +import "github.com/perses/perses/go-sdk/prometheus/promql" + +promql.Expr("group by (namespace) (kube_namespace_labels{}") +``` + +Define the promQL metadata name and the display name. + +### LabelName + +```golang +import "github.com/perses/perses/go-sdk/prometheus/promql" + +promql.LabelName("my_super_label_name") +``` + +Define a label name that can filter the result of the expression. + +### Datasource + +```golang +import "github.com/perses/perses/go-sdk/prometheus/promql" + +promql.Datasource("datasourceName") +``` + +Define the datasource where the expression will be executed. + +## Example + +```golang +package main + +import ( + "github.com/perses/perses/go-sdk/dashboard" + "github.com/perses/perses/go-sdk/prometheus/variable/promql" + listvariable "github.com/perses/perses/go-sdk/variable/list-variable" +) + +func main() { + dashboard.New("Example Dashboard", + dashboard.AddVariable("namespace", listvariable.List( + promql.PrometheusPromQL("group by (namespace) (kube_namespace_labels{stack=\"$stack\",prometheus=\"$prometheus\",prometheus_namespace=\"$prometheus_namespace\"})", + promql.LabelName("namespace"), + promql.Datasource("promDemo"), + ), + listvariable.AllowMultiple(true), + )), + ) +} +``` \ No newline at end of file diff --git a/docs/docs/dac/go/querybuilder.md b/docs/docs/dac/go/querybuilder.md new file mode 100644 index 0000000..cc64c84 --- /dev/null +++ b/docs/docs/dac/go/querybuilder.md @@ -0,0 +1,57 @@ +## Constructor + +```golang +import "github.com/perses/perses/go-sdk/query" + +var options []query.Option +query.New(options...) +``` + +Need to provide a list of options. + +## Default options + +- None + +## Available options + +None + +## Query Plugin Options + +### Prometheus Query + +```golang +import "github.com/perses/perses/go-sdk/prometheus/query" + +query.PromQL("max by (container) (container_memory_rss{})") +``` + +Set Prometheus Query plugin for the query. More info at [Prometheus Query](./prometheus/query.md). + +## Example + +```golang +package main + +import ( + "github.com/perses/perses/go-sdk/dashboard" + "github.com/perses/perses/go-sdk/panel" + panelgroup "github.com/perses/perses/go-sdk/panel-group" + timeseries "github.com/perses/perses/go-sdk/panel/time-series" + "github.com/perses/perses/go-sdk/prometheus/query" +) + +func main() { + dashboard.New("Example Dashboard", + dashboard.AddPanelGroup("Resource usage", + panelgroup.AddPanel("Container memory", + timeseries.Chart(), + panel.AddQuery( + query.PromQL("max by (container) (container_memory_rss{stack=\"$stack\",prometheus=\"$prometheus\",prometheus_namespace=\"$prometheus_namespace\",namespace=\"$namespace\",pod=\"$pod\",container=\"$container\"})"), + ), + ), + ), + ) +} +``` \ No newline at end of file diff --git a/docs/docs/dac/go/statpanelbuilder.md b/docs/docs/dac/go/statpanelbuilder.md new file mode 100644 index 0000000..f4f8295 --- /dev/null +++ b/docs/docs/dac/go/statpanelbuilder.md @@ -0,0 +1,96 @@ +## Constructor + +```golang +import "github.com/perses/perses/go-sdk/panel/stat" + +var options []stat.Option +stat.Chart(options...) +``` + +Need a list of options. + +## Default options + +- Calculation(): last + +## Available options + +### Calculation + +```golang +import "github.com/perses/perses/go-sdk/common" +import "github.com/perses/perses/go-sdk/panel/stat" + +stat.Calculation(common.Last) +``` + +Define the chart calculation. + +### Format + +```golang +import "github.com/perses/perses/go-sdk/common" +import "github.com/perses/perses/go-sdk/panel/stat" + +stat.Format(common.Format{...}) +``` + +Define the chart format. + +### Thresholds + +```golang +import "github.com/perses/perses/go-sdk/common" +import "github.com/perses/perses/go-sdk/panel/stat" + +stat.Thresholds(common.Thresholds{...}) +``` + +Define chart thresholds. + +### WithSparkline + +```golang +import "github.com/perses/perses/go-sdk/panel/stat" + +stat.WithSparkline(stat.Sparkline{...}) +``` + +Define the sparkline of the chart. + +### ValueFontSize + +```golang +import "github.com/perses/perses/go-sdk/panel/stat" + +stat.ValueFontSize(12) +``` + +Define the font size of the value. + +## Example + +```golang +package main + +import ( + "github.com/perses/perses/go-sdk/dashboard" + panelgroup "github.com/perses/perses/go-sdk/panel-group" + "github.com/perses/perses/go-sdk/panel/stat" +) + +func main() { + dashboard.New("Example Dashboard", + dashboard.AddPanelGroup("Resource usage", + panelgroup.AddPanel("Container memory", + stat.Chart( + stat.WithSparkline(stat.Sparkline{ + Color: "#e65013", + Width: 1, + }), + ), + ), + ), + ) +} +``` \ No newline at end of file diff --git a/docs/docs/dac/go/timeseriespanelbuilder.md b/docs/docs/dac/go/timeseriespanelbuilder.md new file mode 100644 index 0000000..1d68648 --- /dev/null +++ b/docs/docs/dac/go/timeseriespanelbuilder.md @@ -0,0 +1,111 @@ +## Constructor + +```golang +import "github.com/perses/perses/go-sdk/panel/time-series" + +var options []timeseries.Option +timeseries.Chart(options...) +``` + +Need a list of options. + +## Default options + +- None + +## Available options + +### WithLegend + +```golang +import "github.com/perses/perses/go-sdk/common" +import "github.com/perses/perses/go-sdk/panel/time-series" + +timeseries.WithLegend(timeseries.Legend{...}) +``` + +Define legend properties of the chart. + +### WithTooltip + +```golang +import "github.com/perses/perses/go-sdk/common" +import "github.com/perses/perses/go-sdk/panel/time-series" + +timeseries.WithTooltip(timeseries.Tooltip{...}) +``` + +Define tooltip properties of the chart. + +### WithYAxis + +```golang +import "github.com/perses/perses/go-sdk/common" +import "github.com/perses/perses/go-sdk/panel/time-series" + +timeseries.WithYAxis(timeseries.YAxis{...}) +``` + +Define Y axis properties of the chart. + +### Thresholds + +```golang +import "github.com/perses/perses/go-sdk/common" +import "github.com/perses/perses/go-sdk/panel/time-series" + +timeseries.Thresholds(common.Thresholds{...}) +``` + +Define chart thresholds. + +### WithVisual + +```golang +import "github.com/perses/perses/go-sdk/panel/time-series" + +timeseries.WithVisual(timeseries.Visual{...}) +``` + +Define visual properties of the chart. + +### WithQuerySettings + +```golang +import "github.com/perses/perses/go-sdk/panel/time-series" + +timeseries.WithQuerySettings([]timeseries.QuerySettingsItem{...}) +``` + +Define settings for the queries. + +## Example + +```golang +package main + +import ( + "github.com/perses/perses/go-sdk/dashboard" + panelgroup "github.com/perses/perses/go-sdk/panel-group" + timeseries "github.com/perses/perses/go-sdk/panel/time-series" +) + +func main() { + dashboard.New("Example Dashboard", + dashboard.AddPanelGroup("Resource usage", + panelgroup.AddPanel("Container memory", + timeseries.Chart( + timeseries.WithLegend(timeseries.Legend{ + Position: timeseries.BottomPosition, + Mode: timeseries.ListMode, + Size: timeseries.SmallSize, + }), + timeseries.WithTooltip(timeseries.Tooltip{ + EnablePinning: false, + }), + ), + ), + ), + ) +} +``` \ No newline at end of file diff --git a/docs/docs/dac/go/variablebuilder.md b/docs/docs/dac/go/variablebuilder.md new file mode 100644 index 0000000..eab6640 --- /dev/null +++ b/docs/docs/dac/go/variablebuilder.md @@ -0,0 +1,267 @@ +## Constructor + +```golang +import "github.com/perses/perses/go-sdk/variable" + +var options []variable.Option +variable.New("My Super Variable", options...) +``` + +Need to provide the name of the varaible and a list of options. + +## Default options + +- [Name()](#name): with the name provided in the constructor. + +## Available options + +### Name + +```golang +import "github.com/perses/perses/go-sdk/variable" + +variable.Name("My Super Variable") +``` + +Define the variable metadata name and the display name. + +### Filter + +```golang +import "github.com/perses/perses/go-sdk/variable" + +variable.Filter(variables...) +``` + +Mainly used by Mainly used by [variable group](variablegroupbuilder).. It will filter the current variable with the provided variables. +The filter implementation is defined by the variable plugin builder. + +## Spec Options + +### Text Variable + +#### Text Variable Constructor + +```golang +import txtVar "github.com/perses/perses/go-sdk/variable/text-variable" + +var txtVarOptions []txtVar.Option +txtVar.Text("example-value", txtVarOptions...) +``` + +#### Text Variable Options + +##### Value + +```golang +import txtVar "github.com/perses/perses/go-sdk/variable/text-variable" + +txtVar.Value("example-value") +``` + +Define the value of the text variable. + +##### Constant + +```golang +import txtVar "github.com/perses/perses/go-sdk/variable/text-variable" + +txtVar.Constant(true) +``` + +Define if the text variable is a constant. A constant variable is a variable that can't be changed by the user on the dashboard. + +##### Description + +```golang +import txtVar "github.com/perses/perses/go-sdk/variable/text-variable" + +txtVar.Description("This is a super description") +``` + +Set the description of the text variable. + +##### DisplayName + +```golang +import txtVar "github.com/perses/perses/go-sdk/variable/text-variable" + +txtVar.DisplayName("This is a super description") +``` + +Set the display name of the text variable. + +##### Hidden + +```golang +import txtVar "github.com/perses/perses/go-sdk/variable/text-variable" + +txtVar.Hidden(true) +``` + +Define if the text variable is hidden. A hidden variable is a variable that is not displayed on the dashboard. + +### List Variable + +#### List Variable Constructor + +```golang +import listVar "github.com/perses/perses/go-sdk/variable/text-variable" + +var listVarOptions []listVar.Option +listVar.List(listVarOptions...) +``` + +#### List Variable Options + +##### DefaultValue + +```golang +import listVar "github.com/perses/perses/go-sdk/variable/text-variable" + +listVar.DefaultValue("example-value") +``` + +Define a single default value for the list variable. + +##### AllowAllValue + +```golang +import listVar "github.com/perses/perses/go-sdk/variable/text-variable" + +listVar.AllowAllValue(true) +``` + +Define if the "all" value is allowed. If set to true, the list variable will have an "all" option that will select all values for the variable. + +##### AllowMultiple + +```golang +import listVar "github.com/perses/perses/go-sdk/variable/text-variable" + +listVar.AllowMultiple("This is a super description") +``` + +Define if the list variable allows multiple values to be selected. If set to true, the list variable will allow multiple values to be selected by the user on the dashboard. + +##### CustomAllValue + +```golang +import listVar "github.com/perses/perses/go-sdk/variable/text-variable" + +listVar.CustomAllValue("MySuperAllValueCustom") +``` + +Define a custom value for the "all" option. + +##### CapturingRegexp + +```golang +import listVar "github.com/perses/perses/go-sdk/variable/text-variable" + +listVar.CapturingRegexp("^mysuperregexp.*") +``` + +Define a capturing regexp for the list variable. It will only list the values that match the regexp. + +##### SortingBy + +```golang +import listVar "github.com/perses/perses/go-sdk/variable/text-variable" + +listVar.SortingBy(listVar.SortingAlphabeticalAsc) +``` + +Define the sorting order of the list variable. +The available options are: "none", "alphabetical-asc", "alphabetical-desc", "numerical-asc", "numerical-desc", "alphabetical-ci-asc" and "alphabetical-ci-desc". + +##### Description + +```golang +import listVar "github.com/perses/perses/go-sdk/variable/text-variable" + +listVar.Description("This is a super description") +``` + +Set the description of the list variable. + +##### DisplayName + +```golang +import listVar "github.com/perses/perses/go-sdk/variable/text-variable" + +listVar.DisplayName("This is a super description") +``` + +Set the display name of the list variable. + +##### Hidden + +```golang +import listVar "github.com/perses/perses/go-sdk/variable/text-variable" + +listVar.Hidden(true) +``` + +Define if the list variable is hidden. A hidden variable is a variable that is not displayed on the dashboard. + +#### Variable Plugin Options + +##### Prometheus (List Variable) + +```golang +import promqlVar "github.com/perses/perses/go-sdk/prometheus/variable/promql" + +var promqlVarOptions []promqlVar.Option +promqlVar.PrometheusPromQL("group by (namespace) (kube_namespace_labels{})", promqlVarOptions...) +``` + +Use a Prometheus query to populate the list variable. More info at [PromQL Variable](./prometheus/variable/promql.md). + +##### Prometheus Label Name (List Variable) + +```golang +import labelNamesVar "github.com/perses/perses/go-sdk/prometheus/variable/label-names" + +var labelNamesVarOptions []labelNamesVar.Option +labelNamesVar.PrometheusLabelNames(labelNamesVarOptions...) +``` + +Use label names from a Prometheus datasource to populate the list variable. More info at [Label Names Variable](./prometheus/variable/label-names.md). + +##### Prometheus Label Values (List Variable) + +```golang +import labelValuesVar "github.com/perses/perses/go-sdk/prometheus/variable/label-values" + +var labelValuesVarOptions []labelValuesVar.Option +labelValuesVar.PrometheusLabelValues("labelNames", labelNamesVarOptions...) +``` + +Use label values from a Prometheus datasource to populate the list variable. More info at [Label Values Variable](./prometheus/variable/label-values.md). + +## Example + +```golang +package main + +import ( + "github.com/perses/perses/go-sdk/dashboard" + labelvalues "github.com/perses/perses/go-sdk/prometheus/variable/label-values" + listvariable "github.com/perses/perses/go-sdk/variable/list-variable" +) + +func main() { + dashboard.New("ExampleDashboard", + dashboard.AddVariable("stack", + listvariable.List( + labelvalues.PrometheusLabelValues("stack", + labelvalues.Matchers("thanos_build_info{}"), + labelvalues.Datasource("prometheusDemo"), + ), + listvariable.DisplayName("PaaS"), + ), + ), + ) +} +``` \ No newline at end of file diff --git a/docs/docs/dac/go/variablegroupbuilder.md b/docs/docs/dac/go/variablegroupbuilder.md new file mode 100644 index 0000000..cb6c48d --- /dev/null +++ b/docs/docs/dac/go/variablegroupbuilder.md @@ -0,0 +1,124 @@ +Variable group is a helper for adding variables to a dashboard. +It will automatically filter the variables added to the group. +The filter logic is applied by the variable plugin builder. +Variables are filtered by their order in the group: first variable will filter the next ones. +Ignored variables are filtered, but they don't filter the next variables added to the group. + +## Constructor + +```golang +import "github.com/perses/perses/go-sdk/variable-group" + +var options []variablegroup.Option +variablegroup.New(options...) +``` + +Need a list of options. + +## Default options + +- None + +## Available options + +### AddVariable + +```golang +import "github.com/perses/perses/go-sdk/variable-group" +import "github.com/perses/perses/go-sdk/variable" + +var variableOptions []variable.Option +variablegroup.AddVariable("MySuperVariableName", variableOptions...) +``` + +Add a variable to the group, this variable will be filtered by variable already present in the group and will filter next variables added. +More info at [Variable](./variable.md). + +### AddIgnoredVariable + +```golang +import "github.com/perses/perses/go-sdk/variable-group" +import "github.com/perses/perses/go-sdk/variable" + +var variableOptions []variable.Option +variablegroup.AddIgnoredVariable("MySuperVariableName", variableOptions...) +``` + +Add a variable to the group, this variable will be filtered by variable already present in the group. +However, this variable will not filter next variables added. More info at [Variable](./variable.md). + +## Example + +```golang +package main + +import ( + "github.com/perses/perses/go-sdk/dashboard" + labelnames "github.com/perses/perses/go-sdk/prometheus/variable/label-names" + labelvalues "github.com/perses/perses/go-sdk/prometheus/variable/label-values" + "github.com/perses/perses/go-sdk/prometheus/variable/promql" + variablegroup "github.com/perses/perses/go-sdk/variable-group" + listvariable "github.com/perses/perses/go-sdk/variable/list-variable" + textvariable "github.com/perses/perses/go-sdk/variable/text-variable" +) + +func main() { + dashboard.New("ExampleDashboard", + dashboard.AddVariableGroup( + variablegroup.AddVariable("stack", + listvariable.List( + labelvalues.PrometheusLabelValues("stack", + labelvalues.Matchers("thanos_build_info"), + labelvalues.Datasource("promDemo"), + ), + listvariable.DisplayName("PaaS"), + ), + ), + variablegroup.AddVariable("prometheus", + textvariable.Text("platform", textvariable.Constant(true)), + ), + variablegroup.AddVariable("prometheus_namespace", + textvariable.Text("observability", + textvariable.Constant(true), + textvariable.Description("constant to reduce the query scope thus improve performances"), + ), + ), + variablegroup.AddVariable("namespace", listvariable.List( + promql.PrometheusPromQL("group by (namespace) (kube_namespace_labels{stack=\"$stack\",prometheus=\"$prometheus\",prometheus_namespace=\"$prometheus_namespace\"})", + promql.LabelName("namespace"), promql.Datasource("promDemo"), + ), + listvariable.AllowMultiple(true), + )), + variablegroup.AddIgnoredVariable("namespaceLabels", listvariable.List( + labelnames.PrometheusLabelNames( + labelnames.Matchers("kube_namespace_labels"), + labelnames.Datasource("promDemo"), + ), + )), + variablegroup.AddVariable("pod", listvariable.List( + promql.PrometheusPromQL("group by (pod) (kube_pod_info{stack=\"$stack\",prometheus=\"$prometheus\",prometheus_namespace=\"$prometheus_namespace\",namespace=\"$namespace\"})", + promql.LabelName("pod"), promql.Datasource("promDemo"), + ), + listvariable.AllowMultiple(true), + listvariable.AllowAllValue(true), + )), + variablegroup.AddVariable("container", listvariable.List( + promql.PrometheusPromQL("group by (container) (kube_pod_container_info{stack=\"$stack\",prometheus=\"$prometheus\",prometheus_namespace=\"$prometheus_namespace\",namespace=\"$namespace\",pod=\"$pod\"})", + promql.LabelName("container"), promql.Datasource("promDemo"), + ), + listvariable.AllowMultiple(true), + listvariable.AllowAllValue(true), + )), + variablegroup.AddIgnoredVariable("containerLabels", listvariable.List( + listvariable.Description("simply the list of labels for the considered metric"), + listvariable.Hidden(true), + labelnames.PrometheusLabelNames( + labelnames.Matchers("kube_pod_container_info"), + labelnames.Datasource("promDemo"), + ), + )), + ), + ) +} + +``` \ No newline at end of file diff --git a/docs/docs/design/authentication.md b/docs/docs/design/authentication.md new file mode 100644 index 0000000..c32d07f --- /dev/null +++ b/docs/docs/design/authentication.md @@ -0,0 +1,260 @@ +Perses has various authentication flows configurable. You can choose to authenticate from a +[native provider](./authentication.md#native-provider) that will allow you to create some users, +or else rely on an external [identity provider](./authentication.md#external-oidcoauth-providers). + +In both cases +- each new user will be saved in the Perses database. +- at login time, a Perses session (access_token/refresh_token) will be created + +Please note that the number of identity providers is not limited. + +```yaml +authentication: + providers: + # Enable or not the native Perses identity provider + enable_native: true/false + # Register one or several OIDC provider(s) + oidc: [] + # Register one or several OAuth provider(s) + oauth: [] +``` + +## Native provider + +In case a native provider is used, the users and their password are stored in the Perses database. + +Login is done through http POST on /api/auth/providers/native/login. + +## External OIDC/OAuth provider(s) + +It is possible to configure Perses to sign in user with an external identity provider supporting OIDC/Oauth. +For both of these provider's types, the flow is quite similar: + +When a user sign in with an external provider (e.g. Github) the Perses backend will then use the information +collected (email, firstname, lastname, picture) to **sync the user in database**. +Then the backend takes in charge the creation of the access_token/refresh_token that will be used to +authenticate this user in the subsequent requests. + +!!! info "User Synchronization" + + The **user synchronization** can possibly be used to update also its [permissions](./authorization.md), based on + some roles/groups present in the external idp's token. + + There is nothing implemented yet. User have to login first and ask specific permissions to an admin. + +### Configuration examples + +```yaml +authentication: + providers: + oidc: + # Example with an Azure AD OIDC configuration + - slug_id: azure + name: "Azure AD" + client_id: "" + client_secret: "" + issuer: "https://login.microsoftonline.com//v2.0" + redirect_uri: "http://localhost:3000/api/auth/providers/oidc-azure/callback" + scopes: ["openid", "profile", "email", "User.read"] + oauth: + - slug_id: github + name: "Github" + client_id: "" + client_secret: "" + auth_url: "https://github.com/login/oauth/authorize" + token_url: "https://github.com/login/oauth/access_token" + logout_url: "https://github.com/login/oauth/logout" + redirect_uri: "http://localhost:3000/api/auth/providers/oauth-github/callback" + user_infos_url: "https://api.github.com/user" +``` + +#### Login from external OIDC or OAuth2.0 provider with interactive flow, through WEB UI. (`authorization_code`) + +```mermaid +sequenceDiagram + actor hu as John + #actor ro as Robot + participant br as Perses Frontend + participant rp as Perses Backend + participant op as External Identity Provider + + hu->>br: Login with OIDC provider (e.g Azure AD) + activate br + br->>rp: GET /api/auth/providers/{oidc|oauth}/{slug_id}/login + activate rp + rp->>br: 302: redirect to Provider + deactivate rp + br->>op: /oauth/authorize + activate op + op->>br: 302: redirect to Perses + deactivate op + br->>rp: GET /api/auth/providers/{oidc|oauth}/{slug_id}/callback?code=... + activate rp + alt OIDC + rp->>op: GET /oauth/token + activate op + op->>rp: 200: id_token & access_token + deactivate op + rp->>op: GET /api/userinfo
(endpoint from .well-known URL) + activate op + op->>rp: 200: User Info + deactivate op + Note right of rp: User Info + id token are
used to sync user in database + rp->>rp: Create or Update user in DB + else OAUTH 2.0 + rp->>op: GET /oauth/token + activate op + op->>rp: 200: access_token + deactivate op + rp->>op: GET /api/userinfo
(endpoint from Perses Config) + activate op + op->>rp: 200: User Info + deactivate op + Note right of rp: Only User Info is
used to sync user in database + rp->>rp: Create or Update user in DB + end + Note right of rp: A new session is created
with a new signed access_token+refresh_token + rp->>br: 200: save session in cookie + deactivate rp + br->>hu: Home Page + deactivate br + hu->>br: Click on Projects + activate br + br->>rp: GET /api/v1/projects + activate rp + rp->>rp: Verify token and permissions + rp->>br: 200: projects list + deactivate rp + br->>hu: Projects Page + deactivate br +``` + +#### Login from external OIDC or OAuth2.0 provider with interactive flow, through `percli` command line. (`device_code`) + +```mermaid +sequenceDiagram + actor hu as John + #actor ro as Robot + participant pc as percli Command Line + participant rp as Perses Backend + participant op as External Identity Provider + + hu->>pc: EXEC: percli login + activate pc + pc->>rp: GET /api/config + activate rp + rp->>pc: 200: Config
(containing Providers List) + deactivate rp + pc->>hu: PROMPT: which provider? + deactivate pc + hu->>pc: select provider + activate pc + pc->>rp: GET /api/auth/providers/{oidc|oauth}/{slug_id}/device/code + activate rp + rp->>op: GET /oauth/device/code + activate op + op->>rp: 200: Device Code + User Code + Verification URL + deactivate op + rp->>pc: 200: Device Code + User Code + Verification URL + pc->>hu: PRINT: User Code + Verification URL (clickable) + rect rgba(66, 95, 237, 0.2) + Note over hu, op: Through the browser + hu->>op: Go to Verification URL + enter User Code + activate op + op->>hu: 302: Redirect to Authorization prompt + hu->>op: Consent + op->>op: Mark device as authorized + op->>hu: 200: Invite to close browser + deactivate op + end + Note over hu, op: Meanwhile, percli is polling the following endpoint, until it succeed. + pc->>rp: GET /api/auth/providers/{oidc|oauth}/{slug_id}/token + activate rp + alt OIDC + rp->>op: GET /oauth/token + activate op + op->>rp: 200: id_token & access_token + deactivate op + rp->>op: GET /api/userinfo
(endpoint from .well-known URL) + activate op + op->>rp: 200: User Info + deactivate op + Note right of rp: User Info + id token are
used to sync user in database + rp->>rp: Create or Update user in DB + else OAUTH 2.0 + rp->>op: GET /oauth/token + activate op + op->>rp: 200: access_token + deactivate op + rp->>op: GET /api/userinfo
(endpoint from Perses Config) + activate op + op->>rp: 200: User Info + deactivate op + Note right of rp: Only User Info is
used to sync user in database + rp->>rp: Create or Update user in DB + end + Note right of rp: A new session is created
with a new signed acces_token+refresh_token + rp->>pc: 200: access_token + refresh_token + deactivate rp + pc->>pc: WRITE: session into config file + pc->>hu: PRINT: Successfully authenticated! + deactivate pc + hu->>pc: EXEC: percli get projects + activate pc + pc->>rp: GET /api/v1/projects + activate rp + rp->>rp: Verify token and permissions + rp->>pc: 200: Projects list + deactivate rp + pc->>hu: PRINT: Projects list + deactivate pc +``` + +#### Login from external OIDC or OAuth2.0 provider with non-interactive flow. (`client_credentials`) + +> Note: it can be done exactly the same way using directly the backend API. +> Then one would have to manage the access_token and refresh_token by itself, and send access_token as an Authorization header +> in the subsequent requests. + +```mermaid +sequenceDiagram + participant ro as Robot + #actor ro as Robot + participant pc as percli Command Line + participant rp as Perses Backend + participant op as External Identity Provider + + ro->>pc: EXEC: percli login --provider --client-id --client-secret + activate pc + pc->>rp: GET /api/config + activate rp + rp->>pc: 200: Config
(containing Providers List) + deactivate rp + pc->>rp: GET /api/auth/providers/{oidc|oauth}/{slug_id}/token + activate rp + rp->>op: GET /oauth/token + activate op + op->>rp: 200: access_token + deactivate op + rp->>op: GET /api/userinfo
(endpoint from Perses Config or .well-known URL) + activate op + op->>rp: 200: User Info + deactivate op + Note right of rp: Only User Info is
used to sync user in database + rp->>rp: Create or Update user in DB + Note right of rp: A new session is created
with a new signed acces_token+refresh_token + rp->>pc: 200: access_token + refresh_token + deactivate rp + pc->>pc: WRITE: session into config file + pc->>ro: PRINT: Successfully authenticated! + deactivate pc + ro->>pc: EXEC: percli get projects + activate pc + pc->>rp: GET /api/v1/projects + activate rp + rp->>rp: Verify token and permissions + rp->>pc: 200: Projects list + deactivate rp + pc->>ro: PRINT: Projects list + deactivate pc +``` \ No newline at end of file diff --git a/docs/docs/design/authorization.md b/docs/docs/design/authorization.md new file mode 100644 index 0000000..02415f6 --- /dev/null +++ b/docs/docs/design/authorization.md @@ -0,0 +1,114 @@ +Perses will use a Role-based access control (RBAC) for regulating access to resources based on the role of the user. +The RBAC API is based on four kinds of resource: GlobalRole, Role, GlobalRoleBinding and RoleBinding. +Perses RBAC implementation is highly inspired by K8S RBAC implementation. + +## Role and GlobalRole + +An RBAC `Role` or `GlobalRole` contains a set of permissions (rules). Permissions are purely additive (there are no "deny" permissions). + +A `Role` defines a set of permissions within a particular project. When you create a `Role` you need to specify the project it belongs in. +`GlobalRole`, by contrast, is not limited to a project scope. + +### Role example + +Here is an example of Role in "MySuperProject" project that can be used to grant edit access to dashboards: + +```yaml +kind: Role +metadata: + name: dashboard-editor + project: MySuperProject +spec: + permissions: + - actions: ["edit"] + scopes: ["Dashboard"] +``` + +### Global Role example + +A `GlobalRole` can be used to grant the same permissions as a Role. However, because `GlobalRole` are global, you can also use them to grant access to: +- global resources (like Global Datasources, Global Variables, Users, ...) +- project resources (like Dashboards) across all projects + +Here is an example of a `GlobalRole` that can be used to grant edit access to variables in all projects: + +```yaml +kind: GlobalRole +metadata: + name: variable-editor +spec: + permissions: + - actions: ["edit"] + scopes: ["Variable"] +``` + +## RoleBinding and GlobalRoleBinding + +A role binding grants the permissions defined in a role to a user or set of users. +It holds a list of subjects (users or teams) and a reference to the role being granted. A `RoleBinding` grants permissions within a specific project whereas a `GlobalRoleBinding` grants that access global-wide. + +A `RoleBinding` may reference any `Role` in the same project. Similarly, a `GlobalRoleBinding` can reference any `GlobalRole`. + +### RoleBinding example + +Here is an example of a `RoleBinding` that grants the "dashboard-editor" `Role` to the user "jane" within the "MySuperProject" project. This allows "jane" to edit dashboards in the "MySuperProject" project. + +```yaml +kind: RoleBinding +metadata: + name: edit-dashboards + project: MySuperProject +spec: + role: dashboard-editor + subjects: + - kind: User + name: jane +``` + +### GlobalRoleBinding example + +Here is an example of a `GlobalRoleBinding` that grants the "variable-editor" `GlobalRole` to the user "jane" within all projects. This allows "jane" to edit variables in all projects. + +```yaml +kind: GlobalRoleBinding +metadata: + name: edit-variables +spec: + role: variable-editor + subjects: + - kind: User + name: jane +``` + +### RoleBinding and GlobalRoleBinding update restriction + +After you create a binding, you cannot change the `Role` or `GlobalRole` that it refers to. If you try to change a binding's role, you get a validation error. If you do want to change the role for a binding, you need to remove the binding object and create a replacement. + +There are two reasons for this restriction: +- Making role immutable allows granting someone update permission on an existing binding object, so that they can manage the list of subjects, without being able to change the role that is granted to those subjects. +- A binding to a different role is a fundamentally different binding. Requiring a binding to be deleted/recreated in order to change the role reference ensures the full list of subjects in the binding is intended to be granted the new role (as opposed to enabling or accidentally modifying only the role reference without verifying all of the existing subjects should be given the new role's permissions). + +## Referring to resources + +In Perses API, resources are identified and accessed using a string, corresponding to the name in the metadata. You can also refer to all resources using the wildcard `*` character. +Here is an example for granting edit permissions to all resources in all projects: + +```yaml +kind: GlobalRole +metadata: + name: admin-editor +spec: + permissions: + - actions: ["edit"] + scopes: ["*"] +``` + +## RBAC Synchronization + +Roles and RoleBindings of an user are stored in the user's JWT. +If Perses is deployed with multiple instances, Perses RBAC roles and role bindings cache need to be synchronized/replicated between all instances. +To do that there are multiple mechanisms: +- cache is refreshed every X minutes +- cache is refreshed if roles and role bindings retrieve from the user's JWT are different from the cache +- cache is refreshed when a new role is created, edited or deleted +- cache is refreshed when a new rolebinding is created, edited or deleted \ No newline at end of file diff --git a/docs/docs/design/kubernetes.md b/docs/docs/design/kubernetes.md new file mode 100644 index 0000000..9c44226 --- /dev/null +++ b/docs/docs/design/kubernetes.md @@ -0,0 +1,81 @@ +This document aims to describe our vision about how Perses will work on kubernetes. + +## 1. Database schema of Perses (outside kubernetes) + +For the moment we are using ETCD as a primary database for Perses and our documents have the same fields as in +Kubernetes resources a.k.a `kind`/`metadata`/`spec`. + +Using etcd and using the same fields as Kubernetes will help to have Perses natively installed on Kubernetes. + +``` + Perses database model Kubernetes (light) database model + + │ + │ + ┌───────────┐ │ ┌───────────┐ + │ │ │ │ │ + ┌───────────► Project ◄────────────┐ │ ┌───────────► Namespace ◄────────────┐ + │ │ │ │ │ │ │ │ │ + │ └─────▲─────┘ │ │ │ └─────▲─────┘ │ + │ │ │ │ │ │ │ +┌── ─ ─ ──┼── ─ ─ ─ ─ ─ ─ ──┼── ─ ─ ─ ─ ─ ─ ─ ─┼─ ─ ─ ─ ─┐ │ ┌── ─ ─ ──┼── ─ ─ ─ ─ ─ ─ ──┼── ─ ─ ─ ─ ─ ─ ─ ─┼─ ─ ─ ─ ─┐ +│ │ │ │ │ │ │ │ │ │ │ +│ ┌─────┴─────┐ ┌─────┴─────┐ ┌──────┴────┐ │ │ │ ┌─────┴─────┐ ┌─────┴─────┐ ┌──────┴────┐ │ +│ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ +│ │ Datasource│ │ Folder ├─────► Dashboard │ │ │ │ │ Pod │ │ Deployment│ │ Secrets │ │ +│ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ +│ └─────▲─────┘ └───────────┘ └─────┬─────┘ │ │ │ └───────────┘ └───────────┘ └───────────┘ │ +│ │ │ │ │ │ │ +│ │ │ │ │ │ ┌─────────┐ │ +│ │ │ │ │ │ │ ..etc. │ │ +│ └───────────────────────────────────┘ │ │ │ │ │ │ +│ │ │ │ └─────────┘ │ +│ Project Scope │ │ │ Namespace scope │ +└─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ──┘ │ └─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ──┘ + │ + │ + │ +``` + +With no big surprise, we can see that the Perses database model looks like the one from Kubernetes. + +## 2. Document Mapping + +On k8s native, the resource `Project` will be a direct mapping to the k8s resource `Namespace`. + +Others resources such as `Dashboard` or `Folder` would remain the same and installed through CRDs. + +## 3. How does it work for the backend + +In this particular context, the Perses backend is a simple proxy to the k8s API, and will be entirely in read only. That +means no user will be able to edit a dashboard through the Perses UI. + +### 3.1 Perses backend is using the user token + +The user will have to be logged in the k8s API and the UI will use the k8s token to talk with the Perses backend. The +backend will then use the user token when requesting the k8s API. + + + +Note 1: to be entirely in read only, any write endpoint will be deactivated, so even if the user is able to write in its +own namespace, he won't be able to use the Perses API to rewrite a dashboard in his namespace. It's because in this +context, the dashboard(s) is(are) deployed as long as the rest of the application. So you are likely in devops mod and +your deployment is in a git repository (certainly as a helm chart). + +Note 2: in this configuration, user won't be able to see others dashboards if he does not have the right to see other +namespaces / dashboards across namespace. It can happen you would like to share the dashboards to all users. + +### 3.2 Perses backend will use a dedicated token + +Lets imaging you are an SRE in a private company providing the monitoring platform to all your colleagues, they will +need to have full access to every dashboard in order to investigate easily. + +To be able to achieve that with the configuration described in 3.1, that means you will have to give a full read access +to every namespace in the k8s cluster. Likely it won't happen since security and the team in charge of k8s will give you +only access to the namespaces you are in charge of and nothing more. + +So using the user token won't work. To tackle this use case, Perses backend will simply need a personal token that will +give it full access to every Perses resources (in readonly). So everytime the user will make a request to the Perses +API, it will forward the request to the k8s API using a secret token. + + \ No newline at end of file diff --git a/docs/docs/index.md b/docs/docs/index.md new file mode 100644 index 0000000..fb8e39b --- /dev/null +++ b/docs/docs/index.md @@ -0,0 +1,61 @@ +# Introduction + +This section introduces you to the Perses project and provides you with an understanding of its role in the CoreDash +community. + +## Under the CoreDash umbrella + +CoreDash is a centralized effort to define a standard for visualization and dashboards. It's designed as an umbrella +project owned by the Linux Foundation to host sub-project efforts like Perses. For more information on the CoreDash +project: + +- [CoreDash community overview](https://github.com/coredashio/community) + +- [CoreDash contributing guide](https://github.com/coredashio/community/blob/main/CONTRIBUTING.md) + +- [CoreDash subprojects](https://github.com/coredashio/community/blob/main/subprojects.md) + +## What is the Perses project? + +Perses is an exploration into finding an open source standard for visualization and dashboards for metrics monitoring. +Also part of the Linux Foundation with plans to promote to Cloud Native Computing Foundation (CNCF). Some links to +explore: + +- [Perses project overview](https://github.com/perses/perses) + +- [Perses contributing guide](https://github.com/perses/perses/blob/main/CONTRIBUTING.md) + +## Perses project goals + +The project has guiding goals for its development: + +1. Become an open standard dashboard visualization tool + + - have well defined dashboard definition model + + - GitOps compatible for dashboard-as-code workflows + + - Perses runs locally, edit dashboard JSON file in Git + +2. Provide embeddable charts and dashboards in any user interface + + - provide different NPM packages + + - example usage could be to improve graph display in Prometheus (or embed) + +3. Target Kubernetes (k8s) native mode + + - dashboard defs deployed into & read from app namespaces (CRDs) + +4. Provide complete static validation for CI/CD pipelines + + - Provide command line client: percli + +5. Architecture supporting future plugins + +## Chat with Perses project team? + +You can find the project team on Matrix in the #perses-dev channel, see the [contributing guide](https://github.com/perses/perses/blob/main/CONTRIBUTING.md) +for details. + +Matrix dev channel \ No newline at end of file diff --git a/docs/docs/plugins/cue.md b/docs/docs/plugins/cue.md new file mode 100644 index 0000000..6815511 --- /dev/null +++ b/docs/docs/plugins/cue.md @@ -0,0 +1,153 @@ +Perses comes with validation capabilities based on [CUE](https://cuelang.org/), a powerful validation language that permitted us to move the type constraints out of Golang (static language), which in the end makes it possible to modify at runtime the list of objects that Perses can accept. More concretely, this allows Perses to support new kinds of charts and/or datasources dynamically, in the form of plugins written in CUE. + +## Writing plugins + +This section explains about the format any plugin should follow to be accepted & registered by Perses at runtime. + +### Variable + +A variable plugin looks like the following: + +```cue +package model + +kind: "" // e.g kind: "PrometheusLabelValuesVariable" +spec: close({ + labelName: string + matchers: [...string] +}) +``` + +it should define: +- the `model` package, +- the variable's `kind`, +- the variable's `spec` containing any field you want for this variable plugin. + +### Panel + +A panel plugin looks like the following: + +```cue +package model + +kind: "" // e.g kind: "TimeSeriesChart", +spec: { + queries: [...#ts_query] + legend?: #legend + format?: common.#format + thresholds?: common.#thresholds +} +``` + +it should define: +- the `model` package, +- the panel's `kind`, +- the panel's `spec` containing any field you want for this panel plugin. + +### Query + +A query plugin looks like the following: + +```cue +package model + +kind: "" // e.g kind: "PrometheusTimeSeriesQuery" +spec: { + datasource: { + kind: "" // e.g kind: "PrometheusDatasource" + } + query: string + minStep?: =~"^(?:(\\d+)y)?(?:(\\d+)w)?(?:(\\d+)d)?(?:(\\d+)h)?(?:(\\d+)m)?(?:(\\d+)s)?(?:(\\d+)ms)?$" + resolution?: number +} +``` + +it should define: +- the `model` package, +- the query's `kind`, +- the query's `spec` containing: + - a `datasource` field that holds the `kind` of datasource corresponding to this query type, + - any other field you want for this query plugin. + +## Migration from Grafana + +A Perses plugin can optionally embed a `migrate.cue`\* file at its root, that is basically describing in CUE language how to convert a given Grafana object into an instance of this plugin. In such case your plugin is considered as the Perses equivalent of this Grafana object type, i.e it will be used as part of the translation process when a Grafana dashboard is received on the `/api/migrate` endpoint. + +*\* this is mandatory to have it named that way. We put in place this constraint because it makes sense to have a single file containing the remapping logic, with the benefit of making the backend logic easier (no need to search for the file). It's also easier to check the migration file of the different plugins, because you know which one to look for.* + +*:warning: If ever you come to the situation where you have 2 or more plugins describing a migration logic for the same Grafana panel type, be aware that the first one encountered by alphabetical order will take priority.* + +### Variable + +A variable migration file looks like the following: + +```cue +if #var.type == "custom" || #var.type == "interval" { + kind: "StaticListVariable" + spec: { + values: strings.Split(#var.query, ",") + } +}, +``` + +- The file is named `migrate.cue`. +- The file content is made of **one or more conditional block(s)**, separated by commas (even if you have only one). +- Each conditional block defines one or more matches on attributes from the `#var` definition. + - `#var` references a variable object from Grafana. You can access the different fields with like `#var.field.subfield`. To know the list of fields available, check the Grafana datamodel for the considered variable type (from Grafana repo, or by inspecting the JSON of the dashboard on the Grafana UI). + - You most certainly want a check on the `#var.type` value like shown in above example. +- Each conditional block contains a list of fields & assignments, meeting the requirements of the considered Perses variable plugin. Use the `#var.field.subfield` syntax to access the values from the Grafana variable, thus achieve its remapping into Perses. + +### Panel + +A panel migration file looks like the following: + +```cue +if #panel.type == "timeseries" || #panel.type == "graph" { + kind: "TimeSeriesChart" + spec: { + legend: { + position: #panel.options.legend.placement + } + } +}, +``` + +- The file is named `migrate.cue`. +- The file content is made of **one or more conditional block(s)**, separated by commas (even if you have only one). +- Each conditional block defines one or more matches on attributes from the `#panel` definition. + - `#panel` references a panel object from Grafana. You can access the different fields with like `#panel.field.subfield`. To know the list of fields available, check the Grafana datamodel for the considered panel type (from Grafana repo, or by inspecting the JSON of the dashboard on the Grafana UI). + - You most certainly want a check on the `#panel.type` value like shown in above example. +- Each conditional block contains a list of fields & assignments, meeting the requirements of the considered Perses panel plugin. Use the `#panel.field.subfield` syntax to access the values from the Grafana panel, thus achieve its remapping into Perses. + +#### Utilities + +There are some utilities that you can use in your plugin migration logic: + +- `#mapping.unit`: mapping table for the `unit` attribute (key = grafana unit, value = perses equivalent). +- `#mapping.calc`: mapping table for the `calculation` attribute (key = grafana unit, value = perses equivalent). +- `#mapping.sort`: mapping array for the sort attribute (index = grafana sort id, value = perses equivalent). +- `#defaultCalc`: standard default value for the `calculation` attribute. + +### Query + +A query migration file looks like the following: + +```cue +if #target.datasource.type != _|_ if #target.datasource.type == "prometheus" { + kind: "PrometheusTimeSeriesQuery" + spec: { + datasource: { + kind: "PrometheusDatasource" + name: #target.datasource.uid + } + query: #target.expr + } +}, +``` + +- The file is named `migrate.cue`. +- The file content is made of **one or more conditional block(s)**, separated by commas (even if you have only one). +- Each conditional block defines one or more matches on attributes from the `#target` definition. + - `#target` references a target object from Grafana. You can access the different fields with like `#target.field.subfield`. To know the list of fields available, check the Grafana datamodel for the targets (from Grafana repo, or by inspecting the JSON of the dashboard on the Grafana UI). + - You most certainly want a check on the `#target.datasource.type` value like shown in above example. +- Each conditional block contains a list of fields & assignments, meeting the requirements of the considered Perses query plugin. Use the `#target.field.subfield` syntax to access the values from the Grafana target, thus achieve its remapping into Perses. \ No newline at end of file diff --git a/docs/docs/plugins/index.md b/docs/docs/plugins/index.md new file mode 100644 index 0000000..ceba5c3 --- /dev/null +++ b/docs/docs/plugins/index.md @@ -0,0 +1,20 @@ +In Perses, the following object types are available as plugins: + +* Panel +* Datasource +* Query +* Variable + +The objective with this is to eventually empower users to seamlessly enhance Perses' native capabilities through custom plugins, allowing them to: + +* Add panel plugins for more diverse data visualization options. See [Panel plugins](./panels.md) for more details. +* Add datasource plugins to access data from new types of sources. +* Add query plugins to retrieve data from supported sources in additional ways. +* Add variable plugins to build variables for supported sources in additional ways. + +While Panel plugins are relatively self-sufficient, a datasource plugin requires one or more corresponding query and/or variable plugin to be actually usable, and vice versa. For instance, the native support for Prometheus is essentially a comprehensive package that includes all three types of plugins. For more details, refer to [Prometheus-related plugins](./prometheus.md). + +Also, any plugin is made of two parts: + +* The "backend" part, which is the CUE schema that defines the model for the plugin and is used by Perses' backend for validation. Please refer to [CUE in Perses](./cue.md) for more details. +* The "frontend" part, a.k.a all the frontend code responsible of bringing the plugin to life in the Perses UI. \ No newline at end of file diff --git a/docs/docs/plugins/panelplugins.md b/docs/docs/plugins/panelplugins.md new file mode 100644 index 0000000..cac594d --- /dev/null +++ b/docs/docs/plugins/panelplugins.md @@ -0,0 +1,206 @@ +This documentation provides an exhaustive list of the panel plugins supported by Perses. + +## BarChart + +```yaml +kind: "BarChart" +spec: + calculation: + [ format: ] + [ sort: ] + [ mode: ] +``` + +## GaugeChart + +```yaml +kind: "GaugeChart" +spec: + calculation: + [ format: ] + [ thresholds: ] + [ max: ] +``` + +## Markdown + +```yaml +kind: "Markdown" +spec: + text: +``` + +## StatChart + +```yaml +kind: "StatChart" +spec: + calculation: + [ format: ] + [ thresholds: ] + [ sparkline: ] + [ valueFontSize: ] +``` + +### Sparkline specification + +```yaml +[ color: ] +[ width: ] +``` + +## ScatterChart + +```yaml +kind: "ScatterChart" +spec: # TODO document the spec of ScatterChart +``` + +## TimeSeriesChart + +```yaml +kind: "TimeSeriesChart" +spec: + [ legend: ] + [ tooltip: ] + [ yAxis: ] + [ thresholds: ] + [ visual: ] + querySettings: + - [ ] +``` + +### Legend specification + +```yaml +position: +[ mode: ] +[ size: ] +values: + - [ ] +``` + +### Tooltip specification + +```yaml +[ enablePinning: ] +``` + +### YAxis specification + +```yaml +[ show: ] +[ label: ] +[ format: ] +[ min: ] +[ max: ] +``` + +### Visual specification + +```yaml +[ display: ] +# Must be between 0.25 and 3 +[ lineWidth: ] +# Must be between 0 and 1 +[ areaOpacity: ] +[ showPoints: ] +[ palette: ] +# Must be between 0 and 6 +[ pointRadius: ] +[ stack: ] +[ connectNulls: boolean | default = false ] +``` + +#### Palette specification + +```yaml +mode: +``` + +### Query Settings specification + +```yaml +# queryIndex is an unsigned integer that should match an existing index in the panel's `queries` array +queryIndex: +# colorMode represents the coloring strategy to use +# - "fixed": for any serie returned by the query, apply the colorValue defined +# - "fixed-single": if only one serie returned by the query, apply the colorValue defined, otherwise do nothing +colorMode: +# colorValue is an hexadecimal color code +colorValue: +``` + +## Common definitions + +### Calculation specification + +It's an enum. Possible values are: + +- `first` +- `last` +- `first-number` +- `last-number` +- `mean` +- `sum` +- `min` +- `max` + +### Format specification + +The format spec is one of the following: + +#### Time format + +```yaml +unit: +[ decimalPlaces: ] +``` + +#### Percent format + +```yaml +unit: +[ decimalPlaces: ] +``` + +#### Decimal format + +```yaml +unit: "decimal" +[ decimalPlaces: ] +[ shortValues: | default = false ] +``` + +#### Bytes format + +```yaml +unit: "bytes" +[ decimalPlaces: ] +[ shortValues: | default = false ] +``` + +#### Throughput format + +```yaml +unit: < enum = "counts/sec" | "events/sec" | "messages/sec" | "ops/sec" | "packets/sec" | "reads/sec" | "records/sec" | "requests/sec" | "rows/sec" | "writes/sec"> +[ decimalPlaces: ] +[ shortValues: | default = false ] +``` + +### Thresholds specification + +```yaml +[ mode: ] +[ defaultColor: string ] +steps: + - [ ] +``` + +#### Step specification + +```yaml +value: +[ color: ] +[ name: ] +``` \ No newline at end of file diff --git a/docs/docs/plugins/prometheusplugins.md b/docs/docs/plugins/prometheusplugins.md new file mode 100644 index 0000000..9dda4fd --- /dev/null +++ b/docs/docs/plugins/prometheusplugins.md @@ -0,0 +1,287 @@ +This documentation provides the definition of the different plugins related to Prometheus. + +## Datasource + +```yaml +kind: "PrometheusDatasource" +spec: +``` + +### Plugin Specification + +Prometheus as a datasource is basically an HTTP server. So we need to define an HTTP config. + +```yaml +# It is the url of the datasource. +# Leave it empty if you don't want to access the datasource directly from the UI. +# You should define a proxy if you want to access the datasource through the Perses' server. +[ directUrl: ] + +# It is the http configuration that will be used by the Perses' server to redirect to the datasource any query sent by the UI. +[ proxy: ] + +[ scrapeInterval: ] +``` + +#### HTTP Proxy specification + +```yaml +kind: "HTTPProxy" +spec: + # URL is the url of datasource. It is not the url of the proxy. + url: + + # It is a tuple list of http methods and http endpoints that will be accessible. + # Leave it empty if you don't want to restrict the access to the datasource. + allowedEndpoints: + - [ ] + + # It can be used to provide additional headers that need to be forwarded when requesting the datasource + headers: + [ : ] + + # This is the name of the secret that should be used for the proxy or discovery configuration + # It will contain any sensitive information such as password, token, certificate. + # Please read the documentation about secrets to understand how to create one + [ secret: ] +``` + +##### Allowed Endpoints specification + +```yaml +endpointPattern: +method: +``` + +### Example + +A simple Prometheus datasource would be + +```yaml +kind: "Datasource" +metadata: + name: "PrometheusDemo" + project: "perses" +spec: + default: true + plugin: + kind: "PrometheusDatasource" + spec: + directUrl: "https://prometheus.demo.do.prometheus.io" +``` + +A more complex one: + +```yaml +kind: "Datasource" +metadata: + name: "PrometheusDemo" + project: "perses" +spec: + default: true + plugin: + kind: "PrometheusDatasource" + spec: + proxy: + kind: "HTTPProxy" + spec: + url: "https://prometheus.demo.do.prometheus.io" + allowedEndpoints: + - endpointPattern: "/api/v1/labels" + method: "POST" + - endpointPattern: "/api/v1/series" + method: "POST" + - endpointPattern: "/api/v1/metadata" + method: "GET" + - endpointPattern: "/api/v1/query" + method: "POST" + - endpointPattern: "/api/v1/query_range" + method: "POST" + - endpointPattern: "/api/v1/label/([a-zA-Z0-9_-]+)/values" + method: "GET" + secret: "prometheus_secret_config" +``` + +## Query + +Perses currently supports only one kind of query for Prometheus: `PrometheusTimeSeriesQuery`. Others will come in the future. + +```yaml +kind: "PrometheusTimeSeriesQuery" +spec: +``` + +### Timeseries Query specification + +```yaml +#`query` is the promQL expression. +query: + +# `datasource` is a datasource selector. If not provided, the default PrometheusDatasource is used. +# See the documentation about the datasources to understand how it is selected. +[ datasource: ] +[ seriesNameFormat: ] + +# `minStep` is the minimum time interval you want between each data points. +[ minStep: ] +[ resolution: number ] +``` + +#### Example + +A simple one: + +```yaml +kind: "TimeSeriesQuery" +spec: + plugin: + kind: "PrometheusTimeSeriesQuery" + spec: + query: "rate(caddy_http_response_duration_seconds_sum[$interval])" +``` + +## Variable + +### PrometheusLabelNamesVariable + +```yaml +kind: "PrometheusLabelNamesVariable" +spec: +``` + +#### Prometheus Label Names specification + +```yaml +# `datasource` is a datasource selector. If not provided, the default PrometheusDatasource is used. +# See the documentation about the datasources to understand how it is selected. +[ datasource: ] +matchers: + [ - ] +``` + +#### Example + +A simple Prometheus LabelNames variable would be + +```yaml +kind: "Variable" +metadata: + name: "labelNames" + project: "perses" +spec: + kind: "ListVariable" + spec: + plugin: + kind: "PrometheusLabelNamesVariable" +``` + +A more complex one + +```yaml +kind: "Variable" +metadata: + name: "labelNames" + project: "perses" +spec: + kind: "ListVariable" + spec: + allowMultiple: false + allowAllValue: false + plugin: + kind: "PrometheusLabelNamesVariable" + spec: + datasource: + kind: "PrometheusDatasource" + name: "PrometheusDemo" + matchers: + - "up" +``` + +### PrometheusLabelValuesVariable + +```yaml +kind: "PrometheusLabelValuesVariable" +spec: +``` + +#### Prometheus Label Values specification + +```yaml +# `datasource` is a datasource selector. If not provided, the default PrometheusDatasource is used. +# See the documentation about the datasources to understand how it is selected. +[ datasource: ] +labelName: +matchers: + [ - ] +``` + +#### Example + +A simple Prometheus LabelValues variable would be + +```yaml +kind: "Variable" +metadata: + name: "job" + project: "perses" +spec: + kind: "ListVariable" + spec: + allowMultiple: false + allowAllValue: false + plugin: + kind: "PrometheusLabelValuesVariable" + spec: + labelName: "job" +``` + +A more complex one + +```yaml +kind: "Variable" +metadata: + name: "instance" + project: "perses" +spec: + kind: "ListVariable" + spec: + allowMultiple: false + allowAllValue: false + plugin: + kind: "PrometheusLabelValuesVariable" + spec: + datasource: + kind: "PrometheusDatasource" + name: "PrometheusDemo" + labelName: "instance" + matchers: + - "up{job=~\"$job\"}" +``` + +### PrometheusPromQLVariable + +```yaml +kind: "PrometheusPromQLVariable" +spec: +``` + +#### Prometheus PromQL specification + +```yaml +# `datasource` is a datasource selector. If not provided, the default PrometheusDatasource is used. +# See the documentation about the datasources to understand how it is selected. +[ datasource: ] + +# The promql expression +expr: +[ labelName: ] +``` + +### Datasource selector + +```yaml +kind: "PrometheusDatasource" + +# The name of the datasource regardless its level +[ name: ] +``` \ No newline at end of file diff --git a/docs/docs/tooling/index.md b/docs/docs/tooling/index.md new file mode 100644 index 0000000..3db62f4 --- /dev/null +++ b/docs/docs/tooling/index.md @@ -0,0 +1,5 @@ +Tooling related to Perses will be listed here. + +## Perses CLI (percli) + +See [percli](percli.md) \ No newline at end of file diff --git a/docs/docs/tooling/percli.md b/docs/docs/tooling/percli.md new file mode 100644 index 0000000..bfb4d10 --- /dev/null +++ b/docs/docs/tooling/percli.md @@ -0,0 +1,334 @@ +# Perses CLI (percli) + +On top of the application, we also provide a CLI named `percli`. This tool can be used to interact with the backend REST +API to manage the resources such as dashboards, datasources, projects, etc. + +The CLI is available in the docker image or in the archive we created during each release. + +## Tips + +This CLI provides its own documentation using the --help option. This is the main source of truth for documentation, +while this page is here to provide some examples of how to use the main commands, tips & tricks, etc. + +Example: + +```bash +$ percli --help + +Command line interface to interact with the Perses API + +Usage: + percli [command] + +Available Commands: + apply Create or update resources through a file. JSON or YAML format supported + completion Generate the autocompletion script for the specified shell + config display local or remote config + dac Commands related to Dashboard-as-Code + delete Delete resources + describe Show details of a specific resource + get Retrieve any kind of resource from the API. + help Help about any command + lint Static check of the resources + login Log in to the Perses API + migrate migrate a Grafana dashboard to the Perses format + project Select the project used by default. + refresh refresh the access token when it expires + version Display client version. + whoami Display current user used + +Flags: + -h, --help help for percli + --log.level string Set the log verbosity level. Possible values: panic, fatal, error, warning, info, debug, trace (default "info") + --percliconfig string Path to the percliconfig file to use for CLI requests. (default "/Users/ahusson/.perses/config.json") + +Use "percli [command] --help" for more information about a command. +``` + +## Getting started + +### Login + +Most of the command required a connexion to the Perses API. So the first thing you should do is to use the `login` +command. + +The only parameter required to use this command is the URL to the API. + +```bash +$ percli login https://demo.perses.dev +``` + +If the server requires an authentication, you will have to provide either: + +- a token: `--token` can be used to set a Bearer JWT token. +- a user + password: `--username` and `--password` can be used to set a username & password. The command will contact the Perses server + with the credential(s). It will return a Bearer JWT token which expires after 1h. +- delegated auth information: if the server relies on an external OIDC/OAuth provider for authentication, use `--client-id` and `--client-secret` to pass the client credentials, plus `--provider` to pass the identifier of the external provider (e.g `google`, `azure`..). + +The URL and the token will be stored in JSON file that is by default `/.perses/config.json`. + +Note: you can change the location of this file using the global flag `--percliconfig`. + +### Project + +Most of the data belong to a project. You can see a project as a workspace where you will be able to create some +dashboards or datasources. + +#### Get the list of your projects + +To know what are the existing project, you can use the following command: + +```bash +$ percli get project + + NAME | AGE +--------------------+---------- + IncredibleProject | 106751d + perses | 106751d +``` + +#### Select the project + +The project to be used by default when running commands can be set with: + +```bash +$ percli project perses + +project perses selected +``` + +## Resource Management Commands + +### Apply data + +To create or update any data in the Perses API, you can use the `apply` command. This command can receive the data to +create/update from a file or from stdin. + +for example, if you want to create a project, you can proceed like that: + +```bash +project='{ + "kind": "Project", + "metadata": { + "name": "MyProject" + } +}' +echo ${project} | percli apply -f - + +object "Project" "MyProject" has been applied +``` + +### Get data + +To retrieve the data, you can use the `get` command : + +```bash +$ percli get project + + NAME | AGE +--------------------+---------- + IncredibleProject | 106751d + MyProject | 58s + perses | 106751d +``` + +```bash +$ percli get dashboard + + NAME | PROJECT | AGE +------------+---------+------ + Benchmark | perses | 3d + Demo | perses | 9d +``` + +**Note**: This command can be used with the --output flag to get the list either in Json or Yaml format. This +option can be used to export the resources into a file to mass update them. + +### Describe data + +The `describe` command allows you to print the complete definition of an object. By default, the definition will be +printed with the Yaml format, but you can print it using the Json format too. + +```bash +$ percli describe dts PrometheusDemo + +kind: Datasource +metadata: + name: PrometheusDemo + createdAt: 0001-01-01T00:00:00Z + updatedAt: 0001-01-01T00:00:00Z + project: perses +spec: + default: false + plugin: + kind: PrometheusDatasource + spec: + proxy: + kind: HTTPProxy + spec: + allowedEndpoints: + - endpointPattern: /api/v1/labels + method: POST + - endpointPattern: /api/v1/series + method: POST + - endpointPattern: /api/v1/metadata + method: GET + - endpointPattern: /api/v1/query + method: POST + - endpointPattern: /api/v1/query_range + method: POST + - endpointPattern: /api/v1/label/([a-zA-Z0-9_-]+)/values + method: GET + url: https://prometheus.demo.do.prometheus.io +``` + +Or in JSON: + +```bash +$ percli describe dts PrometheusDemo -ojson | jq + +{ + "kind": "Datasource", + "metadata": { + "name": "PrometheusDemo", + "createdAt": "0001-01-01T00:00:00Z", + "updatedAt": "0001-01-01T00:00:00Z", + "project": "perses" + }, + "spec": { + "default": false, + "plugin": { + "kind": "PrometheusDatasource", + "spec": { + "proxy": { + "kind": "HTTPProxy", + "spec": { + "allowedEndpoints": [ + { + "endpointPattern": "/api/v1/labels", + "method": "POST" + }, + { + "endpointPattern": "/api/v1/series", + "method": "POST" + }, + { + "endpointPattern": "/api/v1/metadata", + "method": "GET" + }, + { + "endpointPattern": "/api/v1/query", + "method": "POST" + }, + { + "endpointPattern": "/api/v1/query_range", + "method": "POST" + }, + { + "endpointPattern": "/api/v1/label/([a-zA-Z0-9_-]+)/values", + "method": "GET" + } + ], + "url": "https://prometheus.demo.do.prometheus.io" + } + } + } + } + } +} +``` + +### Delete data + +To remove a resource, you can use the `delete` command : + +```bash +$ percli delete dashboard Demo + +Dashboard Demo has been deleted +``` + +## Advanced Commands + +### Linter + +The CLI provides a command `lint` that is able to validate any data supported by Perses. + +Note that it doesn't necessary mean you won't face any issues when applying them. + +```bash +$ percli lint -f ./resource.json +``` + +By default, the command doesn't require any remote server. We are providing a flag `--online` that will tell the CLI to +use a remote Perses server for additional validation. For example, when it has to validate a dashboard, it will +use the endpoint `/api/validate/dashboards`. That can be useful if you want to be sure that your dashboard is compatible +with the server (because it will match the plugins known by the server instead of the local ones) + +### Migrate from Grafana dashboard to Perses format + +The command `migrate` is for the moment only used to translate a Grafana dashboard to the Perses format. This command +has two modes: + +1. An online mode that requires an active connection to a remote Perses server that holds the translation logic. +2. An offline mode that requires three different folders: + - charts folders + - queries folders + - variables folders + +Each of the above folders should contain a file named `migrate.cue`, that holds the logic of the migration for each +plugin. For more information about these files, please read the documentation about [CUE in Perses](../plugins/cue.md) + +In both modes, if the command runs successfully, it will return the dashboard in the Perses format. + +For example: + +```bash +$ percli migrate -f ./grafana_dashboard.json --online + +kind: Dashboard +metadata: + name: rYdddlPWk + createdAt: 0001-01-01T00:00:00Z + updatedAt: 0001-01-01T00:00:00Z + project: "" +spec: + display: + name: Node Exporter Full + duration: 1h + variables: + - kind: ListVariable + spec: + name: DS_PROMETHEUS + display: + name: datasource + hidden: false + allowAllValue: false + allowMultiple: false + plugin: + kind: StaticListVariable + spec: + values: + - grafana + - migration + - not + - supported + - kind: ListVariable + spec: + name: job + display: + name: Job + hidden: false + allowAllValue: false + allowMultiple: false + plugin: + kind: PrometheusLabelValuesVariable + spec: + labelName: job + matchers: [] +[...] +``` + +### Dashboard-as-Code + +The CLI also comes in handy when you want to create & manage dashboards as code. For this topic please refer to [DaC user guide](../user-guides/dashboard-as-code.md). \ No newline at end of file diff --git a/docs/docs/user-guides/configuration.md b/docs/docs/user-guides/configuration.md new file mode 100644 index 0000000..2c1e35d --- /dev/null +++ b/docs/docs/user-guides/configuration.md @@ -0,0 +1,620 @@ +# Configuration + +Perses is configured via command-line flags and a configuration file + +## Flags available + +```bash + -config string + Path to the yaml configuration file for the api. Configuration can be overridden when using the environment variable + -log.level string + log level. Possible value: panic, fatal, error, warning, info, debug, trace (default "info") + -log.method-trace + include the calling method as a field in the log. Can be useful to see immediately where the log comes from + -web.hide-port + If true, it won t be print on stdout the port listened to receive the HTTP request + -web.listen-address string + The address to listen on for HTTP requests, web interface and telemetry. (default ":8080") + -web.telemetry-path string + Path under which to expose metrics. (default "/metrics") +``` + +Example: + +```bash +perses --config=./config.yaml --log.method-trace +``` + +## Configuration File + +This service can be configured using a yaml file or the environment variable. + +Note: you can use both, environment variable will override the yaml configuration. + +```yaml +database: + file: # the configuration when you want to use the filesystem as a database. Note that you can configure it using the flags, which gives you the choice to not create a configuration file just for that. + folder: "/path/to/the/database/storage" # It's the path where the file will be read/ stored + extension: "yaml" # The extension of the files read / stored. "yaml" or "json" are the only extension accepted. Yaml is the default one +``` + +Note: to have the corresponding environment variable you just have to contact all previous key in the yaml and put it in +uppercase. Every environment variable for this config are prefixed by `PERSES` + +For example, the environment variable corresponding to the file extension of the file DB would be: + +```bash +PERSES_DATABASE_FILE_EXTENSION=yaml +``` + +### Definition + +The file is written in YAML format, defined by the scheme described below. Brackets indicate that a parameter is optional. + +Generic placeholders are defined as follows: + +* ``: a boolean that can take the values `true` or `false` +* ``: a duration matching the regular expression `((([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?|0)`, e.g. `1d`, `1h30m`, `5m`, `10s` +* ``: a valid path in the current working directory +* ``: a valid URL path +* ``: an integer value +* ``: a regular string that is a secret, such as a password +* ``: a regular string +* ``: a string that can take the values `Dashboard`, `Datasource`, `Folder`, `GlobalDatasource`, `GlobalRole`, `GlobalRoleBinding`, `GlobalVariable`, `GlobalSecret`, `Project`, `Role`, `RoleBinding`, `User` or `Variable` (not case-sensitive) + +```yaml +# Use it in case you want to prefix the API path. By default the API is served with the path /api. +# With this config, it will be served with the path /api +[ api_prefix: ] + +# It contains any configuration that changes the API behavior like the endpoints exposed or if the permissions are activated. +[ security: ] + +# Database configuration +[ database: ] + +# The configuration to access the CUE schemas +[ schemas: ] + +# If provided, Perses server will look to the different folders configured and populate the database based on what it is found +# Be careful: the data coming from the provisioning folder will totally override what exists in the database. +[ provisioning: ] + +# If provided, Perses server will generate a list of global datasource based on the discovery chosen. +# Be careful: the data coming from the discovery will totally override what exists in the database. +# Note that this is an experimental feature. Behavior and config may change in the future. +global_datasource_discovery: + [- ] + +# The interval at which to trigger the cleanup of ephemeral dashboards, based on their TTLs. +# This config is deprecated. Please use the config ephemeral_dashboard instead. +[ ephemeral_dashboards_cleanup_interval: ] + +# The config for the ephemeral dashboard feature. This is the way to activate the feature. +[ ephemeral_dashboard: < EphemeralDashboard config > ] + +# Any configuration related to the UI itself +[ frontend: | default = false ] + +# Cookie configuration +[ cookie: ] + +# It contains the config regarding the time to live of the refresh/access token. +[ authentication: ] + +# It contains any configuration that changes authorization behavior like default permissions +[ authorization: ] + +# When it is true, the authentication and authorization config are considered. +# And you will need a valid JWT token to contact most of the endpoints exposed by the API +[ enable_auth: | default = false ] + +# The secret key used to encrypt and decrypt sensitive data stored in the database such as the password of the basic auth for a datasource. +# Note that if it is not provided, it will use a default value. +# On a production instance, you should set this key. +# Also note the key size must be exactly 32 bytes long as we are using AES-256 to encrypt the data. +[ encryption_key: ] + +# The path to the file containing the secret key. +[ encryption_key_file: ] +``` + +### Cookie config + +```yaml +# Set the same_site cookie attribute and prevents the browser from sending the cookie along with cross-site requests. +# The main goal is to mitigate the risk of cross-origin information leakage. +# This setting also provides some protection against cross-site request forgery attacks (CSRF) +[ same_site: < enum | possibleValue = 'strict' | 'lax' | 'none' > | default = lax ] + +# Set to true if you host Perses behind HTTPS. Default is false +[ secure: | default = false ] +``` + +#### Authentication config + +```yaml +# It is the time to live of the access token. By default, it is 15 minutes. +[ access_token_ttl: | default = 15min ] + +# It is the time to live of the refresh token. The refresh token is used to get a new access token when it is expired. +# By default, it is 24 hours. +[ refresh_token_ttl: | default = 24h ] + +# With this attribute, you can deactivate the Sign-up page which induces the deactivation of the endpoint that gives the possibility to create a user. +[ disable_sign_up: | default = false ] + +# Authentication providers +[ providers: ] +``` + +##### Authentication providers + +Check the [helpers](./oauth-configuration-helpers.md) to help you to configure the different providers. + +```yaml +# Enable the native authentication providers +[ enable_native: | default = false ] + +# List of the OIDC authentication providers +oidc: + - [ ] +# List of the OIDC authentication providers +oauth: + - [ ] +``` + +##### OIDC provider + +```yaml +# The id of the provider that will be used in the URLs (must be unique for all providers) +slug_id: + +# A verbose name for the provider. Will be used to visually identify it in the frontend. +name: + +# The Client ID of the Perses application into the provider +client_id: + +# The Client Secret of the Perses application into the provider +client_secret: + +device_code: + # Allow to use a different Client ID for the device code flow + [ client_id: ] + # Allow to use a different Client Secret for the device code flow + [ client_secret: ] + +# The callback URL for authorization code (Have to be + /api/auth/providers/oidc/{slug}/callback) +# If not set it will get it from the request. +[ redirect_uri: ] + +# The needed scopes to authenticate a user in the provider. It's not mandatory because it will depend on the provider +scopes: + - [ ] + +# The provider issuer URL +issuer: + +# A custom discovery URL if different from {issuer}/.well-known/openid-configuration +[ discovery_url: ] + +# Disable PKCE verification +[ disable_pkce: | default = false ] + +# The additional url params that will be appended to /authorize provider's endpoint +url_params: + [ : [, ...] ] +``` + +##### OAuth provider + +```yaml +# The id of the provider that will be used in the URLs (must be unique for all providers) +slug_id: + +# A verbose name for the provider. Will be used to visually identify it in the frontend. +name: + +# The Client ID of the Perses application into the provider +client_id: + +# The Client Secret of the Perses application into the provider +client_secret: + +device_code: + # Allow using a different Client ID for the device code flow + [ client_id: ] + # Allow using a different Client Secret for the device code flow + [ client_secret: ] + # Allow using different Scopes for the device code flow + scopes: + - [ ] + +client_credentials: + # Allow using a different Client ID for the client credentials flow + [ client_id: ] + # Allow using a different Client Secret for the client credentials flow + [ client_secret: ] + # Allow using different Scopes for the client credentials flow + scopes: + - [ ] + +# The callback URL for authorization code (Have to be + /api/auth/providers/oidc/{slug}/callback) +[ redirect_uri: ] + +# The needed scopes to authenticate a user in the provider +scopes: + - [ ] + +# The provider Authorization URL +auth_url: + +# The provider Token URL +token_url: + +# The provider User Infos URL +user_infos_url: + +# The provider Device Auth URL +# If we want to use the device code flow, we need to provide this URL, otherwise an error will fire saying +# it's not supported. +[ device_auth_url: ] + +# Name of the property to get "login" from user infos API (if not in the default list ["login", "username"] ) +# The login is mandatory to store in the database the name of the user. +[ custom_login_property: ] +``` + +#### Authorization config + +```yaml +# Time interval that check if the RBAC cache need to be refreshed with db content. Only for SQL database setup. +[ check_latest_update_interval: | default = 30s ] + +# Default permissions for guest users (logged-in users) +guest_permissions: + - [ ] +``` + +##### Permissions + +```yaml +# Actions authorized by the permission +actions: + - +# Resource kinds that are concerned by the permission +scopes: + - +``` + +### Database config + +```yaml +# Config in case you want to use a file DB. +# Prefer the SQL config in case you are running multiple Perses instances. +[ file: ] + +# The SQL config +[ sql: ] +``` + +#### Database_file config + +```yaml +# The path to the folder containing the database +folder: + +# The file extension and so the file format used when storing and reading data from/to the database +[ extension: | default = yaml ] + +# Whether the database is case-sensitive. +# Be aware that to reflect this config, metadata.project and metadata.name from the resources managed can be modified before the insertion in the database. +[ case_sensitive: | default = false ] +``` + +#### Database SQL config + +```yaml +# TLS configuration. +[ tls_config: ] + +# Username used for the connection +[ user: ] + +# The password associated to the user. Mandatory if the user is set +[ password: ] + +# The path to a file containing a password +[ password_file: ] + +# Network type. For example "tcp" +[ net: ] + +# The network address. If set then `net` is mandatory. Example: "localhost:3306" +[ addr: ] + +# Database name +[ db_name: ] +[ collation: ] + +# Max packet size allowed +[ max_allowed_packet: ] + +# Server public key name +[ server_pub_key: ] + +# Dial timeout +[ timeout: ] + +# I/O read timeout +[ read_timeout: ] + +# I/O write timeout +[ write_timeout: ] + +# Allow all files to be used with LOAD DATA LOCAL INFILE +[ allow_all_files: | default = false ] + +# Allows the cleartext client side plugin +[ allow_cleartext_passwords: | default = false ] + +# Allows fallback to unencrypted connection if server does not support TLS +[ allow_fallback_to_plaintext: | default = false ] + +# Allows the native password authentication method +[ allow_native_passwords: | default = false ] + +# Allows the old insecure password method +[ allow_old_passwords: | default = false ] + +# Check connections for liveness before using them +[ check_conn_liveness: | default = false ] + +# Return number of matching rows instead of rows changed +[ client_found_rows: | default = false ] + +# Prepend table alias to column names +[ columns_with_alias: | default = false ] + +# Interpolate placeholders into query string +[ interpolate_params: | default = false ] + +# Allow multiple statements in one query +[ multi_statements: | default = false ] + +# Parse time values to time.Time +[ parse_time: | default = false ] + +# Reject read-only connections +[ reject_read_only: | default = false ] + +# Whether the database is case-sensitive. +# Be aware that to reflect this config, metadata.project and metadata.name from the resources managed can be modified before the insertion in the database. +[ case_sensitive: | default = false ] +``` + +### Schemas config + +```yaml +# Path to the Cue schemas of the panels +[ panels_path: | default = "schemas/panels" ] + +# Path to the Cue schemas of the queries +[ queries_path: | default = "schemas/queries" ] + +# Path to the Cue schemas of the datasources +[ datasources_path: | default = "schemas/datasources" ] + +# Path to the Cue schemas of the variables +[ variables_path: | default = "schemas/variables" ] + +# The refresh interval of the cue schemas regardless their paths +[ interval: | default = 1h ] +``` + +### TLS config + +A TLS config allows configuring TLS connections. + +```yaml +# CA certificate to validate API server certificate with. At most one of ca and ca_file is allowed. +[ ca: ] +[ ca_file: ] + +# Certificate and key for client cert authentication to the server. +# At most one of cert and cert_file is allowed. +# At most one of key and key_file is allowed. +[ cert: ] +[ cert_file: ] +[ key: ] +[ key_file: ] + +# ServerName extension to indicate the name of the server. +# https://tools.ietf.org/html/rfc4366#section-3.1 +[ server_name: ] + +# Disable validation of the server certificate. +[ insecure_skip_verify: ] + +# Minimum acceptable TLS version. Accepted values: TLS10 (TLS 1.0), TLS11 (TLS +# 1.1), TLS12 (TLS 1.2), TLS13 (TLS 1.3). +# If unset, Prometheus will use Go default minimum version, which is TLS 1.2. +# See MinVersion in https://pkg.go.dev/crypto/tls#Config. +[ min_version: ] +# Maximum acceptable TLS version. Accepted values: TLS10 (TLS 1.0), TLS11 (TLS +# 1.1), TLS12 (TLS 1.2), TLS13 (TLS 1.3). +# If unset, Prometheus will use Go default maximum version, which is TLS 1.3. +# See MaxVersion in https://pkg.go.dev/crypto/tls#Config. +[ max_version: ] +``` + +### Provisioning config + +```yaml +[ interval: | default = 1h ] + +# List of folder that Perses will read periodically. +# Every known data found in the different folders will be injected in the database regardless what exist. +folders: + - +``` + +### GlobalDatasourceDiscovery config + +```yaml +# The name of the discovery config. It is used for logging purposes only +discovery_name: + +# Refresh interval to run the discovery +[ refresh_interval: | default = 5m ] + +# HTTP-based service discovery provides a more generic way to generate a set of global datasource and serves as an interface to plug in custom service discovery mechanisms. +# It fetches an HTTP endpoint containing a list of zero or more global datasources. +# The target must reply with an HTTP 200 response. +# The HTTP header Content-Type must be application/json, and the body must be valid array of JSON. +[ http_sd: ] + +# Kubernetes SD configurations allow retrieving global datasource from Kubernetes' REST API +# and always staying synchronized with the cluster state. +[ kubernetes_sd: ] +``` + +#### HTTPSD Config + +```yaml +# URL of the HTTP server exposing the global datasource list to retrieve. +url: + +[ basicAuth: ] + +# The HTTP authorization credentials for the targets. +# Basic Auth and authorization are mutually exclusive. Use one or the other not both at the same time. +[ authorization: ] + +# Config used to connect to the targets. +[ tlsConfig: ] + +headers: + [:] +``` + +##### Basic Auth specification + +See the [BasicAuth](../api/secret.md#basic-auth-specification) specification. + +##### Authorization specification + +See the [Authorization](../api/secret.md#authorization-specification) specification. + +##### TLS Config specification + +See the [TLS Config](../api/secret.md#tls-config-specification) specification. + +#### KubernetesSD Config + +```yaml +# The name of the datasource plugin that should be filled when creating datasources found. +datasource_plugin_kind: + +# Kubernetes namespace to constraint the query to only one namespace. +# Leave empty if you are looking for datasource cross-namespace. +[ namespace: ] + +# Configuration when you want to discover the services in Kubernetes +[ service_configuration: ] + +# Configuration when you want to discover the pods in Kubernetes +[ pod_configuration: ] + +# The labels used to filter the list of resource when contacting the Kubernetes API. +labels: + [:] +``` + +##### KubeServiceDiscovery Config + +```yaml +# If set to true, Perses server will discovery the service +[ enable: | default = false ] + +# Name of the service port for the target. +[ port_name: ] + +# Number of the service port for the target. +[ port_number: ] + +# The type of the service. +[ service_type: < enum | possibleValue = 'ClusterIP' | 'NodePort' | 'LoadBalancer' | 'ExternalName' > ] +``` + +##### KubePodDiscovery Config + +```yaml +# If set to true, Perses server will discover the pods +[ enable: | default = false ] + +# Name of the container the target address points to. +[ container_name: ] + +# Name of the container port. +[ container_port_name: ] + +# Number of the container port. +[ container_port_number: ] +``` + +### EphemeralDashboard config + +```yaml +# When true user will be able to use the ephemeral dashboard at project level +[ enable: | default = false ] + +# The interval at which to trigger the cleanup of ephemeral dashboards, based on their TTLs. +[ cleanup_interval: | default = 1d ] +``` + +### Frontend config + +```yaml +# When it is true, Perses won't serve the frontend anymore. +[ disable: | default = false ] + +# A list of dashboards you would like to display in the UI home page +important_dashboards: + - [ ] + +# The markdown content to be displayed on the UI home page +[ information: ] + +# TimeRange configuration +[ time_range: ] +``` + +#### TimeRange config + +```yaml +# The different relative timerange options available in dashboards and explorer +# Use duration format. The display will be computed automatically. Eg: "5m: will be display "Last 5 minutes" +[ options: | default = [ "5m", "15m", "30m", "1h", "6h", "12h", "1d", "1w", "2w" ] ] +# Allow you to disable the custom time range (absolute time range) +[ disable_custom: | default = false ] +``` + +#### Dashboard Selector config + +```yaml +# The project name (dashboard.metadata.project) +project: + +# The dashboard name (dashboard.metadata.name) +dashboard: +``` \ No newline at end of file diff --git a/docs/docs/user-guides/dashboardascode.md b/docs/docs/user-guides/dashboardascode.md new file mode 100644 index 0000000..b025dc7 --- /dev/null +++ b/docs/docs/user-guides/dashboardascode.md @@ -0,0 +1,204 @@ +Perses offers the possibility to define dashboards as code i nstead of going through manipulations on the UI. +But why would you want to do this? Basically Dashboard-as-Code (DaC) is something that becomes useful +at scale, when you have many dashboards to maintain, to keep aligned on certain parts, etc. + +DaC benefits can be summarized as follows: + +* **Operational efficiency**, by the reusability of a common basis of dashboard components for standard monitoring use cases. +* **Implementation cost reduction**, by leveraging on existing components when creating new dashboards. +* **Maintenance cost reduction**, by making it easier to: cascade the same update on multiple dashboards, keep multiple components aligned with each other, etc.. + +Most of these benefits comes from not dealing with the Perses JSON format directly: instead, we provide SDKs in languages that enable factorization, code imports and more, namely: + +* [CUE](https://cuelang.org/): a powerful templating language with a strong emphasis on data validation. +* [Go](https://go.dev/): an opensource programming language, that probably doesn't need to be introduced... + +Just pick your favorite to start with DaC. If you don't have one, give a try to both! + +!!! info "A note on plugins" + CUE is the language used for the data model of the plugins, which means you'll always be able to include any external plugin installed in your Perses server into your code when using the CUE SDK. + + However, the Golang SDK may not support all the plugins: it's basically up to each plugin development team to provide a Go package to enable the DaC use case. + + This statement applies also to any other language we might have a SDK for in the future. + +Also, as-code means it's GitOps-friendly, meaning that you can also benefit from: + +* version history +* peer-review of changes before rollout +* automated deployments +* and more... + +## Getting Started With Cue + +### Prerequisites + +* `percli`, the [CLI of Perses](../tooling/percli.md). +* `cue`, the [CLI of Cuelang](https://cuelang.org/). + +### Repository setup + +Create a new folder that will become your DaC repository, then follow the steps below: + +#### 1. Initialize the CUE module + +``` +cue mod init +``` + +See the [CUE documentation](https://cuelang.org/docs/concept/modules-packages-instances/) for more information about this step. + +#### 2. Retrieve the CUE sources from Perses + +Ideally we should rely on a native dependency management here, but since it's not yet available for CUE as already mentioned, we provide in the meantime a dedicated CLI command `dac setup` in order to add the CUE sources from Perses as external dependencies to your repo: + +``` +percli dac setup --version 0.47.1 # any version you'd like above v0.44.0-rc0 +``` + +You can omit the version flag if you are connected to a Perses server (it will retrieve its version). Otherwise, unless you have a specific case, better to pass the latest version available. + +### Develop dashboards + +You are now fully ready to start developing dashboards as code! + +It's first strongly recommended to ramp up on CUE if you are not familiar with this technology. For this have a look at: + +- The [official website](https://cuelang.org/) of Cuelang. +- [Cuetorials](https://cuetorials.com/), a 3rd party source of information that is a very good complement. + +You should then have a look at the [CUE SDK documentation](../dac/cue/) to better understand how to use the framework. + +You can also check an example of DaC usage [here](../../internal/test/dac/input.cue). + +## Getting started with Go SDK + +### Prerequisites + +- `percli`, the [CLI of Perses](../tooling/cli.md). +- `go`, the [programming language](https://go.dev/). + +### Repository setup + +Create a new folder that will become your DaC repository, then follow the steps below: + +#### 1. Initialize the Go module + +``` +go mod init +``` + +See the [Go documentation](https://go.dev/doc/tutorial/create-module) for more information about this step. + +#### 2. Install the Perses SDK + +``` +go get github.com/perses/perses +``` + +If you need a specific version, you can specify it as follows: + +``` +go get github.com/perses/perses v0.43.0 +``` + +### Develop dashboards + +You are now fully ready to start developing dashboards as code! + +It's first strongly recommended to ramp up on Go if you are not familiar with this technology. For this have a look at: +- The [official website](https://go.dev/) of Go. + +You should then have a look at the [Go SDK documentation](../dac/go/) to better understand how to use the framework. + +You can also check an example of DaC usage [here](../../internal/cli/cmd/dac/build/testdata/go/main.go). + + +!!! warning "A note on logging" + Do not log / print on the standard stdout! It would break the output of the `dac build` command. + +Quick start example: + +```golang +package main + +import ( + "flag" + + "github.com/perses/perses/go-sdk" + "github.com/perses/perses/go-sdk/dashboard" + "github.com/perses/perses/go-sdk/panel" + "github.com/perses/perses/go-sdk/prometheus/query" + "github.com/perses/perses/go-sdk/panel-group" + + timeSeriesPanel "github.com/perses/perses/go-sdk/panel/time-series" + promDs "github.com/perses/perses/go-sdk/prometheus/datasource" + labelValuesVar "github.com/perses/perses/go-sdk/prometheus/variable/label-values" + listVar "github.com/perses/perses/go-sdk/variable/list-variable" +) + +func main() { + flag.Parse() + exec := sdk.NewExec() + builder, buildErr := dashboard.New("ContainersMonitoring", + dashboard.ProjectName("MyProject"), + + dashboard.AddVariable("stack", + listVar.List( + labelValuesVar.PrometheusLabelValues("paas", + labelValuesVar.Matchers("thanos_build_info{}"), + labelValuesVar.Datasource("promDemo"), + ), + listVar.DisplayName("My Super PaaS"), + ), + ), + + dashboard.AddPanelGroup("Resource usage", + panelgroup.PanelsPerLine(3), + panelgroup.AddPanel("Container memory", + timeSeriesPanel.Chart(), + panel.AddQuery( + query.PromQL("max by (container) (container_memory_rss{paas=\"$paas\",namespace=\"$namespace\",pod=\"$pod\",container=\"$container\"})"), + ), + ), + ), + + dashboard.AddDatasource("promDemo", promDs.Prometheus(promDs.HTTPProxy("https://demo.prometheus.com"))), + ) + exec.BuildDashboard(builder, buildErr) +} +``` + +## Build dashboards + +Anytime you want to build the final dashboard definition (i.e: Perses dashboard in JSON or YAML format) corresponding to your as-code definition, you can use the `dac build` command, as the following: + +```shell +percli dac build -f main.go -ojson +percli dac build -f my_dashboard.cue -ojson +``` + +If the build is successful, the result can be found in the generated `built` folder. + +!!! info "output" + the `-o` (alternatively `--output`) flag is optional (the default output format is YAML). + +### Build multiple dashboards at once + +If you want to develop multiple dashboards as code, you should have **1 dashboard per file** and then call the build command with the directory option: + +``` +percli dac build -d my_dashboards +``` + +## Deploy dashboards + +Once you are satisfied with the result of your DaC definition for a given dashboard, you can finally deploy it to Perses with the `apply` command: + +``` +percli apply -f built/my_dashboard.json +``` + +### CICD setup + +TODO \ No newline at end of file diff --git a/docs/docs/user-guides/embeddingpanels.md b/docs/docs/user-guides/embeddingpanels.md new file mode 100644 index 0000000..8e8b228 --- /dev/null +++ b/docs/docs/user-guides/embeddingpanels.md @@ -0,0 +1,189 @@ +# Embedding Perses Panels + +This page aims to provide you the minimum code needed to have a Perses panel into your React +application. + +!!! info + We are working actively on reducing the amount of required dependencies/providers + by working on some default values or opt-in/opt-out mechanisms. + +## Getting started (npm example) + +```bash +# For example you can use the create-react-app command line or reuse the code of your app +npx create-react-app perses-embedded-panel --template typescript + +# Install perses dependencies +npm i --save @perses-dev/components \ + @perses-dev/plugin-system @perses-dev/panels-plugin \ + @tanstack/react-query @perses-dev/dashboards \ + @mui/material @perses-dev/prometheus-plugin \ + @emotion/styled @hookform/resolvers +``` + +## Minimal code + +Here replacing your App.tsx + +```tsx +import React from 'react'; +import './App.css'; + +import { ChartsProvider, generateChartsTheme, getTheme, SnackbarProvider } from "@perses-dev/components"; +import { + DataQueriesProvider, + dynamicImportPluginLoader, PluginModuleResource, + PluginRegistry, + TimeRangeProvider +} from "@perses-dev/plugin-system"; +import { TimeSeriesChart } from '@perses-dev/panels-plugin'; +import { ThemeProvider } from "@mui/material"; +import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; +import { DatasourceStoreProvider, VariableProvider } from "@perses-dev/dashboards"; +import prometheusResource from '@perses-dev/prometheus-plugin/plugin.json'; +import panelsResource from '@perses-dev/panels-plugin/plugin.json'; +import { DashboardResource, GlobalDatasource, ProjectDatasource } from '@perses-dev/core'; +import { DatasourceApi } from '@perses-dev/dashboards'; + + +const fakeDatasource: GlobalDatasource = { + kind: 'GlobalDatasource', + metadata: { name: 'hello' }, + spec: { + default: true, + plugin: { + kind: 'PrometheusDatasource', + spec: { + directUrl: "https://prometheus.demo.do.prometheus.io" + }, + }, + }, +}; + +class DatasourceApiImpl implements DatasourceApi { + getDatasource(): Promise { + return Promise.resolve(undefined); + } + + getGlobalDatasource(): Promise { + return Promise.resolve(fakeDatasource); + } + + listDatasources(): Promise { + return Promise.resolve([]); + } + + listGlobalDatasources(): Promise { + return Promise.resolve([fakeDatasource]); + } + + buildProxyUrl(): string { + return '/prometheus'; + } +} +export const fakeDatasourceApi = new DatasourceApiImpl(); +export const fakeDashboard = { kind: 'Dashboard', metadata: {}, spec: {} } as DashboardResource; + +function App() { + const muiTheme = getTheme('light'); + const chartsTheme = generateChartsTheme(muiTheme, {}); + const pluginLoader = dynamicImportPluginLoader([ + { + resource: prometheusResource as PluginModuleResource, + importPlugin: () => import('@perses-dev/prometheus-plugin'), + }, + { + resource: panelsResource as PluginModuleResource, + importPlugin: () => import('@perses-dev/panels-plugin'), + }, + ]); + + const queryClient = new QueryClient({ + defaultOptions: { + queries: { + refetchOnWindowFocus: false, + retry: 0, + }, + }, + }); + return ( + + + + + + + + + + + + + + + + + + + + ); +} + + +export default App; + +``` + +You should see a perses panel going to your browser + + + +## Definitions by provider + +!!! info + Check each Provider's source code/jsdoc for more details. + +- `DataQueriesProvider`: Provide the queries' definition, with the query type, the value. This is to be inside the + chart below. For each query, one line will be displayed in the chart. +- `DatasourceStoreProvider`: Provide the datasources. In other terms, the place from which the data will be collected. +- `VariableProvider`: Provide the variables that can be used inside the chart. + It will allow you to reference any variable into the queries thanks to the `${myVar}` syntax. + Available variables will be either the builtin variables or the local/external variables that you can pass to the provider. +- `TimeRangeProvider`: Provide `time range` of the query, but also the `refresh interval` (time between each query + automatic replay) +- `QueryClientProvider`: Provide a `@tanstack/react-query` `QueryClient`, which is a mandatory dependency. + (We advise to configure it with `refetchOnWindowFocus: false` except if you want to replay the queries every time + you change window) +- `QueryParamProvider`: Provide the ability to take time range, refresh interval, and different variables from the + url query params. +- `BrowserRouter`: Provide necessary elements for the `QueryParamProvider` +- `PluginRegistry`: Provide the different Perses plugins that will be used in the providers/charts below. +- `SnackbarProvider`: Provide the toaster that will occurs in case of error/success. +- `ChartsProvider`: Provider for the option of [apache/echarts](https://echarts.apache.org/en/option.html) library. + Which is used for all the charts display. +- `ThemeProvider`: Provider of the [Material UI theme](https://mui.com/material-ui/customization/theming/) which is + currently the theme used in Perses. \ No newline at end of file diff --git a/docs/docs/user-guides/installingfromsource.md b/docs/docs/user-guides/installingfromsource.md new file mode 100644 index 0000000..120f07c --- /dev/null +++ b/docs/docs/user-guides/installingfromsource.md @@ -0,0 +1,71 @@ +This sections continues with installing using the source code, test the project, build the project, configure examples, +and run the Perses dashboard project on your local machine. + +## Building requirements + +To build the Perses project from source you need minimum versions of the following: + +- GO v1.21+ +- Node v16+ +- NPM v8+ + +## Downloading the source + +You can obtain the source code of the Perses project at the main product page in various compression formats or you can +clone the git repository as shown here: + +```shell +git clone https://github.com/perses/perses.git +``` + +Now just move to the Perses project directory and build the project: + +```shell +cd perses + +make build + +... +... LOTS OF BUILD LOG LINES HERE ... +... +>> build the perses cli +CGO_ENABLED=0 GOARCH=arm64 GOOS=darwin go build -ldflags "-s -w -X github.com/prometheus/common/version.Version=0.42.1 +-X github.com/prometheus/common/version.Revision=20a69c0d8e063bcb193f9f209d4d571c1bbadde2 +-X github.com/prometheus/common/version.BuildDate=2024-01-02 +-X github.com/prometheus/common/version.Branch=main" -o ./bin/percli ./cmd/percli +``` + +Note the last line stating that you have successfully built your own instance of Perses! + +## Starting the Perses server + +To start the server you just built: + +```shell +./bin/perses --config dev/config.yaml + ___________ +\___________/ + ___________ ______ + \___________/ | ___ \ + ___________ | |_/ /__ _ __ ___ ___ ___ +\___________/ | __/ _ \ '__/ __|/ _ \/ __| + ___ | | | __/ | \__ \ __/\__ \ +\___/ \_| \___|_| |___/\___||___/ 0.47.0 +__________________________________________________________ + +⇨ http server started on [::]:8080 +``` + +If you are interested in exploring how to configure your Perses server, please see the +[configuration documentation](configuration.md). + +## Connect a browser (default) + +Open the Perses UI at http://localhost:8080. + +You are presented with the home page, in light mode. +For fun, you can optionally flip the switch in the top right corner to enable dark mode. + +## What's next? + +In the next section, you start exploring Perses and the available tooling. \ No newline at end of file diff --git a/docs/docs/user-guides/installingincontainer.md b/docs/docs/user-guides/installingincontainer.md new file mode 100644 index 0000000..9dd5a98 --- /dev/null +++ b/docs/docs/user-guides/installingincontainer.md @@ -0,0 +1,54 @@ +# Installing Perses in a container + +This section is explaining how you can install Perses using a container manager like [Podman](https://podman.io/){target=_blank} or [Docker](https://www.docker.com/){target=_blank}. + +It assumes you have already installed and are familiar with either the Podman or the Docker commandline tooling. + +## Running container image + +Start the Perses container image using one of the following commands depending on your tooling choice: + +```shell +# podman command. +# +$ podman run --name perses -d -p 127.0.0.1:8080:8080 persesdev/perses +``` + +```shell +# docker command. +# +$ docker run --name perses -d -p 127.0.0.1:8080:8080 persesdev/perses +``` + +The details in this command are that we give the container a referencable name (`--name perses`), detach the container +from the command line (`-d`), map the local machine port `8080` to the container port `8080` (`-p 127.0.0.1:8080:8080`), and use +the image version supported in these instructions (`latest`). Note: you can use any local port you have available, but you +need to map to container port `8080`. + +### Tags + +We are publishing a set of tags to match different requirements when running Perses in a container: + +1. Our images can run either on **arm64** or on **amd64** platform. +1. We have two different types of image: `distroless` and `distroless-debug`. + The first one is meant to be used in production as it doesn't contain anything excepting the Perses binaries. + The second one contains a shell and should be used to debug any issue you might encounter with your container. +1. The tag `latest` is an alias for the `distroless` distribution and is erased with the latest release. +1. The tag `latest-debug` is an alias for the `distroless-debug` distribution and is erased with the latest release. +1. We are also providing an image for each commit created on the `main` branch. + The tag created for each commit is following this pattern: `main---` + +Examples: + +* images built from the main branch: `persesdev/perses:main-2023-12-14-f66e10ce-distroless-debug` + or `persesdev/perses:main-2023-12-14-f66e10ce-distroless` +* latest Perses image: `persesdev/perses` or `persesdev/perses:latest-debug` +* precise release image: `persesdev/perses:v0.42.1`, `persesdev/perses:v0.42.1-debug`, `persesdev/perses:v0.42.1-distroless`, `persesdev/perses:v0.42.1-distroless-debug` +* minor release image: `persesdev/perses:v0.42`, `persesdev/perses:v0.42-debug`, `persesdev/perses:v0.42-distroless`, `persesdev/perses:v0.42-distroless-debug` + +## Connect a browser (default) + +Open the Perses UI at `http://localhost:8080`. + +You are presented with the home page, in light mode. +For fun, you can optionally flip the switch in the top right corner to enable dark mode. \ No newline at end of file diff --git a/docs/docs/user-guides/oauthconfiguration.md b/docs/docs/user-guides/oauthconfiguration.md new file mode 100644 index 0000000..5a10ecb --- /dev/null +++ b/docs/docs/user-guides/oauthconfiguration.md @@ -0,0 +1,54 @@ +As we agree that the configuration of an external OAuth/OIDC provider can be a pain, this page is dedicated to +help you configure the most common providers. + +### Supported OAuth flows + +We support three types of authentication flows. +See [authentication.md](authentication.md) for more information. + +#### Authorization Code Flow [RFC 6749](https://datatracker.ietf.org/doc/html/rfc6749#section-1.3.1){target=_blank} + +When the user login with their own personal credentials in the external provider's website through the Perses UI. + +#### Device Code Flow [RFC 8628](https://datatracker.ietf.org/doc/html/rfc8628){target=_blank} + +When the user login with their own personal credentials in the external provider's website but this time from the Perses +command line (`percli`). User will be invited to go to the provider's website to enter a device code, and then login. + +#### Client Credentials Flow [RFC 6749](https://datatracker.ietf.org/doc/html/rfc6749#section-1.3.4){target=_blank} + +Here we log in as an application, not a user. This is useful for scripted tasks not necessarily requiring a user to be logged in. + +### List of providers + +For each of the providers, the main pre-requisite is always to create an app in the provider's console and to get the +client ID and client secret, but we realised that each of them had their own little oddities that we'll try to list up +there. + +> Disclaimer: We try to keep this page up-to-date, but the provider's documentation is always the most reliable source +> of information. + +#### Azure AD + +```yaml +authentication: + providers: + oidc: + - slug_id: azure + name: "Azure AD" + client_id: "" + client_secret: "" + issuer: "https://login.microsoftonline.com//v2.0" + scopes: ["openid", "profile", "email", "User.read"] # For Auth code / Device code + client_credentials: + scopes: ["https://graph.microsoft.com/.default"] # For Client Credentials +``` + +!!! tip + The **scope** used to generate a token from client credentials is different from the one used in other flows. + *Ref: https://learn.microsoft.com/en-us/entra/identity-platform/v2-oauth2-client-creds-grant-flow* + + +#### + +... (don't hesitate to propose new providers!) \ No newline at end of file diff --git a/docs/docs/user-guides/provisioning.md b/docs/docs/user-guides/provisioning.md new file mode 100644 index 0000000..eb5c24d --- /dev/null +++ b/docs/docs/user-guides/provisioning.md @@ -0,0 +1,18 @@ +The provisioning feature allows to inject any kind of resources in the database when Perses is starting. + +That can be useful in case you would like to populate your database with a set of predefined datasources for example. + +To ensure these data are not removed at the runtime, the provisioning is re-injecting them at a configured frequency (by +default 1 hour). + +If you want to activate this feature, you need to complete your configuration file with the following section: + +```yaml +provisioning: + folders: + - /folder/foo/bar + - /another/folder +``` + +You can add any folder you would like. Perses will ignore any files not managed and will loop recursively through any +subfolders contained in the folders configured. \ No newline at end of file diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..1f1bd48 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,43 @@ +--- +hide: + - navigation + - toc + - search + - path +--- + +
+![perses logo](https://perses.dev/images/perses_logo_cropped.png) + +# Open-source Apache-2.0 Licensed + +## An open specification for dashboards. The open dashboard tool for Prometheus and other data sources. +
+ +
+ +- ## GitOps Native + + --- + + Facilitates a seamless "dashboards as code" workflow by introducing an innovative and precisely defined dashboard definition model. + + [:octicons-arrow-right-24: Link here](#) + +- ## Extensible + + --- + + Perses, with its plugin-based architecture, offers effortless extension and reuse of plugins across different projects. + + [:octicons-arrow-right-24: Link here](#) + +- ## Static Validation + + --- + + Perses supports hassle-free dashboard-as-code usage with built-in static validation. Validate your dashboard in CI/CD using the Perses CLI (percli). + + [:octicons-arrow-right-24: Link here](#) + +
\ No newline at end of file diff --git a/mkdocs.yml b/mkdocs.yml new file mode 100644 index 0000000..defaba1 --- /dev/null +++ b/mkdocs.yml @@ -0,0 +1,134 @@ +site_name: Perses +site_url: "https://perses.dev" +repo_name: "Perses on GitHub" +repo_url: "https://github.com/perses/perses" +theme: + name: material + palette: + # Palette toggle for automatic mode + - media: "(prefers-color-scheme)" + primary: black + toggle: + icon: material/brightness-auto + name: Switch to light mode + + # Palette toggle for light mode + - media: "(prefers-color-scheme: light)" + primary: black + scheme: default + toggle: + icon: material/brightness-7 + name: Switch to dark mode + + # Palette toggle for dark mode + - media: "(prefers-color-scheme: dark)" + primary: black + scheme: slate + toggle: + icon: material/brightness-4 + name: Switch to system preference + features: + - navigation.tabs + - content.code.copy +markdown_extensions: + - attr_list + - md_in_html + - pymdownx.emoji: + emoji_index: !!python/name:material.extensions.emoji.twemoji + emoji_generator: !!python/name:material.extensions.emoji.to_svg + - pymdownx.highlight: + anchor_linenums: true + line_spans: __span + pygments_lang_class: true + - pymdownx.inlinehilite + - pymdownx.superfences: + custom_fences: + - name: mermaid + class: mermaid + format: !!python/name:pymdownx.superfences.fence_code_format + - toc: + permalink: "#" + - admonition +extra_css: + - 'css/style.css' +# extra_javascript: +# - 'js/main.js' + +# Enable versioning +extra: + version: + provider: mike + +nav: + - 'Home': 'index.md' + - 'Docs': + - 'docs/index.md' + - 'User Guides': + - 'Configuration': 'docs/user-guides/configuration.md' + - 'Dashboard as Code': 'docs/user-guides/dashboardascode.md' + - 'Embedding Perses Panels': 'docs/user-guides/embeddingpanels.md' + - 'Installing from the Source': 'docs/user-guides/installingfromsource.md' + - 'Installing in a Container': 'docs/user-guides/installingincontainer.md' + - 'OAuth Configuration': 'docs/user-guides/oauthconfiguration.md' + - 'Provisioning': 'docs/user-guides/provisioning.md' + - 'Design Docs': + - 'Authentication': 'docs/design/authentication.md' + - 'Authorization': 'docs/design/authorization.md' + - 'Perses on Kubernetes': 'docs/design/kubernetes.md' + - 'API': + - 'API Reference': 'docs/api/index.md' + - 'Dashboard': 'docs/api/dashboard.md' + - 'Datasource': 'docs/api/datasource.md' + - 'Ephemeral Dashboard': 'docs/api/ephemeral-dashboard.md' + - 'Project': 'docs/api/project.md' + - 'Role': 'docs/api/role.md' + - 'Role Binding': 'docs/api/rolebinding.md' + - 'Secret': 'docs/api/secret.md' + - 'User': 'docs/api/user.md' + - 'Variable': 'docs/api/variable.md' + - 'Dashboard as Code': + - 'Cue': + - 'Cue Reference': 'docs/dac/cue/index.md' + - 'Dashboard Builder': 'docs/dac/cue/dashboardbuilder.md' + - 'Filter Builder': 'docs/dac/cue/filterbuilder.md' + - 'Label Names Variable Builder': 'docs/dac/cue/labelnamesvariablebuilder.md' + - 'Label Values Variable Builder': 'docs/dac/cue/labelvaluesvariablebuilder.md' + - 'Panel Groups Builder': 'docs/dac/cue/panelgroupsbuilder.md' + - 'Prometheus Panel Builder': 'docs/dac/cue/prometheuspanelbuilder.md' + - 'PromQL Variable Builder': 'docs/dac/cue/promqlvariablebuilder.md' + - 'Static List Variable Builder': 'docs/dac/cue/staticlistvariablebuilder.md' + - 'Text Variable Builder': 'docs/dac/cue/textvariablebuilder.md' + - 'Variable Group Builder': 'docs/dac/cue/variablegroupbuilder.md' + - 'Go': + - 'Go Reference': 'docs/dac/go/index.md' + - 'Dashboard Builder': 'docs/dac/go/dashboardbuilder.md' + - 'Datasource Builder': 'docs/dac/go/datasourcebuilder.md' + - 'Panel Builder': 'docs/dac/go/panelbuilder.md' + - 'Panel Group Builder': 'docs/dac/go/panelgroupbuilder.md' + - 'Query Builder': 'docs/dac/go/querybuilder.md' + - 'Variable Builder': 'docs/dac/go/variablebuilder.md' + - 'Variable Group Builder': 'docs/dac/go/variablegroupbuilder.md' + - 'Bar Panel Builder': 'docs/dac/go/barpanelbuilder.md' + - 'Guage Panel Builder': 'docs/dac/go/guagepanelbuilder.md' + - 'Markdown Panel Builder': 'docs/dac/go/markdownpanelbuilder.md' + - 'Stat Panel Builder': 'docs/dac/go/statpanelbuilder.md' + - 'Time Series Panel Builder': 'docs/dac/go/timeseriespanelbuilder.md' + - 'HTTP Builder': 'docs/dac/go/httpbuilder.md' + - 'Prometheus Datasource Builder': 'docs/dac/go/prometheusdatasourcebuilder.md' + - 'Prometheus Query Builder': 'docs/dac/go/prometheusquerybuilder.md' + - 'PromQL Variable Builder': 'docs/dac/go/promqlvariablebuilder.md' + - 'Label Names Variable Builder': 'docs/dac/go/labelnamesvariablebuilder.md' + - 'Label Values Variable Builder': 'docs/dac/go/labelvaluesvariablebuilder.md' + - 'Plugins': + - 'Plugins Reference': 'docs/plugins/index.md' + - 'CUE in Perses': 'docs/plugins/cue.md' + - 'Panel Plugins': 'docs/plugins/panelplugins.md' + - 'Prometheus Plugins': 'docs/plugins/prometheusplugins.md' + - 'Tooling': + - 'Tooling Reference': 'docs/tooling/index.md' + - 'Perses CLI (percli)': 'docs/tooling/percli.md' + + + + + - 'Demo': 'https://demo.perses.dev' \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..b221123 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +mkdocs-material == 9.5.34 +mike == 2.1.3 \ No newline at end of file