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-11-21 07:12:27 +00:00
"net/http"
2019-10-24 19:20:49 +00:00
"os"
"path/filepath"
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-11-15 17:35:55 +00:00
"gopkg.in/yaml.v3"
2019-10-24 19:20:49 +00:00
)
2019-11-18 18:50:45 +00:00
type pkgSVCFn func ( cliReq httpClientOpts ) ( pkger . SVC , error )
2019-11-21 23:10:39 +00:00
func cmdPkg ( svcFn pkgSVCFn , opts ... genericCLIOptfn ) * cobra . Command {
return newCmdPkgBuilder ( svcFn , opts ... ) . cmdPkg ( )
2019-11-15 17:35:55 +00:00
}
2019-11-21 23:10:39 +00:00
type cmdPkgBuilder struct {
genericCLIOpts
svcFn pkgSVCFn
file string
hasColor bool
hasTableBorders bool
meta pkger . Metadata
orgID string
quiet bool
applyOpts struct {
forceOnConflict bool
}
exportOpts struct {
resourceType string
buckets string
dashboards string
labels string
variables string
}
2019-11-21 07:12:27 +00:00
}
2019-11-21 23:10:39 +00:00
func newCmdPkgBuilder ( svcFn pkgSVCFn , opts ... genericCLIOptfn ) * cmdPkgBuilder {
opt := genericCLIOpts {
in : os . Stdin ,
w : os . Stdout ,
}
for _ , o := range opts {
o ( & opt )
}
return & cmdPkgBuilder {
genericCLIOpts : opt ,
svcFn : svcFn ,
2019-10-24 19:20:49 +00:00
}
2019-11-21 23:10:39 +00:00
}
func ( b * cmdPkgBuilder ) cmdPkg ( ) * cobra . Command {
cmd := b . cmdPkgApply ( )
cmd . AddCommand (
b . cmdPkgNew ( ) ,
b . cmdPkgExport ( ) ,
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 {
cmd := b . newCmd ( "pkg" )
cmd . Short = "Apply a pkg to create resources"
cmd . Flags ( ) . StringVarP ( & b . file , "file" , "f" , "" , "Path to package file" )
2019-11-21 07:12:27 +00:00
cmd . MarkFlagFilename ( "file" , "yaml" , "yml" , "json" )
2019-11-21 23:10:39 +00:00
cmd . Flags ( ) . BoolVar ( & b . applyOpts . forceOnConflict , "force-on-conflict" , true , "TTY input, if package will have destructive changes, proceed if set true." )
cmd . Flags ( ) . BoolVarP ( & b . quiet , "quiet" , "q" , false , "disable output printing" )
2019-10-24 19:20:49 +00:00
2019-11-21 23:10:39 +00:00
cmd . Flags ( ) . StringVarP ( & b . orgID , "org-id" , "o" , "" , "The ID of the organization that owns the bucket" )
2019-10-24 19:20:49 +00:00
cmd . MarkFlagRequired ( "org-id" )
2019-11-21 23:10:39 +00:00
cmd . Flags ( ) . BoolVarP ( & b . hasColor , "color" , "c" , true , "Enable color in output, defaults true" )
cmd . Flags ( ) . BoolVar ( & b . hasTableBorders , "table-borders" , true , "Enable table borders, defaults true" )
2019-10-30 17:55:13 +00:00
2019-11-21 23:10:39 +00:00
cmd . RunE = b . pkgApplyRunEFn ( )
2019-10-24 19:20:49 +00:00
return cmd
}
2019-11-21 23:10:39 +00:00
func ( b * cmdPkgBuilder ) pkgApplyRunEFn ( ) func ( * cobra . Command , [ ] string ) error {
2019-10-24 19:20:49 +00:00
return func ( cmd * cobra . Command , args [ ] string ) ( e error ) {
2019-11-21 23:10:39 +00:00
color . NoColor = ! b . hasColor
2019-10-30 17:55:13 +00:00
2019-11-21 23:10:39 +00:00
influxOrgID , err := influxdb . IDFromString ( b . orgID )
2019-10-25 21:39:38 +00:00
if err != nil {
return err
}
2019-11-21 23:10:39 +00:00
svc , err := b . svcFn ( flags . httpClientOpts ( ) )
2019-10-24 19:20:49 +00:00
if err != nil {
return err
}
2019-11-21 23:10:39 +00:00
pkg , isTTY , err := b . readPkgStdInOrFile ( b . file )
2019-10-24 19:20:49 +00:00
if err != nil {
return err
}
2019-10-28 22:23:40 +00:00
_ , diff , err := svc . DryRun ( context . Background ( ) , * influxOrgID , pkg )
if err != nil {
return err
}
2019-11-21 23:10:39 +00:00
if ! b . quiet {
b . printPkgDiff ( diff )
2019-11-21 07:12:27 +00:00
}
2019-10-24 19:20:49 +00:00
2019-11-21 07:12:27 +00:00
if ! isTTY {
ui := & input . UI {
Writer : os . Stdout ,
Reader : os . Stdin ,
}
confirm := getInput ( ui , "Confirm application of the above resources (y/n)" , "n" )
if strings . ToLower ( confirm ) != "y" {
fmt . Fprintln ( os . Stdout , "aborted application of package" )
return nil
}
2019-10-24 19:20:49 +00:00
}
2019-11-21 23:10:39 +00:00
if ! b . applyOpts . forceOnConflict && isTTY && diff . HasConflicts ( ) {
2019-11-21 07:12:27 +00:00
return errors . New ( "package has conflicts with existing resources and cannot safely apply" )
2019-10-24 19:20:49 +00:00
}
summary , err := svc . Apply ( context . Background ( ) , * influxOrgID , pkg )
if err != nil {
return err
}
2019-11-21 23:10:39 +00:00
if ! b . quiet {
b . printPkgSummary ( summary )
2019-11-21 07:12:27 +00:00
}
2019-10-24 19:20:49 +00:00
return nil
}
}
2019-11-21 23:10:39 +00:00
func ( b * cmdPkgBuilder ) cmdPkgNew ( ) * cobra . Command {
cmd := b . newCmd ( "new" )
cmd . Short = "Create a reusable pkg to create resources in a declarative manner"
2019-11-15 17:35:55 +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" )
cmd . Flags ( ) . BoolVarP ( & b . quiet , "quiet" , "q" , false , "skip interactive mode" )
cmd . Flags ( ) . StringVarP ( & b . meta . Name , "name" , "n" , "" , "name for new pkg" )
cmd . Flags ( ) . StringVarP ( & b . meta . Description , "description" , "d" , "" , "description for new pkg" )
cmd . Flags ( ) . StringVarP ( & b . meta . Version , "version" , "v" , "" , "version for new pkg" )
2019-11-15 17:35:55 +00:00
2019-11-21 23:10:39 +00:00
cmd . RunE = b . pkgNewRunEFn ( )
2019-11-15 17:35:55 +00:00
return cmd
}
2019-11-21 23:10:39 +00:00
func ( b * cmdPkgBuilder ) pkgNewRunEFn ( ) func ( * cobra . Command , [ ] string ) error {
2019-11-15 17:35:55 +00:00
return func ( cmd * cobra . Command , args [ ] string ) error {
2019-11-21 23:10:39 +00:00
if ! b . quiet {
2019-11-15 17:35:55 +00:00
ui := & input . UI {
2019-11-21 23:10:39 +00:00
Writer : b . w ,
Reader : b . in ,
2019-11-15 17:35:55 +00:00
}
2019-11-21 23:10:39 +00:00
if b . meta . Name == "" {
b . meta . Name = getInput ( ui , "pkg name" , "" )
2019-11-15 17:35:55 +00:00
}
2019-11-21 23:10:39 +00:00
if b . meta . Description == "" {
b . meta . Description = getInput ( ui , "pkg description" , "" )
2019-11-15 17:35:55 +00:00
}
2019-11-21 23:10:39 +00:00
if b . meta . Version == "" {
b . meta . Version = getInput ( ui , "pkg version" , "" )
2019-11-15 17:35:55 +00:00
}
}
2019-11-21 23:10:39 +00:00
pkgSVC , err := b . svcFn ( flags . httpClientOpts ( ) )
2019-11-18 18:50:45 +00:00
if err != nil {
return err
}
2019-11-21 23:10:39 +00:00
return b . writePkg ( cmd . OutOrStdout ( ) , pkgSVC , b . file , pkger . CreateWithMetadata ( b . meta ) )
2019-11-21 00:38:12 +00:00
}
}
2019-11-21 23:10:39 +00:00
func ( b * cmdPkgBuilder ) cmdPkgExport ( ) * cobra . Command {
cmd := b . newCmd ( "export" )
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 ( ) . StringVarP ( & b . meta . Name , "name" , "n" , "" , "name for new pkg" )
cmd . Flags ( ) . StringVarP ( & b . meta . Description , "description" , "d" , "" , "description for new pkg" )
cmd . Flags ( ) . StringVarP ( & b . meta . Version , "version" , "v" , "" , "version for new pkg" )
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" )
cmd . Flags ( ) . StringVar ( & b . exportOpts . dashboards , "dashboards" , "" , "List of dashboard ids comma separated" )
cmd . Flags ( ) . StringVar ( & b . exportOpts . labels , "labels" , "" , "List of label ids comma separated" )
cmd . Flags ( ) . StringVar ( & b . exportOpts . variables , "variables" , "" , "List of variable ids comma separated" )
cmd . RunE = b . pkgExportRunEFn ( )
2019-11-21 00:38:12 +00:00
return cmd
}
2019-11-21 23:10:39 +00:00
func ( b * cmdPkgBuilder ) pkgExportRunEFn ( ) func ( * cobra . Command , [ ] string ) error {
2019-11-21 00:38:12 +00:00
return func ( cmd * cobra . Command , args [ ] string ) error {
2019-11-21 23:10:39 +00:00
pkgSVC , err := b . svcFn ( flags . httpClientOpts ( ) )
2019-11-21 00:38:12 +00:00
if err != nil {
return err
}
2019-11-21 23:10:39 +00:00
opts := [ ] pkger . CreatePkgSetFn { pkger . CreateWithMetadata ( b . meta ) }
2019-11-21 00:38:12 +00:00
resTypes := [ ] struct {
kind pkger . Kind
idStrs [ ] string
} {
2019-11-21 23:10:39 +00:00
{ kind : pkger . KindBucket , idStrs : strings . Split ( b . exportOpts . buckets , "," ) } ,
{ kind : pkger . KindDashboard , idStrs : strings . Split ( b . exportOpts . dashboards , "," ) } ,
{ kind : pkger . KindLabel , idStrs : strings . Split ( b . exportOpts . labels , "," ) } ,
{ kind : pkger . KindVariable , idStrs : strings . Split ( b . exportOpts . variables , "," ) } ,
2019-11-21 00:38:12 +00:00
}
for _ , rt := range resTypes {
2019-11-21 23:10:39 +00:00
newOpt , err := newResourcesToClone ( rt . kind , rt . idStrs )
2019-11-21 00:38:12 +00:00
if err != nil {
return ierror . Wrap ( err , rt . kind . String ( ) )
}
opts = append ( opts , newOpt )
}
2019-11-21 23:10:39 +00:00
if b . exportOpts . resourceType == "" {
return b . writePkg ( cmd . OutOrStdout ( ) , pkgSVC , b . file , opts ... )
2019-11-21 00:38:12 +00:00
}
2019-11-21 23:10:39 +00:00
kind := pkger . NewKind ( b . exportOpts . resourceType )
2019-11-21 00:38:12 +00:00
if err := kind . OK ( ) ; err != nil {
2019-11-21 23:10:39 +00:00
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
}
2019-11-21 23:10:39 +00:00
if stdin , err := b . inStdIn ( ) ; err == nil {
stdinInpt , _ := b . readLines ( stdin )
if len ( stdinInpt ) > 0 {
args = stdinInpt
}
2019-11-21 00:38:12 +00:00
}
2019-11-21 23:10:39 +00:00
resTypeOpt , err := newResourcesToClone ( kind , args )
2019-11-15 17:35:55 +00:00
if err != nil {
return err
}
2019-11-21 23:10:39 +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 {
cmd := b . newCmd ( "all" )
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" )
cmd . Flags ( ) . StringVarP ( & b . orgID , "org-id" , "o" , "" , "organization id" )
cmd . Flags ( ) . StringVarP ( & b . meta . Name , "name" , "n" , "" , "name for new pkg" )
cmd . Flags ( ) . StringVarP ( & b . meta . Description , "description" , "d" , "" , "description for new pkg" )
cmd . Flags ( ) . StringVarP ( & b . meta . Version , "version" , "v" , "" , "version for new pkg" )
2019-11-21 00:38:12 +00:00
2019-11-21 23:10:39 +00:00
cmd . RunE = b . pkgExportAllRunEFn ( )
2019-11-21 00:38:12 +00:00
return cmd
}
2019-11-21 23:10:39 +00:00
func ( b * cmdPkgBuilder ) pkgExportAllRunEFn ( ) func ( * cobra . Command , [ ] string ) error {
2019-11-21 00:38:12 +00:00
return func ( cmd * cobra . Command , args [ ] string ) error {
2019-11-21 23:10:39 +00:00
pkgSVC , err := b . svcFn ( flags . httpClientOpts ( ) )
2019-11-21 00:38:12 +00:00
if err != nil {
return err
2019-11-15 17:35:55 +00:00
}
2019-11-21 00:38:12 +00:00
2019-11-21 23:10:39 +00:00
opts := [ ] pkger . CreatePkgSetFn { pkger . CreateWithMetadata ( b . meta ) }
2019-11-21 00:38:12 +00:00
2019-11-21 23:10:39 +00:00
orgID , err := influxdb . IDFromString ( b . orgID )
2019-11-21 00:38:12 +00:00
if err != nil {
2019-11-15 17:35:55 +00:00
return err
}
2019-11-21 00:38:12 +00:00
opts = append ( opts , pkger . CreateWithAllOrgResources ( * orgID ) )
2019-11-21 23:10:39 +00:00
return b . writePkg ( cmd . OutOrStdout ( ) , pkgSVC , b . file , opts ... )
2019-11-21 00:38:12 +00:00
}
}
2019-11-21 23:10:39 +00:00
func ( b * cmdPkgBuilder ) cmdPkgValidate ( ) * cobra . Command {
cmd := b . newCmd ( "validate" )
cmd . Short = "Validate the provided package"
2019-11-21 21:12:15 +00:00
inPath := cmd . Flags ( ) . StringP ( "file" , "f" , "" , "input file for pkg; if none provided will use TTY input" )
cmd . RunE = func ( cmd * cobra . Command , args [ ] string ) error {
2019-11-21 23:10:39 +00:00
pkg , _ , err := b . readPkgStdInOrFile ( * inPath )
2019-11-21 21:12:15 +00:00
if err != nil {
return err
}
return pkg . Validate ( )
}
return cmd
}
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
}
2019-11-21 23:10:39 +00:00
func ( b * cmdPkgBuilder ) readPkgStdInOrFile ( file string ) ( * pkger . Pkg , bool , error ) {
if file != "" {
pkg , err := pkgFromFile ( file )
return pkg , false , err
}
var isTTY bool
if _ , err := b . inStdIn ( ) ; err == nil {
isTTY = true
}
pkg , err := pkgFromReader ( b . in )
return pkg , isTTY , err
}
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
}
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 ) {
var (
buf bytes . Buffer
enc interface {
Encode ( interface { } ) error
}
)
switch ext := filepath . Ext ( outPath ) ; ext {
case ".json" :
jsonEnc := json . NewEncoder ( & buf )
jsonEnc . SetIndent ( "" , "\t" )
enc = jsonEnc
default :
enc = yaml . NewEncoder ( & buf )
}
if err := enc . Encode ( pkg ) ; err != nil {
return nil , err
}
return & buf , nil
2019-11-18 18:50:45 +00:00
}
2019-11-07 00:45:00 +00:00
2019-11-18 18:50:45 +00:00
func newPkgerSVC ( cliReqOpts httpClientOpts ) ( pkger . SVC , error ) {
2019-11-07 00:45:00 +00:00
return pkger . NewService (
2019-11-21 07:12:27 +00:00
pkger . WithBucketSVC ( & ihttp . BucketService {
2019-11-18 18:50:45 +00:00
Addr : cliReqOpts . addr ,
Token : cliReqOpts . token ,
InsecureSkipVerify : cliReqOpts . skipVerify ,
} ) ,
2019-11-21 07:12:27 +00:00
pkger . WithDashboardSVC ( & ihttp . DashboardService {
2019-11-18 18:50:45 +00:00
Addr : cliReqOpts . addr ,
Token : cliReqOpts . token ,
InsecureSkipVerify : cliReqOpts . skipVerify ,
} ) ,
2019-11-21 07:12:27 +00:00
pkger . WithLabelSVC ( & ihttp . LabelService {
2019-11-18 18:50:45 +00:00
Addr : cliReqOpts . addr ,
Token : cliReqOpts . token ,
InsecureSkipVerify : cliReqOpts . skipVerify ,
} ) ,
2019-11-21 07:12:27 +00:00
pkger . WithVariableSVC ( & ihttp . VariableService {
2019-11-18 18:50:45 +00:00
Addr : cliReqOpts . addr ,
Token : cliReqOpts . token ,
InsecureSkipVerify : cliReqOpts . skipVerify ,
} ) ,
2019-11-07 00:45:00 +00:00
) , nil
2019-10-30 21:13:42 +00:00
}
2019-11-21 23:10:39 +00:00
func pkgFromReader ( stdin io . Reader ) ( * pkger . Pkg , error ) {
2019-11-21 07:12:27 +00:00
b , err := ioutil . ReadAll ( stdin )
if err != nil {
return nil , err
}
var enc pkger . Encoding
switch http . DetectContentType ( b [ 0 : 512 ] ) {
case "application/json" :
enc = pkger . EncodingJSON
default :
enc = pkger . EncodingYAML
}
return pkger . Parse ( enc , pkger . FromString ( string ( b ) ) )
}
2019-10-24 19:20:49 +00:00
func pkgFromFile ( path string ) ( * pkger . Pkg , error ) {
var enc pkger . Encoding
switch ext := filepath . Ext ( path ) ; ext {
case ".yaml" , ".yml" :
enc = pkger . EncodingYAML
case ".json" :
enc = pkger . EncodingJSON
default :
return nil , errors . New ( "file provided must be one of yaml/yml/json extension but got: " + ext )
}
return pkger . Parse ( enc , pkger . FromFile ( path ) )
}
2019-11-21 23:10:39 +00:00
func ( b * cmdPkgBuilder ) printPkgDiff ( diff pkger . Diff ) {
2019-10-28 22:23:40 +00:00
red := color . New ( color . FgRed ) . SprintfFunc ( )
green := color . New ( color . FgHiGreen , color . Bold ) . SprintfFunc ( )
strDiff := func ( isNew bool , old , new string ) string {
if isNew {
return green ( new )
2019-10-26 02:11:47 +00:00
}
2019-10-28 22:23:40 +00:00
if old == new {
return new
}
return fmt . Sprintf ( "%s\n%s" , red ( "%q" , old ) , green ( "%q" , new ) )
}
boolDiff := func ( b bool ) string {
bb := strconv . FormatBool ( b )
if b {
return green ( bb )
}
return bb
}
durDiff := func ( isNew bool , oldDur , newDur time . Duration ) string {
o := oldDur . String ( )
if oldDur == 0 {
o = "inf"
}
n := newDur . String ( )
if newDur == 0 {
n = "inf"
}
if isNew {
return green ( n )
}
if oldDur == newDur {
return n
}
return fmt . Sprintf ( "%s\n%s" , red ( o ) , green ( n ) )
}
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-07 00:45:00 +00:00
tablePrintFn ( "LABELS" , headers , len ( labels ) , func ( w * tablewriter . Table ) {
2019-10-30 21:13:42 +00:00
for _ , l := range labels {
2019-10-28 22:23:40 +00:00
w . Append ( [ ] string {
boolDiff ( l . IsNew ( ) ) ,
l . ID . String ( ) ,
l . Name ,
strDiff ( l . IsNew ( ) , l . OldColor , l . NewColor ) ,
strDiff ( l . IsNew ( ) , l . OldDesc , l . NewDesc ) ,
} )
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-07 00:45:00 +00:00
tablePrintFn ( "BUCKETS" , headers , len ( bkts ) , func ( w * tablewriter . Table ) {
2019-10-30 21:13:42 +00:00
for _ , b := range bkts {
2019-10-28 22:23:40 +00:00
w . Append ( [ ] string {
boolDiff ( b . IsNew ( ) ) ,
b . ID . String ( ) ,
b . Name ,
durDiff ( b . IsNew ( ) , b . OldRetention , b . NewRetention ) ,
strDiff ( b . IsNew ( ) , b . OldDesc , b . NewDesc ) ,
} )
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-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-07 00:45:00 +00:00
tablePrintFn ( "DASHBOARDS" , headers , len ( dashes ) , func ( w * tablewriter . Table ) {
2019-10-30 21:13:42 +00:00
for _ , d := range dashes {
w . Append ( [ ] string {
2019-11-01 18:11:42 +00:00
boolDiff ( true ) ,
2019-10-30 21:13:42 +00:00
d . Name ,
2019-11-01 18:11:42 +00:00
green ( d . Desc ) ,
green ( strconv . Itoa ( len ( d . Charts ) ) ) ,
2019-10-30 21:13:42 +00:00
} )
}
} )
}
2019-11-07 00:45:00 +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 ( w * tablewriter . Table ) {
for _ , v := range vars {
var oldArgType string
if v . OldArgs != nil {
oldArgType = v . OldArgs . Type
}
var newArgType string
if v . NewArgs != nil {
newArgType = v . NewArgs . Type
}
w . Append ( [ ] string {
boolDiff ( v . IsNew ( ) ) ,
v . ID . String ( ) ,
v . Name ,
strDiff ( v . IsNew ( ) , v . OldDesc , v . NewDesc ) ,
strDiff ( v . IsNew ( ) , oldArgType , newArgType ) ,
strDiff ( v . IsNew ( ) , printVarArgs ( v . OldArgs ) , printVarArgs ( v . NewArgs ) ) ,
} )
}
} )
}
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-07 00:45:00 +00:00
tablePrintFn ( "LABEL MAPPINGS" , headers , len ( diff . LabelMappings ) , func ( w * tablewriter . Table ) {
2019-10-28 22:23:40 +00:00
for _ , m := range diff . LabelMappings {
w . Append ( [ ] 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-07 00:45:00 +00:00
tablePrintFn ( "LABELS" , headers , len ( labels ) , func ( w * tablewriter . Table ) {
2019-10-28 22:23:40 +00:00
for _ , l := range labels {
w . Append ( [ ] string {
l . ID . String ( ) ,
l . Name ,
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-07 00:45:00 +00:00
tablePrintFn ( "BUCKETS" , headers , len ( buckets ) , func ( w * tablewriter . Table ) {
2019-10-28 22:23:40 +00:00
for _ , bucket := range buckets {
w . Append ( [ ] 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-10-30 21:13:42 +00:00
if dashes := sum . Dashboards ; len ( dashes ) > 0 {
headers := [ ] string { "ID" , "Name" , "Description" }
2019-11-07 00:45:00 +00:00
tablePrintFn ( "DASHBOARDS" , headers , len ( dashes ) , func ( w * tablewriter . Table ) {
2019-10-30 21:13:42 +00:00
for _ , d := range dashes {
w . Append ( [ ] string {
d . ID . String ( ) ,
d . Name ,
d . Description ,
} )
}
} )
}
2019-11-07 00:45:00 +00:00
if vars := sum . Variables ; len ( vars ) > 0 {
headers := [ ] string { "ID" , "Name" , "Description" , "Arg Type" , "Arg Values" }
tablePrintFn ( "VARIABLES" , headers , len ( vars ) , func ( w * tablewriter . Table ) {
for _ , v := range vars {
args := v . Arguments
w . Append ( [ ] 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-07 00:45:00 +00:00
tablePrintFn ( "LABEL MAPPINGS" , headers , len ( mappings ) , func ( w * tablewriter . Table ) {
2019-10-28 22:23:40 +00:00
for _ , m := range mappings {
w . Append ( [ ] string {
string ( m . ResourceType ) ,
m . ResourceName ,
m . ResourceID . String ( ) ,
m . LabelName ,
m . LabelID . String ( ) ,
} )
}
} )
}
}
2019-11-21 23:10:39 +00:00
func ( b * cmdPkgBuilder ) tablePrinterGen ( ) func ( table string , headers [ ] string , count int , appendFn func ( w * tablewriter . Table ) ) {
2019-11-07 00:45:00 +00:00
return func ( table string , headers [ ] string , count int , appendFn func ( w * tablewriter . Table ) ) {
2019-11-21 23:10:39 +00:00
tablePrinter ( b . w , table , headers , count , b . hasColor , b . hasTableBorders , appendFn )
2019-11-07 00:45:00 +00:00
}
}
2019-11-21 23:10:39 +00:00
func tablePrinter ( wr io . Writer , table string , headers [ ] string , count int , hasColor , hasTableBorders bool , appendFn func ( w * tablewriter . Table ) ) {
2019-10-28 22:23:40 +00:00
descrCol := - 1
for i , h := range headers {
if strings . ToLower ( h ) == "description" {
descrCol = i
break
2019-10-24 19:20:49 +00:00
}
}
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-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
}
color . New ( color . FgYellow , color . Bold ) . Fprintln ( os . Stdout , strings . ToUpper ( table ) )
w . SetHeader ( headers )
2019-11-01 18:11:42 +00:00
w . SetColumnAlignment ( alignments )
2019-10-28 22:23:40 +00:00
appendFn ( w )
footers := make ( [ ] string , len ( headers ) )
footers [ len ( footers ) - 2 ] = "TOTAL"
footers [ len ( footers ) - 1 ] = strconv . Itoa ( count )
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-11-01 18:11:42 +00:00
colors [ len ( colors ) - 2 ] = tablewriter . Color ( tablewriter . FgHiBlueColor )
colors [ len ( colors ) - 1 ] = 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 ( )
fmt . Fprintln ( os . Stdout )
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 ( )
}