diff --git a/pkg/api/datasources.go b/pkg/api/datasources.go index 747ef8f25e6..27b91bc2802 100644 --- a/pkg/api/datasources.go +++ b/pkg/api/datasources.go @@ -33,6 +33,7 @@ func GetDataSources(c *middleware.Context) Response { BasicAuth: ds.BasicAuth, IsDefault: ds.IsDefault, JsonData: ds.JsonData, + ReadOnly: ds.ReadOnly, } if plugin, exists := plugins.DataSources[ds.Type]; exists { @@ -76,9 +77,20 @@ func DeleteDataSourceById(c *middleware.Context) { return } + ds, err := getRawDataSourceById(id, c.OrgId) + if err != nil { + c.JsonApiErr(400, "Failed to delete datasource", nil) + return + } + + if ds.ReadOnly { + c.JsonApiErr(403, "Cannot delete read-only data source", nil) + return + } + cmd := &m.DeleteDataSourceByIdCommand{Id: id, OrgId: c.OrgId} - err := bus.Dispatch(cmd) + err = bus.Dispatch(cmd) if err != nil { c.JsonApiErr(500, "Failed to delete datasource", err) return @@ -95,8 +107,18 @@ func DeleteDataSourceByName(c *middleware.Context) { return } - cmd := &m.DeleteDataSourceByNameCommand{Name: name, OrgId: c.OrgId} + getCmd := &m.GetDataSourceByNameQuery{Name: name, OrgId: c.OrgId} + if err := bus.Dispatch(getCmd); err != nil { + c.JsonApiErr(500, "Failed to delete datasource", err) + return + } + if getCmd.Result.ReadOnly { + c.JsonApiErr(403, "Cannot delete read-only data source", nil) + return + } + + cmd := &m.DeleteDataSourceByNameCommand{Name: name, OrgId: c.OrgId} err := bus.Dispatch(cmd) if err != nil { c.JsonApiErr(500, "Failed to delete datasource", err) @@ -160,11 +182,14 @@ func fillWithSecureJsonData(cmd *m.UpdateDataSourceCommand) error { } ds, err := getRawDataSourceById(cmd.Id, cmd.OrgId) - if err != nil { return err } + if ds.ReadOnly { + return m.ErrDatasourceIsReadOnly + } + secureJsonData := ds.SecureJsonData.Decrypt() for k, v := range secureJsonData { @@ -201,6 +226,7 @@ func GetDataSourceByName(c *middleware.Context) Response { } dtos := convertModelToDtos(query.Result) + dtos.ReadOnly = true return Json(200, &dtos) } @@ -242,6 +268,7 @@ func convertModelToDtos(ds *m.DataSource) dtos.DataSource { JsonData: ds.JsonData, SecureJsonFields: map[string]bool{}, Version: ds.Version, + ReadOnly: ds.ReadOnly, } for k, v := range ds.SecureJsonData { diff --git a/pkg/api/dtos/datasource.go b/pkg/api/dtos/datasource.go index 7cb36e61ab4..f760486c561 100644 --- a/pkg/api/dtos/datasource.go +++ b/pkg/api/dtos/datasource.go @@ -26,6 +26,7 @@ type DataSource struct { JsonData *simplejson.Json `json:"jsonData,omitempty"` SecureJsonFields map[string]bool `json:"secureJsonFields"` Version int `json:"version"` + ReadOnly bool `json:"readOnly"` } type DataSourceListItemDTO struct { @@ -42,6 +43,7 @@ type DataSourceListItemDTO struct { BasicAuth bool `json:"basicAuth"` IsDefault bool `json:"isDefault"` JsonData *simplejson.Json `json:"jsonData,omitempty"` + ReadOnly bool `json:"readOnly"` } type DataSourceList []DataSourceListItemDTO diff --git a/pkg/models/datasource.go b/pkg/models/datasource.go index 62166192808..fe948b5d660 100644 --- a/pkg/models/datasource.go +++ b/pkg/models/datasource.go @@ -27,6 +27,7 @@ var ( ErrDataSourceNotFound = errors.New("Data source not found") ErrDataSourceNameExists = errors.New("Data source with same name already exists") ErrDataSourceUpdatingOldVersion = errors.New("Trying to update old version of datasource") + ErrDatasourceIsReadOnly = errors.New("Data source is readonly. Can only be updated from configuration.") ) type DsAccess string @@ -50,6 +51,7 @@ type DataSource struct { IsDefault bool JsonData *simplejson.Json SecureJsonData securejsondata.SecureJsonData + ReadOnly bool Created time.Time Updated time.Time @@ -109,6 +111,7 @@ type AddDataSourceCommand struct { IsDefault bool `json:"isDefault"` JsonData *simplejson.Json `json:"jsonData"` SecureJsonData map[string]string `json:"secureJsonData"` + ReadOnly bool `json:"readOnly"` OrgId int64 `json:"-"` @@ -132,6 +135,7 @@ type UpdateDataSourceCommand struct { JsonData *simplejson.Json `json:"jsonData"` SecureJsonData map[string]string `json:"secureJsonData"` Version int `json:"version"` + ReadOnly bool `json:"readOnly"` OrgId int64 `json:"-"` Id int64 `json:"-"` diff --git a/pkg/services/provisioning/datasources/types.go b/pkg/services/provisioning/datasources/types.go index c708c23b551..6da5650b65d 100644 --- a/pkg/services/provisioning/datasources/types.go +++ b/pkg/services/provisioning/datasources/types.go @@ -50,6 +50,7 @@ func createInsertCommand(ds DataSourceFromConfig) *models.AddDataSourceCommand { IsDefault: ds.IsDefault, JsonData: jsonData, SecureJsonData: ds.SecureJsonData, + ReadOnly: true, } } @@ -76,5 +77,6 @@ func createUpdateCommand(ds DataSourceFromConfig, id int64) *models.UpdateDataSo IsDefault: ds.IsDefault, JsonData: jsonData, SecureJsonData: ds.SecureJsonData, + ReadOnly: true, } } diff --git a/pkg/services/sqlstore/datasource.go b/pkg/services/sqlstore/datasource.go index c38d269af47..8a3a22c2bef 100644 --- a/pkg/services/sqlstore/datasource.go +++ b/pkg/services/sqlstore/datasource.go @@ -106,6 +106,7 @@ func AddDataSource(cmd *m.AddDataSourceCommand) error { Created: time.Now(), Updated: time.Now(), Version: 1, + ReadOnly: cmd.ReadOnly, } if _, err := sess.Insert(ds); err != nil { @@ -151,6 +152,7 @@ func UpdateDataSource(cmd *m.UpdateDataSourceCommand) error { JsonData: cmd.JsonData, SecureJsonData: securejsondata.GetEncryptedJsonData(cmd.SecureJsonData), Updated: time.Now(), + ReadOnly: cmd.ReadOnly, Version: cmd.Version + 1, } diff --git a/pkg/services/sqlstore/migrations/datasource_mig.go b/pkg/services/sqlstore/migrations/datasource_mig.go index cc8a7f05177..919881adaba 100644 --- a/pkg/services/sqlstore/migrations/datasource_mig.go +++ b/pkg/services/sqlstore/migrations/datasource_mig.go @@ -126,4 +126,8 @@ func addDataSourceMigration(mg *Migrator) { Sqlite(setVersionToOneWhereZero). Postgres(setVersionToOneWhereZero). Mysql(setVersionToOneWhereZero)) + + mg.AddMigration("Add read_only data column", NewAddColumnMigration(tableV2, &Column{ + Name: "read_only", Type: DB_Bool, Nullable: true, + })) } diff --git a/public/app/features/plugins/ds_edit_ctrl.ts b/public/app/features/plugins/ds_edit_ctrl.ts index d388783400d..6bb98a348ab 100644 --- a/public/app/features/plugins/ds_edit_ctrl.ts +++ b/public/app/features/plugins/ds_edit_ctrl.ts @@ -149,6 +149,10 @@ export class DataSourceEditCtrl { return; } + if (this.current.readOnly) { + return; + } + if (this.current.id) { return this.backendSrv.put('/api/datasources/' + this.current.id, this.current).then((result) => { this.current = result.datasource; diff --git a/public/app/features/plugins/partials/ds_edit.html b/public/app/features/plugins/partials/ds_edit.html index ebe6ff48bc5..61afebbe014 100644 --- a/public/app/features/plugins/partials/ds_edit.html +++ b/public/app/features/plugins/partials/ds_edit.html @@ -6,6 +6,8 @@

Add data source

Edit data source

+
Disclaimer. This datasource was added by config and cannot be modified using the UI. Please contact your server admin to update this datasource.
+
@@ -71,9 +73,9 @@
- - - + + Cancel