5
5
package kibana
6
6
7
7
import (
8
+ "bytes"
8
9
"encoding/json"
9
10
"fmt"
11
+ "mime/multipart"
10
12
"net/http"
11
13
"sort"
12
14
"strings"
@@ -93,11 +95,11 @@ func (c *Client) findDashboardsNextPage(page int) (*savedObjectsResponse, error)
93
95
path := fmt .Sprintf ("%s/_find?type=dashboard&fields=title&per_page=%d&page=%d" , SavedObjectsAPI , findDashboardsPerPage , page )
94
96
statusCode , respBody , err := c .get (path )
95
97
if err != nil {
96
- return nil , fmt .Errorf ("could not find dashboards; API status code = %d; response body = %s: %w" , statusCode , respBody , err )
98
+ return nil , fmt .Errorf ("could not find dashboards; API status code = %d; response body = %s: %w" , statusCode , string ( respBody ) , err )
97
99
}
98
100
99
101
if statusCode != http .StatusOK {
100
- return nil , fmt .Errorf ("could not find dashboards; API status code = %d; response body = %s" , statusCode , respBody )
102
+ return nil , fmt .Errorf ("could not find dashboards; API status code = %d; response body = %s" , statusCode , string ( respBody ) )
101
103
}
102
104
103
105
var r savedObjectsResponse
@@ -107,3 +109,146 @@ func (c *Client) findDashboardsNextPage(page int) (*savedObjectsResponse, error)
107
109
}
108
110
return & r , nil
109
111
}
112
+
113
+ // SetManagedSavedObject method sets the managed property in a saved object.
114
+ // For example managed dashboards cannot be edited, and setting managed to false will
115
+ // allow to edit them.
116
+ // Managed property cannot be directly changed, so we modify it by exporting the
117
+ // saved object and importing it again, overwriting the original one.
118
+ func (c * Client ) SetManagedSavedObject (savedObjectType string , id string , managed bool ) error {
119
+ exportRequest := ExportSavedObjectsRequest {
120
+ ExcludeExportDetails : true ,
121
+ IncludeReferencesDeep : false ,
122
+ Objects : []ExportSavedObjectsRequestObject {
123
+ {
124
+ ID : id ,
125
+ Type : savedObjectType ,
126
+ },
127
+ },
128
+ }
129
+ objects , err := c .ExportSavedObjects (exportRequest )
130
+ if err != nil {
131
+ return fmt .Errorf ("failed to export %s %s: %w" , savedObjectType , id , err )
132
+ }
133
+
134
+ for _ , o := range objects {
135
+ o ["managed" ] = managed
136
+ }
137
+
138
+ importRequest := ImportSavedObjectsRequest {
139
+ Overwrite : true ,
140
+ Objects : objects ,
141
+ }
142
+ _ , err = c .ImportSavedObjects (importRequest )
143
+ if err != nil {
144
+ return fmt .Errorf ("failed to import %s %s: %w" , savedObjectType , id , err )
145
+ }
146
+
147
+ return nil
148
+ }
149
+
150
+ type ExportSavedObjectsRequest struct {
151
+ ExcludeExportDetails bool `json:"excludeExportDetails"`
152
+ IncludeReferencesDeep bool `json:"includeReferencesDeep"`
153
+ Objects []ExportSavedObjectsRequestObject `json:"objects"`
154
+ }
155
+
156
+ type ExportSavedObjectsRequestObject struct {
157
+ ID string `json:"id"`
158
+ Type string `json:"type"`
159
+ }
160
+
161
+ func (c * Client ) ExportSavedObjects (request ExportSavedObjectsRequest ) ([]map [string ]any , error ) {
162
+ body , err := json .Marshal (request )
163
+ if err != nil {
164
+ return nil , fmt .Errorf ("failed to encode request: %w" , err )
165
+ }
166
+
167
+ path := SavedObjectsAPI + "/_export"
168
+ statusCode , respBody , err := c .SendRequest (http .MethodPost , path , body )
169
+ if err != nil {
170
+ return nil , fmt .Errorf ("could not export saved objects; API status code = %d; response body = %s: %w" , statusCode , string (respBody ), err )
171
+ }
172
+ if statusCode != http .StatusOK {
173
+ return nil , fmt .Errorf ("could not export saved objects; API status code = %d; response body = %s" , statusCode , string (respBody ))
174
+ }
175
+
176
+ var objects []map [string ]any
177
+ decoder := json .NewDecoder (bytes .NewReader (respBody ))
178
+ for decoder .More () {
179
+ var object map [string ]any
180
+ err := decoder .Decode (& object )
181
+ if err != nil {
182
+ return nil , fmt .Errorf ("unmarshalling response failed (body: \n %s): %w" , string (respBody ), err )
183
+ }
184
+
185
+ objects = append (objects , object )
186
+ }
187
+
188
+ return objects , nil
189
+ }
190
+
191
+ type ImportSavedObjectsRequest struct {
192
+ Overwrite bool
193
+ Objects []map [string ]any
194
+ }
195
+
196
+ type ImportSavedObjectsResponse struct {
197
+ Success bool `json:"success"`
198
+ Count int `json:"successCount"`
199
+ Results []ImportResult `json:"successResults"`
200
+ Errors []ImportResult `json:"errors"`
201
+ }
202
+
203
+ type ImportResult struct {
204
+ ID string `json:"id"`
205
+ Type string `json:"type"`
206
+ Title string `json:"title"`
207
+ Error map [string ]any `json:"error"`
208
+ Meta map [string ]any `json:"meta"`
209
+ }
210
+
211
+ func (c * Client ) ImportSavedObjects (importRequest ImportSavedObjectsRequest ) (* ImportSavedObjectsResponse , error ) {
212
+ var body bytes.Buffer
213
+ multipartWriter := multipart .NewWriter (& body )
214
+ fileWriter , err := multipartWriter .CreateFormFile ("file" , "file.ndjson" )
215
+ if err != nil {
216
+ return nil , fmt .Errorf ("failed to create multipart form file: %w" , err )
217
+ }
218
+ enc := json .NewEncoder (fileWriter )
219
+ for _ , object := range importRequest .Objects {
220
+ // Encode includes the newline delimiter.
221
+ err := enc .Encode (object )
222
+ if err != nil {
223
+ return nil , fmt .Errorf ("failed to encode object as json: %w" , err )
224
+ }
225
+ }
226
+ multipartWriter .Close ()
227
+
228
+ path := SavedObjectsAPI + "/_import"
229
+ request , err := c .newRequest (http .MethodPost , path , & body )
230
+ if err != nil {
231
+ return nil , fmt .Errorf ("cannot create new request: %w" , err )
232
+ }
233
+ request .Header .Set ("Content-Type" , multipartWriter .FormDataContentType ())
234
+ if importRequest .Overwrite {
235
+ q := request .URL .Query ()
236
+ q .Set ("overwrite" , "true" )
237
+ request .URL .RawQuery = q .Encode ()
238
+ }
239
+
240
+ statusCode , respBody , err := c .doRequest (request )
241
+ if err != nil {
242
+ return nil , fmt .Errorf ("could not import saved objects; API status code = %d; response body = %s: %w" , statusCode , string (respBody ), err )
243
+ }
244
+ if statusCode != http .StatusOK {
245
+ return nil , fmt .Errorf ("could not import saved objects; API status code = %d; response body = %s" , statusCode , string (respBody ))
246
+ }
247
+
248
+ var results ImportSavedObjectsResponse
249
+ err = json .Unmarshal (respBody , & results )
250
+ if err != nil {
251
+ return nil , fmt .Errorf ("could not decode response; response body: %s: %w" , respBody , err )
252
+ }
253
+ return & results , nil
254
+ }
0 commit comments