Upgrading from v0.53.0 to v0.54.0#
This document provides instructions for upgrading Perses specially when dealing with breaking changes. As Perses is a rapidly evolving project, it's important to keep your installation up to date to benefit from the latest features and improvements.
Then, upgrading Perses is also depending on your usage as Perses can be used in different ways (e.g. as a standalone application, as a library, etc.). Therefore, the upgrade process may vary based on your specific use case.
Perses application#
SQL Database default configuration changes#
We have changed the behavior of the SQL database config regarding the default value of few fields. It has been done to follow the default behavior of the driver: https://github.com/go-sql-driver/mysql/blob/master/dsn.go#L97
If you do not use the SQL config, then this does not concern you. If you use the SQL config, here the fields that the default value have been changed:
database:
sql:
allow_native_passwords: true # previously false
check_conn_liveness: true # previously false
We also have added more field to the configuration to give you more facilities to customize the database connection:
database:
sql:
# Maximum amount of time a connection may be reused. Keep it shorter than the server's wait_timeout
# to avoid reusing connections the server has already closed.
conn_max_lifetime: <duration> | default = 3m # Optional
# Maximum amount of time a connection may be idle before it is closed.
conn_max_idle_time: <duration> | default = 1m # Optional
# Maximum number of open connections to the database. A value <= 0 means unlimited.
max_open_conns: <int> # Optional
# Maximum number of connections in the idle connection pool. A value <= 0 keeps the Go default (2).
max_idle_conns: <int> # Optional
Plugin developer#
Core package deprecated#
We have deprecated the core package and accordingly moved all its types and functionalities into other packages including spec, dashboards, components, plugin-system, and client. We are planing to drop the core package completely in the subsequent release. Therefore, we kindly ask all contributors to avoid importing core package members, and instead use the relevant types from the mentioned packages. Furthermore, should your PRs already import core members, you should replace them with the relevant types from the mentioned packages. This also means that meanwhile we cease developing core, because as it has been already mentioned the subsequent release will drop core completely.
The dependencies from core had been used in all repositories and different packages including perses/perses (the Perses app), perses/plugins, and perses/shared. Please note that the shared is the host of the of the components, plugin-system, dashboards, and client packages. The spec as its name suggests exposes the specifications and had no dependency to core. However, some of the core members have been moved to spec already.
The following example shows the Table plugin and its dependencies at the moment
"@perses-dev/components": "^0.54.0",
"@perses-dev/spec": "^0.2.0",
"@perses-dev/plugin-system": "^0.54.0",
"@perses-dev/dashboards": "^0.54.0"
For instance, if you take a look at the imported members in table\src\components\TablePanel.tsx you find many types that used to be imported from core. Now, after this change the core has been replaced accordingly.
/* For example FormatOptions used to reside in core package
But now it is taken from @perses-dev/components
Take a look at ui\core\src\model\units\units.ts
You will find FormatOptions
Now it is coming from
components\src\model\units.ts
*/
import {
FormatOptions,
formatValue,
Table,
TableCellConfigs,
TableColumnConfig,
transformData,
useSelection,
} from '@perses-dev/components';
core dependency is used in your changes. If it has been used already, it should be simply replaced with its equivalent from the mentioned packages. This should be no challenge as most of the IDEs suggest substitutes. For example, in VSCODE, if you can remove the core dependency, the IDE will suggest the substitutes. Simply select the suggested import and it will be added to your file automatically.
Plugin migration example (v0.53.1 to v0.54.0)#
Let's for example, take a closer look at a plugin and see how it was in v0.53.1 and how it changed in v0.54.0.
The example has been inspired by the actual Table Plugin from the plugin repo.
So here in v0.53.1, the following types have been imported from @perses-dev/core
CalculationsMapformatValueQueryDataTypeTimeSeriesDatatransformData
After migrating to v0.54.0, we need to replace them with the proper substitute from the relevant packages.
/* v0.53.1 */
import { Table, TableCellConfigs, TableColumnConfig, useSelection } from '@perses-dev/components';
/* @perses-dev/core */
import { CalculationsMap, formatValue, QueryDataType, TimeSeriesData, transformData } from '@perses-dev/core';
import { useSelectionItemActions } from '@perses-dev/dashboards';
import {
ActionOptions,
PanelData,
PanelProps,
replaceVariablesInString,
useAllVariableValues,
VariableStateMap,
} from '@perses-dev/plugin-system';
/* OTHER IMPORTED MEMBERS*/
export const APlugin = (): ReactElement => {
/**
* THE PLUGIN LOGIC
*/
return <Box sx={{ display: 'flex', alignItems: 'center', width: '100%', gap: 1 }}>{/* THE PLUGIN STRUCTURE */}</Box>;
};
v.0.54.0 the plugin itself remains INTACT and you do NOT need to change anything.
The only thing that you need to do
- remove the core dependencies
- find the relevant substitutes for the removed imported members
So, in v.0.54.0 only the import section of the plugin has changed and the rest remain as it is. Why? Because, the same type has been moved to a different package while the structure is intact.
/* v0.54.0 */
import {
formatValue,
Table,
TableCellConfigs,
TableColumnConfig,
transformData,
useSelection,
} from '@perses-dev/components';
import { useSelectionItemActions } from '@perses-dev/dashboards';
import {
ActionOptions,
CalculationsMap,
PanelData,
PanelProps,
replaceVariablesInString,
useAllVariableValues,
VariableStateMap,
} from '@perses-dev/plugin-system';
import { QueryDataType, TimeSeriesData } from '@perses-dev/spec';
/* OTHER IMPORTED MEMBERS*/
export const APlugin = (): ReactElement => {
/**
* THE PLUGIN LOGIC
*/
return <Box sx={{ display: 'flex', alignItems: 'center', width: '100%', gap: 1 }}>{/* THE PLUGIN STRUCTURE */}</Box>;
};
The following table, shows how in this example the imports have changed after moving to v0.54.0 from v.053.1
| @perses-dev/core Types | Types new package |
|---|---|
| CalculationsMap | @perses-dev/plugin-system |
| formatValue | @perses-dev/components |
| transformData | @perses-dev/components |
| QueryDataType | @perses-dev/spec |
| TimeSeriesData | @perses-dev/spec |
If you already working on a change that has added new members to the core, you need to move them to the proper package accordingly. Where your new type should reside depends on its usage. Please note that if the new introduced member has only internal Perses App usage, it should reside in the perses/perses.
GO-SDK: Import path change#
Query plugin definition#
Since the definition of the dashboard and datasource has been moved to the repository perses/spec, few import path
needs to be updated.
If you are defining a query plugin, you probably have the following definition:
package yourquery
import (
"github.com/perses/perses/go-sdk/datasource"
"github.com/perses/perses/go-sdk/query"
"github.com/perses/perses/pkg/model/api/v1/plugin"
"github.com/perses/perses/pkg/model/api/v1/common"
)
const PluginKind = "YourLogQuery"
type PluginSpec struct {
Datasource *datasource.Selector `json:"datasource,omitempty" yaml:"datasource,omitempty"`
Query string `json:"query" yaml:"query"`
}
type Option func(plugin *Builder) error
func create(query string, options ...Option) (Builder, error) {
builder := &Builder{
PluginSpec: PluginSpec{},
}
defaults := []Option{
Query(query),
}
for _, opt := range append(defaults, options...) {
if err := opt(builder); err != nil {
return *builder, err
}
}
return *builder, nil
}
type Builder struct {
PluginSpec `json:",inline" yaml:",inline"`
}
func YourLogQuery(expr string, options ...Option) query.Option {
plg, err := create(expr, options...)
return query.Option{
Kind: plugin.KindLogQuery,
Plugin: common.Plugin{
Kind: PluginKind,
Spec: plg,
},
Error: err,
}
}
In this situation, you simply need to replace the import path of the plugin and common packages to
"github.com/perses/spec/go/plugin":
package yourquery
import (
"github.com/perses/perses/go-sdk/datasource"
"github.com/perses/perses/go-sdk/query"
"github.com/perses/spec/go/plugin"
)
const PluginKind = "YourLogQuery"
type PluginSpec struct {
Datasource *datasource.Selector `json:"datasource,omitempty" yaml:"datasource,omitempty"`
Query string `json:"query" yaml:"query"`
}
type Option func(plugin *Builder) error
func create(query string, options ...Option) (Builder, error) {
builder := &Builder{
PluginSpec: PluginSpec{},
}
defaults := []Option{
Query(query),
}
for _, opt := range append(defaults, options...) {
if err := opt(builder); err != nil {
return *builder, err
}
}
return *builder, nil
}
type Builder struct {
PluginSpec `json:",inline" yaml:",inline"`
}
func YourLogQuery(expr string, options ...Option) query.Option {
plg, err := create(expr, options...)
return query.Option{
Kind: plugin.KindLogQuery,
Plugin: plugin.Plugin{
Kind: PluginKind,
Spec: plg,
},
Error: err,
}
}
Note that if you are using more things than plugin in the github.com/perses/perses/pkg/model/api/v1/common package,
you should also update the import path to "github.com/perses/spec/go/common".
Datasource plugin definition#
There are two possibilities:
- If you are defining an HTTP datasource plugin with the simple struct:
package yourdatasource
import "github.com/perses/perses/pkg/model/api/v1/datasource/http"
type PluginSpec struct {
DirectURL string `json:"directUrl,omitempty" yaml:"directUrl,omitempty"`
Proxy *http.Proxy `json:"proxy,omitempty" yaml:"proxy,omitempty"`
}
In this case, we have provided a new struct datasource.HTTPDatasourceSpec from the package
github.com/perses/spec/go/datasource that can be used instead of defining it manually. You can simply removed your
struct and use the new one.
package yourdatasource
import (
"github.com/perses/perses/go-sdk/datasource"
datasourceSpec "github.com/perses/spec/go/datasource"
)
const (
PluginKind = "YourDatasource"
)
type Option func(plugin *Builder) error
func create(options ...Option) (Builder, error) {
builder := &Builder{
HTTPDatasourceSpec: datasourceSpec.HTTPDatasourceSpec{},
}
var defaults []Option
for _, opt := range append(defaults, options...) {
if err := opt(builder); err != nil {
return *builder, err
}
}
return *builder, nil
}
type Builder struct {
datasourceSpec.HTTPDatasourceSpec `json:",inline" yaml:",inline"`
}
func YourDatasource(options ...Option) datasource.Option {
return func(builder *datasource.Builder) error {
plugin, err := create(options...)
if err != nil {
return err
}
builder.Spec.Plugin.Kind = PluginKind
builder.Spec.Plugin.Spec = plugin.HTTPDatasourceSpec
return nil
}
}
func Selector(datasourceName string) *datasource.Selector {
return &datasource.Selector{
Kind: PluginKind,
Name: datasourceName,
}
}
- If you are defining a datasource plugin with a more complex struct, you can replace the import path of the
httppackage to"github.com/perses/spec/go/datasource/proxy/http".
package yourdatasource
import "github.com/perses/spec/go/datasource/proxy/http"
type PluginSpec struct {
DirectURL string `json:"directUrl,omitempty" yaml:"directUrl,omitempty"`
Proxy *http.Proxy `json:"proxy,omitempty" yaml:"proxy,omitempty"`
OtherField string `json:"otherField,omitempty" yaml:"otherField,omitempty"`
}