• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

uber / cadence / 0186bdce-5e78-4bd9-9a33-eb4f2319ec8d

07 Mar 2023 09:06PM UTC coverage: 57.058% (-0.1%) from 57.174%
0186bdce-5e78-4bd9-9a33-eb4f2319ec8d

push

buildkite

GitHub
move sample logger into persistence metric client for cleaness (#5129)

12 of 12 new or added lines in 5 files covered. (100.0%)

85162 of 149256 relevant lines covered (57.06%)

2249.29 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/tools/cli/adminConfigStoreCommands.go
1
// Copyright (c) 2017 Uber Technologies, Inc.
2
//
3
// Permission is hereby granted, free of charge, to any person obtaining a copy
4
// of this software and associated documentation files (the "Software"), to deal
5
// in the Software without restriction, including without limitation the rights
6
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
// copies of the Software, and to permit persons to whom the Software is
8
// furnished to do so, subject to the following conditions:
9
//
10
// The above copyright notice and this permission notice shall be included in
11
// all copies or substantial portions of the Software.
12
//
13
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
// THE SOFTWARE.
20

21
package cli
22

23
import (
24
        "encoding/json"
25
        "fmt"
26
        "sort"
27

28
        "github.com/uber/cadence/common/dynamicconfig"
29
        "github.com/uber/cadence/common/types"
30

31
        "github.com/olekukonko/tablewriter"
32
        "github.com/urfave/cli"
33
)
34

35
type cliEntry struct {
36
        Name         string
37
        DefaultValue interface{} `json:"defaultValue,omitempty"`
38
        Values       []*cliValue
39
}
40

41
type cliValue struct {
42
        Value   interface{}
43
        Filters []*cliFilter
44
}
45

46
type cliFilter struct {
47
        Name  string
48
        Value interface{}
49
}
50

51
// AdminGetDynamicConfig gets value of specified dynamic config parameter matching specified filter
52
func AdminGetDynamicConfig(c *cli.Context) {
×
53
        adminClient := cFactory.ServerAdminClient(c)
×
54

×
55
        dcName := getRequiredOption(c, FlagDynamicConfigName)
×
56
        filters := c.StringSlice(FlagDynamicConfigFilter)
×
57

×
58
        ctx, cancel := newContext(c)
×
59
        defer cancel()
×
60

×
61
        if len(filters) == 0 {
×
62
                req := &types.ListDynamicConfigRequest{
×
63
                        ConfigName: dcName,
×
64
                }
×
65

×
66
                val, err := adminClient.ListDynamicConfig(ctx, req)
×
67
                if err != nil {
×
68
                        ErrorAndExit("Failed to get dynamic config value(s)", err)
×
69
                }
×
70

71
                if val == nil || val.Entries == nil || len(val.Entries) == 0 {
×
72
                        fmt.Printf("No dynamic config values stored to list.\n")
×
73
                } else {
×
74
                        cliEntries := make([]*cliEntry, 0, len(val.Entries))
×
75
                        for _, dcEntry := range val.Entries {
×
76
                                cliEntry, err := convertToInputEntry(dcEntry)
×
77
                                if err != nil {
×
78
                                        fmt.Printf("Cannot parse list response.\n")
×
79
                                }
×
80
                                cliEntries = append(cliEntries, cliEntry)
×
81
                        }
82
                        prettyPrintJSONObject(cliEntries)
×
83
                }
84
        } else {
×
85
                parsedFilters, err := parseInputFilterArray(filters)
×
86
                if err != nil {
×
87
                        ErrorAndExit("Failed to parse input filter array", err)
×
88
                }
×
89

90
                req := &types.GetDynamicConfigRequest{
×
91
                        ConfigName: dcName,
×
92
                        Filters:    parsedFilters,
×
93
                }
×
94

×
95
                val, err := adminClient.GetDynamicConfig(ctx, req)
×
96
                if err != nil {
×
97
                        ErrorAndExit("Failed to get dynamic config value", err)
×
98
                }
×
99

100
                var umVal interface{}
×
101
                err = json.Unmarshal(val.Value.Data, &umVal)
×
102
                if err != nil {
×
103
                        ErrorAndExit("Failed to unmarshal response", err)
×
104
                }
×
105

106
                if umVal == nil {
×
107
                        fmt.Printf("No values stored for specified dynamic config.\n")
×
108
                } else {
×
109
                        prettyPrintJSONObject(umVal)
×
110
                }
×
111
        }
112
}
113

114
// AdminUpdateDynamicConfig updates specified dynamic config parameter with specified values
115
func AdminUpdateDynamicConfig(c *cli.Context) {
×
116
        adminClient := cFactory.ServerAdminClient(c)
×
117

×
118
        dcName := getRequiredOption(c, FlagDynamicConfigName)
×
119
        dcValues := c.StringSlice(FlagDynamicConfigValue)
×
120

×
121
        ctx, cancel := newContext(c)
×
122
        defer cancel()
×
123

×
124
        var parsedValues []*types.DynamicConfigValue
×
125

×
126
        if dcValues != nil {
×
127
                parsedValues = make([]*types.DynamicConfigValue, 0, len(dcValues))
×
128

×
129
                for _, valueString := range dcValues {
×
130
                        var parsedInputValue *cliValue
×
131
                        err := json.Unmarshal([]byte(valueString), &parsedInputValue)
×
132
                        if err != nil {
×
133
                                ErrorAndExit("Unable to unmarshal value to inputValue", err)
×
134
                        }
×
135
                        parsedValue, err := convertFromInputValue(parsedInputValue)
×
136
                        if err != nil {
×
137
                                ErrorAndExit("Unable to convert from inputValue to DynamicConfigValue", err)
×
138
                        }
×
139
                        parsedValues = append(parsedValues, parsedValue)
×
140
                }
141
        } else {
×
142
                parsedValues = nil
×
143
        }
×
144

145
        req := &types.UpdateDynamicConfigRequest{
×
146
                ConfigName:   dcName,
×
147
                ConfigValues: parsedValues,
×
148
        }
×
149

×
150
        err := adminClient.UpdateDynamicConfig(ctx, req)
×
151
        if err != nil {
×
152
                ErrorAndExit("Failed to update dynamic config value", err)
×
153
        }
×
154
        fmt.Printf("Dynamic Config %q updated with %s \n", dcName, dcValues)
×
155
}
156

157
// AdminRestoreDynamicConfig removes values of specified dynamic config parameter matching specified filter
158
func AdminRestoreDynamicConfig(c *cli.Context) {
×
159
        adminClient := cFactory.ServerAdminClient(c)
×
160

×
161
        dcName := getRequiredOption(c, FlagDynamicConfigName)
×
162
        filters := c.StringSlice(FlagDynamicConfigFilter)
×
163

×
164
        ctx, cancel := newContext(c)
×
165
        defer cancel()
×
166

×
167
        parsedFilters, err := parseInputFilterArray(filters)
×
168
        if err != nil {
×
169
                ErrorAndExit("Failed to parse input filter array", err)
×
170
        }
×
171

172
        req := &types.RestoreDynamicConfigRequest{
×
173
                ConfigName: dcName,
×
174
                Filters:    parsedFilters,
×
175
        }
×
176

×
177
        err = adminClient.RestoreDynamicConfig(ctx, req)
×
178
        if err != nil {
×
179
                ErrorAndExit("Failed to restore dynamic config value", err)
×
180
        }
×
181
        fmt.Printf("Dynamic Config %q restored\n", dcName)
×
182
}
183

184
// AdminListDynamicConfig lists all values associated with specified dynamic config parameter or all values for all dc parameter if none is specified.
185
func AdminListDynamicConfig(c *cli.Context) {
×
186
        adminClient := cFactory.ServerAdminClient(c)
×
187

×
188
        ctx, cancel := newContext(c)
×
189
        defer cancel()
×
190

×
191
        req := &types.ListDynamicConfigRequest{
×
192
                ConfigName: "", // empty string means all config values
×
193
        }
×
194

×
195
        val, err := adminClient.ListDynamicConfig(ctx, req)
×
196
        if err != nil {
×
197
                ErrorAndExit("Failed to list dynamic config value(s)", err)
×
198
        }
×
199

200
        if val == nil || val.Entries == nil || len(val.Entries) == 0 {
×
201
                fmt.Printf("No dynamic config values stored to list.\n")
×
202
        } else {
×
203
                cliEntries := make([]*cliEntry, 0, len(val.Entries))
×
204
                for _, dcEntry := range val.Entries {
×
205
                        cliEntry, err := convertToInputEntry(dcEntry)
×
206
                        if err != nil {
×
207
                                fmt.Printf("Cannot parse list response.\n")
×
208
                        }
×
209
                        cliEntries = append(cliEntries, cliEntry)
×
210
                }
211
                prettyPrintJSONObject(cliEntries)
×
212
        }
213
}
214

215
// AdminListConfigKeys lists all available dynamic config keys with description and default value
216
func AdminListConfigKeys(c *cli.Context) {
×
217

×
218
        type ConfigRow struct {
×
219
                Name        string      `header:"Name" json:"name"`
×
220
                Description string      `header:"Description" json:"description"`
×
221
                Default     interface{} `header:"Default value" json:"default"`
×
222
        }
×
223

×
224
        var rows []ConfigRow
×
225

×
226
        for name, k := range dynamicconfig.GetAllKeys() {
×
227
                rows = append(rows, ConfigRow{
×
228
                        Name:        name,
×
229
                        Description: k.Description(),
×
230
                        Default:     k.DefaultValue(),
×
231
                })
×
232
        }
×
233
        // sorting config key names alphabetically
234
        sort.SliceStable(rows, func(i, j int) bool {
×
235
                return rows[i].Name < rows[j].Name
×
236
        })
×
237

238
        Render(c, rows, RenderOptions{
×
239
                DefaultTemplate: templateTable,
×
240
                Color:           true,
×
241
                Border:          true,
×
242
                ColumnAlignment: []int{tablewriter.ALIGN_LEFT, tablewriter.ALIGN_LEFT, tablewriter.ALIGN_RIGHT}},
×
243
        )
×
244
}
245

246
func convertToInputEntry(dcEntry *types.DynamicConfigEntry) (*cliEntry, error) {
×
247
        newValues := make([]*cliValue, 0, len(dcEntry.Values))
×
248
        for _, value := range dcEntry.Values {
×
249
                newValue, err := convertToInputValue(value)
×
250
                if err != nil {
×
251
                        return nil, err
×
252
                }
×
253
                newValues = append(newValues, newValue)
×
254
        }
255
        return &cliEntry{
×
256
                Name:   dcEntry.Name,
×
257
                Values: newValues,
×
258
        }, nil
×
259
}
260

261
func convertToInputValue(dcValue *types.DynamicConfigValue) (*cliValue, error) {
×
262
        newFilters := make([]*cliFilter, 0, len(dcValue.Filters))
×
263
        for _, filter := range dcValue.Filters {
×
264
                newFilter, err := convertToInputFilter(filter)
×
265
                if err != nil {
×
266
                        return nil, err
×
267
                }
×
268
                newFilters = append(newFilters, newFilter)
×
269
        }
270

271
        var val interface{}
×
272
        err := json.Unmarshal(dcValue.Value.Data, &val)
×
273
        if err != nil {
×
274
                return nil, err
×
275
        }
×
276

277
        return &cliValue{
×
278
                Value:   val,
×
279
                Filters: newFilters,
×
280
        }, nil
×
281
}
282

283
func convertToInputFilter(dcFilter *types.DynamicConfigFilter) (*cliFilter, error) {
×
284
        var val interface{}
×
285
        err := json.Unmarshal(dcFilter.Value.Data, &val)
×
286
        if err != nil {
×
287
                return nil, err
×
288
        }
×
289

290
        return &cliFilter{
×
291
                Name:  dcFilter.Name,
×
292
                Value: val,
×
293
        }, nil
×
294
}
295

296
func convertFromInputValue(inputValue *cliValue) (*types.DynamicConfigValue, error) {
×
297
        encodedValue, err := json.Marshal(inputValue.Value)
×
298
        if err != nil {
×
299
                return nil, err
×
300
        }
×
301

302
        blob := &types.DataBlob{
×
303
                EncodingType: types.EncodingTypeJSON.Ptr(),
×
304
                Data:         encodedValue,
×
305
        }
×
306

×
307
        dcFilters := make([]*types.DynamicConfigFilter, 0, len(inputValue.Filters))
×
308
        for _, inputFilter := range inputValue.Filters {
×
309
                dcFilter, err := convertFromInputFilter(inputFilter)
×
310
                if err != nil {
×
311
                        return nil, err
×
312
                }
×
313
                dcFilters = append(dcFilters, dcFilter)
×
314
        }
315

316
        return &types.DynamicConfigValue{
×
317
                Value:   blob,
×
318
                Filters: dcFilters,
×
319
        }, nil
×
320
}
321

322
func convertFromInputFilter(inputFilter *cliFilter) (*types.DynamicConfigFilter, error) {
×
323
        encodedValue, err := json.Marshal(inputFilter.Value)
×
324
        if err != nil {
×
325
                return nil, err
×
326
        }
×
327

328
        return &types.DynamicConfigFilter{
×
329
                Name: inputFilter.Name,
×
330
                Value: &types.DataBlob{
×
331
                        EncodingType: types.EncodingTypeJSON.Ptr(),
×
332
                        Data:         encodedValue,
×
333
                },
×
334
        }, nil
×
335
}
336

337
func parseInputFilterArray(inputFilters []string) ([]*types.DynamicConfigFilter, error) {
×
338
        var parsedFilters []*types.DynamicConfigFilter
×
339

×
340
        if len(inputFilters) == 1 && (inputFilters[0] == "" || inputFilters[0] == "{}") {
×
341
                parsedFilters = nil
×
342
        } else {
×
343
                parsedFilters = make([]*types.DynamicConfigFilter, 0, len(inputFilters))
×
344

×
345
                for _, filterString := range inputFilters {
×
346
                        var parsedInputFilter *cliFilter
×
347
                        err := json.Unmarshal([]byte(filterString), &parsedInputFilter)
×
348
                        if err != nil {
×
349
                                return nil, err
×
350
                        }
×
351

352
                        filter, err := convertFromInputFilter(parsedInputFilter)
×
353
                        if err != nil {
×
354
                                return nil, err
×
355
                        }
×
356

357
                        parsedFilters = append(parsedFilters, filter)
×
358
                }
359
        }
360

361
        return parsedFilters, nil
×
362
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc