Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/workflows/go.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
- name: Install Go
uses: actions/setup-go@v6
with:
go-version: ${{ vars.GO_VERSION || '1.24.11' }}
go-version: ${{ vars.GO_VERSION || '1.24.13' }}
cache: true

- name: Verify dependencies
Expand Down Expand Up @@ -52,7 +52,7 @@ jobs:
- name: Install Go
uses: actions/setup-go@v6
with:
go-version: ${{ vars.GO_VERSION || '1.24.11' }}
go-version: ${{ vars.GO_VERSION || '1.24.13' }}
cache: true

- name: Run golangci-lint
Expand All @@ -71,5 +71,5 @@ jobs:
- name: Run govulncheck
uses: golang/govulncheck-action@v1
with:
go-version-input: ${{ vars.GO_VERSION || '1.24.11' }}
go-version-input: ${{ vars.GO_VERSION || '1.24.13' }}
go-package: ./...
2 changes: 1 addition & 1 deletion .github/workflows/goreleaser-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jobs:
- name: Set up Go
uses: actions/setup-go@v6
with:
go-version: ${{ vars.GO_VERSION || '1.24.11' }}
go-version: ${{ vars.GO_VERSION || '1.24.13' }}
cache: true

- name: Run GoReleaser Check
Expand Down
2 changes: 2 additions & 0 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"github.com/civo/cli/cmd/teams"
"github.com/civo/cli/cmd/volume"
"github.com/civo/cli/cmd/volumetype"
"github.com/civo/cli/cmd/vpc"
"github.com/civo/cli/common"
"github.com/civo/cli/config"
"github.com/civo/cli/utility"
Expand Down Expand Up @@ -163,4 +164,5 @@ func init() {
rootCmd.AddCommand(volume.VolumeCmd)
rootCmd.AddCommand(volumetype.VolumeTypeCmd)
rootCmd.AddCommand(snapshot.SnapshotCmd)
rootCmd.AddCommand(vpc.VPCCmd)
}
154 changes: 154 additions & 0 deletions cmd/vpc/vpc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
package vpc

import (
"errors"

"github.com/spf13/cobra"
)

// VPCCmd manages Civo VPC resources
var VPCCmd = &cobra.Command{
Use: "vpc",
Aliases: []string{},
Short: "Details of Civo VPC resources",
RunE: func(cmd *cobra.Command, args []string) error {
err := cmd.Help()
if err != nil {
return err
}
return errors.New("a valid subcommand is required")
},
}

func init() {
// Sub-resource commands
VPCCmd.AddCommand(vpcNetworkCmd)
VPCCmd.AddCommand(vpcSubnetCmd)
VPCCmd.AddCommand(vpcFirewallCmd)
VPCCmd.AddCommand(vpcLoadBalancerCmd)
VPCCmd.AddCommand(vpcIPCmd)

// --- Network subcommands ---
vpcNetworkCmd.AddCommand(vpcNetworkListCmd)
vpcNetworkCmd.AddCommand(vpcNetworkCreateCmd)
vpcNetworkCmd.AddCommand(vpcNetworkShowCmd)
vpcNetworkCmd.AddCommand(vpcNetworkUpdateCmd)
vpcNetworkCmd.AddCommand(vpcNetworkRemoveCmd)

// Network create flags
vpcNetworkCreateCmd.Flags().StringVarP(&vpcNetCIDRv4, "cidr-v4", "", "", "Custom IPv4 CIDR")
vpcNetworkCreateCmd.Flags().StringSliceVarP(&vpcNetNameserversV4, "nameservers-v4", "", nil, "Custom list of IPv4 nameservers (comma-separated)")
vpcNetworkCreateCmd.Flags().BoolVarP(&vpcNetIPv4Enabled, "ipv4-enabled", "", true, "Enable IPv4 for the network")
vpcNetworkCreateCmd.Flags().BoolVarP(&vpcNetIPv6Enabled, "ipv6-enabled", "", false, "Enable IPv6 for the network")
vpcNetworkCreateCmd.Flags().StringSliceVarP(&vpcNetNameserversV6, "nameservers-v6", "", nil, "Custom list of IPv6 nameservers (comma-separated)")

// --- Subnet subcommands ---
vpcSubnetCmd.AddCommand(vpcSubnetListCmd)
vpcSubnetCmd.AddCommand(vpcSubnetCreateCmd)
vpcSubnetCmd.AddCommand(vpcSubnetShowCmd)
vpcSubnetCmd.AddCommand(vpcSubnetRemoveCmd)
vpcSubnetCmd.AddCommand(vpcSubnetAttachCmd)
vpcSubnetCmd.AddCommand(vpcSubnetDetachCmd)

// Subnet flags (all require --network)
vpcSubnetListCmd.Flags().StringVarP(&subnetListNetworkID, "network", "n", "", "Network name or ID")
_ = vpcSubnetListCmd.MarkFlagRequired("network")

vpcSubnetCreateCmd.Flags().StringVarP(&subnetCreateNetworkID, "network", "n", "", "Network name or ID")
_ = vpcSubnetCreateCmd.MarkFlagRequired("network")

vpcSubnetShowCmd.Flags().StringVarP(&subnetShowNetworkID, "network", "n", "", "Network name or ID")
_ = vpcSubnetShowCmd.MarkFlagRequired("network")

vpcSubnetRemoveCmd.Flags().StringVarP(&subnetRemoveNetworkID, "network", "n", "", "Network name or ID")
_ = vpcSubnetRemoveCmd.MarkFlagRequired("network")

vpcSubnetAttachCmd.Flags().StringVarP(&subnetAttachNetworkID, "network", "n", "", "Network name or ID")
_ = vpcSubnetAttachCmd.MarkFlagRequired("network")
vpcSubnetAttachCmd.Flags().StringVar(&subnetAttachResourceID, "resource-id", "", "Resource ID to attach to")
_ = vpcSubnetAttachCmd.MarkFlagRequired("resource-id")
vpcSubnetAttachCmd.Flags().StringVar(&subnetAttachResourceType, "resource-type", "", "Resource type (e.g. instance)")
_ = vpcSubnetAttachCmd.MarkFlagRequired("resource-type")

vpcSubnetDetachCmd.Flags().StringVarP(&subnetDetachNetworkID, "network", "n", "", "Network name or ID")
_ = vpcSubnetDetachCmd.MarkFlagRequired("network")

// --- Firewall subcommands ---
vpcFirewallCmd.AddCommand(vpcFirewallListCmd)
vpcFirewallCmd.AddCommand(vpcFirewallCreateCmd)
vpcFirewallCmd.AddCommand(vpcFirewallShowCmd)
vpcFirewallCmd.AddCommand(vpcFirewallUpdateCmd)
vpcFirewallCmd.AddCommand(vpcFirewallRemoveCmd)

// Firewall create flags
vpcFirewallCreateCmd.Flags().StringVarP(&vpcFwNetwork, "network", "n", "default", "The network to create the firewall in")
vpcFirewallCreateCmd.Flags().BoolVarP(&vpcFwNoDefaultRules, "no-default-rules", "", false, "Create firewall without default rules")

// --- Firewall Rule subcommands ---
vpcFirewallCmd.AddCommand(vpcFirewallRuleCmd)
vpcFirewallRuleCmd.AddCommand(vpcFirewallRuleListCmd)
vpcFirewallRuleCmd.AddCommand(vpcFirewallRuleCreateCmd)
vpcFirewallRuleCmd.AddCommand(vpcFirewallRuleRemoveCmd)

// Firewall rule create flags
vpcFirewallRuleCreateCmd.Flags().StringVarP(&vpcFwRuleProtocol, "protocol", "p", "TCP", "The protocol choice (TCP, UDP, ICMP)")
vpcFirewallRuleCreateCmd.Flags().StringVarP(&vpcFwRuleStartPort, "startport", "s", "", "The start port of the rule")
vpcFirewallRuleCreateCmd.Flags().StringVarP(&vpcFwRuleEndPort, "endport", "e", "", "The end port of the rule")
vpcFirewallRuleCreateCmd.Flags().StringVarP(&vpcFwRuleCidr, "cidr", "c", "0.0.0.0/0", "The CIDR of the rule")
vpcFirewallRuleCreateCmd.Flags().StringVarP(&vpcFwRuleDirection, "direction", "d", "ingress", "The direction of the rule (ingress or egress)")
vpcFirewallRuleCreateCmd.Flags().StringVarP(&vpcFwRuleAction, "action", "a", "allow", "The action of the rule (allow or deny)")
vpcFirewallRuleCreateCmd.Flags().StringVarP(&vpcFwRuleLabel, "label", "l", "", "A label for this rule")
_ = vpcFirewallRuleCreateCmd.MarkFlagRequired("startport")

// --- Load Balancer subcommands ---
vpcLoadBalancerCmd.AddCommand(vpcLoadBalancerListCmd)
vpcLoadBalancerCmd.AddCommand(vpcLoadBalancerCreateCmd)
vpcLoadBalancerCmd.AddCommand(vpcLoadBalancerShowCmd)
vpcLoadBalancerCmd.AddCommand(vpcLoadBalancerUpdateCmd)
vpcLoadBalancerCmd.AddCommand(vpcLoadBalancerRemoveCmd)

// Load balancer create flags
vpcLoadBalancerCreateCmd.Flags().StringVarP(&vpcLBNetwork, "network", "n", "", "Network name or ID")
_ = vpcLoadBalancerCreateCmd.MarkFlagRequired("network")
vpcLoadBalancerCreateCmd.Flags().StringVar(&vpcLBAlgorithm, "algorithm", "round_robin", "Load balancing algorithm")
vpcLoadBalancerCreateCmd.Flags().StringVar(&vpcLBExternalTrafficPolicy, "external-traffic-policy", "", "External traffic policy")
vpcLoadBalancerCreateCmd.Flags().StringVar(&vpcLBSessionAffinity, "session-affinity", "", "Session affinity")
vpcLoadBalancerCreateCmd.Flags().Int32Var(&vpcLBSessionAffinityTimeout, "session-affinity-timeout", 0, "Session affinity timeout in seconds")
vpcLoadBalancerCreateCmd.Flags().StringVar(&vpcLBEnableProxyProtocol, "enable-proxy-protocol", "", "Enable proxy protocol")
vpcLoadBalancerCreateCmd.Flags().StringVar(&vpcLBFirewallID, "firewall-id", "", "Firewall ID to associate")
vpcLoadBalancerCreateCmd.Flags().IntVar(&vpcLBMaxConcurrentRequests, "max-concurrent-requests", 0, "Maximum concurrent requests")
vpcLoadBalancerCreateCmd.Flags().StringSliceVar(&vpcLBBackends, "backend", nil, "Backend in format ip:source_port:target_port:protocol:health_check_port (repeatable)")

// Load balancer update flags
vpcLoadBalancerUpdateCmd.Flags().StringVar(&vpcLBUpdateName, "name", "", "New name for the load balancer")
vpcLoadBalancerUpdateCmd.Flags().StringVar(&vpcLBUpdateAlgorithm, "algorithm", "", "Load balancing algorithm")
vpcLoadBalancerUpdateCmd.Flags().StringVar(&vpcLBUpdateExternalTrafficPolicy, "external-traffic-policy", "", "External traffic policy")
vpcLoadBalancerUpdateCmd.Flags().StringVar(&vpcLBUpdateSessionAffinity, "session-affinity", "", "Session affinity")
vpcLoadBalancerUpdateCmd.Flags().Int32Var(&vpcLBUpdateSessionAffinityTimeout, "session-affinity-timeout", 0, "Session affinity timeout in seconds")
vpcLoadBalancerUpdateCmd.Flags().StringVar(&vpcLBUpdateEnableProxyProtocol, "enable-proxy-protocol", "", "Enable proxy protocol")
vpcLoadBalancerUpdateCmd.Flags().StringVar(&vpcLBUpdateFirewallID, "firewall-id", "", "Firewall ID to associate")
vpcLoadBalancerUpdateCmd.Flags().IntVar(&vpcLBUpdateMaxConcurrentRequests, "max-concurrent-requests", 0, "Maximum concurrent requests")
vpcLoadBalancerUpdateCmd.Flags().StringSliceVar(&vpcLBUpdateBackends, "backend", nil, "Backend in format ip:source_port:target_port:protocol:health_check_port (repeatable)")

// --- IP subcommands ---
vpcIPCmd.AddCommand(vpcIPListCmd)
vpcIPCmd.AddCommand(vpcIPCreateCmd)
vpcIPCmd.AddCommand(vpcIPShowCmd)
vpcIPCmd.AddCommand(vpcIPUpdateCmd)
vpcIPCmd.AddCommand(vpcIPAssignCmd)
vpcIPCmd.AddCommand(vpcIPUnassignCmd)
vpcIPCmd.AddCommand(vpcIPRemoveCmd)

// IP create flags
vpcIPCreateCmd.Flags().StringVarP(&vpcIPName, "name", "n", "", "Name of the reserved IP")

// IP update flags
vpcIPUpdateCmd.Flags().StringVarP(&vpcIPUpdateName, "name", "n", "", "New name for the reserved IP")
_ = vpcIPUpdateCmd.MarkFlagRequired("name")

// IP assign flags
vpcIPAssignCmd.Flags().StringVar(&vpcIPAssignResourceID, "resource-id", "", "Resource ID to assign the IP to")
_ = vpcIPAssignCmd.MarkFlagRequired("resource-id")
vpcIPAssignCmd.Flags().StringVar(&vpcIPAssignResourceType, "resource-type", "", "Resource type (e.g. instance, loadbalancer)")
_ = vpcIPAssignCmd.MarkFlagRequired("resource-type")
}
20 changes: 20 additions & 0 deletions cmd/vpc/vpc_firewall.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package vpc

import (
"errors"

"github.com/spf13/cobra"
)

var vpcFirewallCmd = &cobra.Command{
Use: "firewall",
Aliases: []string{"firewalls", "fw"},
Short: "Details of Civo VPC firewalls",
RunE: func(cmd *cobra.Command, args []string) error {
err := cmd.Help()
if err != nil {
return err
}
return errors.New("a valid subcommand is required")
},
}
78 changes: 78 additions & 0 deletions cmd/vpc/vpc_firewall_create.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package vpc

import (
"fmt"
"os"

"github.com/civo/civogo"
"github.com/civo/cli/common"
"github.com/civo/cli/config"
"github.com/civo/cli/utility"
"github.com/spf13/cobra"
)

var (
vpcFwNetwork string
vpcFwNoDefaultRules bool
)

var vpcFirewallCreateCmd = &cobra.Command{
Use: "create",
Aliases: []string{"new", "add"},
Short: "Create a new VPC firewall",
Example: "civo vpc firewall create NAME [flags]",
Args: cobra.MinimumNArgs(1),
Run: func(cmd *cobra.Command, args []string) {
utility.EnsureCurrentRegion()

client, err := config.CivoAPIClient()
if common.RegionSet != "" {
client.Region = common.RegionSet
}
if err != nil {
utility.Error("Creating the connection to Civo's API failed with %s", err)
os.Exit(1)
}

var networkID string
if vpcFwNetwork == "default" {
defaultNetwork, err := client.GetDefaultVPCNetwork()
if err != nil {
utility.Error("Network %s", err)
os.Exit(1)
}
networkID = defaultNetwork.ID
} else {
network, err := client.FindVPCNetwork(vpcFwNetwork)
if err != nil {
utility.Error("Network %s", err)
os.Exit(1)
}
networkID = network.ID
}

createRules := !vpcFwNoDefaultRules

firewall, err := client.NewVPCFirewall(&civogo.FirewallConfig{
Name: args[0],
NetworkID: networkID,
CreateRules: &createRules,
Region: client.Region,
})
if err != nil {
utility.Error("%s", err)
os.Exit(1)
}

ow := utility.NewOutputWriterWithMap(map[string]string{"id": firewall.ID, "name": firewall.Name})

switch common.OutputFormat {
case "json":
ow.WriteSingleObjectJSON(common.PrettySet)
case "custom":
ow.WriteCustomOutput(common.OutputFields)
default:
fmt.Printf("Created a VPC firewall called %s with ID %s\n", utility.Green(firewall.Name), utility.Green(firewall.ID))
}
},
}
72 changes: 72 additions & 0 deletions cmd/vpc/vpc_firewall_list.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package vpc

import (
"os"
"strconv"

"github.com/civo/cli/common"
"github.com/civo/cli/config"
"github.com/civo/cli/utility"
"github.com/spf13/cobra"
)

var vpcFirewallListCmd = &cobra.Command{
Use: "ls",
Aliases: []string{"list", "all"},
Short: "List VPC firewalls",
Long: `List all current VPC firewalls.
If you wish to use a custom format, the available fields are:

* id
* name
* network
* rules_count
* instances_count
* clusters_count
* loadbalancer_count

Example: civo vpc firewall ls -o custom -f "ID: Name"`,
Run: func(cmd *cobra.Command, args []string) {
utility.EnsureCurrentRegion()

client, err := config.CivoAPIClient()
if common.RegionSet != "" {
client.Region = common.RegionSet
}
if err != nil {
utility.Error("Creating the connection to Civo's API failed with %s", err)
os.Exit(1)
}

firewalls, err := client.ListVPCFirewalls()
if err != nil {
utility.Error("%s", err)
os.Exit(1)
}

networks, err := client.ListVPCNetworks()
if err != nil {
utility.Error("%s", err)
os.Exit(1)
}

networkMap := make(map[string]string)
for _, network := range networks {
networkMap[network.ID] = network.Label
}

ow := utility.NewOutputWriter()
for _, firewall := range firewalls {
ow.StartLine()
ow.AppendDataWithLabel("id", firewall.ID, "ID")
ow.AppendDataWithLabel("name", firewall.Name, "Name")
ow.AppendDataWithLabel("network", networkMap[firewall.NetworkID], "Network")
ow.AppendDataWithLabel("rules_count", strconv.Itoa(firewall.RulesCount), "Total rules")
ow.AppendDataWithLabel("instances_count", strconv.Itoa(firewall.InstanceCount), "Total Instances")
ow.AppendDataWithLabel("clusters_count", strconv.Itoa(firewall.ClusterCount), "Total Clusters")
ow.AppendDataWithLabel("loadbalancer_count", strconv.Itoa(firewall.LoadBalancerCount), "Total LoadBalancer")
}

ow.FinishAndPrintOutput()
},
}
Loading
Loading