mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
datasource as cfg: adds readonly datasources
This commit is contained in:
parent
c6a6ae261f
commit
36676e23c1
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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:"-"`
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
}))
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -6,6 +6,8 @@
|
||||
<h1 ng-show="ctrl.isNew">Add data source</h1>
|
||||
<h1 ng-hide="ctrl.isNew">Edit data source</h1>
|
||||
|
||||
<div ng-if="ctrl.current.readOnly" class="grafana-info-box span8">Disclaimer. This datasource was added by config and cannot be modified using the UI. Please contact your server admin to update this datasource.</div>
|
||||
|
||||
<div class="page-header-tabs" ng-show="ctrl.hasDashboards">
|
||||
<ul class="gf-tabs">
|
||||
<li class="gf-tabs-item">
|
||||
@ -29,20 +31,20 @@
|
||||
<div class="gf-form-inline">
|
||||
<div class="gf-form max-width-30">
|
||||
<span class="gf-form-label width-7">Name</span>
|
||||
<input class="gf-form-input max-width-23" type="text" ng-model="ctrl.current.name" placeholder="name" required>
|
||||
<input class="gf-form-input max-width-23" type="text" ng-model="ctrl.current.name" placeholder="name" ng-disabled="ctrl.current.readOnly" required>
|
||||
<info-popover offset="0px -135px" mode="right-absolute">
|
||||
The name is used when you select the data source in panels.
|
||||
The <em>Default</em> data source is preselected in new
|
||||
panels.
|
||||
</info-popover>
|
||||
</div>
|
||||
<gf-form-switch class="gf-form" label="Default" checked="ctrl.current.isDefault" switch-class="max-width-6"></gf-form-switch>
|
||||
<gf-form-switch class="gf-form" label="Default" checked="ctrl.current.isDefault" ng-disabled="ctrl.current.readOnly" switch-class="max-width-6"></gf-form-switch>
|
||||
</div>
|
||||
|
||||
<div class="gf-form max-width-30">
|
||||
<span class="gf-form-label width-7">Type</span>
|
||||
<div class="gf-form-select-wrapper max-width-23">
|
||||
<select class="gf-form-input" ng-model="ctrl.current.type" ng-options="v.id as v.name for v in ctrl.types" ng-change="ctrl.userChangedType()"></select>
|
||||
<select class="gf-form-input" ng-model="ctrl.current.type" ng-disabled="ctrl.current.readOnly" ng-options="v.id as v.name for v in ctrl.types" ng-change="ctrl.userChangedType()"></select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -71,9 +73,9 @@
|
||||
</div>
|
||||
|
||||
<div class="gf-form-button-row">
|
||||
<button type="submit" class="btn btn-success width-6" ng-show="ctrl.isNew" ng-click="ctrl.saveChanges()">Add</button>
|
||||
<button type="submit" class="btn btn-success width-8" ng-show="!ctrl.isNew" ng-click="ctrl.saveChanges()">Save & Test</button>
|
||||
<button type="submit" class="btn btn-danger width-6" ng-show="!ctrl.isNew" ng-click="ctrl.delete()">
|
||||
<button type="submit" class="btn btn-success width-6" ng-disabled="ctrl.current.readOnly" ng-show="ctrl.isNew" ng-click="ctrl.saveChanges()">Add</button>
|
||||
<button type="submit" class="btn btn-success width-8" ng-disabled="ctrl.current.readOnly" ng-show="!ctrl.isNew" ng-click="ctrl.saveChanges()">Save & Test</button>
|
||||
<button type="submit" class="btn btn-danger width-6" ng-disabled="ctrl.current.readOnly" ng-show="!ctrl.isNew" ng-click="ctrl.delete()">
|
||||
Delete
|
||||
</button>
|
||||
<a class="btn btn-link" href="datasources">Cancel</a>
|
||||
|
Loading…
Reference in New Issue
Block a user