diff --git a/.golangci.yaml b/.golangci.yaml index ac058ee6..180b843f 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -119,17 +119,11 @@ issues: # Default: https://golangci-lint.run/usage/false-positives/#default-exclusions exclude: - abcdef + - ST1023 exclude-rules: # Exclude some linters from running on tests files. - path: cmd/printer/ linters: - - funlen - - gocyclo - dupl - - lll - - gomnd - - gocritic - - stylecheck - run: timeout: 5m diff --git a/cmd/dnsRecord.go b/cmd/dnsRecord.go index e11a6e34..721e2c7e 100644 --- a/cmd/dnsRecord.go +++ b/cmd/dnsRecord.go @@ -115,7 +115,7 @@ var recordCreate = &cobra.Command{ os.Exit(1) } - printer.DnsRecord(record) + printer.DNSRecord(record) }, } @@ -139,7 +139,7 @@ var recordGet = &cobra.Command{ os.Exit(1) } - printer.DnsRecord(record) + printer.DNSRecord(record) }, } @@ -163,7 +163,7 @@ var recordList = &cobra.Command{ os.Exit(1) } - printer.DnsRecordsList(records, meta) + printer.DNSRecordsList(records, meta) }, } diff --git a/cmd/printer/account.go b/cmd/printer/account.go index 018fd1a3..9d0c9700 100644 --- a/cmd/printer/account.go +++ b/cmd/printer/account.go @@ -5,8 +5,15 @@ import ( ) func Account(account *govultr.Account) { - col := columns{"BALANCE", "PENDING CHARGES", "LAST PAYMENT DATE", "LAST PAYMENT AMOUNT", "NAME", "EMAIL", "ACLS"} - display(col) - display(columns{account.Balance, account.PendingCharges, account.LastPaymentDate, account.LastPaymentAmount, account.Name, account.Email, account.ACL}) - flush() + defer flush() + display(columns{"BALANCE", "PENDING CHARGES", "LAST PAYMENT DATE", "LAST PAYMENT AMOUNT", "NAME", "EMAIL", "ACLS"}) + display(columns{ + account.Balance, + account.PendingCharges, + account.LastPaymentDate, + account.LastPaymentAmount, + account.Name, + account.Email, + account.ACL, + }) } diff --git a/cmd/printer/application.go b/cmd/printer/application.go index 94f5955e..387959fc 100644 --- a/cmd/printer/application.go +++ b/cmd/printer/application.go @@ -5,12 +5,27 @@ import ( ) func Application(apps []govultr.Application, meta *govultr.Meta) { - col := columns{"ID", "NAME", "SHORT NAME", "DEPLOY NAME", "TYPE", "VENDOR", "IMAGE ID"} - display(col) - for _, a := range apps { - display(columns{a.ID, a.Name, a.ShortName, a.DeployName, a.Type, a.Vendor, a.ImageID}) + defer flush() + + display(columns{"ID", "NAME", "SHORT NAME", "DEPLOY NAME", "TYPE", "VENDOR", "IMAGE ID"}) + + if len(apps) == 0 { + display(columns{"---", "---", "---", "---", "---", "---", "---"}) + Meta(meta) + return + } + + for i := range apps { + display(columns{ + apps[i].ID, + apps[i].Name, + apps[i].ShortName, + apps[i].DeployName, + apps[i].Type, + apps[i].Vendor, + apps[i].ImageID, + }) } Meta(meta) - flush() } diff --git a/cmd/printer/backup.go b/cmd/printer/backup.go index 46f56c9a..71abf68b 100644 --- a/cmd/printer/backup.go +++ b/cmd/printer/backup.go @@ -5,19 +5,32 @@ import ( ) func Backups(bs []govultr.Backup, meta *govultr.Meta) { - col := columns{"ID", "DATE CREATED", "DESCRIPTION", "SIZE", "STATUS"} - display(col) - for _, b := range bs { - display(columns{b.ID, b.DateCreated, b.Description, b.Size, b.Status}) + defer flush() + + display(columns{"ID", "DATE CREATED", "DESCRIPTION", "SIZE", "STATUS"}) + + if len(bs) == 0 { + display(columns{"---", "---", "---", "---", "---"}) + Meta(meta) + return + } + + for i := range bs { + display(columns{ + bs[i].ID, + bs[i].DateCreated, + bs[i].Description, + bs[i].Size, + bs[i].Status, + }) } Meta(meta) - flush() } func Backup(bs *govultr.Backup) { - col := columns{"ID", "DATE CREATED", "DESCRIPTION", "SIZE", "STATUS"} - display(col) + defer flush() - flush() + display(columns{"ID", "DATE CREATED", "DESCRIPTION", "SIZE", "STATUS"}) + display(columns{bs.ID, bs.DateCreated, bs.Description, bs.Size, bs.Status}) } diff --git a/cmd/printer/bareMetal.go b/cmd/printer/bareMetal.go index ee9a9e1c..a19fc090 100644 --- a/cmd/printer/bareMetal.go +++ b/cmd/printer/bareMetal.go @@ -5,65 +5,130 @@ import ( ) func BareMetal(b *govultr.BareMetalServer) { - col := columns{"ID", "IP", "TAG", "MAC ADDRESS", "LABEL", "OS", "STATUS", "REGION", "CPU", "RAM", "DISK", "FEATURES", "TAGS"} - display(col) + defer flush() + display(columns{"ID", "IP", "TAG", "MAC ADDRESS", "LABEL", "OS", "STATUS", "REGION", "CPU", "RAM", "DISK", "FEATURES", "TAGS"}) display(columns{b.ID, b.MainIP, b.Tag, b.MacAddress, b.Label, b.Os, b.Status, b.Region, b.CPUCount, b.RAM, b.Disk, b.Features, b.Tags}) //nolint:all - - flush() } func BareMetalList(bms []govultr.BareMetalServer, meta *govultr.Meta) { - col := columns{"ID", "IP", "TAG", "MAC ADDRESS", "LABEL", "OS", "STATUS", "REGION", "CPU", "RAM", "DISK", "FEATURES", "TAGS"} - display(col) - for _, b := range bms { - display(columns{b.ID, b.MainIP, b.Tag, b.MacAddress, b.Label, b.Os, b.Status, b.Region, b.CPUCount, b.RAM, b.Disk, b.Features, b.Tags}) //nolint:all + defer flush() + + display(columns{"ID", "IP", "TAG", "MAC ADDRESS", "LABEL", "OS", "STATUS", "REGION", "CPU", "RAM", "DISK", "FEATURES", "TAGS"}) + + if len(bms) == 0 { + display(columns{"---", "---", "---", "---", "---", "---", "---", "---", "---", "---", "---", "---", "---"}) + Meta(meta) + return } - Meta(meta) + for i := range bms { + display(columns{ + bms[i].ID, + bms[i].MainIP, + bms[i].MacAddress, + bms[i].Label, + bms[i].Os, + bms[i].Status, + bms[i].Region, + bms[i].CPUCount, + bms[i].RAM, + bms[i].Disk, + bms[i].Features, + bms[i].Tags, + }) + } - flush() + Meta(meta) } func BareMetalBandwidth(bw *govultr.Bandwidth) { + defer flush() + display(columns{"DATE", "INCOMING BYTES", "OUTGOING BYTES"}) - for k, b := range bw.Bandwidth { - display(columns{k, b.IncomingBytes, b.OutgoingBytes}) + if len(bw.Bandwidth) == 0 { + display(columns{"---", "---", "---"}) + return + } + + for i := range bw.Bandwidth { + display(columns{ + i, + bw.Bandwidth[i].IncomingBytes, + bw.Bandwidth[i].OutgoingBytes, + }) } - flush() } func BareMetalIPV4Info(info []govultr.IPv4, meta *govultr.Meta) { + defer flush() + display(columns{"IP", "NETMASK", "GATEWAY", "TYPE"}) - for _, i := range info { - display(columns{i.IP, i.Netmask, i.Gateway, i.Type}) + + if len(info) == 0 { + display(columns{"---", "---", "---", "---"}) + Meta(meta) + return + } + + for i := range info { + display(columns{ + info[i].IP, + info[i].Netmask, + info[i].Gateway, + info[i].Type, + }) } Meta(meta) - flush() } func BareMetalIPV6Info(info []govultr.IPv6, meta *govultr.Meta) { + defer flush() + display(columns{"IP", "NETWORK", "NETWORK SIZE", "TYPE"}) - for _, i := range info { - display(columns{i.IP, i.Network, i.NetworkSize, i.Type}) + + if len(info) == 0 { + display(columns{"---", "---", "---", "---"}) + Meta(meta) + return + } + + for i := range info { + display(columns{ + info[i].IP, + info[i].Network, + info[i].NetworkSize, + info[i].Type, + }) } Meta(meta) - flush() } func BareMetalVNCUrl(vnc *govultr.VNCUrl) { + defer flush() + display(columns{"VNC URL"}) display(columns{vnc.URL}) - flush() } // BareMetalVPC2List Generate a printer display of all VPC 2.0 networks attached to a given server func BareMetalVPC2List(vpc2s []govultr.VPC2Info) { + defer flush() + display(columns{"ID", "MAC ADDRESS", "IP ADDRESS"}) - for _, r := range vpc2s { - display(columns{r.ID, r.MacAddress, r.IPAddress}) + + if len(vpc2s) == 0 { + display(columns{"---", "---", "---"}) + return + } + + for i := range vpc2s { + display(columns{ + vpc2s[i].ID, + vpc2s[i].MacAddress, + vpc2s[i].IPAddress, + }) } - flush() } diff --git a/cmd/printer/billing.go b/cmd/printer/billing.go index cf25db21..74e37388 100644 --- a/cmd/printer/billing.go +++ b/cmd/printer/billing.go @@ -5,41 +5,84 @@ import ( ) func BillingHistory(bh []govultr.History, meta *govultr.Meta) { - col := columns{"ID", "DATE", "TYPE", "DESCRIPTION", "AMOUNT", "BALANCE"} - display(col) - for _, b := range bh { - display(columns{b.ID, b.Date, b.Type, b.Description, b.Amount, b.Balance}) + defer flush() + + display(columns{"ID", "DATE", "TYPE", "DESCRIPTION", "AMOUNT", "BALANCE"}) + + if len(bh) == 0 { + display(columns{"---", "---", "---", "---", "---", "---"}) + Meta(meta) + return + } + + for i := range bh { + display(columns{ + bh[i].ID, + bh[i].Date, + bh[i].Type, + bh[i].Description, + bh[i].Amount, + bh[i].Balance, + }) } Meta(meta) - flush() } func Invoices(inv []govultr.Invoice, meta *govultr.Meta) { - col := columns{"ID", "DATE", "DESCRIPTION", "AMOUNT", "BALANCE"} - display(col) - for _, i := range inv { - display(columns{i.ID, i.Date, i.Description, i.Amount, i.Balance}) + defer flush() + + display(columns{"ID", "DATE", "DESCRIPTION", "AMOUNT", "BALANCE"}) + + if len(inv) == 0 { + display(columns{"---", "---", "---", "---", "---"}) + Meta(meta) + return + } + + for i := range inv { + display(columns{ + inv[i].ID, + inv[i].Date, + inv[i].Description, + inv[i].Amount, + inv[i].Balance, + }) } Meta(meta) - flush() } func Invoice(i *govultr.Invoice) { + defer flush() + display(columns{"ID", "DATE", "DESCRIPTION", "AMOUNT", "BALANCE"}) display(columns{i.ID, i.Date, i.Description, i.Amount, i.Balance}) - - flush() } func InvoiceItems(inv []govultr.InvoiceItem, meta *govultr.Meta) { - col := columns{"DESCRIPTION", "PRODUCT", "START DATE", "END DATE", "UNITS", "UNIT TYPE", "UNIT PRICE", "TOTAL"} - display(col) - for _, i := range inv { - display(columns{i.Description, i.Product, i.StartDate, i.EndDate, i.Units, i.UnitType, i.UnitPrice, i.Total}) + defer flush() + + display(columns{"DESCRIPTION", "PRODUCT", "START DATE", "END DATE", "UNITS", "UNIT TYPE", "UNIT PRICE", "TOTAL"}) + + if len(inv) == 0 { + display(columns{"---", "---", "---", "---", "---", "---", "---", "---"}) + Meta(meta) + return + } + + for i := range inv { + display(columns{ + inv[i].Description, + inv[i].Product, + inv[i].StartDate, + inv[i].EndDate, + inv[i].Units, + inv[i].UnitType, + inv[i].UnitPrice, + inv[i].Total, + }) } Meta(meta) - flush() } diff --git a/cmd/printer/blockStorage.go b/cmd/printer/blockStorage.go index ef468f9e..066128c9 100644 --- a/cmd/printer/blockStorage.go +++ b/cmd/printer/blockStorage.go @@ -7,21 +7,39 @@ import ( ) func BlockStorage(bs []govultr.BlockStorage, meta *govultr.Meta) { - col := columns{"ID", "REGION ID", "INSTANCE ID", "SIZE GB", "STATUS", "LABEL", "BLOCK TYPE", "DATE CREATED", "MONTHLY COST", "MOUNT ID"} - display(col) - for _, b := range bs { - cost := fmt.Sprintf("$%v", b.Cost) - display(columns{b.ID, b.Region, b.AttachedToInstance, b.SizeGB, b.Status, b.Label, b.BlockType, b.DateCreated, cost, b.MountID}) + defer flush() + + display(columns{"ID", "REGION ID", "INSTANCE ID", "SIZE GB", "STATUS", "LABEL", "BLOCK TYPE", "DATE CREATED", "MONTHLY COST", "MOUNT ID"}) + + if len(bs) == 0 { + display(columns{"---", "---", "---", "---", "---", "---", "---", "---", "---", "---"}) + Meta(meta) + return + } + + for i := range bs { + cost := fmt.Sprintf("$%v", bs[i].Cost) + display(columns{ + bs[i].ID, + bs[i].Region, + bs[i].AttachedToInstance, + bs[i].SizeGB, + bs[i].Status, + bs[i].Label, + bs[i].BlockType, + bs[i].DateCreated, + cost, + bs[i].MountID, + }) } Meta(meta) - flush() } func SingleBlockStorage(b *govultr.BlockStorage) { - col := columns{"ID", "REGION ID", "INSTANCE ID", "SIZE GB", "STATUS", "LABEL", "BLOCK TYPE", "DATE CREATED", "MONTHLY COST", "MOUNT ID"} - display(col) + defer flush() + + display(columns{"ID", "REGION ID", "INSTANCE ID", "SIZE GB", "STATUS", "LABEL", "BLOCK TYPE", "DATE CREATED", "MONTHLY COST", "MOUNT ID"}) cost := fmt.Sprintf("$%v", b.Cost) display(columns{b.ID, b.Region, b.AttachedToInstance, b.SizeGB, b.Status, b.Label, b.BlockType, b.DateCreated, cost, b.MountID}) - flush() } diff --git a/cmd/printer/database.go b/cmd/printer/database.go index e4181ca0..3546254e 100644 --- a/cmd/printer/database.go +++ b/cmd/printer/database.go @@ -8,6 +8,13 @@ import ( // DatabasePlanList will generate a printer display of available Managed Database plans func DatabasePlanList(databasePlans []govultr.DatabasePlan, meta *govultr.Meta) { + defer flush() + + if len(databasePlans) == 0 { + displayString("No database plans available") + return + } + for p := range databasePlans { display(columns{"ID", databasePlans[p].ID}) display(columns{"NUMBER OF NODES", databasePlans[p].NumberOfNodes}) @@ -37,11 +44,17 @@ func DatabasePlanList(databasePlans []govultr.DatabasePlan, meta *govultr.Meta) } MetaDBaaS(meta) - flush() } // DatabaseList will generate a printer display of all Managed Databases on the account -func DatabaseList(databases []govultr.Database, meta *govultr.Meta) { +func DatabaseList(databases []govultr.Database, meta *govultr.Meta) { //nolint: funlen,gocyclo + defer flush() + + if len(databases) == 0 { + displayString("No active databases") + return + } + for d := range databases { display(columns{"ID", databases[d].ID}) display(columns{"DATE CREATED", databases[d].DateCreated}) @@ -159,22 +172,42 @@ func DatabaseList(databases []govultr.Database, meta *govultr.Meta) { } MetaDBaaS(meta) - flush() } // DatabaseListSummary will generate a summarized printer display of all Managed Databases on the account func DatabaseListSummary(databases []govultr.Database, meta *govultr.Meta) { + defer flush() + display(columns{"ID", "REGION", "LABEL", "STATUS", "ENGINE", "VERSION", "HOST", "PORT", "USER", "PASSWORD"}) - for _, d := range databases { - display(columns{d.ID, d.Region, d.Label, d.Status, d.DatabaseEngine, d.DatabaseEngineVersion, d.Host, d.Port, d.User, d.Password}) + + if len(databases) == 0 { + display(columns{"---", "---", "---", "---", "---", "---", "---", "---", "---", "---"}) + MetaDBaaS(meta) + return + } + + for i := range databases { + display(columns{ + databases[i].ID, + databases[i].Region, + databases[i].Label, + databases[i].Status, + databases[i].DatabaseEngine, + databases[i].DatabaseEngineVersion, + databases[i].Host, + databases[i].Port, + databases[i].User, + databases[i].Password, + }) } MetaDBaaS(meta) - flush() } // Database will generate a printer display of a given Managed Database -func Database(database *govultr.Database) { +func Database(database *govultr.Database) { //nolint: funlen,gocyclo + defer flush() + display(columns{"ID", database.ID}) display(columns{"DATE CREATED", database.DateCreated}) display(columns{"PLAN", database.Plan}) @@ -286,12 +319,18 @@ func Database(database *govultr.Database) { display(columns{"CLUSTER TIME ZONE", database.ReadReplicas[r].ClusterTimeZone}) } } - - flush() } // DatabaseUserList will generate a printer display of users within a Managed Database func DatabaseUserList(databaseUsers []govultr.DatabaseUser, meta *govultr.Meta) { + defer flush() + + if len(databaseUsers) == 0 { + displayString("No database users") + MetaDBaaS(meta) + return + } + for u := range databaseUsers { display(columns{"USERNAME", databaseUsers[u].Username}) display(columns{"PASSWORD", databaseUsers[u].Password}) @@ -302,51 +341,67 @@ func DatabaseUserList(databaseUsers []govultr.DatabaseUser, meta *govultr.Meta) } MetaDBaaS(meta) - flush() } // DatabaseUser will generate a printer display of a given user within a Managed Database func DatabaseUser(databaseUser govultr.DatabaseUser) { + defer flush() + display(columns{"USERNAME", databaseUser.Username}) display(columns{"PASSWORD", databaseUser.Password}) if databaseUser.Encryption != "" { display(columns{"ENCRYPTION", databaseUser.Encryption}) } - - flush() } // DatabaseDBList will generate a printer display of logical databases within a Managed Database cluster func DatabaseDBList(databaseDBs []govultr.DatabaseDB, meta *govultr.Meta) { + defer flush() + + if len(databaseDBs) == 0 { + displayString("No database DBs") + MetaDBaaS(meta) + return + } + for u := range databaseDBs { display(columns{"NAME", databaseDBs[u].Name}) display(columns{"---------------------------"}) } MetaDBaaS(meta) - flush() } // DatabaseDB will generate a printer display of a given logical database within a Managed Database cluster func DatabaseDB(databaseDB govultr.DatabaseDB) { + defer flush() + display(columns{"NAME", databaseDB.Name}) - flush() } // DatabaseUpdates will generate a printer display of available updates for a Managed Database cluster func DatabaseUpdates(databaseUpdates []string) { + defer flush() + display(columns{"AVAILABLE UPDATES", databaseUpdates}) - flush() } // DatabaseMessage will generate a printer display of a generic information message for a Managed Database cluster func DatabaseMessage(message string) { + defer flush() + display(columns{"MESSAGE", message}) - flush() } // DatabaseAlertsList will generate a printer display of service alerts for a Managed Database func DatabaseAlertsList(databaseAlerts []govultr.DatabaseAlert) { + defer flush() + + if len(databaseAlerts) == 0 { + displayString("No active database alerts") + return + } + for a := range databaseAlerts { display(columns{"TIMESTAMP", databaseAlerts[a].Timestamp}) display(columns{"MESSAGE TYPE", databaseAlerts[a].MessageType}) @@ -370,12 +425,12 @@ func DatabaseAlertsList(databaseAlerts []govultr.DatabaseAlert) { display(columns{"---------------------------"}) } - - flush() } // DatabaseMigrationStatus will generate a printer display of the current migration status of a Managed Database cluster func DatabaseMigrationStatus(databaseMigration *govultr.DatabaseMigration) { + defer flush() + display(columns{"STATUS", databaseMigration.Status}) if databaseMigration.Method != "" { @@ -403,12 +458,12 @@ func DatabaseMigrationStatus(databaseMigration *govultr.DatabaseMigration) { } display(columns{"SSL", *databaseMigration.Credentials.SSL}) - - flush() } // DatabaseBackupInfo will generate a printer display of the latest and oldest backups for a Managed Database cluster func DatabaseBackupInfo(databaseBackups *govultr.DatabaseBackups) { + defer flush() + display(columns{"LATEST BACKUP"}) display(columns{"DATE", databaseBackups.LatestBackup.Date}) display(columns{"TIME", databaseBackups.LatestBackup.Time}) @@ -418,12 +473,12 @@ func DatabaseBackupInfo(databaseBackups *govultr.DatabaseBackups) { display(columns{"OLDEST BACKUP"}) display(columns{"DATE", databaseBackups.OldestBackup.Date}) display(columns{"TIME", databaseBackups.OldestBackup.Time}) - - flush() } // DatabaseConnectionPoolList will generate a printer display of connection pools within a PostgreSQL Managed Database -func DatabaseConnectionPoolList(databaseConnections *govultr.DatabaseConnections, databaseConnectionPools []govultr.DatabaseConnectionPool, meta *govultr.Meta) { +func DatabaseConnectionPoolList(databaseConnections *govultr.DatabaseConnections, databaseConnectionPools []govultr.DatabaseConnectionPool, meta *govultr.Meta) { //nolint: lll + defer flush() + display(columns{"CONNECTIONS"}) display(columns{"USED", databaseConnections.Used}) display(columns{"AVAILABLE", databaseConnections.Available}) @@ -442,22 +497,23 @@ func DatabaseConnectionPoolList(databaseConnections *govultr.DatabaseConnections } MetaDBaaS(meta) - flush() } // DatabaseConnectionPool will generate a printer display of a given connection pool within a PostgreSQL Managed Database func DatabaseConnectionPool(databaseConnectionPool govultr.DatabaseConnectionPool) { + defer flush() + display(columns{"NAME", databaseConnectionPool.Name}) display(columns{"DATABASE", databaseConnectionPool.Database}) display(columns{"USERNAME", databaseConnectionPool.Username}) display(columns{"MODE", databaseConnectionPool.Mode}) display(columns{"SIZE", databaseConnectionPool.Size}) - - flush() } // DatabaseAdvancedOptions will generate a printer display of advanced configuration options for a PostgreSQL Managed Database -func DatabaseAdvancedOptions(databaseConfiguredOptions *govultr.DatabaseAdvancedOptions, databaseAvailableOptions []govultr.AvailableOption) { +func DatabaseAdvancedOptions(databaseConfiguredOptions *govultr.DatabaseAdvancedOptions, databaseAvailableOptions []govultr.AvailableOption) { //nolint: lll + defer flush() + if *databaseConfiguredOptions == (govultr.DatabaseAdvancedOptions{}) { display(columns{"CONFIGURED OPTIONS", "None"}) } else { @@ -500,12 +556,11 @@ func DatabaseAdvancedOptions(databaseConfiguredOptions *govultr.DatabaseAdvanced display(columns{"---------------------------"}) } - - flush() } // DatabaseAvailableVersions will generate a printer display of a list of available version upgrades for a Managed Database func DatabaseAvailableVersions(databaseAvailableVersions []string) { + defer flush() + display(columns{"AVAILABLE VERSIONS", databaseAvailableVersions}) - flush() } diff --git a/cmd/printer/dnsDomain.go b/cmd/printer/dnsDomain.go index 09b3fa42..5cbd32cf 100644 --- a/cmd/printer/dnsDomain.go +++ b/cmd/printer/dnsDomain.go @@ -3,36 +3,54 @@ package printer import "github.com/vultr/govultr/v3" func SecInfo(info []string) { - col := columns{"DNSSEC INFO"} - display(col) - for _, i := range info { - display(columns{i}) + defer flush() + + display(columns{"DNSSEC INFO"}) + + if len(info) == 0 { + display(columns{"---"}) + return + } + + for i := range info { + display(columns{ + info[i], + }) } - flush() } func DomainList(domain []govultr.Domain, meta *govultr.Meta) { - col := columns{"DOMAIN", "DATE CREATED", "DNS SEC"} - display(col) - for _, d := range domain { - display(columns{d.Domain, d.DateCreated, d.DNSSec}) + defer flush() + + display(columns{"DOMAIN", "DATE CREATED", "DNS SEC"}) + + if len(domain) == 0 { + display(columns{"---", "---", "---"}) + Meta(meta) + return + } + + for i := range domain { + display(columns{ + domain[i].Domain, + domain[i].DateCreated, + domain[i].DNSSec, + }) } Meta(meta) - flush() } func Domain(domain *govultr.Domain) { - col := columns{"DOMAIN", "DATE CREATED", "DNS SEC"} - display(col) - display(columns{domain.Domain, domain.DateCreated, domain.DNSSec}) + defer flush() - flush() + display(columns{"DOMAIN", "DATE CREATED", "DNS SEC"}) + display(columns{domain.Domain, domain.DateCreated, domain.DNSSec}) } func SoaInfo(soa *govultr.Soa) { - col := columns{"NS PRIMARY", "EMAIL"} - display(col) + defer flush() + + display(columns{"NS PRIMARY", "EMAIL"}) display(columns{soa.NSPrimary, soa.Email}) - flush() } diff --git a/cmd/printer/dnsRecord.go b/cmd/printer/dnsRecord.go index 13ec62e7..44c6964c 100644 --- a/cmd/printer/dnsRecord.go +++ b/cmd/printer/dnsRecord.go @@ -2,21 +2,34 @@ package printer import "github.com/vultr/govultr/v3" -func DnsRecordsList(records []govultr.DomainRecord, meta *govultr.Meta) { - col := columns{"ID", "TYPE", "NAME", "DATA", "PRIORITY", "TTL"} - display(col) - for _, r := range records { - display(columns{r.ID, r.Type, r.Name, r.Data, r.Priority, r.TTL}) +func DNSRecordsList(records []govultr.DomainRecord, meta *govultr.Meta) { + defer flush() + + display(columns{"ID", "TYPE", "NAME", "DATA", "PRIORITY", "TTL"}) + + if len(records) == 0 { + display(columns{"---", "---", "---", "---", "---", "---"}) + Meta(meta) + return + } + + for i := range records { + display(columns{ + records[i].ID, + records[i].Type, + records[i].Name, + records[i].Data, + records[i].Priority, + records[i].TTL, + }) } Meta(meta) - flush() } -func DnsRecord(record *govultr.DomainRecord) { - col := columns{"ID", "TYPE", "NAME", "DATA", "PRIORITY", "TTL"} - display(col) +func DNSRecord(record *govultr.DomainRecord) { + defer flush() + display(columns{"ID", "TYPE", "NAME", "DATA", "PRIORITY", "TTL"}) display(columns{record.ID, record.Type, record.Name, record.Data, record.Priority, record.TTL}) - flush() } diff --git a/cmd/printer/firewallGroup.go b/cmd/printer/firewallGroup.go index d8cd8229..7a5ee7a2 100644 --- a/cmd/printer/firewallGroup.go +++ b/cmd/printer/firewallGroup.go @@ -5,20 +5,34 @@ import ( ) func FirewallGroups(fwg []govultr.FirewallGroup, meta *govultr.Meta) { - col := columns{"ID", "DATE CREATED", "DATE MODIFIED", "INSTANCE COUNT", "RULE COUNT", "MAX RULE COUNT", "DESCRIPTION"} - display(col) - for _, f := range fwg { - display(columns{f.ID, f.DateCreated, f.DateModified, f.InstanceCount, f.RuleCount, f.MaxRuleCount, f.Description}) + defer flush() + + display(columns{"ID", "DATE CREATED", "DATE MODIFIED", "INSTANCE COUNT", "RULE COUNT", "MAX RULE COUNT", "DESCRIPTION"}) + + if len(fwg) == 0 { + display(columns{"---", "---", "---", "---", "---", "---", "---"}) + Meta(meta) + return + } + + for i := range fwg { + display(columns{ + fwg[i].ID, + fwg[i].DateCreated, + fwg[i].DateModified, + fwg[i].InstanceCount, + fwg[i].RuleCount, + fwg[i].MaxRuleCount, + fwg[i].Description, + }) } Meta(meta) - flush() } func FirewallGroup(fwg *govultr.FirewallGroup) { - col := columns{"ID", "DATE CREATED", "DATE MODIFIED", "INSTANCE COUNT", "RULE COUNT", "MAX RULE COUNT", "DESCRIPTION"} - display(col) + defer flush() + display(columns{"ID", "DATE CREATED", "DATE MODIFIED", "INSTANCE COUNT", "RULE COUNT", "MAX RULE COUNT", "DESCRIPTION"}) display(columns{fwg.ID, fwg.DateCreated, fwg.DateModified, fwg.InstanceCount, fwg.RuleCount, fwg.MaxRuleCount, fwg.Description}) - flush() } diff --git a/cmd/printer/firewallRule.go b/cmd/printer/firewallRule.go index 2b1f497b..86340278 100644 --- a/cmd/printer/firewallRule.go +++ b/cmd/printer/firewallRule.go @@ -7,21 +7,46 @@ import ( ) func FirewallRules(fwr []govultr.FirewallRule, meta *govultr.Meta) { - col := columns{"RULE NUMBER", "ACTION", "TYPE", "PROTOCOL", "PORT", "NETWORK", "SOURCE", "NOTES"} - display(col) - for _, f := range fwr { - display(columns{f.ID, f.Action, f.IPType, f.Protocol, f.Port, getFirewallNetwork(f.Subnet, f.SubnetSize), getFirewallSource(f.Source), f.Notes}) + defer flush() + + display(columns{"RULE NUMBER", "ACTION", "TYPE", "PROTOCOL", "PORT", "NETWORK", "SOURCE", "NOTES"}) + + if len(fwr) == 0 { + display(columns{"---", "---", "---", "---", "---", "---", "---", "---"}) + Meta(meta) + return + } + + for i := range fwr { + display(columns{ + fwr[i].ID, + fwr[i].Action, + fwr[i].IPType, + fwr[i].Protocol, + fwr[i].Port, + getFirewallNetwork(fwr[i].Subnet, fwr[i].SubnetSize), + getFirewallSource(fwr[i].Source), + fwr[i].Notes, + }) } Meta(meta) - flush() } func FirewallRule(fwr *govultr.FirewallRule) { - col := columns{"RULE NUMBER", "ACTION", "TYPE", "PROTOCOL", "PORT", "NETWORK", "SOURCE", "NOTES"} - display(col) - display(columns{fwr.ID, fwr.Action, fwr.IPType, fwr.Protocol, fwr.Port, getFirewallNetwork(fwr.Subnet, fwr.SubnetSize), getFirewallSource(fwr.Source), fwr.Notes}) - flush() + defer flush() + + display(columns{"RULE NUMBER", "ACTION", "TYPE", "PROTOCOL", "PORT", "NETWORK", "SOURCE", "NOTES"}) + display(columns{ + fwr.ID, + fwr.Action, + fwr.IPType, + fwr.Protocol, + fwr.Port, + getFirewallNetwork(fwr.Subnet, fwr.SubnetSize), + getFirewallSource(fwr.Source), + fwr.Notes, + }) } func getFirewallSource(source string) string { diff --git a/cmd/printer/instance.go b/cmd/printer/instance.go index ccc23080..b4c7024f 100644 --- a/cmd/printer/instance.go +++ b/cmd/printer/instance.go @@ -3,8 +3,7 @@ package printer import "github.com/vultr/govultr/v3" func InstanceBandwidth(bandwidth *govultr.Bandwidth) { - col := columns{"DATE", "INCOMING BYTES", "OUTGOING BYTES"} - display(col) + display(columns{"DATE", "INCOMING BYTES", "OUTGOING BYTES"}) for k, b := range bandwidth.Bandwidth { display(columns{k, b.IncomingBytes, b.OutgoingBytes}) } @@ -12,41 +11,87 @@ func InstanceBandwidth(bandwidth *govultr.Bandwidth) { } func InstanceIPV4(ip []govultr.IPv4, meta *govultr.Meta) { - col := columns{"IP", "NETMASK", "GATEWAY", "TYPE", "REVERSE"} - display(col) - for _, i := range ip { - display(columns{i.IP, i.Netmask, i.Gateway, i.Type, i.Reverse}) + defer flush() + + display(columns{"IP", "NETMASK", "GATEWAY", "TYPE", "REVERSE"}) + + if len(ip) == 0 { + display(columns{"---", "---", "---", "---", "---"}) + Meta(meta) + return + } + + for i := range ip { + display(columns{ + ip[i].IP, + ip[i].Netmask, + ip[i].Gateway, + ip[i].Type, + ip[i].Reverse, + }) } Meta(meta) - flush() } func InstanceIPV6(ip []govultr.IPv6, meta *govultr.Meta) { - col := columns{"IP", "NETWORK", "NETWORK SIZE", "TYPE"} - display(col) - for _, i := range ip { - display(columns{i.IP, i.Network, i.NetworkSize, i.Type}) + defer flush() + + display(columns{"IP", "NETWORK", "NETWORK SIZE", "TYPE"}) + + if len(ip) == 0 { + display(columns{"---", "---", "---", "---"}) + Meta(meta) + return + } + + for i := range ip { + display(columns{ + ip[i].IP, + ip[i].Network, + ip[i].NetworkSize, + ip[i].Type, + }) } Meta(meta) - flush() } func InstanceList(instance []govultr.Instance, meta *govultr.Meta) { - col := columns{"ID", "IP", "LABEL", "OS", "STATUS", "Region", "CPU", "RAM", "DISK", "BANDWIDTH", "TAGS"} - display(col) - for _, s := range instance { - display(columns{s.ID, s.MainIP, s.Label, s.Os, s.Status, s.Region, s.VCPUCount, s.RAM, s.Disk, s.AllowedBandwidth, s.Tags}) + defer flush() + + display(columns{"ID", "IP", "LABEL", "OS", "STATUS", "REGION", "CPU", "RAM", "DISK", "BANDWIDTH", "TAGS"}) + + if len(instance) == 0 { + display(columns{"---", "---", "---", "---", "---", "---", "---", "---", "---", "---", "---"}) + Meta(meta) + return + } + + for i := range instance { + display(columns{ + instance[i].ID, + instance[i].MainIP, + instance[i].Label, + instance[i].Os, + instance[i].Status, + instance[i].Region, + instance[i].VCPUCount, + instance[i].RAM, + instance[i].Disk, + instance[i].AllowedBandwidth, + instance[i].Tags, + }) } Meta(meta) - flush() } func Instance(instance *govultr.Instance) { - col := columns{"INSTANCE INFO"} - display(col) + defer flush() + + display(columns{"INSTANCE INFO"}) + display(columns{"ID", instance.ID}) display(columns{"Os", instance.Os}) display(columns{"RAM", instance.RAM}) @@ -74,54 +119,82 @@ func Instance(instance *govultr.Instance) { display(columns{"V6 NETWORK SIZE", instance.V6NetworkSize}) display(columns{"FEATURES", instance.Features}) display(columns{"TAGS", instance.Tags}) - - flush() } func OsList(os []govultr.OS) { - col := columns{"ID", "NAME", "ARCH", "FAMILY"} - display(col) - for _, o := range os { - display(columns{o.ID, o.Name, o.Arch, o.Family}) + defer flush() + + display(columns{"ID", "NAME", "ARCH", "FAMILY"}) + + if len(os) == 0 { + display(columns{"---", "---", "---", "---"}) + return + } + + for i := range os { + display(columns{ + os[i].ID, + os[i].Name, + os[i].Arch, + os[i].Family, + }) } - flush() } func AppList(app []govultr.Application) { - col := columns{"ID", "NAME", "SHORT NAME", "DEPLOY NAME", "TYPE", "VENDOR", "IMAGE ID"} - display(col) - for _, a := range app { - display(columns{a.ID, a.Name, a.ShortName, a.DeployName, a.Type, a.Vendor, a.ImageID}) + defer flush() + + display(columns{"ID", "NAME", "SHORT NAME", "DEPLOY NAME", "TYPE", "VENDOR", "IMAGE ID"}) + + if len(app) == 0 { + display(columns{"---", "---", "---", "---", "---", "---", "---"}) + return + } + + for i := range app { + display(columns{ + app[i].ID, + app[i].Name, + app[i].ShortName, + app[i].DeployName, + app[i].Type, + app[i].Vendor, + app[i].ImageID, + }) } - flush() } func BackupsGet(b *govultr.BackupSchedule) { - col := columns{"ENABLED", "CRON TYPE", "NEXT RUN", "HOUR", "DOW", "DOM"} - display(col) + defer flush() + + display(columns{"ENABLED", "CRON TYPE", "NEXT RUN", "HOUR", "DOW", "DOM"}) display(columns{*b.Enabled, b.Type, b.NextScheduleTimeUTC, b.Hour, b.Dow, b.Dom}) - flush() } func IsoStatus(iso *govultr.Iso) { - col := columns{"ISO ID", "STATE"} - display(col) + defer flush() + + display(columns{"ISO ID", "STATE"}) display(columns{iso.IsoID, iso.State}) - flush() } func PlansList(plans []string) { - col := columns{"PLAN NAME"} - display(col) - for _, p := range plans { - display(columns{p}) + defer flush() + + display(columns{"PLAN NAME"}) + + if len(plans) == 0 { + display(columns{"---"}) + return + } + + for i := range plans { + display(columns{plans[i]}) } - flush() } func ReverseIpv6(rip []govultr.ReverseIP) { - col := columns{"IP", "REVERSE"} - display(col) + display(columns{"IP", "REVERSE"}) for _, r := range rip { display(columns{r.IP, r.Reverse}) } @@ -130,11 +203,23 @@ func ReverseIpv6(rip []govultr.ReverseIP) { // InstanceVPC2List Generate a printer display of all VPC 2.0 networks attached to a given instance func InstanceVPC2List(vpc2s []govultr.VPC2Info, meta *govultr.Meta) { + defer flush() + display(columns{"ID", "MAC ADDRESS", "IP ADDRESS"}) - for _, r := range vpc2s { - display(columns{r.ID, r.MacAddress, r.IPAddress}) + + if len(vpc2s) == 0 { + display(columns{"---", "---", "---"}) + Meta(meta) + return + } + + for i := range vpc2s { + display(columns{ + vpc2s[i].ID, + vpc2s[i].MacAddress, + vpc2s[i].IPAddress, + }) } Meta(meta) - flush() } diff --git a/cmd/printer/iso.go b/cmd/printer/iso.go index d4faf5e0..f10312dd 100644 --- a/cmd/printer/iso.go +++ b/cmd/printer/iso.go @@ -3,30 +3,56 @@ package printer import "github.com/vultr/govultr/v3" func IsoPrivates(iso []govultr.ISO, meta *govultr.Meta) { - col := columns{"ID", "FILE NAME", "SIZE", "STATUS", "MD5SUM", "SHA512SUM", "DATE CREATED"} - display(col) - for _, i := range iso { - display(columns{i.ID, i.FileName, i.Size, i.Status, i.MD5Sum, i.SHA512Sum, i.DateCreated}) + defer flush() + + display(columns{"ID", "FILE NAME", "SIZE", "STATUS", "MD5SUM", "SHA512SUM", "DATE CREATED"}) + + if len(iso) == 0 { + display(columns{"---", "---", "---", "---", "---", "---", "---"}) + Meta(meta) + return + } + + for i := range iso { + display(columns{ + iso[i].ID, + iso[i].FileName, + iso[i].Size, + iso[i].Status, + iso[i].MD5Sum, + iso[i].SHA512Sum, + iso[i].DateCreated, + }) } Meta(meta) - flush() } func IsoPrivate(iso *govultr.ISO) { - col := columns{"ID", "FILE NAME", "SIZE", "STATUS", "MD5SUM", "SHA512SUM", "DATE CREATED"} - display(col) + defer flush() + + display(columns{"ID", "FILE NAME", "SIZE", "STATUS", "MD5SUM", "SHA512SUM", "DATE CREATED"}) display(columns{iso.ID, iso.FileName, iso.Size, iso.Status, iso.MD5Sum, iso.SHA512Sum, iso.DateCreated}) - flush() } func IsoPublic(iso []govultr.PublicISO, meta *govultr.Meta) { - col := columns{"ID", "NAME", "DESCRIPTION"} - display(col) - for _, i := range iso { - display(columns{i.ID, i.Name, i.Description}) + defer flush() + + display(columns{"ID", "NAME", "DESCRIPTION"}) + + if len(iso) == 0 { + display(columns{"---", "---", "---"}) + Meta(meta) + return + } + + for i := range iso { + display(columns{ + iso[i].ID, + iso[i].Name, + iso[i].Description, + }) } Meta(meta) - flush() } diff --git a/cmd/printer/kubernetes.go b/cmd/printer/kubernetes.go index 6f50f757..83202143 100644 --- a/cmd/printer/kubernetes.go +++ b/cmd/printer/kubernetes.go @@ -5,39 +5,51 @@ import ( ) func Clusters(cluster []govultr.Cluster, meta *govultr.Meta) { - for _, k := range cluster { - display(columns{"ID", k.ID}) - display(columns{"LABEL", k.Label}) - display(columns{"DATE CREATED", k.DateCreated}) - display(columns{"CLUSTER SUBNET", k.ClusterSubnet}) - display(columns{"SERVICE SUBNET", k.ServiceSubnet}) - display(columns{"IP", k.IP}) - display(columns{"ENDPOINT", k.Endpoint}) - display(columns{"VERSION", k.Version}) - display(columns{"REGION", k.Region}) - display(columns{"STATUS", k.Status}) + defer flush() + + if len(cluster) == 0 { + displayString("No active kubernetes clusters") + return + } + + for i := range cluster { + display(columns{"ID", cluster[i].ID}) + display(columns{"LABEL", cluster[i].Label}) + display(columns{"DATE CREATED", cluster[i].DateCreated}) + display(columns{"CLUSTER SUBNET", cluster[i].ClusterSubnet}) + display(columns{"SERVICE SUBNET", cluster[i].ServiceSubnet}) + display(columns{"IP", cluster[i].IP}) + display(columns{"ENDPOINT", cluster[i].Endpoint}) + display(columns{"VERSION", cluster[i].Version}) + display(columns{"REGION", cluster[i].Region}) + display(columns{"STATUS", cluster[i].Status}) display(columns{" "}) display(columns{"NODE POOLS"}) - for _, np := range k.NodePools { - display(columns{"ID", np.ID}) - display(columns{"DATE CREATED", np.DateCreated}) - display(columns{"DATE UPDATED", np.DateUpdated}) - display(columns{"LABEL", np.Label}) - display(columns{"TAG", np.Tag}) - display(columns{"PLAN", np.Plan}) - display(columns{"STATUS", np.Status}) - display(columns{"NODE QUANTITY", np.NodeQuantity}) - display(columns{"AUTO SCALER", np.AutoScaler}) - display(columns{"MIN NODES", np.MinNodes}) - display(columns{"MAX NODES", np.MaxNodes}) + for n := range cluster[i].NodePools { + display(columns{"ID", cluster[i].NodePools[n].ID}) + display(columns{"DATE CREATED", cluster[i].NodePools[n].DateCreated}) + display(columns{"DATE UPDATED", cluster[i].NodePools[n].DateUpdated}) + display(columns{"LABEL", cluster[i].NodePools[n].Label}) + display(columns{"TAG", cluster[i].NodePools[n].Tag}) + display(columns{"PLAN", cluster[i].NodePools[n].Plan}) + display(columns{"STATUS", cluster[i].NodePools[n].Status}) + display(columns{"NODE QUANTITY", cluster[i].NodePools[n].NodeQuantity}) + display(columns{"AUTO SCALER", cluster[i].NodePools[n].AutoScaler}) + display(columns{"MIN NODES", cluster[i].NodePools[n].MinNodes}) + display(columns{"MAX NODES", cluster[i].NodePools[n].MaxNodes}) display(columns{" "}) display(columns{"NODES"}) - for _, n := range np.Nodes { + for j := range cluster[i].NodePools[n].Nodes { display(columns{"ID", "DATE CREATED", "LABEL", "STATUS"}) - display(columns{n.ID, n.DateCreated, n.Label, n.Status}) + display(columns{ + cluster[i].NodePools[n].Nodes[j].ID, + cluster[i].NodePools[n].Nodes[j].DateCreated, + cluster[i].NodePools[n].Nodes[j].Label, + cluster[i].NodePools[n].Nodes[j].Status, + }) } display(columns{" "}) } @@ -46,10 +58,11 @@ func Clusters(cluster []govultr.Cluster, meta *govultr.Meta) { } Meta(meta) - flush() } func Cluster(k *govultr.Cluster) { + defer flush() + display(columns{"ID", k.ID}) display(columns{"LABEL", k.Label}) display(columns{"DATE CREATED", k.DateCreated}) @@ -63,61 +76,78 @@ func Cluster(k *govultr.Cluster) { display(columns{" "}) display(columns{"NODE POOLS"}) - for _, np := range k.NodePools { - display(columns{"ID", np.ID}) - display(columns{"DATE CREATED", np.DateCreated}) - display(columns{"DATE UPDATED", np.DateUpdated}) - display(columns{"LABEL", np.Label}) - display(columns{"TAG", np.Tag}) - display(columns{"PLAN", np.Plan}) - display(columns{"STATUS", np.Status}) - display(columns{"NODE QUANTITY", np.NodeQuantity}) - display(columns{"AUTO SCALER", np.AutoScaler}) - display(columns{"MIN NODES", np.MinNodes}) - display(columns{"MAX NODES", np.MaxNodes}) + for i := range k.NodePools { + display(columns{"ID", k.NodePools[i].ID}) + display(columns{"DATE CREATED", k.NodePools[i].DateCreated}) + display(columns{"DATE UPDATED", k.NodePools[i].DateUpdated}) + display(columns{"LABEL", k.NodePools[i].Label}) + display(columns{"TAG", k.NodePools[i].Tag}) + display(columns{"PLAN", k.NodePools[i].Plan}) + display(columns{"STATUS", k.NodePools[i].Status}) + display(columns{"NODE QUANTITY", k.NodePools[i].NodeQuantity}) + display(columns{"AUTO SCALER", k.NodePools[i].AutoScaler}) + display(columns{"MIN NODES", k.NodePools[i].MinNodes}) + display(columns{"MAX NODES", k.NodePools[i].MaxNodes}) display(columns{" "}) display(columns{"NODES"}) - for _, n := range np.Nodes { + for n := range k.NodePools[i].Nodes { display(columns{"ID", "DATE CREATED", "LABEL", "STATUS"}) - display(columns{n.ID, n.DateCreated, n.Label, n.Status}) + display(columns{ + k.NodePools[i].Nodes[n].ID, + k.NodePools[i].Nodes[n].DateCreated, + k.NodePools[i].Nodes[n].Label, + k.NodePools[i].Nodes[n].Status, + }) } display(columns{" "}) } - - flush() } func NodePools(nodepool []govultr.NodePool, meta *govultr.Meta) { - for _, np := range nodepool { - display(columns{"ID", np.ID}) - display(columns{"DATE CREATED", np.DateCreated}) - display(columns{"DATE UPDATED", np.DateUpdated}) - display(columns{"LABEL", np.Label}) - display(columns{"TAG", np.Tag}) - display(columns{"PLAN", np.Plan}) - display(columns{"STATUS", np.Status}) - display(columns{"NODE QUANTITY", np.NodeQuantity}) - display(columns{"AUTO SCALER", np.AutoScaler}) - display(columns{"MIN NODES", np.MinNodes}) - display(columns{"MAX NODES", np.MaxNodes}) + defer flush() + + if len(nodepool) == 0 { + // this shouldn't be possible since at least one nodepool is required + displayString("No active nodepools on cluster") + return + } + + for i := range nodepool { + display(columns{"ID", nodepool[i].ID}) + display(columns{"DATE CREATED", nodepool[i].DateCreated}) + display(columns{"DATE UPDATED", nodepool[i].DateUpdated}) + display(columns{"LABEL", nodepool[i].Label}) + display(columns{"TAG", nodepool[i].Tag}) + display(columns{"PLAN", nodepool[i].Plan}) + display(columns{"STATUS", nodepool[i].Status}) + display(columns{"NODE QUANTITY", nodepool[i].NodeQuantity}) + display(columns{"AUTO SCALER", nodepool[i].AutoScaler}) + display(columns{"MIN NODES", nodepool[i].MinNodes}) + display(columns{"MAX NODES", nodepool[i].MaxNodes}) display(columns{" "}) display(columns{"NODES"}) - for _, n := range np.Nodes { - display(columns{"ID", "DATE CREATED", "LABEL", "STATUS"}) - display(columns{n.ID, n.DateCreated, n.Label, n.Status}) + display(columns{"ID", "DATE CREATED", "LABEL", "STATUS"}) + for n := range nodepool[i].Nodes { + display(columns{ + nodepool[i].Nodes[n].ID, + nodepool[i].Nodes[n].DateCreated, + nodepool[i].Nodes[n].Label, + nodepool[i].Nodes[n].Status, + }) } display(columns{"---------------------------"}) } Meta(meta) - flush() } func NodePool(np *govultr.NodePool) { + defer flush() + display(columns{"ID", np.ID}) display(columns{"DATE CREATED", np.DateCreated}) display(columns{"DATE UPDATED", np.DateUpdated}) @@ -133,46 +163,76 @@ func NodePool(np *govultr.NodePool) { display(columns{" "}) display(columns{"NODES"}) - for _, n := range np.Nodes { - display(columns{"ID", "DATE CREATED", "LABEL", "STATUS"}) - display(columns{n.ID, n.DateCreated, n.Label, n.Status}) + display(columns{"ID", "DATE CREATED", "LABEL", "STATUS"}) + for i := range np.Nodes { + display(columns{ + np.Nodes[i].ID, + np.Nodes[i].DateCreated, + np.Nodes[i].Label, + np.Nodes[i].Status, + }) } - - flush() } func ClustersSummary(clusters []govultr.Cluster, meta *govultr.Meta) { + defer flush() + display(columns{"ID", "LABEL", "STATUS", "REGION", "VERSION", "NODEPOOL#", "NODE#"}) - for _, k := range clusters { - nodePoolCount := len(k.NodePools) + if len(clusters) == 0 { + display(columns{"---", "---", "---", "---", "---", "---", "---"}) + Meta(meta) + return + } + + for i := range clusters { + nodePoolCount := len(clusters[i].NodePools) var nodeCount int = 0 - for _, np := range k.NodePools { - nodeCount += len(np.Nodes) + for n := range clusters[i].NodePools { + nodeCount += len(clusters[i].NodePools[n].Nodes) } - display(columns{k.ID, k.Label, k.Status, k.Region, k.Version, nodePoolCount, nodeCount}) + display(columns{ + clusters[i].ID, + clusters[i].Label, + clusters[i].Status, + clusters[i].Region, + clusters[i].Version, + nodePoolCount, + nodeCount, + }) } Meta(meta) - flush() } func K8Versions(versions *govultr.Versions) { + defer flush() + display(columns{"VERSIONS"}) - for _, v := range versions.Versions { - display(columns{v}) + + if len(versions.Versions) == 0 { + display(columns{"---"}) + return } - flush() + for i := range versions.Versions { + display(columns{versions.Versions[i]}) + } } func K8Upgrades(upgrades []string) { + defer flush() + display(columns{"UPGRADES"}) - for _, v := range upgrades { - display(columns{v}) + + if len(upgrades) == 0 { + display(columns{"---"}) + return } - flush() + for i := range upgrades { + display(columns{upgrades[i]}) + } } diff --git a/cmd/printer/loadBalancer.go b/cmd/printer/loadBalancer.go index ebbcab2e..92caf144 100644 --- a/cmd/printer/loadBalancer.go +++ b/cmd/printer/loadBalancer.go @@ -5,41 +5,62 @@ import ( ) func LoadBalancerList(loadbalancer []govultr.LoadBalancer, meta *govultr.Meta) { - for _, lb := range loadbalancer { - display(columns{"ID", lb.ID}) - display(columns{"DATE CREATED", lb.DateCreated}) - display(columns{"REGION", lb.Region}) - display(columns{"LABEL", lb.Label}) - display(columns{"STATUS", lb.Status}) - display(columns{"IPV4", lb.IPV4}) - display(columns{"IPV6", lb.IPV6}) - display(columns{"HAS SSL", *lb.SSLInfo}) - display(columns{"INSTANCES", lb.Instances}) + defer flush() + + if len(loadbalancer) == 0 { + displayString("No active load balancers") + return + } + + for i := range loadbalancer { + display(columns{"ID", loadbalancer[i].ID}) + display(columns{"DATE CREATED", loadbalancer[i].DateCreated}) + display(columns{"REGION", loadbalancer[i].Region}) + display(columns{"LABEL", loadbalancer[i].Label}) + display(columns{"STATUS", loadbalancer[i].Status}) + display(columns{"IPV4", loadbalancer[i].IPV4}) + display(columns{"IPV6", loadbalancer[i].IPV6}) + display(columns{"HAS SSL", *loadbalancer[i].SSLInfo}) + display(columns{"INSTANCES", loadbalancer[i].Instances}) display(columns{" "}) display(columns{"HEALTH CHECKS"}) display(columns{"PROTOCOL", "PORT", "PATH", "CHECK INTERVAL", "RESPONSE TIMEOUT", "UNHEALTHY THRESHOLD", "HEALTHY THRESHOLD"}) - display(columns{lb.HealthCheck.Protocol, lb.HealthCheck.Port, lb.HealthCheck.Path, lb.HealthCheck.CheckInterval, lb.HealthCheck.ResponseTimeout, lb.HealthCheck.UnhealthyThreshold, lb.HealthCheck.HealthyThreshold}) + display(columns{ + loadbalancer[i].HealthCheck.Protocol, + loadbalancer[i].HealthCheck.Port, + loadbalancer[i].HealthCheck.Path, + loadbalancer[i].HealthCheck.CheckInterval, + loadbalancer[i].HealthCheck.ResponseTimeout, + loadbalancer[i].HealthCheck.UnhealthyThreshold, + loadbalancer[i].HealthCheck.HealthyThreshold, + }) display(columns{" "}) display(columns{"GENERIC INFO"}) display(columns{"BALANCING ALGORITHM", "SSL REDIRECT", "COOKIE NAME", "PROXY PROTOCOL", "VPC"}) - display(columns{lb.GenericInfo.BalancingAlgorithm, *lb.GenericInfo.SSLRedirect, lb.GenericInfo.StickySessions.CookieName, *lb.GenericInfo.ProxyProtocol, lb.GenericInfo.VPC}) + display(columns{ + loadbalancer[i].GenericInfo.BalancingAlgorithm, + *loadbalancer[i].GenericInfo.SSLRedirect, + loadbalancer[i].GenericInfo.StickySessions.CookieName, + *loadbalancer[i].GenericInfo.ProxyProtocol, + loadbalancer[i].GenericInfo.VPC, + }) display(columns{" "}) display(columns{"FORWARDING RULES"}) display(columns{"RULEID", "FRONTEND PROTOCOL", "FRONTEND PORT", "BACKEND PROTOCOL", "BACKEND PORT"}) - for _, r := range lb.ForwardingRules { + for _, r := range loadbalancer[i].ForwardingRules { display(columns{r.RuleID, r.FrontendProtocol, r.FrontendPort, r.BackendProtocol, r.BackendPort}) } display(columns{" "}) display(columns{"FIREWALL RULES"}) display(columns{"RULEID", "PORT", "SOURCE", "IP_TYPE"}) - for _, r := range lb.FirewallRules { + for _, r := range loadbalancer[i].FirewallRules { display(columns{r.RuleID, r.Port, r.Source, r.IPType}) } - if len(lb.FirewallRules) < 1 { + if len(loadbalancer[i].FirewallRules) < 1 { display(columns{"-", "-", "-"}) } @@ -47,10 +68,11 @@ func LoadBalancerList(loadbalancer []govultr.LoadBalancer, meta *govultr.Meta) { } Meta(meta) - flush() } func LoadBalancer(lb *govultr.LoadBalancer) { + defer flush() + display(columns{"ID", lb.ID}) display(columns{"DATE CREATED", lb.DateCreated}) display(columns{"REGION", lb.Region}) @@ -64,80 +86,138 @@ func LoadBalancer(lb *govultr.LoadBalancer) { display(columns{" "}) display(columns{"HEALTH CHECKS"}) display(columns{"PROTOCOL", "PORT", "PATH", "CHECK INTERVAL", "RESPONSE TIMEOUT", "UNHEALTHY THRESHOLD", "HEALTHY THRESHOLD"}) - display(columns{lb.HealthCheck.Protocol, lb.HealthCheck.Port, lb.HealthCheck.Path, lb.HealthCheck.CheckInterval, lb.HealthCheck.ResponseTimeout, lb.HealthCheck.UnhealthyThreshold, lb.HealthCheck.HealthyThreshold}) + display(columns{ + lb.HealthCheck.Protocol, + lb.HealthCheck.Port, + lb.HealthCheck.Path, + lb.HealthCheck.CheckInterval, + lb.HealthCheck.ResponseTimeout, + lb.HealthCheck.UnhealthyThreshold, + lb.HealthCheck.HealthyThreshold, + }) display(columns{" "}) display(columns{"GENERIC INFO"}) display(columns{"BALANCING ALGORITHM", "SSL REDIRECT", "COOKIE NAME", "PROXY PROTOCOL", "VPC"}) - display(columns{lb.GenericInfo.BalancingAlgorithm, *lb.GenericInfo.SSLRedirect, lb.GenericInfo.StickySessions.CookieName, *lb.GenericInfo.ProxyProtocol, lb.GenericInfo.VPC}) + display(columns{ + lb.GenericInfo.BalancingAlgorithm, + *lb.GenericInfo.SSLRedirect, + lb.GenericInfo.StickySessions.CookieName, + *lb.GenericInfo.ProxyProtocol, + lb.GenericInfo.VPC, + }) display(columns{" "}) display(columns{"FORWARDING RULES"}) display(columns{"RULEID", "FRONTEND PROTOCOL", "FRONTEND PORT", "BACKEND PROTOCOL", "BACKEND PORT"}) - for _, r := range lb.ForwardingRules { - display(columns{r.RuleID, r.FrontendProtocol, r.FrontendPort, r.BackendProtocol, r.BackendPort}) + for i := range lb.ForwardingRules { + display(columns{ + lb.ForwardingRules[i].RuleID, + lb.ForwardingRules[i].FrontendProtocol, + lb.ForwardingRules[i].FrontendPort, + lb.ForwardingRules[i].BackendProtocol, + lb.ForwardingRules[i].BackendPort, + }) } display(columns{" "}) display(columns{"FIREWALL RULES"}) display(columns{"RULEID", "PORT", "SOURCE", "IP_TYPE"}) - for _, r := range lb.FirewallRules { - display(columns{r.RuleID, r.Port, r.Source, r.IPType}) + for i := range lb.FirewallRules { + display(columns{ + lb.FirewallRules[i].RuleID, + lb.FirewallRules[i].Port, + lb.FirewallRules[i].Source, + lb.FirewallRules[i].IPType, + }) } if len(lb.FirewallRules) < 1 { display(columns{"-", "-", "-"}) } - flush() } func LoadBalancerRuleList(rules []govultr.ForwardingRule, meta *govultr.Meta) { + defer flush() + display(columns{"RULEID", "FRONTEND PROTOCOL", "FRONTEND PORT", "BACKEND PROTOCOL", "BACKEND PORT"}) - for _, r := range rules { - display(columns{r.RuleID, r.FrontendProtocol, r.FrontendPort, r.BackendProtocol, r.BackendPort}) + if len(rules) == 0 { + display(columns{"---", "---", "---", "---", "---"}) + Meta(meta) + return + } + + for i := range rules { + display(columns{ + rules[i].RuleID, + rules[i].FrontendProtocol, + rules[i].FrontendPort, + rules[i].BackendProtocol, + rules[i].BackendPort, + }) } Meta(meta) - flush() } func LoadBalancerRule(rule *govultr.ForwardingRule) { + defer flush() + display(columns{"RULEID", "FRONTEND PROTOCOL", "FRONTEND PORT", "BACKEND PROTOCOL", "BACKEND PORT"}) display(columns{rule.RuleID, rule.FrontendProtocol, rule.FrontendPort, rule.BackendProtocol, rule.BackendPort}) - - flush() } func LoadBalancerFWRuleList(rules []govultr.LBFirewallRule, meta *govultr.Meta) { + defer flush() + display(columns{"RULEID", "PORT", "SOURCE", "IP_TYPE"}) - for _, r := range rules { - display(columns{r.RuleID, r.Port, r.Source, r.IPType}) + if len(rules) == 0 { + display(columns{"---", "---", "---", "---"}) + Meta(meta) + return + } + + for i := range rules { + display(columns{ + rules[i].RuleID, + rules[i].Port, + rules[i].Source, + rules[i].IPType, + }) } Meta(meta) - flush() } func LoadBalancerFWRule(rule *govultr.LBFirewallRule) { + defer flush() + display(columns{"RULEID", "PORT", "SOURCE", "IP_TYPE"}) display(columns{rule.RuleID, rule.Port, rule.Source, rule.IPType}) - - flush() } func LoadBalancerListSummary(loadbalancer []govultr.LoadBalancer, meta *govultr.Meta) { + defer flush() + display(columns{"ID", "LABEL", "STATUS", "REGION", "INSTANCE#", "FORWARD#", "FIREWALL#"}) - for _, lb := range loadbalancer { - forwardRuleCount := len(lb.ForwardingRules) - firewallRuleCount := len(lb.FirewallRules) - instanceCount := len(lb.Instances) + + if len(loadbalancer) == 0 { + display(columns{"---", "---", "---", "---", "---", "---", "---"}) + Meta(meta) + return + } + + for i := range loadbalancer { + forwardRuleCount := len(loadbalancer[i].ForwardingRules) + firewallRuleCount := len(loadbalancer[i].FirewallRules) + instanceCount := len(loadbalancer[i].Instances) display(columns{ - lb.ID, - lb.Label, - lb.Status, - lb.Region, + loadbalancer[i].ID, + loadbalancer[i].Label, + loadbalancer[i].Status, + loadbalancer[i].Region, instanceCount, forwardRuleCount, firewallRuleCount, @@ -145,5 +225,4 @@ func LoadBalancerListSummary(loadbalancer []govultr.LoadBalancer, meta *govultr. } Meta(meta) - flush() } diff --git a/cmd/printer/network.go b/cmd/printer/network.go index 71cfdcc9..a2f8f437 100644 --- a/cmd/printer/network.go +++ b/cmd/printer/network.go @@ -3,19 +3,33 @@ package printer import "github.com/vultr/govultr/v3" func NetworkList(network []govultr.Network, meta *govultr.Meta) { - col := columns{"ID", "REGION", "DESCRIPTION", "V4 SUBNET", "V4 SUBNET MASK", "DATE CREATED"} - display(col) - for _, n := range network { - display(columns{n.NetworkID, n.Region, n.Description, n.V4Subnet, n.V4SubnetMask, n.DateCreated}) + defer flush() + + display(columns{"ID", "REGION", "DESCRIPTION", "V4 SUBNET", "V4 SUBNET MASK", "DATE CREATED"}) + + if len(network) == 0 { + display(columns{"---", "---", "---", "---", "---", "---"}) + Meta(meta) + return + } + + for i := range network { + display(columns{ + network[i].NetworkID, + network[i].Region, + network[i].Description, + network[i].V4Subnet, + network[i].V4SubnetMask, + network[i].DateCreated, + }) } Meta(meta) - flush() } func Network(network *govultr.Network) { + defer flush() + display(columns{"ID", "REGION", "DESCRIPTION", "V4 SUBNET", "V4 SUBNET MASK", "DATE CREATED"}) display(columns{network.NetworkID, network.Region, network.Description, network.V4Subnet, network.V4SubnetMask, network.DateCreated}) - - flush() } diff --git a/cmd/printer/objectStorage.go b/cmd/printer/objectStorage.go index 5a924cb7..0b14e1f2 100644 --- a/cmd/printer/objectStorage.go +++ b/cmd/printer/objectStorage.go @@ -5,35 +5,78 @@ import ( ) func ObjectStorages(obj []govultr.ObjectStorage, meta *govultr.Meta) { + defer flush() + display(columns{"ID", "REGION", "OBJSTORECLUSTER ID", "STATUS", "LABEL", "DATE CREATED", "S3 HOSTNAME", "S3 ACCESS KEY", "S3 SECRET KEY"}) - for _, o := range obj { - vals := columns{o.ID, o.Region, o.ObjectStoreClusterID, o.Status, o.Label, o.DateCreated, o.S3Keys.S3Hostname, o.S3Keys.S3AccessKey, o.S3Keys.S3SecretKey} + + if len(obj) == 0 { + display(columns{"---", "---", "---", "---", "---", "---", "S3 HOSTNAME", "S3 ACCESS KEY", "S3 SECRET KEY"}) + Meta(meta) + return + } + + for i := range obj { + vals := columns{ + obj[i].ID, + obj[i].Region, + obj[i].ObjectStoreClusterID, + obj[i].Status, + obj[i].Label, + obj[i].DateCreated, + obj[i].S3Keys.S3Hostname, + obj[i].S3Keys.S3AccessKey, + obj[i].S3Keys.S3SecretKey, + } + display(vals) } Meta(meta) - flush() } func SingleObjectStorage(obj *govultr.ObjectStorage) { - display(columns{"ID", "REGION", "OBJSTORECLUSTER ID", "STATUS", "LABEL", "DATE CREATED", "S3 HOSTNAME", "S3 ACCESS KEY", "S3 SECRET KEY"}) - display(columns{obj.ID, obj.Region, obj.ObjectStoreClusterID, obj.Status, obj.Label, obj.DateCreated, obj.S3Keys.S3Hostname, obj.S3Keys.S3AccessKey, obj.S3Keys.S3SecretKey}) + defer flush() - flush() + display(columns{"ID", "REGION", "OBJSTORECLUSTER ID", "STATUS", "LABEL", "DATE CREATED", "S3 HOSTNAME", "S3 ACCESS KEY", "S3 SECRET KEY"}) + display(columns{ + obj.ID, + obj.Region, + obj.ObjectStoreClusterID, + obj.Status, + obj.Label, + obj.DateCreated, + obj.S3Keys.S3Hostname, + obj.S3Keys.S3AccessKey, + obj.S3Keys.S3SecretKey, + }) } func ObjectStorageClusterList(cluster []govultr.ObjectStorageCluster, meta *govultr.Meta) { + defer flush() + display(columns{"OBJSTORECLUSTER", "REGION ID", "HOSTNAME", "DEPLOY"}) - for _, c := range cluster { - display(columns{c.ID, c.Region, c.Hostname, c.Deploy}) + + if len(cluster) == 0 { + display(columns{"---", "---", "---", "---"}) + Meta(meta) + return + } + + for i := range cluster { + display(columns{ + cluster[i].ID, + cluster[i].Region, + cluster[i].Hostname, + cluster[i].Deploy, + }) } Meta(meta) - flush() } func ObjStorageS3KeyRegenerate(key *govultr.S3Keys) { + defer flush() + display(columns{"S3 HOSTNAME", "S3 ACCESS KEY", "S3 SECRET KEY"}) display(columns{key.S3Hostname, key.S3AccessKey, key.S3SecretKey}) - flush() } diff --git a/cmd/printer/os.go b/cmd/printer/os.go index df2ffd89..5945b5df 100644 --- a/cmd/printer/os.go +++ b/cmd/printer/os.go @@ -5,12 +5,24 @@ import ( ) func Os(vultrOS []govultr.OS, meta *govultr.Meta) { - col := columns{"ID", "NAME", "ARCH", "FAMILY"} - display(col) - for _, os := range vultrOS { - display(columns{os.ID, os.Name, os.Arch, os.Family}) + defer flush() + + display(columns{"ID", "NAME", "ARCH", "FAMILY"}) + + if len(vultrOS) == 0 { + display(columns{"---", "---", "---", "---"}) + Meta(meta) + return + } + + for i := range vultrOS { + display(columns{ + vultrOS[i].ID, + vultrOS[i].Name, + vultrOS[i].Arch, + vultrOS[i].Family, + }) } Meta(meta) - flush() } diff --git a/cmd/printer/plans.go b/cmd/printer/plans.go index 2556d565..6901e5c3 100644 --- a/cmd/printer/plans.go +++ b/cmd/printer/plans.go @@ -5,23 +5,85 @@ import ( ) func Plan(plan []govultr.Plan, meta *govultr.Meta) { - col := columns{"ID", "VCPU COUNT", "RAM", "DISK", "DISK COUNT", "BANDWIDTH GB", "PRICE PER MONTH", "TYPE", "GPU VRAM", "GPU TYPE", "REGIONS"} - display(col) - for _, p := range plan { - display(columns{p.ID, p.VCPUCount, p.RAM, p.Disk, p.DiskCount, p.Bandwidth, p.MonthlyCost, p.Type, p.GPUVRAM, p.GPUType, p.Locations}) + defer flush() + + display(columns{ + "ID", + "VCPU COUNT", + "RAM", + "DISK", + "DISK COUNT", + "BANDWIDTH GB", + "PRICE PER MONTH", + "TYPE", + "GPU VRAM", + "GPU TYPE", + "REGIONS", + }) + + if len(plan) == 0 { + display(columns{"---", "---", "---", "---", "---", "---", "---", "---", "---", "---", "---"}) + Meta(meta) + return + } + + for i := range plan { + display(columns{ + plan[i].ID, + plan[i].VCPUCount, + plan[i].RAM, + plan[i].Disk, + plan[i].DiskCount, + plan[i].Bandwidth, + plan[i].MonthlyCost, + plan[i].Type, + plan[i].GPUVRAM, + plan[i].GPUType, + plan[i].Locations, + }) } Meta(meta) - flush() } func PlanBareMetal(plan []govultr.BareMetalPlan, meta *govultr.Meta) { - col := columns{"ID", "CPU COUNT", "CPU MODEL", "CPU THREADS", "RAM", "DISK", "DISK COUNT", "BANDWIDTH GB", "PRICE PER MONTH", "TYPE", "REGIONS"} - display(col) - for _, p := range plan { - display(columns{p.ID, p.CPUCount, p.CPUModel, p.CPUThreads, p.RAM, p.Disk, p.DiskCount, p.Bandwidth, p.MonthlyCost, p.Type, p.Locations}) + defer flush() + + display(columns{ + "ID", + "CPU COUNT", + "CPU MODEL", + "CPU THREADS", + "RAM", + "DISK", + "DISK COUNT", + "BANDWIDTH GB", + "PRICE PER MONTH", + "TYPE", + "REGIONS", + }) + + if len(plan) == 0 { + display(columns{"---", "---", "---", "---", "---", "---", "---", "---", "---", "---", "---"}) + Meta(meta) + return + } + + for i := range plan { + display(columns{ + plan[i].ID, + plan[i].CPUCount, + plan[i].CPUModel, + plan[i].CPUThreads, + plan[i].RAM, + plan[i].Disk, + plan[i].DiskCount, + plan[i].Bandwidth, + plan[i].MonthlyCost, + plan[i].Type, + plan[i].Locations, + }) } Meta(meta) - flush() } diff --git a/cmd/printer/printer.go b/cmd/printer/printer.go index 0339d14b..92edd5d0 100644 --- a/cmd/printer/printer.go +++ b/cmd/printer/printer.go @@ -1,3 +1,4 @@ +// Package printer provides the console printing functionality for the CLI package printer import ( @@ -8,6 +9,14 @@ import ( "github.com/vultr/govultr/v3" ) +const ( + twMinWidth int = 0 + twTabWidth int = 8 + twPadding int = 2 + twPadChar byte = '\t' + twFlags uint = 0 +) + type Printer interface { display(values columns, lengths []int) flush() @@ -16,11 +25,20 @@ type Printer interface { var tw = new(tabwriter.Writer) func init() { - tw.Init(os.Stdout, 0, 8, 2, '\t', 0) + tw.Init( + os.Stdout, + twMinWidth, + twTabWidth, + twPadding, + twPadChar, + twFlags, + ) } +// columns is a type to contain the strings type columns []interface{} +// display loops over the value `columns` and Fprintf the output to tabwriter func display(values columns) { for i, value := range values { format := "\t%s" @@ -32,22 +50,44 @@ func display(values columns) { fmt.Fprintf(tw, "\n") } +// displayString will `Fprintln` a string to the tabwriter +func displayString(message string) { + fmt.Fprintln(tw, message) +} + +// flush calls the tabwriter `Flush()` to write output func flush() { - tw.Flush() + if err := tw.Flush(); err != nil { + panic("could not flush buffer") + } } +// Meta prints out the pagination details func Meta(meta *govultr.Meta) { - display(columns{"======================================"}) - col := columns{"TOTAL", "NEXT PAGE", "PREV PAGE"} - display(col) + var pageNext string + var pagePrev string + + if meta.Links.Next == "" { + pageNext = "---" + } else { + pageNext = meta.Links.Next + } + + if meta.Links.Prev == "" { + pagePrev = "---" + } else { + pagePrev = meta.Links.Prev + } - display(columns{meta.Total, meta.Links.Next, meta.Links.Prev}) + displayString("======================================") + display(columns{"TOTAL", "NEXT PAGE", "PREV PAGE"}) + display(columns{meta.Total, pageNext, pagePrev}) } +// MetaDBaaS prints out the pagination details used by database commands func MetaDBaaS(meta *govultr.Meta) { - display(columns{"======================================"}) - col := columns{"TOTAL"} - display(col) + displayString("======================================") + display(columns{"TOTAL"}) display(columns{meta.Total}) } diff --git a/cmd/printer/regions.go b/cmd/printer/regions.go index 999ebca3..1f2858e2 100644 --- a/cmd/printer/regions.go +++ b/cmd/printer/regions.go @@ -5,22 +5,40 @@ import ( ) func Regions(avail []govultr.Region, meta *govultr.Meta) { - col := columns{"ID", "CITY", "COUNTRY", "CONTINENT", "OPTIONS"} - display(col) - for _, r := range avail { - display(columns{r.ID, r.City, r.Country, r.Continent, r.Options}) + defer flush() + + display(columns{"ID", "CITY", "COUNTRY", "CONTINENT", "OPTIONS"}) + + if len(avail) == 0 { + display(columns{"---", "---", "---", "---", "---"}) + Meta(meta) + return + } + + for i := range avail { + display(columns{ + avail[i].ID, + avail[i].City, + avail[i].Country, + avail[i].Continent, + avail[i].Options, + }) } Meta(meta) - flush() } func RegionAvailability(avail *govultr.PlanAvailability) { + defer flush() + display(columns{"AVAILABLE PLANS"}) - for _, r := range avail.AvailablePlans { - display(columns{r}) + if len(avail.AvailablePlans) == 0 { + display(columns{"---"}) + return } - flush() + for i := range avail.AvailablePlans { + display(columns{avail.AvailablePlans[i]}) + } } diff --git a/cmd/printer/reservedIP.go b/cmd/printer/reservedIP.go index 313cc28f..77ca7b0b 100644 --- a/cmd/printer/reservedIP.go +++ b/cmd/printer/reservedIP.go @@ -3,20 +3,42 @@ package printer import "github.com/vultr/govultr/v3" func ReservedIPList(reservedIP []govultr.ReservedIP, meta *govultr.Meta) { - col := columns{"ID", "REGION", "IP TYPE", "SUBNET", "SUBNET SIZE", "LABEL", "ATTACHED TO"} - display(col) - for _, r := range reservedIP { - display(columns{r.ID, r.Region, r.IPType, r.Subnet, r.SubnetSize, r.Label, r.InstanceID}) + defer flush() + + display(columns{"ID", "REGION", "IP TYPE", "SUBNET", "SUBNET SIZE", "LABEL", "ATTACHED TO"}) + + if len(reservedIP) == 0 { + display(columns{"---", "---", "---", "---", "---", "---", "---"}) + Meta(meta) + return + } + + for i := range reservedIP { + display(columns{ + reservedIP[i].ID, + reservedIP[i].Region, + reservedIP[i].IPType, + reservedIP[i].Subnet, + reservedIP[i].SubnetSize, + reservedIP[i].Label, + reservedIP[i].InstanceID, + }) } Meta(meta) - flush() } func ReservedIP(reservedIP *govultr.ReservedIP) { - col := columns{"ID", "REGION", "IP TYPE", "SUBNET", "SUBNET SIZE", "LABEL", "ATTACHED TO"} - display(col) - display(columns{reservedIP.ID, reservedIP.Region, reservedIP.IPType, reservedIP.Subnet, reservedIP.SubnetSize, reservedIP.Label, reservedIP.InstanceID}) + defer flush() - flush() + display(columns{"ID", "REGION", "IP TYPE", "SUBNET", "SUBNET SIZE", "LABEL", "ATTACHED TO"}) + display(columns{ + reservedIP.ID, + reservedIP.Region, + reservedIP.IPType, + reservedIP.Subnet, + reservedIP.SubnetSize, + reservedIP.Label, + reservedIP.InstanceID, + }) } diff --git a/cmd/printer/script.go b/cmd/printer/script.go index 47cd111a..ae28ce59 100644 --- a/cmd/printer/script.go +++ b/cmd/printer/script.go @@ -5,23 +5,36 @@ import ( ) func ScriptList(script []govultr.StartupScript, meta *govultr.Meta) { - col := columns{"ID", "DATE CREATED", "DATE MODIFIED", "TYPE", "NAME"} - display(col) - for _, s := range script { - display(columns{s.ID, s.DateCreated, s.DateModified, s.Type, s.Name}) + defer flush() + + display(columns{"ID", "DATE CREATED", "DATE MODIFIED", "TYPE", "NAME"}) + + if len(script) == 0 { + display(columns{"---", "---", "---", "---", "---"}) + Meta(meta) + return + } + + for i := range script { + display(columns{ + script[i].ID, + script[i].DateCreated, + script[i].DateModified, + script[i].Type, + script[i].Name, + }) } Meta(meta) - flush() } func Script(script *govultr.StartupScript) { + defer flush() + display(columns{"ID", script.ID}) display(columns{"DATE CREATED", script.DateCreated}) display(columns{"DATE MODIFIED", script.DateModified}) display(columns{"TYPE", script.Type}) display(columns{"NAME", script.Name}) display(columns{"SCRIPT", script.Script}) - - flush() } diff --git a/cmd/printer/snapshot.go b/cmd/printer/snapshot.go index 3232e7db..55bc5a3b 100644 --- a/cmd/printer/snapshot.go +++ b/cmd/printer/snapshot.go @@ -4,20 +4,44 @@ import ( "github.com/vultr/govultr/v3" ) -func Snapshot(snapshot *govultr.Snapshot) { +func Snapshots(snapshot []govultr.Snapshot, meta *govultr.Meta) { + defer flush() + display(columns{"ID", "DATE CREATED", "SIZE", "COMPRESSED SIZE", "STATUS", "OSID", "APPID", "DESCRIPTION"}) - display(columns{snapshot.ID, snapshot.DateCreated, snapshot.Size, snapshot.CompressedSize, snapshot.Status, snapshot.OsID, snapshot.AppID, snapshot.Description}) - flush() -} + if len(snapshot) == 0 { + display(columns{"---", "---", "---", "---", "---", "---", "---", "---"}) + Meta(meta) + return + } -func Snapshots(snapshot []govultr.Snapshot, meta *govultr.Meta) { - col := columns{"ID", "DATE CREATED", "SIZE", "COMPRESSED SIZE", "STATUS", "OSID", "APPID", "DESCRIPTION"} - display(col) - for _, s := range snapshot { - display(columns{s.ID, s.DateCreated, s.Size, s.CompressedSize, s.Status, s.OsID, s.AppID, s.Description}) + for i := range snapshot { + display(columns{ + snapshot[i].ID, + snapshot[i].DateCreated, + snapshot[i].Size, + snapshot[i].CompressedSize, + snapshot[i].Status, + snapshot[i].OsID, + snapshot[i].AppID, + snapshot[i].Description, + }) } Meta(meta) - flush() +} + +func Snapshot(snapshot *govultr.Snapshot) { + defer flush() + display(columns{"ID", "DATE CREATED", "SIZE", "COMPRESSED SIZE", "STATUS", "OSID", "APPID", "DESCRIPTION"}) + display(columns{ + snapshot.ID, + snapshot.DateCreated, + snapshot.Size, + snapshot.CompressedSize, + snapshot.Status, + snapshot.OsID, + snapshot.AppID, + snapshot.Description, + }) } diff --git a/cmd/printer/ssh-key.go b/cmd/printer/ssh-key.go index 3ec25c82..869e7775 100644 --- a/cmd/printer/ssh-key.go +++ b/cmd/printer/ssh-key.go @@ -5,19 +5,31 @@ import ( ) func SSHKeys(ssh []govultr.SSHKey, meta *govultr.Meta) { - col := columns{"ID", "DATE CREATED", "NAME", "KEY"} - display(col) - for _, s := range ssh { - display(columns{s.ID, s.DateCreated, s.Name, s.SSHKey}) + defer flush() + + display(columns{"ID", "DATE CREATED", "NAME", "KEY"}) + + if len(ssh) == 0 { + display(columns{"---", "---", "---", "---"}) + Meta(meta) + return + } + + for i := range ssh { + display(columns{ + ssh[i].ID, + ssh[i].DateCreated, + ssh[i].Name, + ssh[i].SSHKey, + }) } Meta(meta) - flush() } func SSHKey(ssh *govultr.SSHKey) { + defer flush() + display(columns{"ID", "DATE CREATED", "NAME", "KEY"}) display(columns{ssh.ID, ssh.DateCreated, ssh.Name, ssh.SSHKey}) - - flush() } diff --git a/cmd/printer/user.go b/cmd/printer/user.go index 58e84d91..8aaf0278 100644 --- a/cmd/printer/user.go +++ b/cmd/printer/user.go @@ -5,19 +5,32 @@ import ( ) func Users(user []govultr.User, meta *govultr.Meta) { - col := columns{"ID", "NAME", "EMAIL", "API", "ACL"} - display(col) - for _, u := range user { - display(columns{u.ID, u.Name, u.Email, *u.APIEnabled, u.ACL}) + defer flush() + + display(columns{"ID", "NAME", "EMAIL", "API", "ACL"}) + + if len(user) == 0 { + display(columns{"---", "---", "---", "---", "---"}) + Meta(meta) + return + } + + for i := range user { + display(columns{ + user[i].ID, + user[i].Name, + user[i].Email, + *user[i].APIEnabled, + user[i].ACL, + }) } Meta(meta) - flush() } func User(user *govultr.User) { + defer flush() + display(columns{"ID", "NAME", "EMAIL", "API", "ACL"}) display(columns{user.ID, user.Name, user.Email, *user.APIEnabled, user.ACL}) - - flush() } diff --git a/cmd/printer/userData.go b/cmd/printer/userData.go index 818d9e69..11fe8b66 100644 --- a/cmd/printer/userData.go +++ b/cmd/printer/userData.go @@ -3,18 +3,18 @@ package printer import ( "encoding/base64" "fmt" - "os" "github.com/vultr/govultr/v3" ) func UserData(u *govultr.UserData) { + defer flush() + display(columns{"USERDATA"}) data, err := base64.StdEncoding.DecodeString(u.Data) if err != nil { - fmt.Printf("Error decoding user-data: %v\n", err) - os.Exit(1) + displayString(fmt.Sprintf("Error decoding user-data: %v\n", err)) + return } display(columns{string(data)}) - flush() } diff --git a/cmd/printer/vpc.go b/cmd/printer/vpc.go index 39c9f557..63c2e453 100644 --- a/cmd/printer/vpc.go +++ b/cmd/printer/vpc.go @@ -3,19 +3,33 @@ package printer import "github.com/vultr/govultr/v3" func VPCList(vpc []govultr.VPC, meta *govultr.Meta) { - col := columns{"ID", "REGION", "DESCRIPTION", "V4 SUBNET", "V4 SUBNET MASK", "DATE CREATED"} - display(col) - for _, n := range vpc { - display(columns{n.ID, n.Region, n.Description, n.V4Subnet, n.V4SubnetMask, n.DateCreated}) + defer flush() + + display(columns{"ID", "REGION", "DESCRIPTION", "V4 SUBNET", "V4 SUBNET MASK", "DATE CREATED"}) + + if len(vpc) == 0 { + display(columns{"---", "---", "---", "---", "---", "---"}) + Meta(meta) + return + } + + for i := range vpc { + display(columns{ + vpc[i].ID, + vpc[i].Region, + vpc[i].Description, + vpc[i].V4Subnet, + vpc[i].V4SubnetMask, + vpc[i].DateCreated, + }) } Meta(meta) - flush() } func VPC(vpc *govultr.VPC) { + defer flush() + display(columns{"ID", "REGION", "DESCRIPTION", "V4 SUBNET", "V4 SUBNET MASK", "DATE CREATED"}) display(columns{vpc.ID, vpc.Region, vpc.Description, vpc.V4Subnet, vpc.V4SubnetMask, vpc.DateCreated}) - - flush() } diff --git a/cmd/printer/vpc2.go b/cmd/printer/vpc2.go index 88e705b4..8690aba4 100644 --- a/cmd/printer/vpc2.go +++ b/cmd/printer/vpc2.go @@ -6,29 +6,60 @@ import ( // VPC2List Generates a printer display of all VPC 2.0 networks on the account func VPC2List(vpc2s []govultr.VPC2, meta *govultr.Meta) { + defer flush() + display(columns{"ID", "DATE CREATED", "REGION", "DESCRIPTION", "IP BLOCK", "PREFIX LENGTH"}) - for d := range vpc2s { - display(columns{vpc2s[d].ID, vpc2s[d].DateCreated, vpc2s[d].Region, vpc2s[d].Description, vpc2s[d].IPBlock, vpc2s[d].PrefixLength}) + + if len(vpc2s) == 0 { + display(columns{"---", "---", "---", "---", "---", "---"}) + Meta(meta) + return + } + + for i := range vpc2s { + display(columns{ + vpc2s[i].ID, + vpc2s[i].DateCreated, + vpc2s[i].Region, + vpc2s[i].Description, + vpc2s[i].IPBlock, + vpc2s[i].PrefixLength, + }) } Meta(meta) - flush() } // VPC2 Generates a printer display of a given VPC 2.0 network func VPC2(vpc2 *govultr.VPC2) { + defer flush() + display(columns{"ID", "DATE CREATED", "REGION", "DESCRIPTION", "IP BLOCK", "PREFIX LENGTH"}) display(columns{vpc2.ID, vpc2.DateCreated, vpc2.Region, vpc2.Description, vpc2.IPBlock, vpc2.PrefixLength}) - flush() } // VPC2ListNodes Generates a printer display of all nodes attached to a VPC 2.0 network func VPC2ListNodes(vpc2Nodes []govultr.VPC2Node, meta *govultr.Meta) { + defer flush() + display(columns{"ID", "IP ADDRESS", "MAC ADDRESS", "DESCRIPTION", "TYPE", "NODE STATUS"}) - for d := range vpc2Nodes { - display(columns{vpc2Nodes[d].ID, vpc2Nodes[d].IPAddress, vpc2Nodes[d].MACAddress, vpc2Nodes[d].Description, vpc2Nodes[d].Type, vpc2Nodes[d].NodeStatus}) + + if len(vpc2Nodes) == 0 { + display(columns{"---", "---", "---", "---", "---", "---"}) + Meta(meta) + return + } + + for i := range vpc2Nodes { + display(columns{ + vpc2Nodes[i].ID, + vpc2Nodes[i].IPAddress, + vpc2Nodes[i].MACAddress, + vpc2Nodes[i].Description, + vpc2Nodes[i].Type, + vpc2Nodes[i].NodeStatus, + }) } Meta(meta) - flush() }