-
Notifications
You must be signed in to change notification settings - Fork 396
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[VPC-3359] Implemented vpc peering methods (#1532)
* Implemented vpc peering methods * removed peering id * added error check * addressed pr feedback * Update commands/vpc_peerings.go Co-authored-by: ddatta-do <[email protected]> * Update commands/vpc_peerings.go Co-authored-by: ddatta-do <[email protected]> * Update commands/vpc_peerings.go Co-authored-by: ddatta-do <[email protected]> * Update commands/vpc_peerings.go Co-authored-by: ddatta-do <[email protected]> * Update commands/vpc_peerings.go Co-authored-by: ddatta-do <[email protected]> * address pr feedback * added wait flag for status completion * addressed pr feedback * addressed pr feedback * updated wait to 5s * added requiredopts * resolved pr feedbacks --------- Co-authored-by: ddatta-do <[email protected]>
- Loading branch information
Showing
15 changed files
with
885 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
package displayers | ||
|
||
import ( | ||
"github.com/digitalocean/doctl/do" | ||
"io" | ||
"strings" | ||
) | ||
|
||
type VPCPeering struct { | ||
VPCPeerings do.VPCPeerings | ||
} | ||
|
||
var _ Displayable = &VPCPeering{} | ||
|
||
func (v *VPCPeering) JSON(out io.Writer) error { | ||
return writeJSON(v.VPCPeerings, out) | ||
} | ||
|
||
func (v *VPCPeering) Cols() []string { | ||
return []string{ | ||
"ID", | ||
"Name", | ||
"VPCIDs", | ||
"Status", | ||
"Created", | ||
} | ||
} | ||
|
||
func (v *VPCPeering) ColMap() map[string]string { | ||
return map[string]string{ | ||
"ID": "ID", | ||
"Name": "Name", | ||
"VPCIDs": "VPCIDs", | ||
"Status": "Status", | ||
"Created": "Created At", | ||
} | ||
} | ||
|
||
func (v *VPCPeering) KV() []map[string]any { | ||
out := make([]map[string]any, 0, len(v.VPCPeerings)) | ||
|
||
for _, v := range v.VPCPeerings { | ||
o := map[string]any{ | ||
"ID": v.ID, | ||
"Name": v.Name, | ||
"VPCIDs": strings.Join(v.VPCIDs, ","), | ||
"Status": v.Status, | ||
"Created": v.CreatedAt, | ||
} | ||
out = append(out, o) | ||
} | ||
|
||
return out | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,270 @@ | ||
package commands | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
"os" | ||
"strings" | ||
"time" | ||
|
||
"github.com/digitalocean/doctl" | ||
"github.com/digitalocean/doctl/commands/displayers" | ||
"github.com/digitalocean/doctl/do" | ||
"github.com/digitalocean/godo" | ||
"github.com/spf13/cobra" | ||
) | ||
|
||
// VPCPeerings creates the vpc peerings command. | ||
func VPCPeerings() *Command { | ||
cmd := &Command{ | ||
Command: &cobra.Command{ | ||
Use: "peerings", | ||
Short: "Display commands that manage VPC Peerings", | ||
Long: `The commands under ` + "`" + `doctl vpcs peerings` + "`" + ` are for managing your VPC Peerings. | ||
With the VPC Peerings commands, you can get, list, create, update, or delete VPC Peerings, and manage their configuration details.`, | ||
Hidden: true, | ||
}, | ||
} | ||
|
||
peeringDetails := ` | ||
- The VPC Peering ID | ||
- The VPC Peering Name | ||
- The Peered VPC network IDs | ||
- The VPC Peering Status | ||
- The VPC Peering creation date, in ISO8601 combined date and time format | ||
` | ||
cmdPeeringGet := CmdBuilder(cmd, RunVPCPeeringGet, "get <id>", | ||
"Retrieves a VPC Peering", "Retrieves information about a VPC Peering, including:"+peeringDetails, Writer, | ||
aliasOpt("g"), displayerType(&displayers.VPCPeering{})) | ||
cmdPeeringGet.Example = `The following example retrieves information about a VPC Peering with the ID ` + "`" + `f81d4fae-7dec-11d0-a765-00a0c91e6bf6` + "`" + `: doctl vpcs peerings get f81d4fae-7dec-11d0-a765-00a0c91e6bf6` | ||
|
||
cmdPeeringList := CmdBuilder(cmd, RunVPCPeeringList, "list", "List VPC Peerings", "Retrieves a list of the VPC Peerings on your account, including the following information for each:"+peeringDetails, Writer, | ||
aliasOpt("ls"), displayerType(&displayers.VPCPeering{})) | ||
AddStringFlag(cmdPeeringList, doctl.ArgVPCPeeringVPCID, "", "", | ||
"VPC ID") | ||
cmdPeeringList.Example = `The following example lists the VPC Peerings on your account : doctl vpcs peerings list --format Name,VPCIDs` | ||
|
||
cmdPeeringCreate := CmdBuilder(cmd, RunVPCPeeringCreate, "create", | ||
"Create a new VPC Peering", "Use this command to create a new VPC Peering on your account.", Writer, aliasOpt("c")) | ||
AddStringFlag(cmdPeeringCreate, doctl.ArgVPCPeeringVPCIDs, "", "", | ||
"Peering VPC IDs should be comma separated", requiredOpt()) | ||
AddBoolFlag(cmdPeeringCreate, doctl.ArgCommandWait, "", false, "Boolean that specifies whether to wait for a VPC Peering creation to complete before returning control to the terminal") | ||
cmdPeeringCreate.Example = `The following example creates a VPC Peering named ` + | ||
"`" + `example-peering-name` + "`" + | ||
` : doctl vpcs peerings create example-peering-name --vpc-ids f81d4fae-7dec-11d0-a765-00a0c91e6bf6,3f900b61-30d7-40d8-9711-8c5d6264b268` | ||
|
||
cmdPeeringUpdate := CmdBuilder(cmd, RunVPCPeeringUpdate, "update <id>", | ||
"Update a VPC Peering's name", `Use this command to update the name of a VPC Peering`, Writer, aliasOpt("u")) | ||
AddStringFlag(cmdPeeringUpdate, doctl.ArgVPCPeeringName, "", "", | ||
"The VPC Peering's name", requiredOpt()) | ||
cmdPeeringUpdate.Example = `The following example updates the name of a VPC Peering with the ID ` + | ||
"`" + `f81d4fae-7dec-11d0-a765-00a0c91e6bf6` + "`" + ` to ` + "`" + `new-name` + "`" + | ||
`: doctl vpcs peerings update f81d4fae-7dec-11d0-a765-00a0c91e6bf6 --name new-name` | ||
|
||
cmdPeeringDelete := CmdBuilder(cmd, RunVPCPeeringDelete, "delete <id>", | ||
"Permanently delete a VPC Peering", `Permanently deletes the specified VPC Peering. This is irreversible.`, Writer, aliasOpt("d", "rm")) | ||
AddBoolFlag(cmdPeeringDelete, doctl.ArgForce, doctl.ArgShortForce, false, | ||
"Delete the VPC Peering without any confirmation prompt") | ||
AddBoolFlag(cmdPeeringDelete, doctl.ArgCommandWait, "", false, | ||
"Boolean that specifies whether to wait for a VPC Peering deletion to complete before returning control to the terminal") | ||
cmdPeeringDelete.Example = `The following example deletes the VPC Peering with the ID ` + "`" + `f81d4fae-7dec-11d0-a765-00a0c91e6bf6` + "`" + | ||
`: doctl vpcs peerings delete f81d4fae-7dec-11d0-a765-00a0c91e6bf6` | ||
|
||
return cmd | ||
} | ||
|
||
// RunVPCPeeringGet retrieves an existing VPC Peering by its identifier. | ||
func RunVPCPeeringGet(c *CmdConfig) error { | ||
err := ensureOneArg(c) | ||
if err != nil { | ||
return err | ||
} | ||
peeringID := c.Args[0] | ||
|
||
peering, err := c.VPCs().GetPeering(peeringID) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
item := &displayers.VPCPeering{VPCPeerings: do.VPCPeerings{*peering}} | ||
return c.Display(item) | ||
} | ||
|
||
// RunVPCPeeringCreate creates a new VPC Peering with a given configuration. | ||
func RunVPCPeeringCreate(c *CmdConfig) error { | ||
if len(c.Args) == 0 { | ||
return doctl.NewMissingArgsErr(c.NS) | ||
} | ||
peeringName := c.Args[0] | ||
|
||
r := new(godo.VPCPeeringCreateRequest) | ||
r.Name = peeringName | ||
|
||
vpcIDs, err := c.Doit.GetString(c.NS, doctl.ArgVPCPeeringVPCIDs) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
for _, v := range strings.Split(vpcIDs, ",") { | ||
if v == "" { | ||
return errors.New("VPC ID is empty") | ||
} | ||
|
||
r.VPCIDs = append(r.VPCIDs, strings.TrimSpace(v)) | ||
} | ||
|
||
if len(r.VPCIDs) != 2 { | ||
return errors.New("VPC IDs length should be 2") | ||
} | ||
|
||
vpcService := c.VPCs() | ||
peering, err := vpcService.CreateVPCPeering(r) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
wait, err := c.Doit.GetBool(c.NS, doctl.ArgCommandWait) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
if wait { | ||
notice("VPC Peering creation is in progress, waiting for VPC Peering to become active") | ||
|
||
err := waitForVPCPeering(vpcService, peering.ID, "ACTIVE", false) | ||
if err != nil { | ||
return fmt.Errorf("VPC Peering couldn't enter `active` state: %v", err) | ||
} | ||
|
||
peering, _ = vpcService.GetPeering(peering.ID) | ||
} | ||
|
||
item := &displayers.VPCPeering{VPCPeerings: do.VPCPeerings{*peering}} | ||
return c.Display(item) | ||
} | ||
|
||
// RunVPCPeeringList lists VPC Peerings | ||
func RunVPCPeeringList(c *CmdConfig) error { | ||
vpcID, err := c.Doit.GetString(c.NS, doctl.ArgVPCPeeringVPCID) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
var list do.VPCPeerings | ||
if vpcID == "" { | ||
list, err = c.VPCs().ListVPCPeerings() | ||
if err != nil { | ||
return err | ||
} | ||
} else { | ||
list, err = c.VPCs().ListVPCPeeringsByVPCID(vpcID) | ||
if err != nil { | ||
return err | ||
} | ||
} | ||
|
||
item := &displayers.VPCPeering{VPCPeerings: list} | ||
return c.Display(item) | ||
} | ||
|
||
// RunVPCPeeringUpdate updates an existing VPC Peering with new configuration. | ||
func RunVPCPeeringUpdate(c *CmdConfig) error { | ||
err := ensureOneArg(c) | ||
if err != nil { | ||
return err | ||
} | ||
peeringID := c.Args[0] | ||
|
||
r := new(godo.VPCPeeringUpdateRequest) | ||
name, err := c.Doit.GetString(c.NS, doctl.ArgVPCPeeringName) | ||
if err != nil { | ||
return err | ||
} | ||
r.Name = name | ||
|
||
peering, err := c.VPCs().UpdateVPCPeering(peeringID, r) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
item := &displayers.VPCPeering{VPCPeerings: do.VPCPeerings{*peering}} | ||
return c.Display(item) | ||
} | ||
|
||
// RunVPCPeeringDelete deletes a VPC Peering by its identifier. | ||
func RunVPCPeeringDelete(c *CmdConfig) error { | ||
if len(c.Args) == 0 { | ||
return doctl.NewMissingArgsErr(c.NS) | ||
} | ||
|
||
peeringID := c.Args[0] | ||
|
||
force, err := c.Doit.GetBool(c.NS, doctl.ArgForce) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
if force || AskForConfirmDelete("VPC Peering", 1) == nil { | ||
vpcs := c.VPCs() | ||
if err := vpcs.DeleteVPCPeering(peeringID); err != nil { | ||
return err | ||
} | ||
|
||
wait, err := c.Doit.GetBool(c.NS, doctl.ArgCommandWait) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
if wait { | ||
notice("VPC Peering deletion is in progress, waiting for VPC Peering to be deleted") | ||
|
||
err := waitForVPCPeering(vpcs, peeringID, "DELETED", true) | ||
if err != nil { | ||
return fmt.Errorf("VPC Peering couldn't be deleted : %v", err) | ||
} | ||
} | ||
|
||
} else { | ||
return fmt.Errorf("operation aborted") | ||
} | ||
notice("VPC Peering is successfully deleted") | ||
return nil | ||
} | ||
|
||
func waitForVPCPeering(vpcService do.VPCsService, peeringID string, wantStatus string, terminateOnNotFound bool) error { | ||
const maxAttempts = 360 | ||
const errStatus = "ERROR" | ||
attempts := 0 | ||
printNewLineSet := false | ||
|
||
for i := 0; i < maxAttempts; i++ { | ||
if attempts != 0 { | ||
fmt.Fprint(os.Stderr, ".") | ||
if !printNewLineSet { | ||
printNewLineSet = true | ||
defer fmt.Fprintln(os.Stderr) | ||
} | ||
} | ||
|
||
peering, err := vpcService.GetPeering(peeringID) | ||
if err != nil { | ||
if terminateOnNotFound && strings.Contains(err.Error(), "not found") { | ||
return nil | ||
} | ||
return err | ||
} | ||
|
||
if peering.Status == errStatus { | ||
return fmt.Errorf("VPC Peering (%s) entered status `%s`", peeringID, errStatus) | ||
} | ||
|
||
if peering.Status == wantStatus { | ||
return nil | ||
} | ||
|
||
attempts++ | ||
time.Sleep(5 * time.Second) | ||
} | ||
|
||
return fmt.Errorf("timeout waiting for VPC Peering (%s) to become %s", peeringID, wantStatus) | ||
} |
Oops, something went wrong.