feat: all-access and operator token from CLI (#285)

* chore: include enum values in openapi generated code

* chore: add enum template to list of template overrides

* chore: update template and generated code

* feat: generate permissions list from openapi spec

* feat: all-access and operator token from CLI

Closes #22510

* fix: cloud fixed the resources endpoint

* fix: all access and operator permissions cannot be composed

* fix: review comments from dan-moran
This commit is contained in:
Sam Arnold 2021-10-05 14:33:02 -04:00 committed by GitHub
parent ade82cc4fe
commit 714a73d9eb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 1144 additions and 190 deletions

View File

@ -0,0 +1,203 @@
/*
* Subset of Influx API covered by Influx CLI
*
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* API version: 2.0.0
*/
// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT.
package api
import (
_context "context"
_fmt "fmt"
_io "io"
_nethttp "net/http"
_neturl "net/url"
)
// Linger please
var (
_ _context.Context
)
type ResourceListApi interface {
/*
* GetResources List all known resources
* @param ctx _context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background().
* @return ApiGetResourcesRequest
*/
GetResources(ctx _context.Context) ApiGetResourcesRequest
/*
* GetResourcesExecute executes the request
* @return []string
*/
GetResourcesExecute(r ApiGetResourcesRequest) ([]string, error)
// Sets additional descriptive text in the error message if any request in
// this API fails, indicating that it is intended to be used only on OSS
// servers.
OnlyOSS() ResourceListApi
// Sets additional descriptive text in the error message if any request in
// this API fails, indicating that it is intended to be used only on cloud
// servers.
OnlyCloud() ResourceListApi
}
// ResourceListApiService ResourceListApi service
type ResourceListApiService service
func (a *ResourceListApiService) OnlyOSS() ResourceListApi {
a.isOnlyOSS = true
return a
}
func (a *ResourceListApiService) OnlyCloud() ResourceListApi {
a.isOnlyCloud = true
return a
}
type ApiGetResourcesRequest struct {
ctx _context.Context
ApiService ResourceListApi
zapTraceSpan *string
}
func (r ApiGetResourcesRequest) ZapTraceSpan(zapTraceSpan string) ApiGetResourcesRequest {
r.zapTraceSpan = &zapTraceSpan
return r
}
func (r ApiGetResourcesRequest) GetZapTraceSpan() *string {
return r.zapTraceSpan
}
func (r ApiGetResourcesRequest) Execute() ([]string, error) {
return r.ApiService.GetResourcesExecute(r)
}
/*
* GetResources List all known resources
* @param ctx _context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background().
* @return ApiGetResourcesRequest
*/
func (a *ResourceListApiService) GetResources(ctx _context.Context) ApiGetResourcesRequest {
return ApiGetResourcesRequest{
ApiService: a,
ctx: ctx,
}
}
/*
* Execute executes the request
* @return []string
*/
func (a *ResourceListApiService) GetResourcesExecute(r ApiGetResourcesRequest) ([]string, error) {
var (
localVarHTTPMethod = _nethttp.MethodGet
localVarPostBody interface{}
localVarFormFileName string
localVarFileName string
localVarFileBytes []byte
localVarReturnValue []string
)
localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "ResourceListApiService.GetResources")
if err != nil {
return localVarReturnValue, GenericOpenAPIError{error: err.Error()}
}
localVarPath := localBasePath + "/resources"
localVarHeaderParams := make(map[string]string)
localVarQueryParams := _neturl.Values{}
localVarFormParams := _neturl.Values{}
// to determine the Content-Type header
localVarHTTPContentTypes := []string{}
// set Content-Type header
localVarHTTPContentType := selectHeaderContentType(localVarHTTPContentTypes)
if localVarHTTPContentType != "" {
localVarHeaderParams["Content-Type"] = localVarHTTPContentType
}
// to determine the Accept header
localVarHTTPHeaderAccepts := []string{"application/json"}
// set Accept header
localVarHTTPHeaderAccept := selectHeaderAccept(localVarHTTPHeaderAccepts)
if localVarHTTPHeaderAccept != "" {
localVarHeaderParams["Accept"] = localVarHTTPHeaderAccept
}
if r.zapTraceSpan != nil {
localVarHeaderParams["Zap-Trace-Span"] = parameterToString(*r.zapTraceSpan, "")
}
req, err := a.client.prepareRequest(r.ctx, localVarPath, localVarHTTPMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFormFileName, localVarFileName, localVarFileBytes)
if err != nil {
return localVarReturnValue, err
}
localVarHTTPResponse, err := a.client.callAPI(req)
if err != nil || localVarHTTPResponse == nil {
return localVarReturnValue, err
}
var errorPrefix string
if a.isOnlyOSS {
errorPrefix = "InfluxDB OSS-only command failed: "
} else if a.isOnlyCloud {
errorPrefix = "InfluxDB Cloud-only command failed: "
}
if localVarHTTPResponse.StatusCode >= 300 {
body, err := GunzipIfNeeded(localVarHTTPResponse)
if err != nil {
body.Close()
return localVarReturnValue, _fmt.Errorf("%s%w", errorPrefix, err)
}
localVarBody, err := _io.ReadAll(body)
body.Close()
if err != nil {
return localVarReturnValue, _fmt.Errorf("%s%w", errorPrefix, err)
}
newErr := GenericOpenAPIError{
body: localVarBody,
error: _fmt.Sprintf("%s%s", errorPrefix, localVarHTTPResponse.Status),
}
var v Error
err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type"))
if err != nil {
newErr.error = _fmt.Sprintf("%s: %s", newErr.Error(), err.Error())
return localVarReturnValue, newErr
}
v.SetMessage(_fmt.Sprintf("%s: %s", newErr.Error(), v.GetMessage()))
newErr.model = &v
return localVarReturnValue, newErr
}
body, err := GunzipIfNeeded(localVarHTTPResponse)
if err != nil {
body.Close()
return localVarReturnValue, _fmt.Errorf("%s%w", errorPrefix, err)
}
localVarBody, err := _io.ReadAll(body)
body.Close()
if err != nil {
return localVarReturnValue, _fmt.Errorf("%s%w", errorPrefix, err)
}
err = a.client.decode(&localVarReturnValue, localVarBody, localVarHTTPResponse.Header.Get("Content-Type"))
if err != nil {
newErr := GenericOpenAPIError{
body: localVarBody,
error: _fmt.Sprintf("%s%s", errorPrefix, err.Error()),
}
return localVarReturnValue, newErr
}
return localVarReturnValue, nil
}

52
api/cli-extras.gen.yml Normal file
View File

@ -0,0 +1,52 @@
openapi: 3.0.0
info:
title: Extra configuration to force openapi to generate enum validators
version: 2.0.0
servers: []
paths: {}
components:
schemas:
ResourceEnumOSS:
type: string
enum:
- authorizations
- buckets
- dashboards
- orgs
- sources
- tasks
- telegrafs
- users
- variables
- scrapers
- secrets
- labels
- views
- documents
- notificationRules
- notificationEndpoints
- checks
- dbrp
- notebooks
ResourceEnumCloud:
type: string
enum:
- authorizations
- buckets
- dashboards
- orgs
- tasks
- telegrafs
- users
- variables
- secrets
- labels
- views
- documents
- notificationRules
- notificationEndpoints
- checks
- dbrp
- flows
- annotations
- functions

View File

@ -72,6 +72,8 @@ type APIClient struct {
ReplicationsApi ReplicationsApi
ResourceListApi ResourceListApi
RestoreApi RestoreApi
SecretsApi SecretsApi
@ -122,6 +124,7 @@ func NewAPIClient(cfg *Configuration) *APIClient {
c.QueryApi = (*QueryApiService)(&c.common)
c.RemoteConnectionsApi = (*RemoteConnectionsApiService)(&c.common)
c.ReplicationsApi = (*ReplicationsApiService)(&c.common)
c.ResourceListApi = (*ResourceListApiService)(&c.common)
c.RestoreApi = (*RestoreApiService)(&c.common)
c.SecretsApi = (*SecretsApiService)(&c.common)
c.SetupApi = (*SetupApiService)(&c.common)

View File

@ -0,0 +1,13 @@
openapi: "3.0.0"
info:
title: Extra configuration to force openapi to generate enum validators
version: 2.0.0
servers: []
paths: {}
components:
schemas:
ResourceEnumOSS:
$ref: "./openapi/src/common/schemas/Resource.yml#/properties/type"
ResourceEnumCloud:
$ref: "./openapi/src/cloud/schemas/Resource.yml#/properties/type"

View File

@ -63,6 +63,8 @@ paths:
$ref: "./overrides/paths/backup_metadata.yml"
/backup/shards/{shardID}:
$ref: "./openapi/src/oss/paths/backup_shards_shardID.yml"
/resources:
$ref: "./openapi/src/common/paths/resources.yml"
/restore/kv:
$ref: "./openapi/src/oss/paths/restore_kv.yml"
/restore/sql:

View File

@ -0,0 +1 @@
README.md

11
api/extras/README.md Normal file
View File

@ -0,0 +1,11 @@
# Influx CLI - extra files supporting HTTP client
The `.go` files in this module are generated using [`OpenAPITools/openapi-generator`](https://github.com/OpenAPITools/openapi-generator),
based off of our public API documentation.
See https://github.com/OpenAPITools/openapi-generator/issues/2360 - enums are not generated by default if they are defined inline.
Even if they were generated by default, there appears to be no way to turn off the validation, which would be bad if the client
started receiving new string values that were unrecognized (using an old client with a newer InfluxDB instance).
So the go files in this directory are generated from some enums where we want to know the list of 'known' valid values, but
we don't want to always validate on marshal/unmarshal.

View File

@ -0,0 +1,104 @@
/*
* Extra configuration to force openapi to generate enum validators
*
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* API version: 2.0.0
*/
// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT.
package extras
import (
"encoding/json"
"fmt"
)
// ResourceEnumCloud the model 'ResourceEnumCloud'
type ResourceEnumCloud string
// List of ResourceEnumCloud
const (
RESOURCEENUMCLOUD_AUTHORIZATIONS ResourceEnumCloud = "authorizations"
RESOURCEENUMCLOUD_BUCKETS ResourceEnumCloud = "buckets"
RESOURCEENUMCLOUD_DASHBOARDS ResourceEnumCloud = "dashboards"
RESOURCEENUMCLOUD_ORGS ResourceEnumCloud = "orgs"
RESOURCEENUMCLOUD_TASKS ResourceEnumCloud = "tasks"
RESOURCEENUMCLOUD_TELEGRAFS ResourceEnumCloud = "telegrafs"
RESOURCEENUMCLOUD_USERS ResourceEnumCloud = "users"
RESOURCEENUMCLOUD_VARIABLES ResourceEnumCloud = "variables"
RESOURCEENUMCLOUD_SECRETS ResourceEnumCloud = "secrets"
RESOURCEENUMCLOUD_LABELS ResourceEnumCloud = "labels"
RESOURCEENUMCLOUD_VIEWS ResourceEnumCloud = "views"
RESOURCEENUMCLOUD_DOCUMENTS ResourceEnumCloud = "documents"
RESOURCEENUMCLOUD_NOTIFICATION_RULES ResourceEnumCloud = "notificationRules"
RESOURCEENUMCLOUD_NOTIFICATION_ENDPOINTS ResourceEnumCloud = "notificationEndpoints"
RESOURCEENUMCLOUD_CHECKS ResourceEnumCloud = "checks"
RESOURCEENUMCLOUD_DBRP ResourceEnumCloud = "dbrp"
RESOURCEENUMCLOUD_FLOWS ResourceEnumCloud = "flows"
RESOURCEENUMCLOUD_ANNOTATIONS ResourceEnumCloud = "annotations"
RESOURCEENUMCLOUD_FUNCTIONS ResourceEnumCloud = "functions"
)
func ResourceEnumCloudValues() []ResourceEnumCloud {
return []ResourceEnumCloud{"authorizations", "buckets", "dashboards", "orgs", "tasks", "telegrafs", "users", "variables", "secrets", "labels", "views", "documents", "notificationRules", "notificationEndpoints", "checks", "dbrp", "flows", "annotations", "functions"}
}
func (v *ResourceEnumCloud) UnmarshalJSON(src []byte) error {
var value string
err := json.Unmarshal(src, &value)
if err != nil {
return err
}
enumTypeValue := ResourceEnumCloud(value)
for _, existing := range []ResourceEnumCloud{"authorizations", "buckets", "dashboards", "orgs", "tasks", "telegrafs", "users", "variables", "secrets", "labels", "views", "documents", "notificationRules", "notificationEndpoints", "checks", "dbrp", "flows", "annotations", "functions"} {
if existing == enumTypeValue {
*v = enumTypeValue
return nil
}
}
return fmt.Errorf("%+v is not a valid ResourceEnumCloud", value)
}
// Ptr returns reference to ResourceEnumCloud value
func (v ResourceEnumCloud) Ptr() *ResourceEnumCloud {
return &v
}
type NullableResourceEnumCloud struct {
value *ResourceEnumCloud
isSet bool
}
func (v NullableResourceEnumCloud) Get() *ResourceEnumCloud {
return v.value
}
func (v *NullableResourceEnumCloud) Set(val *ResourceEnumCloud) {
v.value = val
v.isSet = true
}
func (v NullableResourceEnumCloud) IsSet() bool {
return v.isSet
}
func (v *NullableResourceEnumCloud) Unset() {
v.value = nil
v.isSet = false
}
func NewNullableResourceEnumCloud(val *ResourceEnumCloud) *NullableResourceEnumCloud {
return &NullableResourceEnumCloud{value: val, isSet: true}
}
func (v NullableResourceEnumCloud) MarshalJSON() ([]byte, error) {
return json.Marshal(v.value)
}
func (v *NullableResourceEnumCloud) UnmarshalJSON(src []byte) error {
v.isSet = true
return json.Unmarshal(src, &v.value)
}

View File

@ -0,0 +1,104 @@
/*
* Extra configuration to force openapi to generate enum validators
*
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* API version: 2.0.0
*/
// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT.
package extras
import (
"encoding/json"
"fmt"
)
// ResourceEnumOSS the model 'ResourceEnumOSS'
type ResourceEnumOSS string
// List of ResourceEnumOSS
const (
RESOURCEENUMOSS_AUTHORIZATIONS ResourceEnumOSS = "authorizations"
RESOURCEENUMOSS_BUCKETS ResourceEnumOSS = "buckets"
RESOURCEENUMOSS_DASHBOARDS ResourceEnumOSS = "dashboards"
RESOURCEENUMOSS_ORGS ResourceEnumOSS = "orgs"
RESOURCEENUMOSS_SOURCES ResourceEnumOSS = "sources"
RESOURCEENUMOSS_TASKS ResourceEnumOSS = "tasks"
RESOURCEENUMOSS_TELEGRAFS ResourceEnumOSS = "telegrafs"
RESOURCEENUMOSS_USERS ResourceEnumOSS = "users"
RESOURCEENUMOSS_VARIABLES ResourceEnumOSS = "variables"
RESOURCEENUMOSS_SCRAPERS ResourceEnumOSS = "scrapers"
RESOURCEENUMOSS_SECRETS ResourceEnumOSS = "secrets"
RESOURCEENUMOSS_LABELS ResourceEnumOSS = "labels"
RESOURCEENUMOSS_VIEWS ResourceEnumOSS = "views"
RESOURCEENUMOSS_DOCUMENTS ResourceEnumOSS = "documents"
RESOURCEENUMOSS_NOTIFICATION_RULES ResourceEnumOSS = "notificationRules"
RESOURCEENUMOSS_NOTIFICATION_ENDPOINTS ResourceEnumOSS = "notificationEndpoints"
RESOURCEENUMOSS_CHECKS ResourceEnumOSS = "checks"
RESOURCEENUMOSS_DBRP ResourceEnumOSS = "dbrp"
RESOURCEENUMOSS_NOTEBOOKS ResourceEnumOSS = "notebooks"
)
func ResourceEnumOSSValues() []ResourceEnumOSS {
return []ResourceEnumOSS{"authorizations", "buckets", "dashboards", "orgs", "sources", "tasks", "telegrafs", "users", "variables", "scrapers", "secrets", "labels", "views", "documents", "notificationRules", "notificationEndpoints", "checks", "dbrp", "notebooks"}
}
func (v *ResourceEnumOSS) UnmarshalJSON(src []byte) error {
var value string
err := json.Unmarshal(src, &value)
if err != nil {
return err
}
enumTypeValue := ResourceEnumOSS(value)
for _, existing := range []ResourceEnumOSS{"authorizations", "buckets", "dashboards", "orgs", "sources", "tasks", "telegrafs", "users", "variables", "scrapers", "secrets", "labels", "views", "documents", "notificationRules", "notificationEndpoints", "checks", "dbrp", "notebooks"} {
if existing == enumTypeValue {
*v = enumTypeValue
return nil
}
}
return fmt.Errorf("%+v is not a valid ResourceEnumOSS", value)
}
// Ptr returns reference to ResourceEnumOSS value
func (v ResourceEnumOSS) Ptr() *ResourceEnumOSS {
return &v
}
type NullableResourceEnumOSS struct {
value *ResourceEnumOSS
isSet bool
}
func (v NullableResourceEnumOSS) Get() *ResourceEnumOSS {
return v.value
}
func (v *NullableResourceEnumOSS) Set(val *ResourceEnumOSS) {
v.value = val
v.isSet = true
}
func (v NullableResourceEnumOSS) IsSet() bool {
return v.isSet
}
func (v *NullableResourceEnumOSS) Unset() {
v.value = nil
v.isSet = false
}
func NewNullableResourceEnumOSS(val *ResourceEnumOSS) *NullableResourceEnumOSS {
return &NullableResourceEnumOSS{value: val, isSet: true}
}
func (v NullableResourceEnumOSS) MarshalJSON() ([]byte, error) {
return json.Marshal(v.value)
}
func (v *NullableResourceEnumOSS) UnmarshalJSON(src []byte) error {
v.isSet = true
return json.Unmarshal(src, &v.value)
}

328
api/extras/utils.gen.go Normal file
View File

@ -0,0 +1,328 @@
/*
* Extra configuration to force openapi to generate enum validators
*
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* API version: 2.0.0
*/
// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT.
package extras
import (
"encoding/json"
"time"
)
// PtrBool is a helper routine that returns a pointer to given boolean value.
func PtrBool(v bool) *bool { return &v }
// PtrInt is a helper routine that returns a pointer to given integer value.
func PtrInt(v int) *int { return &v }
// PtrInt32 is a helper routine that returns a pointer to given integer value.
func PtrInt32(v int32) *int32 { return &v }
// PtrInt64 is a helper routine that returns a pointer to given integer value.
func PtrInt64(v int64) *int64 { return &v }
// PtrFloat32 is a helper routine that returns a pointer to given float value.
func PtrFloat32(v float32) *float32 { return &v }
// PtrFloat64 is a helper routine that returns a pointer to given float value.
func PtrFloat64(v float64) *float64 { return &v }
// PtrString is a helper routine that returns a pointer to given string value.
func PtrString(v string) *string { return &v }
// PtrTime is helper routine that returns a pointer to given Time value.
func PtrTime(v time.Time) *time.Time { return &v }
type NullableBool struct {
value *bool
isSet bool
}
func (v NullableBool) Get() *bool {
return v.value
}
func (v *NullableBool) Set(val *bool) {
v.value = val
v.isSet = true
}
func (v NullableBool) IsSet() bool {
return v.isSet
}
func (v *NullableBool) Unset() {
v.value = nil
v.isSet = false
}
func NewNullableBool(val *bool) *NullableBool {
return &NullableBool{value: val, isSet: true}
}
func (v NullableBool) MarshalJSON() ([]byte, error) {
return json.Marshal(v.value)
}
func (v *NullableBool) UnmarshalJSON(src []byte) error {
v.isSet = true
return json.Unmarshal(src, &v.value)
}
type NullableInt struct {
value *int
isSet bool
}
func (v NullableInt) Get() *int {
return v.value
}
func (v *NullableInt) Set(val *int) {
v.value = val
v.isSet = true
}
func (v NullableInt) IsSet() bool {
return v.isSet
}
func (v *NullableInt) Unset() {
v.value = nil
v.isSet = false
}
func NewNullableInt(val *int) *NullableInt {
return &NullableInt{value: val, isSet: true}
}
func (v NullableInt) MarshalJSON() ([]byte, error) {
return json.Marshal(v.value)
}
func (v *NullableInt) UnmarshalJSON(src []byte) error {
v.isSet = true
return json.Unmarshal(src, &v.value)
}
type NullableInt32 struct {
value *int32
isSet bool
}
func (v NullableInt32) Get() *int32 {
return v.value
}
func (v *NullableInt32) Set(val *int32) {
v.value = val
v.isSet = true
}
func (v NullableInt32) IsSet() bool {
return v.isSet
}
func (v *NullableInt32) Unset() {
v.value = nil
v.isSet = false
}
func NewNullableInt32(val *int32) *NullableInt32 {
return &NullableInt32{value: val, isSet: true}
}
func (v NullableInt32) MarshalJSON() ([]byte, error) {
return json.Marshal(v.value)
}
func (v *NullableInt32) UnmarshalJSON(src []byte) error {
v.isSet = true
return json.Unmarshal(src, &v.value)
}
type NullableInt64 struct {
value *int64
isSet bool
}
func (v NullableInt64) Get() *int64 {
return v.value
}
func (v *NullableInt64) Set(val *int64) {
v.value = val
v.isSet = true
}
func (v NullableInt64) IsSet() bool {
return v.isSet
}
func (v *NullableInt64) Unset() {
v.value = nil
v.isSet = false
}
func NewNullableInt64(val *int64) *NullableInt64 {
return &NullableInt64{value: val, isSet: true}
}
func (v NullableInt64) MarshalJSON() ([]byte, error) {
return json.Marshal(v.value)
}
func (v *NullableInt64) UnmarshalJSON(src []byte) error {
v.isSet = true
return json.Unmarshal(src, &v.value)
}
type NullableFloat32 struct {
value *float32
isSet bool
}
func (v NullableFloat32) Get() *float32 {
return v.value
}
func (v *NullableFloat32) Set(val *float32) {
v.value = val
v.isSet = true
}
func (v NullableFloat32) IsSet() bool {
return v.isSet
}
func (v *NullableFloat32) Unset() {
v.value = nil
v.isSet = false
}
func NewNullableFloat32(val *float32) *NullableFloat32 {
return &NullableFloat32{value: val, isSet: true}
}
func (v NullableFloat32) MarshalJSON() ([]byte, error) {
return json.Marshal(v.value)
}
func (v *NullableFloat32) UnmarshalJSON(src []byte) error {
v.isSet = true
return json.Unmarshal(src, &v.value)
}
type NullableFloat64 struct {
value *float64
isSet bool
}
func (v NullableFloat64) Get() *float64 {
return v.value
}
func (v *NullableFloat64) Set(val *float64) {
v.value = val
v.isSet = true
}
func (v NullableFloat64) IsSet() bool {
return v.isSet
}
func (v *NullableFloat64) Unset() {
v.value = nil
v.isSet = false
}
func NewNullableFloat64(val *float64) *NullableFloat64 {
return &NullableFloat64{value: val, isSet: true}
}
func (v NullableFloat64) MarshalJSON() ([]byte, error) {
return json.Marshal(v.value)
}
func (v *NullableFloat64) UnmarshalJSON(src []byte) error {
v.isSet = true
return json.Unmarshal(src, &v.value)
}
type NullableString struct {
value *string
isSet bool
}
func (v NullableString) Get() *string {
return v.value
}
func (v *NullableString) Set(val *string) {
v.value = val
v.isSet = true
}
func (v NullableString) IsSet() bool {
return v.isSet
}
func (v *NullableString) Unset() {
v.value = nil
v.isSet = false
}
func NewNullableString(val *string) *NullableString {
return &NullableString{value: val, isSet: true}
}
func (v NullableString) MarshalJSON() ([]byte, error) {
return json.Marshal(v.value)
}
func (v *NullableString) UnmarshalJSON(src []byte) error {
v.isSet = true
return json.Unmarshal(src, &v.value)
}
type NullableTime struct {
value *time.Time
isSet bool
}
func (v NullableTime) Get() *time.Time {
return v.value
}
func (v *NullableTime) Set(val *time.Time) {
v.value = val
v.isSet = true
}
func (v NullableTime) IsSet() bool {
return v.isSet
}
func (v *NullableTime) Unset() {
v.value = nil
v.isSet = false
}
func NewNullableTime(val *time.Time) *NullableTime {
return &NullableTime{value: val, isSet: true}
}
func (v NullableTime) MarshalJSON() ([]byte, error) {
return v.value.MarshalJSON()
}
func (v *NullableTime) UnmarshalJSON(src []byte) error {
v.isSet = true
return json.Unmarshal(src, &v.value)
}

View File

@ -27,6 +27,10 @@ const (
COLUMNDATATYPE_UNSIGNED ColumnDataType = "unsigned"
)
func ColumnDataTypeValues() []ColumnDataType {
return []ColumnDataType{"integer", "float", "boolean", "string", "unsigned"}
}
func (v *ColumnDataType) UnmarshalJSON(src []byte) error {
var value string
err := json.Unmarshal(src, &value)

View File

@ -25,6 +25,10 @@ const (
COLUMNSEMANTICTYPE_FIELD ColumnSemanticType = "field"
)
func ColumnSemanticTypeValues() []ColumnSemanticType {
return []ColumnSemanticType{"timestamp", "tag", "field"}
}
func (v *ColumnSemanticType) UnmarshalJSON(src []byte) error {
var value string
err := json.Unmarshal(src, &value)

View File

@ -35,6 +35,10 @@ const (
ERRORCODE_UNSUPPORTED_MEDIA_TYPE ErrorCode = "unsupported media type"
)
func ErrorCodeValues() []ErrorCode {
return []ErrorCode{"internal error", "not found", "conflict", "invalid", "unprocessable entity", "empty value", "unavailable", "forbidden", "too many requests", "unauthorized", "method not allowed", "request too large", "unsupported media type"}
}
func (v *ErrorCode) UnmarshalJSON(src []byte) error {
var value string
err := json.Unmarshal(src, &value)

View File

@ -24,6 +24,10 @@ const (
HEALTHCHECKSTATUS_FAIL HealthCheckStatus = "fail"
)
func HealthCheckStatusValues() []HealthCheckStatus {
return []HealthCheckStatus{"pass", "fail"}
}
func (v *HealthCheckStatus) UnmarshalJSON(src []byte) error {
var value string
err := json.Unmarshal(src, &value)

View File

@ -28,6 +28,10 @@ const (
LINEPROTOCOLERRORCODE_UNAVAILABLE LineProtocolErrorCode = "unavailable"
)
func LineProtocolErrorCodeValues() []LineProtocolErrorCode {
return []LineProtocolErrorCode{"internal error", "not found", "conflict", "invalid", "empty value", "unavailable"}
}
func (v *LineProtocolErrorCode) UnmarshalJSON(src []byte) error {
var value string
err := json.Unmarshal(src, &value)

View File

@ -23,6 +23,10 @@ const (
LINEPROTOCOLLENGTHERRORCODE_INVALID LineProtocolLengthErrorCode = "invalid"
)
func LineProtocolLengthErrorCodeValues() []LineProtocolLengthErrorCode {
return []LineProtocolLengthErrorCode{"invalid"}
}
func (v *LineProtocolLengthErrorCode) UnmarshalJSON(src []byte) error {
var value string
err := json.Unmarshal(src, &value)

View File

@ -24,6 +24,10 @@ const (
SCHEMATYPE_EXPLICIT SchemaType = "explicit"
)
func SchemaTypeValues() []SchemaType {
return []SchemaType{"implicit", "explicit"}
}
func (v *SchemaType) UnmarshalJSON(src []byte) error {
var value string
err := json.Unmarshal(src, &value)

View File

@ -24,6 +24,10 @@ const (
TASKSTATUSTYPE_INACTIVE TaskStatusType = "inactive"
)
func TaskStatusTypeValues() []TaskStatusType {
return []TaskStatusType{"active", "inactive"}
}
func (v *TaskStatusType) UnmarshalJSON(src []byte) error {
var value string
err := json.Unmarshal(src, &value)

View File

@ -24,6 +24,10 @@ const (
TEMPLATEAPPLYACTIONKIND_SKIP_RESOURCE TemplateApplyActionKind = "skipResource"
)
func TemplateApplyActionKindValues() []TemplateApplyActionKind {
return []TemplateApplyActionKind{"skipKind", "skipResource"}
}
func (v *TemplateApplyActionKind) UnmarshalJSON(src []byte) error {
var value string
err := json.Unmarshal(src, &value)

View File

@ -26,6 +26,10 @@ const (
WRITEPRECISION_NS WritePrecision = "ns"
)
func WritePrecisionValues() []WritePrecision {
return []WritePrecision{"ms", "s", "us", "ns"}
}
func (v *WritePrecision) UnmarshalJSON(src []byte) error {
var value string
err := json.Unmarshal(src, &value)

View File

@ -32,6 +32,9 @@ multiple locations.
* Deleted `ContextOAuth2` key to match modification in client
* Fixed error strings to be idiomatic according to staticcheck (lowercase, no punctuation)
`model_enum.mustache`
* Add a function to build and return a slice of the valid values for the enum, named <enum_name>Values
`model_oneof.mustache`
* Fixed error strings to be idiomatic according to staticcheck (lowercase, no punctuation)

View File

@ -0,0 +1,75 @@
// {{{classname}}} {{#description}}{{{.}}}{{/description}}{{^description}}the model '{{{classname}}}'{{/description}}
type {{{classname}}} {{^format}}{{dataType}}{{/format}}{{#format}}{{{format}}}{{/format}}
// List of {{{name}}}
const (
{{#allowableValues}}
{{#enumVars}}
{{^-first}}
{{/-first}}
{{#enumClassPrefix}}{{{classname.toUpperCase}}}_{{/enumClassPrefix}}{{name}} {{{classname}}} = {{{value}}}
{{/enumVars}}
{{/allowableValues}}
)
func {{{classname}}}Values() []{{{classname}}} {
return []{{classname}}{ {{#allowableValues}}{{#enumVars}}{{{value}}}, {{/enumVars}} {{/allowableValues}} }
}
func (v *{{{classname}}}) UnmarshalJSON(src []byte) error {
var value {{^format}}{{dataType}}{{/format}}{{#format}}{{{format}}}{{/format}}
err := json.Unmarshal(src, &value)
if err != nil {
return err
}
enumTypeValue := {{{classname}}}(value)
for _, existing := range []{{classname}}{ {{#allowableValues}}{{#enumVars}}{{{value}}}, {{/enumVars}} {{/allowableValues}} } {
if existing == enumTypeValue {
*v = enumTypeValue
return nil
}
}
return fmt.Errorf("%+v is not a valid {{classname}}", value)
}
// Ptr returns reference to {{{name}}} value
func (v {{{classname}}}) Ptr() *{{{classname}}} {
return &v
}
type Nullable{{{classname}}} struct {
value *{{{classname}}}
isSet bool
}
func (v Nullable{{classname}}) Get() *{{classname}} {
return v.value
}
func (v *Nullable{{classname}}) Set(val *{{classname}}) {
v.value = val
v.isSet = true
}
func (v Nullable{{classname}}) IsSet() bool {
return v.isSet
}
func (v *Nullable{{classname}}) Unset() {
v.value = nil
v.isSet = false
}
func NewNullable{{classname}}(val *{{classname}}) *Nullable{{classname}} {
return &Nullable{{classname}}{value: val, isSet: true}
}
func (v Nullable{{{classname}}}) MarshalJSON() ([]byte, error) {
return json.Marshal(v.value)
}
func (v *Nullable{{{classname}}}) UnmarshalJSON(src []byte) error {
v.isSet = true
return json.Unmarshal(src, &v.value)
}

View File

@ -5,6 +5,7 @@ import (
"fmt"
"github.com/influxdata/influx-cli/v2/api"
"github.com/influxdata/influx-cli/v2/api/extras"
"github.com/influxdata/influx-cli/v2/clients"
"github.com/influxdata/influx-cli/v2/pkg/influxid"
)
@ -14,6 +15,7 @@ type Client struct {
api.AuthorizationsApi
api.UsersApi
api.OrganizationsApi
api.ResourceListApi
}
const (
@ -37,43 +39,71 @@ type printParams struct {
tokens []token
}
type ResourcePermission struct {
Name string
Read bool
Write bool
IsCloud bool
IsOss bool
}
type CreateParams struct {
clients.OrgParams
User string
Description string
WriteUserPermission bool
ReadUserPermission bool
WriteBucketsPermission bool
ReadBucketsPermission bool
ResourcePermissions []*ResourcePermission
WriteBucketIds []string
ReadBucketIds []string
WriteTasksPermission bool
ReadTasksPermission bool
OperatorPermission bool
AllAccess bool
}
WriteTelegrafsPermission bool
ReadTelegrafsPermission bool
func BuildResourcePermissions() []*ResourcePermission {
cloudResources := make(map[string]struct{})
ossResources := make(map[string]struct{})
for _, val := range extras.ResourceEnumCloudValues() {
cloudResources[string(val)] = struct{}{}
}
for _, val := range extras.ResourceEnumOSSValues() {
ossResources[string(val)] = struct{}{}
}
WriteOrganizationsPermission bool
ReadOrganizationsPermission bool
perms := make([]*ResourcePermission, 0, len(ossResources))
// First the common permissions in order
for _, val := range extras.ResourceEnumOSSValues() {
if _, ok := cloudResources[string(val)]; ok {
perms = append(perms, &ResourcePermission{
Name: string(val),
IsCloud: true,
IsOss: true,
})
}
}
WriteDashboardsPermission bool
ReadDashboardsPermission bool
// Then oss-only in order
for _, val := range extras.ResourceEnumOSSValues() {
if _, ok := cloudResources[string(val)]; !ok {
perms = append(perms, &ResourcePermission{
Name: string(val),
IsOss: true,
})
}
}
WriteCheckPermission bool
ReadCheckPermission bool
// Then cloud-only in order
for _, val := range extras.ResourceEnumCloudValues() {
if _, ok := ossResources[string(val)]; !ok {
perms = append(perms, &ResourcePermission{
Name: string(val),
IsCloud: true,
})
}
}
WriteNotificationRulePermission bool
ReadNotificationRulePermission bool
WriteNotificationEndpointPermission bool
ReadNotificationEndpointPermission bool
WriteDBRPPermission bool
ReadDBRPPermission bool
return perms
}
func (c Client) Create(ctx context.Context, params *CreateParams) error {
@ -90,6 +120,13 @@ func (c Client) Create(ctx context.Context, params *CreateParams) error {
{action: WriteAction, perms: params.WriteBucketIds},
}
// Get the user ID because the command only takes a username, not ID
users, err := c.UsersApi.GetUsers(ctx).Name(params.User).Execute()
if err != nil || len(users.GetUsers()) == 0 {
return fmt.Errorf("could not find user with name %q: %w", params.User, err)
}
userID := users.GetUsers()[0].GetId()
var permissions []api.Permission
for _, bp := range bucketPerms {
for _, p := range bp.perms {
@ -106,86 +143,81 @@ func (c Client) Create(ctx context.Context, params *CreateParams) error {
}
}
providedPerm := []struct {
readPerm, writePerm bool
resourceType string
}{
{
readPerm: params.ReadBucketsPermission,
writePerm: params.WriteBucketsPermission,
resourceType: "buckets",
},
{
readPerm: params.ReadCheckPermission,
writePerm: params.WriteCheckPermission,
resourceType: "checks",
},
{
readPerm: params.ReadDashboardsPermission,
writePerm: params.WriteDashboardsPermission,
resourceType: "dashboards",
},
{
readPerm: params.ReadNotificationEndpointPermission,
writePerm: params.WriteNotificationEndpointPermission,
resourceType: "notificationEndpoints",
},
{
readPerm: params.ReadNotificationRulePermission,
writePerm: params.WriteNotificationRulePermission,
resourceType: "notificationRules",
},
{
readPerm: params.ReadOrganizationsPermission,
writePerm: params.WriteOrganizationsPermission,
resourceType: "orgs",
},
{
readPerm: params.ReadTasksPermission,
writePerm: params.WriteTasksPermission,
resourceType: "tasks",
},
{
readPerm: params.ReadTelegrafsPermission,
writePerm: params.WriteTelegrafsPermission,
resourceType: "telegrafs",
},
{
readPerm: params.ReadUserPermission,
writePerm: params.WriteUserPermission,
resourceType: "users",
},
{
readPerm: params.ReadDBRPPermission,
writePerm: params.WriteDBRPPermission,
resourceType: "dbrp",
},
}
for _, provided := range providedPerm {
for _, resourcePermission := range params.ResourcePermissions {
var actions []string
if provided.readPerm {
if resourcePermission.Read {
actions = append(actions, ReadAction)
}
if provided.writePerm {
if resourcePermission.Write {
actions = append(actions, WriteAction)
}
for _, action := range actions {
p := api.Permission{
Action: action,
Resource: makePermResource(provided.resourceType, "", orgID),
Resource: makePermResource(resourcePermission.Name, "", orgID),
}
permissions = append(permissions, p)
}
}
// Get the user ID because the command only takes a username, not ID
users, err := c.UsersApi.GetUsers(ctx).Name(params.User).Execute()
if err != nil || len(users.GetUsers()) == 0 {
return fmt.Errorf("could not find user with name %q: %w", params.User, err)
if params.OperatorPermission {
if len(permissions) > 0 {
return fmt.Errorf("cannot compose other permissions with operator permissions")
}
resources, err := c.GetResources(ctx).Execute()
if err != nil {
return err
}
for _, r := range resources {
for _, action := range []string{ReadAction, WriteAction} {
permissions = append(permissions, api.Permission{
Action: action,
Resource: makePermResource(r, "", ""),
})
}
}
}
if params.AllAccess {
if len(permissions) > 0 {
return fmt.Errorf("cannot compose other permissions with all access permissions")
}
resources, err := c.GetResources(ctx).Execute()
if err != nil {
return err
}
for _, r := range resources {
if r == string(extras.RESOURCEENUMCLOUD_ORGS) {
// orgs are handled specifically - all access is for a single org, not global access to all orgs
permissions = append(permissions, api.Permission{
Action: ReadAction,
Resource: api.PermissionResource{
Type: r,
Id: &orgID,
},
})
} else if r == string(extras.RESOURCEENUMCLOUD_USERS) {
// users are handled specifically - all access is for a single user, not global to all users
for _, action := range []string{ReadAction, WriteAction} {
permissions = append(permissions, api.Permission{
Action: action,
Resource: api.PermissionResource{
Type: r,
Id: &userID,
},
})
}
} else {
for _, action := range []string{ReadAction, WriteAction} {
permissions = append(permissions, api.Permission{
Action: action,
Resource: makePermResource(r, "", orgID),
})
}
}
}
}
userID := users.GetUsers()[0].GetId()
authReq := api.AuthorizationPostRequest{
OrgID: orgID,

View File

@ -1,6 +1,8 @@
package main
import (
"fmt"
"github.com/influxdata/influx-cli/v2/clients/auth"
"github.com/influxdata/influx-cli/v2/pkg/cli/middleware"
"github.com/urfave/cli"
@ -21,9 +23,32 @@ func newAuthCommand() cli.Command {
}
}
func helpText(perm string) struct{ readHelp, writeHelp string } {
var helpOverrides = map[string]struct{ readHelp, writeHelp string }{
"user": {"perform read actions against organization users", "perform mutative actions against organization users"},
"buckets": {"perform read actions against organization buckets", "perform mutative actions against organization buckets"},
"telegrafs": {"read telegraf configs", "create telegraf configs"},
"orgs": {"read organizations", "create organizations"},
"dbrps": {"read database retention policy mappings", "create database retention policy mappings"},
}
help := helpOverrides[perm]
if help.readHelp == "" {
help.readHelp = fmt.Sprintf("read %s", perm)
}
if help.writeHelp == "" {
help.writeHelp = fmt.Sprintf("create or update %s", perm)
}
help.readHelp = "Grants the permission to " + help.readHelp
help.writeHelp = "Grants the permission to " + help.writeHelp
return help
}
func newCreateCommand() cli.Command {
var params auth.CreateParams
flags := append(commonFlags(), getOrgFlags(&params.OrgParams)...)
flags = append(flags,
&cli.StringFlag{
Name: "user, u",
@ -35,27 +60,6 @@ func newCreateCommand() cli.Command {
Usage: "Token description",
Destination: &params.Description,
},
&cli.BoolFlag{
Name: "write-user",
Usage: "Grants the permission to perform mutative actions against organization users",
Destination: &params.WriteUserPermission,
},
&cli.BoolFlag{
Name: "read-user",
Usage: "Grants the permission to perform read actions against organization users",
Destination: &params.ReadUserPermission,
},
&cli.BoolFlag{
Name: "write-buckets",
Usage: "Grants the permission to perform mutative actions against organization buckets",
Destination: &params.WriteBucketsPermission,
},
&cli.BoolFlag{
Name: "read-buckets",
Usage: "Grants the permission to perform read actions against organization buckets",
Destination: &params.ReadBucketsPermission,
},
&cli.StringSliceFlag{
Name: "write-bucket",
Usage: "The bucket id",
@ -65,86 +69,40 @@ func newCreateCommand() cli.Command {
Usage: "The bucket id",
},
&cli.BoolFlag{
Name: "write-tasks",
Usage: "Grants the permission to create tasks",
Destination: &params.WriteTasksPermission,
Name: "operator",
Usage: "Grants all permissions in all organizations",
Destination: &params.OperatorPermission,
},
&cli.BoolFlag{
Name: "read-tasks",
Usage: "Grants the permission to read tasks",
Destination: &params.ReadTasksPermission,
},
&cli.BoolFlag{
Name: "write-telegrafs",
Usage: "Grants the permission to create telegraf configs",
Destination: &params.WriteTelegrafsPermission,
},
&cli.BoolFlag{
Name: "read-telegrafs",
Usage: "Grants the permission to read telegraf configs",
Destination: &params.ReadTelegrafsPermission,
},
&cli.BoolFlag{
Name: "write-orgs",
Usage: "Grants the permission to create organizations",
Destination: &params.WriteOrganizationsPermission,
},
&cli.BoolFlag{
Name: "read-orgs",
Usage: "Grants the permission to read organizations",
Destination: &params.ReadOrganizationsPermission,
},
&cli.BoolFlag{
Name: "write-dashboards",
Usage: "Grants the permission to create dashboards",
Destination: &params.WriteDashboardsPermission,
},
&cli.BoolFlag{
Name: "read-dashboards",
Usage: "Grants the permission to read dashboards",
Destination: &params.ReadDashboardsPermission,
},
&cli.BoolFlag{
Name: "write-checks",
Usage: "Grants the permission to create checks",
Destination: &params.WriteCheckPermission,
},
&cli.BoolFlag{
Name: "read-checks",
Usage: "Grants the permission to read checks",
Destination: &params.ReadCheckPermission,
},
&cli.BoolFlag{
Name: "write-notificationRules",
Usage: "Grants the permission to create notificationRules",
Destination: &params.WriteNotificationRulePermission,
},
&cli.BoolFlag{
Name: "read-notificationRules",
Usage: "Grants the permission to read notificationRules",
Destination: &params.ReadNotificationRulePermission,
},
&cli.BoolFlag{
Name: "write-notificationEndpoints",
Usage: "Grants the permission to create notificationEndpoints",
Destination: &params.WriteNotificationEndpointPermission,
},
&cli.BoolFlag{
Name: "read-notificationEndpoints",
Usage: "Grants the permission to read notificationEndpoints",
Destination: &params.ReadNotificationEndpointPermission,
},
&cli.BoolFlag{
Name: "write-dbrps",
Usage: "Grants the permission to create database retention policy mappings",
Destination: &params.WriteDBRPPermission,
},
&cli.BoolFlag{
Name: "read-dbrps",
Usage: "Grants the permission to read database retention policy mappings",
Destination: &params.ReadDBRPPermission,
Name: "all-access",
Usage: "Grants all permissions in a single organization",
Destination: &params.AllAccess,
},
)
params.ResourcePermissions = auth.BuildResourcePermissions()
for _, perm := range params.ResourcePermissions {
help := helpText(perm.Name)
ossVsCloud := ""
if perm.IsCloud && !perm.IsOss {
ossVsCloud = " (Cloud only)"
}
if !perm.IsCloud && perm.IsOss {
ossVsCloud = " (OSS only)"
}
flags = append(flags,
&cli.BoolFlag{
Name: "read-" + perm.Name,
Usage: help.readHelp + ossVsCloud,
Destination: &perm.Read,
},
&cli.BoolFlag{
Name: "write-" + perm.Name,
Usage: help.writeHelp + ossVsCloud,
Destination: &perm.Write,
})
}
return cli.Command{
Name: "create",
Usage: "Create authorization",
@ -160,6 +118,7 @@ func newCreateCommand() cli.Command {
AuthorizationsApi: api.AuthorizationsApi,
UsersApi: api.UsersApi,
OrganizationsApi: api.OrganizationsApi,
ResourceListApi: api.ResourceListApi,
}
return client.Create(getContext(ctx), &params)
},

View File

@ -20,6 +20,15 @@ docker run --rm -it -u "$(id -u):$(id -g)" \
--outfile /api/cli.gen.yml \
--type yaml
# Merge extras to a separate file
docker run --rm -it -u "$(id -u):$(id -g)" \
-v "${API_DIR}":/api \
${MERGE_DOCKER_IMG} \
swagger-cli bundle /api/contract/cli-extras.yml \
--outfile /api/cli-extras.gen.yml \
--type yaml
# Run the generator - This produces many more files than we want to track in git.
docker run --rm -it -u "$(id -u):$(id -g)" \
-v "${API_DIR}":/api \
@ -31,10 +40,24 @@ docker run --rm -it -u "$(id -u):$(id -g)" \
-t /api/templates \
--additional-properties packageName=api,enumClassPrefix=true,generateInterfaces=true
# Run the generator for extras
docker run --rm -it -u "$(id -u):$(id -g)" \
-v "${API_DIR}":/api \
${GENERATOR_DOCKER_IMG} \
generate \
-g go \
-i /api/cli-extras.gen.yml \
-o /api/extras \
-t /api/templates \
--additional-properties packageName=extras,enumClassPrefix=true,generateInterfaces=true
rm ${API_DIR}/extras/{client.go,configuration.go,response.go}
# Edit the generated files.
for DIR in "${API_DIR}" "${API_DIR}/extras" ; do
(
# Clean up files we don't care about.
cd "${API_DIR}"
cd $DIR
rm -rf go.mod go.sum git_push.sh api docs .openapi-generator .travis.yml .gitignore
# Change extension of generated files.
@ -42,8 +65,9 @@ docker run --rm -it -u "$(id -u):$(id -g)" \
base=$(basename ${f} .go)
mv ${f} ${base}.gen.go
done
# Clean up the generated code.
cd "${ROOT_DIR}"
>/dev/null make fmt
)
done
# Clean up the generated code.
cd "${ROOT_DIR}"
>/dev/null make fmt