2019-10-23 17:09:04 +00:00
package main
2019-10-24 19:20:49 +00:00
import (
2019-11-15 17:35:55 +00:00
"bytes"
2019-10-24 19:20:49 +00:00
"context"
2019-11-07 00:45:00 +00:00
"encoding/json"
2019-10-24 19:20:49 +00:00
"errors"
"fmt"
2019-11-21 00:38:12 +00:00
"io"
2019-11-15 17:35:55 +00:00
"io/ioutil"
2019-10-24 19:20:49 +00:00
"os"
2020-01-23 21:45:32 +00:00
"path"
2019-10-24 19:20:49 +00:00
"path/filepath"
2019-11-22 23:22:10 +00:00
"reflect"
2020-02-06 05:42:01 +00:00
"sort"
2019-10-28 22:23:40 +00:00
"strconv"
2019-10-24 19:20:49 +00:00
"strings"
"time"
2019-10-28 22:23:40 +00:00
"github.com/fatih/color"
2019-10-24 19:20:49 +00:00
"github.com/influxdata/influxdb"
2019-11-21 07:12:27 +00:00
ihttp "github.com/influxdata/influxdb/http"
2019-11-21 00:38:12 +00:00
ierror "github.com/influxdata/influxdb/kit/errors"
2019-10-24 19:20:49 +00:00
"github.com/influxdata/influxdb/pkger"
2019-10-28 22:23:40 +00:00
"github.com/olekukonko/tablewriter"
2019-10-24 19:20:49 +00:00
"github.com/spf13/cobra"
input "github.com/tcnksm/go-input"
)
2019-12-12 19:09:32 +00:00
type pkgSVCsFn func ( ) ( pkger . SVC , influxdb . OrganizationService , error )
2019-11-18 18:50:45 +00:00
2020-02-19 20:43:06 +00:00
func cmdPkg ( f * globalFlags , opts genericCLIOpts ) * cobra . Command {
return newCmdPkgBuilder ( newPkgerSVC , opts ) . cmd ( )
2019-11-15 17:35:55 +00:00
}
2019-11-21 23:10:39 +00:00
type cmdPkgBuilder struct {
genericCLIOpts
2019-12-12 17:33:15 +00:00
svcFn pkgSVCsFn
2019-11-21 23:10:39 +00:00
2020-01-17 15:28:09 +00:00
encoding string
file string
2020-02-06 20:43:01 +00:00
files [ ] string
2020-03-06 23:50:04 +00:00
filters [ ] string
2020-01-17 15:28:09 +00:00
disableColor bool
disableTableBorders bool
org organization
quiet bool
2020-02-06 23:12:58 +00:00
recurse bool
2020-02-07 00:37:09 +00:00
urls [ ] string
2019-11-21 23:10:39 +00:00
applyOpts struct {
2020-02-06 05:42:01 +00:00
envRefs [ ] string
2019-12-27 19:22:05 +00:00
force string
secrets [ ] string
2019-11-21 23:10:39 +00:00
}
2020-03-06 23:50:04 +00:00
2019-11-21 23:10:39 +00:00
exportOpts struct {
resourceType string
buckets string
2019-12-19 01:03:19 +00:00
checks string
2019-11-21 23:10:39 +00:00
dashboards string
2019-12-16 20:10:45 +00:00
endpoints string
2019-11-21 23:10:39 +00:00
labels string
2019-12-20 20:51:27 +00:00
rules string
2019-12-23 22:31:56 +00:00
tasks string
2019-12-05 00:17:35 +00:00
telegrafs string
2019-11-21 23:10:39 +00:00
variables string
}
2019-11-21 07:12:27 +00:00
}
2020-02-19 20:43:06 +00:00
func newCmdPkgBuilder ( svcFn pkgSVCsFn , opts genericCLIOpts ) * cmdPkgBuilder {
2019-11-21 23:10:39 +00:00
return & cmdPkgBuilder {
2020-02-19 20:43:06 +00:00
genericCLIOpts : opts ,
2019-11-21 23:10:39 +00:00
svcFn : svcFn ,
2019-10-24 19:20:49 +00:00
}
2019-11-21 23:10:39 +00:00
}
2020-01-13 19:13:37 +00:00
func ( b * cmdPkgBuilder ) cmd ( ) * cobra . Command {
2019-11-21 23:10:39 +00:00
cmd := b . cmdPkgApply ( )
cmd . AddCommand (
b . cmdPkgExport ( ) ,
2019-11-21 23:43:10 +00:00
b . cmdPkgSummary ( ) ,
2019-11-21 23:10:39 +00:00
b . cmdPkgValidate ( ) ,
)
return cmd
}
2019-10-24 19:20:49 +00:00
2019-11-21 23:10:39 +00:00
func ( b * cmdPkgBuilder ) cmdPkgApply ( ) * cobra . Command {
2020-01-11 01:00:44 +00:00
cmd := b . newCmd ( "pkg" , b . pkgApplyRunEFn )
2019-11-21 23:10:39 +00:00
cmd . Short = "Apply a pkg to create resources"
2020-01-14 22:23:47 +00:00
b . org . register ( cmd , false )
2020-02-07 00:37:09 +00:00
b . registerPkgFileFlags ( cmd )
2020-01-17 17:31:07 +00:00
cmd . Flags ( ) . BoolVarP ( & b . quiet , "quiet" , "q" , false , "Disable output printing" )
2019-12-27 19:22:05 +00:00
cmd . Flags ( ) . StringVar ( & b . applyOpts . force , "force" , "" , ` TTY input, if package will have destructive changes, proceed if set "true" ` )
2020-01-17 15:28:09 +00:00
cmd . Flags ( ) . BoolVarP ( & b . disableColor , "disable-color" , "c" , false , "Disable color in output" )
cmd . Flags ( ) . BoolVar ( & b . disableTableBorders , "disable-table-borders" , false , "Disable table borders" )
2019-10-30 17:55:13 +00:00
2019-12-27 19:22:05 +00:00
b . applyOpts . secrets = [ ] string { }
2020-01-09 21:51:19 +00:00
cmd . Flags ( ) . StringSliceVar ( & b . applyOpts . secrets , "secret" , nil , "Secrets to provide alongside the package; format should --secret=SECRET_KEY=SECRET_VALUE --secret=SECRET_KEY_2=SECRET_VALUE_2" )
2020-02-06 05:42:01 +00:00
cmd . Flags ( ) . StringSliceVar ( & b . applyOpts . envRefs , "env-ref" , nil , "Environment references to provide alongside the package; format should --env-ref=REF_KEY=REF_VALUE --env-ref=REF_KEY_2=REF_VALUE_2" )
2019-12-27 19:22:05 +00:00
2019-10-24 19:20:49 +00:00
return cmd
}
2020-02-06 05:42:01 +00:00
func ( b * cmdPkgBuilder ) pkgApplyRunEFn ( cmd * cobra . Command , args [ ] string ) error {
2020-01-11 01:00:44 +00:00
if err := b . org . validOrgFlags ( ) ; err != nil {
return err
}
2020-01-17 15:28:09 +00:00
color . NoColor = b . disableColor
2019-12-10 23:46:36 +00:00
2020-01-11 01:00:44 +00:00
svc , orgSVC , err := b . svcFn ( )
if err != nil {
return err
}
2019-10-25 21:39:38 +00:00
2020-01-11 01:00:44 +00:00
if err := b . org . validOrgFlags ( ) ; err != nil {
return err
}
2019-12-17 19:55:35 +00:00
2020-01-11 01:00:44 +00:00
influxOrgID , err := b . org . getID ( orgSVC )
if err != nil {
return err
}
2019-10-24 19:20:49 +00:00
2020-02-07 00:37:09 +00:00
pkg , isTTY , err := b . readPkg ( )
2020-01-11 01:00:44 +00:00
if err != nil {
return err
}
2019-10-24 19:20:49 +00:00
2020-02-06 05:42:01 +00:00
providedEnvRefs := mapKeys ( pkg . Summary ( ) . MissingEnvs , b . applyOpts . envRefs )
if ! isTTY {
for _ , envRef := range missingValKeys ( providedEnvRefs ) {
prompt := "Please provide environment reference value for key " + envRef
providedEnvRefs [ envRef ] = b . getInput ( prompt , "" )
}
2020-01-11 01:00:44 +00:00
}
2019-10-28 22:23:40 +00:00
2020-02-06 05:42:01 +00:00
drySum , diff , err := svc . DryRun ( context . Background ( ) , influxOrgID , 0 , pkg , pkger . ApplyWithEnvRefs ( providedEnvRefs ) )
if err != nil {
return err
2020-01-11 01:00:44 +00:00
}
2019-12-27 19:22:05 +00:00
2020-02-06 05:42:01 +00:00
providedSecrets := mapKeys ( drySum . MissingSecrets , b . applyOpts . secrets )
2020-01-11 01:00:44 +00:00
if ! isTTY {
2020-02-06 05:42:01 +00:00
const skipDefault = "$$skip-this-key$$"
for _ , secretKey := range missingValKeys ( providedSecrets ) {
2020-01-11 01:00:44 +00:00
prompt := "Please provide secret value for key " + secretKey + " (optional, press enter to skip)"
2020-02-06 05:42:01 +00:00
secretVal := b . getInput ( prompt , skipDefault )
2020-01-11 01:00:44 +00:00
if secretVal != "" && secretVal != skipDefault {
providedSecrets [ secretKey ] = secretVal
2019-11-21 07:12:27 +00:00
}
2019-10-24 19:20:49 +00:00
}
2020-01-11 01:00:44 +00:00
}
2019-10-24 19:20:49 +00:00
2020-01-11 01:00:44 +00:00
if ! b . quiet {
b . printPkgDiff ( diff )
}
2019-10-24 19:20:49 +00:00
2020-01-11 01:00:44 +00:00
isForced , _ := strconv . ParseBool ( b . applyOpts . force )
if ! isTTY && ! isForced && b . applyOpts . force != "conflict" {
2020-02-06 05:42:01 +00:00
confirm := b . getInput ( "Confirm application of the above resources (y/n)" , "n" )
2020-01-11 01:00:44 +00:00
if strings . ToLower ( confirm ) != "y" {
2020-02-06 05:42:01 +00:00
fmt . Fprintln ( b . w , "aborted application of package" )
2020-01-11 01:00:44 +00:00
return nil
2019-11-21 07:12:27 +00:00
}
2020-01-11 01:00:44 +00:00
}
2019-10-24 19:20:49 +00:00
2020-01-11 01:00:44 +00:00
if b . applyOpts . force != "conflict" && isTTY && diff . HasConflicts ( ) {
return errors . New ( "package has conflicts with existing resources and cannot safely apply" )
2019-10-24 19:20:49 +00:00
}
2020-01-11 01:00:44 +00:00
2020-02-06 05:42:01 +00:00
summary , err := svc . Apply ( context . Background ( ) , influxOrgID , 0 , pkg , pkger . ApplyWithEnvRefs ( providedEnvRefs ) , pkger . ApplyWithSecrets ( providedSecrets ) )
2020-01-11 01:00:44 +00:00
if err != nil {
return err
}
if ! b . quiet {
b . printPkgSummary ( summary )
}
return nil
2019-10-24 19:20:49 +00:00
}
2019-11-21 23:10:39 +00:00
func ( b * cmdPkgBuilder ) cmdPkgExport ( ) * cobra . Command {
2020-01-11 01:00:44 +00:00
cmd := b . newCmd ( "export" , b . pkgExportRunEFn )
2019-11-21 23:10:39 +00:00
cmd . Short = "Export existing resources as a package"
cmd . AddCommand ( b . cmdPkgExportAll ( ) )
cmd . Flags ( ) . StringVarP ( & b . file , "file" , "f" , "" , "output file for created pkg; defaults to std out if no file provided; the extension of provided file (.yml/.json) will dictate encoding" )
cmd . Flags ( ) . StringVar ( & b . exportOpts . resourceType , "resource-type" , "" , "The resource type provided will be associated with all IDs via stdin." )
cmd . Flags ( ) . StringVar ( & b . exportOpts . buckets , "buckets" , "" , "List of bucket ids comma separated" )
2019-12-19 01:03:19 +00:00
cmd . Flags ( ) . StringVar ( & b . exportOpts . checks , "checks" , "" , "List of check ids comma separated" )
2019-11-21 23:10:39 +00:00
cmd . Flags ( ) . StringVar ( & b . exportOpts . dashboards , "dashboards" , "" , "List of dashboard ids comma separated" )
2019-12-16 20:10:45 +00:00
cmd . Flags ( ) . StringVar ( & b . exportOpts . endpoints , "endpoints" , "" , "List of notification endpoint ids comma separated" )
2019-11-21 23:10:39 +00:00
cmd . Flags ( ) . StringVar ( & b . exportOpts . labels , "labels" , "" , "List of label ids comma separated" )
2019-12-20 20:51:27 +00:00
cmd . Flags ( ) . StringVar ( & b . exportOpts . rules , "rules" , "" , "List of notification rule ids comma separated" )
2019-12-23 22:31:56 +00:00
cmd . Flags ( ) . StringVar ( & b . exportOpts . tasks , "tasks" , "" , "List of task ids comma separated" )
2019-12-05 00:17:35 +00:00
cmd . Flags ( ) . StringVar ( & b . exportOpts . telegrafs , "telegraf-configs" , "" , "List of telegraf config ids comma separated" )
2019-11-21 23:10:39 +00:00
cmd . Flags ( ) . StringVar ( & b . exportOpts . variables , "variables" , "" , "List of variable ids comma separated" )
2019-11-21 00:38:12 +00:00
return cmd
}
2020-01-11 01:00:44 +00:00
func ( b * cmdPkgBuilder ) pkgExportRunEFn ( cmd * cobra . Command , args [ ] string ) error {
pkgSVC , _ , err := b . svcFn ( )
if err != nil {
return err
}
2019-11-21 00:38:12 +00:00
2020-01-13 19:13:37 +00:00
opts := [ ] pkger . CreatePkgSetFn { }
2020-01-11 01:00:44 +00:00
resTypes := [ ] struct {
kind pkger . Kind
idStrs [ ] string
} {
{ kind : pkger . KindBucket , idStrs : strings . Split ( b . exportOpts . buckets , "," ) } ,
{ kind : pkger . KindCheck , idStrs : strings . Split ( b . exportOpts . checks , "," ) } ,
{ kind : pkger . KindDashboard , idStrs : strings . Split ( b . exportOpts . dashboards , "," ) } ,
{ kind : pkger . KindLabel , idStrs : strings . Split ( b . exportOpts . labels , "," ) } ,
{ kind : pkger . KindNotificationEndpoint , idStrs : strings . Split ( b . exportOpts . endpoints , "," ) } ,
{ kind : pkger . KindNotificationRule , idStrs : strings . Split ( b . exportOpts . rules , "," ) } ,
{ kind : pkger . KindTask , idStrs : strings . Split ( b . exportOpts . tasks , "," ) } ,
{ kind : pkger . KindTelegraf , idStrs : strings . Split ( b . exportOpts . telegrafs , "," ) } ,
{ kind : pkger . KindVariable , idStrs : strings . Split ( b . exportOpts . variables , "," ) } ,
}
for _ , rt := range resTypes {
newOpt , err := newResourcesToClone ( rt . kind , rt . idStrs )
if err != nil {
return ierror . Wrap ( err , rt . kind . String ( ) )
2019-11-21 00:38:12 +00:00
}
2020-01-11 01:00:44 +00:00
opts = append ( opts , newOpt )
}
2019-11-21 00:38:12 +00:00
2020-01-11 01:00:44 +00:00
if b . exportOpts . resourceType == "" {
return b . writePkg ( cmd . OutOrStdout ( ) , pkgSVC , b . file , opts ... )
}
2019-11-21 00:38:12 +00:00
2020-01-13 19:13:37 +00:00
kind := pkger . Kind ( b . exportOpts . resourceType )
2020-01-11 01:00:44 +00:00
if err := kind . OK ( ) ; err != nil {
return errors . New ( "resource type must be one of bucket|dashboard|label|variable; got: " + b . exportOpts . resourceType )
}
2019-11-21 00:38:12 +00:00
2020-01-11 01:00:44 +00:00
if stdin , err := b . inStdIn ( ) ; err == nil {
stdinInpt , _ := b . readLines ( stdin )
if len ( stdinInpt ) > 0 {
args = stdinInpt
2019-11-15 17:35:55 +00:00
}
2020-01-11 01:00:44 +00:00
}
2019-11-15 17:35:55 +00:00
2020-01-11 01:00:44 +00:00
resTypeOpt , err := newResourcesToClone ( kind , args )
if err != nil {
return err
2019-11-21 00:38:12 +00:00
}
2020-01-11 01:00:44 +00:00
return b . writePkg ( cmd . OutOrStdout ( ) , pkgSVC , b . file , append ( opts , resTypeOpt ) ... )
2019-11-21 00:38:12 +00:00
}
2019-11-21 23:10:39 +00:00
func ( b * cmdPkgBuilder ) cmdPkgExportAll ( ) * cobra . Command {
2020-01-11 01:00:44 +00:00
cmd := b . newCmd ( "all" , b . pkgExportAllRunEFn )
2019-11-21 23:10:39 +00:00
cmd . Short = "Export all existing resources for an organization as a package"
2019-11-21 00:38:12 +00:00
2019-11-21 23:10:39 +00:00
cmd . Flags ( ) . StringVarP ( & b . file , "file" , "f" , "" , "output file for created pkg; defaults to std out if no file provided; the extension of provided file (.yml/.json) will dictate encoding" )
2020-03-06 23:50:04 +00:00
cmd . Flags ( ) . StringArrayVar ( & b . filters , "filter" , nil , "Filter exported resources by labelName or resourceKind (format: --filter=labelName=example)" )
2019-12-17 19:55:35 +00:00
2020-01-10 00:34:30 +00:00
b . org . register ( cmd , false )
2019-12-17 19:55:35 +00:00
2019-11-21 00:38:12 +00:00
return cmd
}
2020-01-11 01:00:44 +00:00
func ( b * cmdPkgBuilder ) pkgExportAllRunEFn ( cmd * cobra . Command , args [ ] string ) error {
pkgSVC , orgSVC , err := b . svcFn ( )
if err != nil {
return err
}
2019-11-21 00:38:12 +00:00
2020-01-11 01:00:44 +00:00
orgID , err := b . org . getID ( orgSVC )
if err != nil {
return err
2019-11-21 00:38:12 +00:00
}
2020-01-11 01:00:44 +00:00
2020-03-06 23:50:04 +00:00
var (
labelNames [ ] string
resourceKinds [ ] pkger . Kind
)
for _ , filter := range b . filters {
pair := strings . SplitN ( filter , "=" , 2 )
if len ( pair ) < 2 {
continue
}
switch key , val := pair [ 0 ] , pair [ 1 ] ; key {
case "labelName" :
labelNames = append ( labelNames , val )
case "resourceKind" :
k := pkger . Kind ( val )
if err := k . OK ( ) ; err != nil {
return err
}
resourceKinds = append ( resourceKinds , k )
default :
return fmt . Errorf ( "invalid filter provided %q; filter must be 1 in [labelName, resourceKind]" , filter )
}
}
2020-03-06 18:52:18 +00:00
orgOpt := pkger . CreateWithAllOrgResources ( pkger . CreateByOrgIDOpt {
2020-03-06 23:50:04 +00:00
OrgID : orgID ,
LabelNames : labelNames ,
ResourceKinds : resourceKinds ,
2020-03-06 18:52:18 +00:00
} )
return b . writePkg ( cmd . OutOrStdout ( ) , pkgSVC , b . file , orgOpt )
2019-11-21 00:38:12 +00:00
}
2019-11-21 23:43:10 +00:00
func ( b * cmdPkgBuilder ) cmdPkgSummary ( ) * cobra . Command {
2020-01-11 01:00:44 +00:00
runE := func ( cmd * cobra . Command , args [ ] string ) error {
2020-02-07 00:37:09 +00:00
pkg , _ , err := b . readPkg ( )
2019-11-21 23:43:10 +00:00
if err != nil {
return err
}
b . printPkgSummary ( pkg . Summary ( ) )
return nil
}
2020-01-11 01:00:44 +00:00
cmd := b . newCmd ( "summary" , runE )
cmd . Short = "Summarize the provided package"
2020-02-07 00:37:09 +00:00
b . registerPkgFileFlags ( cmd )
2020-01-17 15:28:09 +00:00
cmd . Flags ( ) . BoolVarP ( & b . disableColor , "disable-color" , "c" , false , "Disable color in output" )
cmd . Flags ( ) . BoolVar ( & b . disableTableBorders , "disable-table-borders" , false , "Disable table borders" )
2020-01-11 01:00:44 +00:00
2019-11-21 23:43:10 +00:00
return cmd
}
2019-11-21 23:10:39 +00:00
func ( b * cmdPkgBuilder ) cmdPkgValidate ( ) * cobra . Command {
2020-01-11 01:00:44 +00:00
runE := func ( cmd * cobra . Command , args [ ] string ) error {
2020-02-07 00:37:09 +00:00
pkg , _ , err := b . readPkg ( )
2019-11-21 21:12:15 +00:00
if err != nil {
return err
}
return pkg . Validate ( )
}
2020-01-11 01:00:44 +00:00
cmd := b . newCmd ( "validate" , runE )
cmd . Short = "Validate the provided package"
2020-02-07 00:37:09 +00:00
b . registerPkgFileFlags ( cmd )
2020-01-11 01:00:44 +00:00
2019-11-21 21:12:15 +00:00
return cmd
}
2020-02-07 00:37:09 +00:00
func ( b * cmdPkgBuilder ) registerPkgFileFlags ( cmd * cobra . Command ) {
2020-02-06 23:12:58 +00:00
cmd . Flags ( ) . StringSliceVarP ( & b . files , "file" , "f" , nil , "Path to package file" )
cmd . MarkFlagFilename ( "file" , "yaml" , "yml" , "json" , "jsonnet" )
cmd . Flags ( ) . BoolVarP ( & b . recurse , "recurse" , "R" , false , "Process the directory used in -f, --file recursively. Useful when you want to manage related manifests organized within the same directory." )
2020-02-07 00:37:09 +00:00
cmd . Flags ( ) . StringSliceVarP ( & b . urls , "url" , "u" , nil , "URL to a package file" )
cmd . Flags ( ) . StringVarP ( & b . encoding , "encoding" , "e" , "" , "Encoding for the input stream. If a file is provided will gather encoding type from file extension. If extension provided will override." )
cmd . MarkFlagFilename ( "encoding" , "yaml" , "yml" , "json" , "jsonnet" )
2020-02-06 23:12:58 +00:00
}
2019-11-21 23:10:39 +00:00
func ( b * cmdPkgBuilder ) writePkg ( w io . Writer , pkgSVC pkger . SVC , outPath string , opts ... pkger . CreatePkgSetFn ) error {
pkg , err := pkgSVC . CreatePkg ( context . Background ( ) , opts ... )
2019-11-21 07:12:27 +00:00
if err != nil {
2019-11-21 23:10:39 +00:00
return err
2019-11-21 07:12:27 +00:00
}
2019-11-21 23:10:39 +00:00
buf , err := createPkgBuf ( pkg , outPath )
if err != nil {
return err
2019-11-21 07:12:27 +00:00
}
2019-11-21 23:10:39 +00:00
if outPath == "" {
_ , err := io . Copy ( w , buf )
return err
}
return ioutil . WriteFile ( outPath , buf . Bytes ( ) , os . ModePerm )
2019-11-21 07:12:27 +00:00
}
2020-02-07 00:37:09 +00:00
func ( b * cmdPkgBuilder ) readRawPkgsFromFiles ( filePaths [ ] string , recurse bool ) ( [ ] * pkger . Pkg , error ) {
2020-02-06 23:12:58 +00:00
mFiles := make ( map [ string ] struct { } )
for _ , f := range filePaths {
files , err := readFilesFromPath ( f , recurse )
if err != nil {
return nil , err
}
for _ , ff := range files {
mFiles [ ff ] = struct { } { }
2020-02-06 20:43:01 +00:00
}
2020-02-06 23:12:58 +00:00
}
var rawPkgs [ ] * pkger . Pkg
for f := range mFiles {
2020-02-07 00:37:09 +00:00
pkg , err := pkger . Parse ( b . convertFileEncoding ( f ) , pkger . FromFile ( f ) , pkger . ValidSkipParseError ( ) )
2020-02-06 23:12:58 +00:00
if err != nil {
return nil , err
}
rawPkgs = append ( rawPkgs , pkg )
}
2020-02-07 00:37:09 +00:00
return rawPkgs , nil
2020-02-06 23:12:58 +00:00
}
2020-02-07 00:37:09 +00:00
func ( b * cmdPkgBuilder ) readRawPkgsFromURLs ( urls [ ] string ) ( [ ] * pkger . Pkg , error ) {
mURLs := make ( map [ string ] struct { } )
for _ , f := range urls {
mURLs [ f ] = struct { } { }
}
var rawPkgs [ ] * pkger . Pkg
for u := range mURLs {
pkg , err := pkger . Parse ( b . convertURLEncoding ( u ) , pkger . FromHTTPRequest ( u ) , pkger . ValidSkipParseError ( ) )
if err != nil {
return nil , err
}
rawPkgs = append ( rawPkgs , pkg )
2019-11-21 23:10:39 +00:00
}
2020-02-07 00:37:09 +00:00
return rawPkgs , nil
}
2019-11-21 23:10:39 +00:00
2020-02-07 00:37:09 +00:00
func ( b * cmdPkgBuilder ) readPkg ( ) ( * pkger . Pkg , bool , error ) {
pkgs , err := b . readRawPkgsFromFiles ( b . files , b . recurse )
if err != nil {
return nil , false , err
}
2019-11-21 23:10:39 +00:00
2020-02-07 00:37:09 +00:00
urlPkgs , err := b . readRawPkgsFromURLs ( b . urls )
if err != nil {
return nil , false , err
2019-11-21 23:10:39 +00:00
}
2020-02-07 00:37:09 +00:00
pkgs = append ( pkgs , urlPkgs ... )
2019-11-21 23:10:39 +00:00
2020-02-07 00:37:09 +00:00
if _ , err := b . inStdIn ( ) ; err != nil {
pkg , err := pkger . Combine ( pkgs ... )
return pkg , false , err
}
stdinPkg , err := pkger . Parse ( b . convertEncoding ( ) , pkger . FromReader ( b . in ) , pkger . ValidSkipParseError ( ) )
if err != nil {
return nil , true , err
}
pkg , err := pkger . Combine ( append ( pkgs , stdinPkg ) ... )
return pkg , true , err
2019-11-21 23:10:39 +00:00
}
func ( b * cmdPkgBuilder ) inStdIn ( ) ( * os . File , error ) {
stdin , _ := b . in . ( * os . File )
if stdin != os . Stdin {
return nil , errors . New ( "input not stdIn" )
}
info , err := stdin . Stat ( )
if err != nil {
2019-11-21 07:12:27 +00:00
return nil , err
}
2019-11-21 23:10:39 +00:00
if ( info . Mode ( ) & os . ModeCharDevice ) == os . ModeCharDevice {
return nil , errors . New ( "input not stdIn" )
}
return stdin , nil
}
2019-11-21 07:12:27 +00:00
2019-11-21 23:10:39 +00:00
func ( b * cmdPkgBuilder ) readLines ( r io . Reader ) ( [ ] string , error ) {
bb , err := ioutil . ReadAll ( r )
2019-11-21 07:12:27 +00:00
if err != nil {
return nil , err
}
var stdinInput [ ] string
2019-11-21 23:10:39 +00:00
for _ , bs := range bytes . Split ( bb , [ ] byte ( "\n" ) ) {
trimmed := bytes . TrimSpace ( bs )
2019-11-21 07:12:27 +00:00
if len ( trimmed ) == 0 {
continue
}
stdinInput = append ( stdinInput , string ( trimmed ) )
}
return stdinInput , nil
}
2020-02-06 05:42:01 +00:00
func ( b * cmdPkgBuilder ) getInput ( msg , defaultVal string ) string {
ui := & input . UI {
Writer : b . w ,
Reader : b . in ,
}
return getInput ( ui , msg , defaultVal )
}
2020-02-07 00:37:09 +00:00
func ( b * cmdPkgBuilder ) convertURLEncoding ( url string ) pkger . Encoding {
urlBase := path . Ext ( url )
switch {
case strings . HasPrefix ( urlBase , ".jsonnet" ) :
return pkger . EncodingJsonnet
case strings . HasPrefix ( urlBase , ".json" ) :
return pkger . EncodingJSON
case strings . HasPrefix ( urlBase , ".yml" ) || strings . HasPrefix ( urlBase , ".yaml" ) :
return pkger . EncodingYAML
}
return b . convertEncoding ( )
}
func ( b * cmdPkgBuilder ) convertFileEncoding ( file string ) pkger . Encoding {
2020-02-06 23:12:58 +00:00
ext := filepath . Ext ( file )
2020-01-14 22:23:47 +00:00
switch {
2020-02-07 00:37:09 +00:00
case strings . HasPrefix ( ext , ".jsonnet" ) :
return pkger . EncodingJsonnet
case strings . HasPrefix ( ext , ".json" ) :
return pkger . EncodingJSON
case strings . HasPrefix ( ext , ".yml" ) || strings . HasPrefix ( ext , ".yaml" ) :
return pkger . EncodingYAML
}
return b . convertEncoding ( )
}
func ( b * cmdPkgBuilder ) convertEncoding ( ) pkger . Encoding {
switch {
case b . encoding == "json" :
2020-01-14 22:23:47 +00:00
return pkger . EncodingJSON
2020-02-07 00:37:09 +00:00
case b . encoding == "yml" || b . encoding == "yaml" :
2020-01-14 22:23:47 +00:00
return pkger . EncodingYAML
2020-02-07 00:37:09 +00:00
case b . encoding == "jsonnet" :
2020-01-14 22:23:47 +00:00
return pkger . EncodingJsonnet
default :
return pkger . EncodingSource
}
}
2019-11-21 23:10:39 +00:00
func newResourcesToClone ( kind pkger . Kind , idStrs [ ] string ) ( pkger . CreatePkgSetFn , error ) {
ids , err := toInfluxIDs ( idStrs )
if err != nil {
return nil , err
}
var resources [ ] pkger . ResourceToClone
for _ , id := range ids {
resources = append ( resources , pkger . ResourceToClone {
Kind : kind ,
ID : id ,
} )
}
return pkger . CreateWithExistingResources ( resources ... ) , nil
}
2019-11-21 07:12:27 +00:00
func toInfluxIDs ( args [ ] string ) ( [ ] influxdb . ID , error ) {
var (
ids [ ] influxdb . ID
errs [ ] string
)
for _ , arg := range args {
normedArg := strings . TrimSpace ( strings . ToLower ( arg ) )
if normedArg == "" {
continue
}
id , err := influxdb . IDFromString ( normedArg )
if err != nil {
errs = append ( errs , "arg must provide a valid 16 length ID; got: " + arg )
continue
}
ids = append ( ids , * id )
}
if len ( errs ) > 0 {
return nil , errors . New ( strings . Join ( errs , "\n\t" ) )
}
return ids , nil
2019-11-21 00:38:12 +00:00
}
func createPkgBuf ( pkg * pkger . Pkg , outPath string ) ( * bytes . Buffer , error ) {
2020-01-13 19:13:37 +00:00
var encoding pkger . Encoding
2019-11-21 00:38:12 +00:00
switch ext := filepath . Ext ( outPath ) ; ext {
case ".json" :
2020-01-13 19:13:37 +00:00
encoding = pkger . EncodingJSON
2019-11-21 00:38:12 +00:00
default :
2020-01-13 19:13:37 +00:00
encoding = pkger . EncodingYAML
2019-11-21 00:38:12 +00:00
}
2020-01-13 19:13:37 +00:00
b , err := pkg . Encode ( encoding )
if err != nil {
2019-11-21 00:38:12 +00:00
return nil , err
}
2020-01-13 19:13:37 +00:00
return bytes . NewBuffer ( b ) , nil
2019-11-18 18:50:45 +00:00
}
2019-11-07 00:45:00 +00:00
2019-12-12 19:09:32 +00:00
func newPkgerSVC ( ) ( pkger . SVC , influxdb . OrganizationService , error ) {
2019-12-07 18:54:03 +00:00
httpClient , err := newHTTPClient ( )
2019-12-07 00:23:09 +00:00
if err != nil {
2019-12-12 17:33:15 +00:00
return nil , nil , err
}
orgSvc := & ihttp . OrganizationService {
Client : httpClient ,
2019-12-07 00:23:09 +00:00
}
2020-02-03 19:22:47 +00:00
return & pkger . HTTPRemoteService { Client : httpClient } , orgSvc , nil
2019-10-30 21:13:42 +00:00
}
2019-11-21 23:10:39 +00:00
func ( b * cmdPkgBuilder ) printPkgDiff ( diff pkger . Diff ) {
2019-11-22 23:22:10 +00:00
red := color . New ( color . FgRed ) . SprintFunc ( )
green := color . New ( color . FgHiGreen , color . Bold ) . SprintFunc ( )
2019-10-28 22:23:40 +00:00
2019-11-22 23:22:10 +00:00
diffLn := func ( isNew bool , old , new interface { } ) string {
2019-10-28 22:23:40 +00:00
if isNew {
return green ( new )
2019-10-26 02:11:47 +00:00
}
2019-11-22 23:22:10 +00:00
if reflect . DeepEqual ( old , new ) {
return fmt . Sprint ( new )
2019-10-28 22:23:40 +00:00
}
2019-11-22 23:22:10 +00:00
return fmt . Sprintf ( "%s\n%s" , red ( old ) , green ( new ) )
2019-10-28 22:23:40 +00:00
}
boolDiff := func ( b bool ) string {
bb := strconv . FormatBool ( b )
if b {
return green ( bb )
}
return bb
}
2019-11-21 23:10:39 +00:00
tablePrintFn := b . tablePrinterGen ( )
2019-10-30 21:13:42 +00:00
if labels := diff . Labels ; len ( labels ) > 0 {
2019-10-28 22:23:40 +00:00
headers := [ ] string { "New" , "ID" , "Name" , "Color" , "Description" }
2019-11-22 23:22:10 +00:00
tablePrintFn ( "LABELS" , headers , len ( labels ) , func ( i int ) [ ] string {
l := labels [ i ]
var old pkger . DiffLabelValues
if l . Old != nil {
old = * l . Old
}
return [ ] string {
boolDiff ( l . IsNew ( ) ) ,
l . ID . String ( ) ,
l . Name ,
diffLn ( l . IsNew ( ) , old . Color , l . New . Color ) ,
diffLn ( l . IsNew ( ) , old . Description , l . New . Description ) ,
2019-10-26 02:11:47 +00:00
}
2019-10-28 22:23:40 +00:00
} )
}
2019-10-30 21:13:42 +00:00
if bkts := diff . Buckets ; len ( bkts ) > 0 {
2019-10-28 22:23:40 +00:00
headers := [ ] string { "New" , "ID" , "Name" , "Retention Period" , "Description" }
2019-11-22 23:22:10 +00:00
tablePrintFn ( "BUCKETS" , headers , len ( bkts ) , func ( i int ) [ ] string {
b := bkts [ i ]
var old pkger . DiffBucketValues
if b . Old != nil {
old = * b . Old
}
return [ ] string {
boolDiff ( b . IsNew ( ) ) ,
b . ID . String ( ) ,
b . Name ,
diffLn ( b . IsNew ( ) , old . RetentionRules . RP ( ) . String ( ) , b . New . RetentionRules . RP ( ) . String ( ) ) ,
diffLn ( b . IsNew ( ) , old . Description , b . New . Description ) ,
2019-10-26 02:11:47 +00:00
}
2019-10-28 22:23:40 +00:00
} )
2019-10-25 21:39:38 +00:00
}
2019-12-18 07:05:28 +00:00
if checks := diff . Checks ; len ( checks ) > 0 {
headers := [ ] string { "New" , "ID" , "Name" , "Description" }
tablePrintFn ( "CHECKS" , headers , len ( checks ) , func ( i int ) [ ] string {
c := checks [ i ]
var oldDesc string
if c . Old != nil {
oldDesc = c . Old . GetDescription ( )
}
return [ ] string {
boolDiff ( c . IsNew ( ) ) ,
c . ID . String ( ) ,
c . Name ,
diffLn ( c . IsNew ( ) , oldDesc , c . New . GetDescription ( ) ) ,
}
} )
}
2019-10-30 21:13:42 +00:00
if dashes := diff . Dashboards ; len ( dashes ) > 0 {
2019-11-01 18:11:42 +00:00
headers := [ ] string { "New" , "Name" , "Description" , "Num Charts" }
2019-11-22 23:22:10 +00:00
tablePrintFn ( "DASHBOARDS" , headers , len ( dashes ) , func ( i int ) [ ] string {
d := dashes [ i ]
return [ ] string {
boolDiff ( true ) ,
d . Name ,
green ( d . Desc ) ,
green ( strconv . Itoa ( len ( d . Charts ) ) ) ,
2019-10-30 21:13:42 +00:00
}
} )
}
2019-12-10 22:51:11 +00:00
if endpoints := diff . NotificationEndpoints ; len ( endpoints ) > 0 {
headers := [ ] string { "New" , "ID" , "Name" }
tablePrintFn ( "NOTIFICATION ENDPOINTS" , headers , len ( endpoints ) , func ( i int ) [ ] string {
v := endpoints [ i ]
return [ ] string {
boolDiff ( v . IsNew ( ) ) ,
v . ID . String ( ) ,
v . Name ,
}
} )
}
2019-12-19 22:02:34 +00:00
if rules := diff . NotificationRules ; len ( rules ) > 0 {
headers := [ ] string { "New" , "Name" , "Description" , "Every" , "Offset" , "Endpoint Name" , "Endpoint ID" , "Endpoint Type" }
tablePrintFn ( "NOTIFICATION RULES" , headers , len ( rules ) , func ( i int ) [ ] string {
v := rules [ i ]
return [ ] string {
green ( true ) ,
v . Name ,
v . Description ,
v . Every ,
v . Offset ,
v . EndpointName ,
v . EndpointID . String ( ) ,
v . EndpointType ,
}
} )
}
2019-12-23 18:55:55 +00:00
if teles := diff . Telegrafs ; len ( teles ) > 0 {
2019-12-04 01:00:15 +00:00
headers := [ ] string { "New" , "Name" , "Description" }
tablePrintFn ( "TELEGRAF CONFIGS" , headers , len ( teles ) , func ( i int ) [ ] string {
t := teles [ i ]
return [ ] string {
boolDiff ( true ) ,
t . Name ,
green ( t . Description ) ,
}
} )
}
2019-12-23 18:55:55 +00:00
if tasks := diff . Tasks ; len ( tasks ) > 0 {
2019-12-23 19:51:00 +00:00
headers := [ ] string { "New" , "Name" , "Description" , "Cycle" }
2019-12-23 18:55:55 +00:00
tablePrintFn ( "TASKS" , headers , len ( tasks ) , func ( i int ) [ ] string {
t := tasks [ i ]
2019-12-23 19:51:00 +00:00
timing := fmt . Sprintf ( "every: %s offset: %s" , t . Every , t . Offset )
if t . Cron != "" {
timing = t . Cron
}
2019-12-23 18:55:55 +00:00
return [ ] string {
boolDiff ( true ) ,
t . Name ,
green ( t . Description ) ,
2019-12-23 19:51:00 +00:00
green ( timing ) ,
2019-12-23 18:55:55 +00:00
}
} )
}
2019-12-26 19:21:21 +00:00
if vars := diff . Variables ; len ( vars ) > 0 {
headers := [ ] string { "New" , "ID" , "Name" , "Description" , "Arg Type" , "Arg Values" }
tablePrintFn ( "VARIABLES" , headers , len ( vars ) , func ( i int ) [ ] string {
v := vars [ i ]
var old pkger . DiffVariableValues
if v . Old != nil {
old = * v . Old
}
var oldArgType string
if old . Args != nil {
oldArgType = old . Args . Type
}
var newArgType string
if v . New . Args != nil {
newArgType = v . New . Args . Type
}
return [ ] string {
boolDiff ( v . IsNew ( ) ) ,
v . ID . String ( ) ,
v . Name ,
diffLn ( v . IsNew ( ) , old . Description , v . New . Description ) ,
diffLn ( v . IsNew ( ) , oldArgType , newArgType ) ,
diffLn ( v . IsNew ( ) , printVarArgs ( old . Args ) , printVarArgs ( v . New . Args ) ) ,
}
} )
}
2019-10-28 22:23:40 +00:00
if len ( diff . LabelMappings ) > 0 {
headers := [ ] string { "New" , "Resource Type" , "Resource Name" , "Resource ID" , "Label Name" , "Label ID" }
2019-11-22 23:22:10 +00:00
tablePrintFn ( "LABEL MAPPINGS" , headers , len ( diff . LabelMappings ) , func ( i int ) [ ] string {
m := diff . LabelMappings [ i ]
return [ ] string {
boolDiff ( m . IsNew ) ,
string ( m . ResType ) ,
m . ResName ,
m . ResID . String ( ) ,
m . LabelName ,
m . LabelID . String ( ) ,
2019-10-26 02:11:47 +00:00
}
2019-10-28 22:23:40 +00:00
} )
}
}
2019-10-26 02:11:47 +00:00
2019-11-21 23:10:39 +00:00
func ( b * cmdPkgBuilder ) printPkgSummary ( sum pkger . Summary ) {
tablePrintFn := b . tablePrinterGen ( )
2019-10-28 22:23:40 +00:00
if labels := sum . Labels ; len ( labels ) > 0 {
headers := [ ] string { "ID" , "Name" , "Description" , "Color" }
2019-11-22 23:22:10 +00:00
tablePrintFn ( "LABELS" , headers , len ( labels ) , func ( i int ) [ ] string {
l := labels [ i ]
return [ ] string {
l . ID . String ( ) ,
l . Name ,
2019-12-12 19:09:32 +00:00
l . Properties . Description ,
l . Properties . Color ,
2019-10-26 02:11:47 +00:00
}
2019-10-28 22:23:40 +00:00
} )
}
if buckets := sum . Buckets ; len ( buckets ) > 0 {
headers := [ ] string { "ID" , "Name" , "Retention" , "Description" }
2019-11-22 23:22:10 +00:00
tablePrintFn ( "BUCKETS" , headers , len ( buckets ) , func ( i int ) [ ] string {
bucket := buckets [ i ]
return [ ] string {
bucket . ID . String ( ) ,
bucket . Name ,
formatDuration ( bucket . RetentionPeriod ) ,
bucket . Description ,
2019-10-26 02:11:47 +00:00
}
2019-10-28 22:23:40 +00:00
} )
}
2019-12-18 20:23:06 +00:00
if checks := sum . Checks ; len ( checks ) > 0 {
headers := [ ] string { "ID" , "Name" , "Description" }
tablePrintFn ( "CHECKS" , headers , len ( checks ) , func ( i int ) [ ] string {
c := checks [ i ] . Check
return [ ] string {
c . GetID ( ) . String ( ) ,
c . GetName ( ) ,
c . GetDescription ( ) ,
}
} )
}
2019-10-30 21:13:42 +00:00
if dashes := sum . Dashboards ; len ( dashes ) > 0 {
headers := [ ] string { "ID" , "Name" , "Description" }
2019-11-22 23:22:10 +00:00
tablePrintFn ( "DASHBOARDS" , headers , len ( dashes ) , func ( i int ) [ ] string {
d := dashes [ i ]
return [ ] string { d . ID . String ( ) , d . Name , d . Description }
2019-10-30 21:13:42 +00:00
} )
}
2019-12-10 22:51:11 +00:00
if endpoints := sum . NotificationEndpoints ; len ( endpoints ) > 0 {
headers := [ ] string { "ID" , "Name" , "Description" , "Status" }
tablePrintFn ( "NOTIFICATION ENDPOINTS" , headers , len ( endpoints ) , func ( i int ) [ ] string {
v := endpoints [ i ]
return [ ] string {
2019-12-12 19:09:32 +00:00
v . NotificationEndpoint . GetID ( ) . String ( ) ,
v . NotificationEndpoint . GetName ( ) ,
v . NotificationEndpoint . GetDescription ( ) ,
string ( v . NotificationEndpoint . GetStatus ( ) ) ,
2019-12-10 22:51:11 +00:00
}
} )
}
2019-12-20 17:10:10 +00:00
if rules := sum . NotificationRules ; len ( rules ) > 0 {
headers := [ ] string { "ID" , "Name" , "Description" , "Every" , "Offset" , "Endpoint Name" , "Endpoint ID" , "Endpoint Type" }
tablePrintFn ( "NOTIFICATION RULES" , headers , len ( rules ) , func ( i int ) [ ] string {
v := rules [ i ]
return [ ] string {
v . ID . String ( ) ,
v . Name ,
v . Description ,
v . Every ,
v . Offset ,
v . EndpointName ,
v . EndpointID . String ( ) ,
v . EndpointType ,
}
} )
}
2019-12-23 19:51:00 +00:00
if tasks := sum . Tasks ; len ( tasks ) > 0 {
headers := [ ] string { "ID" , "Name" , "Description" , "Cycle" }
tablePrintFn ( "TASKS" , headers , len ( tasks ) , func ( i int ) [ ] string {
t := tasks [ i ]
timing := fmt . Sprintf ( "every: %s offset: %s" , t . Every , t . Offset )
if t . Cron != "" {
timing = t . Cron
}
return [ ] string {
t . ID . String ( ) ,
t . Name ,
t . Description ,
timing ,
}
} )
}
2019-12-04 01:00:15 +00:00
if teles := sum . TelegrafConfigs ; len ( teles ) > 0 {
headers := [ ] string { "ID" , "Name" , "Description" }
tablePrintFn ( "TELEGRAF CONFIGS" , headers , len ( teles ) , func ( i int ) [ ] string {
t := teles [ i ]
return [ ] string {
2019-12-12 19:09:32 +00:00
t . TelegrafConfig . ID . String ( ) ,
t . TelegrafConfig . Name ,
t . TelegrafConfig . Description ,
2019-12-04 01:00:15 +00:00
}
} )
}
2019-12-26 19:21:21 +00:00
if vars := sum . Variables ; len ( vars ) > 0 {
headers := [ ] string { "ID" , "Name" , "Description" , "Arg Type" , "Arg Values" }
tablePrintFn ( "VARIABLES" , headers , len ( vars ) , func ( i int ) [ ] string {
v := vars [ i ]
args := v . Arguments
return [ ] string {
v . ID . String ( ) ,
v . Name ,
v . Description ,
args . Type ,
printVarArgs ( args ) ,
}
} )
}
2019-10-28 22:23:40 +00:00
if mappings := sum . LabelMappings ; len ( mappings ) > 0 {
headers := [ ] string { "Resource Type" , "Resource Name" , "Resource ID" , "Label Name" , "Label ID" }
2019-11-22 23:22:10 +00:00
tablePrintFn ( "LABEL MAPPINGS" , headers , len ( mappings ) , func ( i int ) [ ] string {
m := mappings [ i ]
return [ ] string {
string ( m . ResourceType ) ,
m . ResourceName ,
m . ResourceID . String ( ) ,
m . LabelName ,
m . LabelID . String ( ) ,
2019-10-28 22:23:40 +00:00
}
} )
}
2019-12-27 19:22:05 +00:00
if secrets := sum . MissingSecrets ; len ( secrets ) > 0 {
headers := [ ] string { "Secret Key" }
tablePrintFn ( "MISSING SECRETS" , headers , len ( secrets ) , func ( i int ) [ ] string {
return [ ] string { secrets [ i ] }
} )
}
2019-10-28 22:23:40 +00:00
}
2019-11-22 23:22:10 +00:00
func ( b * cmdPkgBuilder ) tablePrinterGen ( ) func ( table string , headers [ ] string , count int , rowFn func ( i int ) [ ] string ) {
return func ( table string , headers [ ] string , count int , rowFn func ( i int ) [ ] string ) {
2020-01-17 15:28:09 +00:00
tablePrinter ( b . w , table , headers , count , ! b . disableColor , ! b . disableTableBorders , rowFn )
2019-11-07 00:45:00 +00:00
}
}
2019-11-22 23:22:10 +00:00
func tablePrinter ( wr io . Writer , table string , headers [ ] string , count int , hasColor , hasTableBorders bool , rowFn func ( i int ) [ ] string ) {
2020-02-06 05:42:01 +00:00
color . New ( color . FgYellow , color . Bold ) . Fprintln ( wr , strings . ToUpper ( table ) )
2019-10-28 22:23:40 +00:00
2019-11-21 23:10:39 +00:00
w := tablewriter . NewWriter ( wr )
2019-10-30 17:55:13 +00:00
w . SetBorder ( hasTableBorders )
w . SetRowLine ( hasTableBorders )
2019-11-01 18:11:42 +00:00
var alignments [ ] int
for range headers {
alignments = append ( alignments , tablewriter . ALIGN_CENTER )
}
2019-11-22 23:22:10 +00:00
descrCol := find ( "description" , headers )
2019-10-28 22:23:40 +00:00
if descrCol != - 1 {
w . SetColMinWidth ( descrCol , 30 )
2019-11-01 18:11:42 +00:00
alignments [ descrCol ] = tablewriter . ALIGN_LEFT
2019-10-28 22:23:40 +00:00
}
w . SetHeader ( headers )
2019-11-01 18:11:42 +00:00
w . SetColumnAlignment ( alignments )
2019-10-28 22:23:40 +00:00
2019-11-22 23:22:10 +00:00
for i := range make ( [ ] struct { } , count ) {
w . Append ( rowFn ( i ) )
}
2019-10-28 22:23:40 +00:00
footers := make ( [ ] string , len ( headers ) )
2019-12-27 19:22:05 +00:00
if len ( headers ) > 1 {
footers [ len ( footers ) - 2 ] = "TOTAL"
footers [ len ( footers ) - 1 ] = strconv . Itoa ( count )
} else {
footers [ 0 ] = "TOTAL: " + strconv . Itoa ( count )
}
2019-10-28 22:23:40 +00:00
w . SetFooter ( footers )
2019-10-30 17:55:13 +00:00
if hasColor {
var colors [ ] tablewriter . Colors
for i := 0 ; i < len ( headers ) ; i ++ {
colors = append ( colors , tablewriter . Color ( tablewriter . FgHiCyanColor ) )
}
w . SetHeaderColor ( colors ... )
2019-12-27 19:22:05 +00:00
if len ( headers ) > 1 {
colors [ len ( colors ) - 2 ] = tablewriter . Color ( tablewriter . FgHiBlueColor )
colors [ len ( colors ) - 1 ] = tablewriter . Color ( tablewriter . FgHiBlueColor )
} else {
colors [ 0 ] = tablewriter . Color ( tablewriter . FgHiBlueColor )
}
2019-10-30 17:55:13 +00:00
w . SetFooterColor ( colors ... )
}
2019-10-28 22:23:40 +00:00
w . Render ( )
2020-02-06 05:42:01 +00:00
fmt . Fprintln ( wr )
2019-10-24 19:20:49 +00:00
}
2019-11-21 23:10:39 +00:00
func printVarArgs ( a * influxdb . VariableArguments ) string {
if a == nil {
return "<nil>"
}
if a . Type == "map" {
b , err := json . Marshal ( a . Values )
if err != nil {
return "{}"
}
return string ( b )
}
if a . Type == "constant" {
vals , ok := a . Values . ( influxdb . VariableConstantValues )
if ! ok {
return "[]"
}
var out [ ] string
for _ , s := range vals {
out = append ( out , fmt . Sprintf ( "%q" , s ) )
}
return fmt . Sprintf ( "[%s]" , strings . Join ( out , " " ) )
}
if a . Type == "query" {
qVal , ok := a . Values . ( influxdb . VariableQueryValues )
if ! ok {
return ""
}
return fmt . Sprintf ( "language=%q query=%q" , qVal . Language , qVal . Query )
}
return "unknown variable argument"
}
2019-10-24 19:20:49 +00:00
func formatDuration ( d time . Duration ) string {
if d == 0 {
return "inf"
}
return d . String ( )
}
2019-11-22 23:22:10 +00:00
2020-02-06 23:12:58 +00:00
func readFilesFromPath ( filePath string , recurse bool ) ( [ ] string , error ) {
info , err := os . Stat ( filePath )
if err != nil {
return nil , err
}
if ! info . IsDir ( ) {
return [ ] string { filePath } , nil
}
dirFiles , err := ioutil . ReadDir ( filePath )
if err != nil {
return nil , err
}
mFiles := make ( map [ string ] struct { } )
assign := func ( ss ... string ) {
for _ , s := range ss {
mFiles [ s ] = struct { } { }
}
}
for _ , f := range dirFiles {
fileP := filepath . Join ( filePath , f . Name ( ) )
if f . IsDir ( ) {
if recurse {
rFiles , err := readFilesFromPath ( fileP , recurse )
if err != nil {
return nil , err
}
assign ( rFiles ... )
}
continue
}
assign ( fileP )
}
var files [ ] string
for f := range mFiles {
files = append ( files , f )
}
return files , nil
}
2020-02-06 05:42:01 +00:00
func mapKeys ( provided , kvPairs [ ] string ) map [ string ] string {
out := make ( map [ string ] string )
for _ , k := range provided {
out [ k ] = ""
}
for _ , pair := range kvPairs {
pieces := strings . SplitN ( pair , "=" , 2 )
if len ( pieces ) < 2 {
continue
}
k , v := pieces [ 0 ] , pieces [ 1 ]
if _ , ok := out [ k ] ; ! ok {
continue
}
out [ k ] = v
}
return out
}
func missingValKeys ( m map [ string ] string ) [ ] string {
out := make ( [ ] string , 0 , len ( m ) )
for k , v := range m {
if v != "" {
continue
}
out = append ( out , k )
}
sort . Slice ( out , func ( i , j int ) bool {
return out [ i ] < out [ j ]
} )
return out
}
2019-11-22 23:22:10 +00:00
func find ( needle string , haystack [ ] string ) int {
for i , h := range haystack {
if strings . ToLower ( h ) == needle {
return i
}
}
return - 1
}