From 9aae29d46942c982f6e8b67fd59e69e2fb7f4f72 Mon Sep 17 00:00:00 2001 From: Vasubabu <3358152+vasubabu@users.noreply.github.com> Date: Thu, 3 Aug 2023 20:44:38 +0530 Subject: [PATCH] Added support for Metal Interconnections --- cmd/cli.go | 2 + docs/metal.md | 1 + docs/metal_interconnections.md | 36 +++++++ docs/metal_interconnections_create.md | 55 +++++++++++ docs/metal_interconnections_delete.md | 45 +++++++++ docs/metal_interconnections_get.md | 55 +++++++++++ go.mod | 2 +- go.sum | 4 +- internal/interconnections/create.go | 71 ++++++++++++++ internal/interconnections/createvc.go | 85 ++++++++++++++++ internal/interconnections/createvlanvc.go | 81 ++++++++++++++++ internal/interconnections/createvrfvc.go | 96 +++++++++++++++++++ internal/interconnections/delete.go | 37 +++++++ internal/interconnections/interconnections.go | 52 ++++++++++ internal/interconnections/retrieve.go | 72 ++++++++++++++ internal/interconnections/update.go | 84 ++++++++++++++++ internal/pagination/pager.go | 20 ++++ 17 files changed, 795 insertions(+), 3 deletions(-) create mode 100644 docs/metal_interconnections.md create mode 100644 docs/metal_interconnections_create.md create mode 100644 docs/metal_interconnections_delete.md create mode 100644 docs/metal_interconnections_get.md create mode 100644 internal/interconnections/create.go create mode 100644 internal/interconnections/createvc.go create mode 100644 internal/interconnections/createvlanvc.go create mode 100644 internal/interconnections/createvrfvc.go create mode 100644 internal/interconnections/delete.go create mode 100644 internal/interconnections/interconnections.go create mode 100644 internal/interconnections/retrieve.go create mode 100644 internal/interconnections/update.go diff --git a/cmd/cli.go b/cmd/cli.go index 41ee8629..a245d30e 100644 --- a/cmd/cli.go +++ b/cmd/cli.go @@ -15,6 +15,7 @@ import ( "github.com/equinix/metal-cli/internal/gateway" "github.com/equinix/metal-cli/internal/hardware" initPkg "github.com/equinix/metal-cli/internal/init" + "github.com/equinix/metal-cli/internal/interconnections" "github.com/equinix/metal-cli/internal/ips" "github.com/equinix/metal-cli/internal/metros" "github.com/equinix/metal-cli/internal/organizations" @@ -93,5 +94,6 @@ func (cli *Cli) RegisterCommands(client *root.Client) { twofa.NewClient(client, cli.Outputer).NewCommand(), gateway.NewClient(client, cli.Outputer).NewCommand(), ports.NewClient(client, cli.Outputer).NewCommand(), + interconnections.NewClient(client, cli.Outputer).NewCommand(), ) } diff --git a/docs/metal.md b/docs/metal.md index b20f223a..c3974cd6 100644 --- a/docs/metal.md +++ b/docs/metal.md @@ -36,6 +36,7 @@ Command line interface for Equinix Metal * [metal gateway](metal_gateway.md) - Metal Gateway operations: create, delete, and retrieve. * [metal hardware-reservation](metal_hardware-reservation.md) - Hardware reservation operations: get, move. * [metal init](metal_init.md) - Create a configuration file. +* [metal interconnections](metal_interconnections.md) - interconnections operations: create, get. * [metal ip](metal_ip.md) - IP address, reservations, and assignment operations: assign, unassign, remove, available, request and get. * [metal metros](metal_metros.md) - Metro operations: get. * [metal operating-systems](metal_operating-systems.md) - Operating system operations: get. diff --git a/docs/metal_interconnections.md b/docs/metal_interconnections.md new file mode 100644 index 00000000..2a2d4e15 --- /dev/null +++ b/docs/metal_interconnections.md @@ -0,0 +1,36 @@ +## metal interconnections + +interconnections operations: create, get. + +### Synopsis + +Get information on Metro locations. For more information on https://deploy.equinix.com/developers/docs/metal/interconnections. + +### Options + +``` + -h, --help help for interconnections +``` + +### Options inherited from parent commands + +``` + --config string Path to JSON or YAML configuration file + --exclude strings Comma separated Href references to collapse in results, may be dotted three levels deep + --filter stringArray Filter 'get' actions with name value pairs. Filter is not supported by all resources and is implemented as request query parameters. + --http-header strings Headers to add to requests (in format key=value) + --include strings Comma separated Href references to expand in results, may be dotted three levels deep + -o, --output string Output format (*table, json, yaml). env output formats are (*sh, terraform, capp). + --search string Search keyword for use in 'get' actions. Search is not supported by all resources. + --sort-by string Sort fields for use in 'get' actions. Sort is not supported by all resources. + --sort-dir string Sort field direction for use in 'get' actions. Sort is not supported by all resources. + --token string Metal API Token (METAL_AUTH_TOKEN) +``` + +### SEE ALSO + +* [metal](metal.md) - Command line interface for Equinix Metal +* [metal interconnections create](metal_interconnections_create.md) - Creates an interconnection. +* [metal interconnections delete](metal_interconnections_delete.md) - Deletes a interconnection. +* [metal interconnections get](metal_interconnections_get.md) - Retrieves interconnections for the current user, an organization, a project or the details of a specific interconnection. + diff --git a/docs/metal_interconnections_create.md b/docs/metal_interconnections_create.md new file mode 100644 index 00000000..ed67b89c --- /dev/null +++ b/docs/metal_interconnections_create.md @@ -0,0 +1,55 @@ +## metal interconnections create + +Creates an interconnection. + +### Synopsis + +Creates a new interconnection as per the organization ID or project ID + +``` +metal interconnections create -n [-m ] [-r ] [-t ] [-p ] | [-O ] [flags] +``` + +### Examples + +``` + # Creates a new interconnection named "it-interconnection": + metal interconnections create -n [-m ] [-r ] [-t "dedicated" ] [-p ] | [-O ] + + metal interconnections create -n [-m ] [-r ] [-t "shared" ] [-p ] | [-O ] -T + + metal interconnections create -n [-m ] [-r ] [-t "shared" ] [-p ] | [-O ] -T -v +``` + +### Options + +``` + -h, --help help for create + -m, --metro string metro in the interconnection + -n, --name string Name of the interconnection + -O, --organizationID string Org ID + -p, --projectID string project ID + -r, --redundancy string Website URL of the organization. + -t, --type string type of of interconnection. + -v, --vrfs strings Return only the specified vrfs. +``` + +### Options inherited from parent commands + +``` + --config string Path to JSON or YAML configuration file + --exclude strings Comma separated Href references to collapse in results, may be dotted three levels deep + --filter stringArray Filter 'get' actions with name value pairs. Filter is not supported by all resources and is implemented as request query parameters. + --http-header strings Headers to add to requests (in format key=value) + --include strings Comma separated Href references to expand in results, may be dotted three levels deep + -o, --output string Output format (*table, json, yaml). env output formats are (*sh, terraform, capp). + --search string Search keyword for use in 'get' actions. Search is not supported by all resources. + --sort-by string Sort fields for use in 'get' actions. Sort is not supported by all resources. + --sort-dir string Sort field direction for use in 'get' actions. Sort is not supported by all resources. + --token string Metal API Token (METAL_AUTH_TOKEN) +``` + +### SEE ALSO + +* [metal interconnections](metal_interconnections.md) - interconnections operations: create, get. + diff --git a/docs/metal_interconnections_delete.md b/docs/metal_interconnections_delete.md new file mode 100644 index 00000000..3e92357a --- /dev/null +++ b/docs/metal_interconnections_delete.md @@ -0,0 +1,45 @@ +## metal interconnections delete + +Deletes a interconnection. + +### Synopsis + +Deletes the specified interconnection. + +``` +metal interconnections delete -i [flags] +``` + +### Examples + +``` + # Deletes the specified interconnection: + metal interconnections delete -i 7ec86e23-8dcf-48ed-bd9b-c25c20958277 +``` + +### Options + +``` + -h, --help help for delete + -i, --id string The UUID of the interconnection. +``` + +### Options inherited from parent commands + +``` + --config string Path to JSON or YAML configuration file + --exclude strings Comma separated Href references to collapse in results, may be dotted three levels deep + --filter stringArray Filter 'get' actions with name value pairs. Filter is not supported by all resources and is implemented as request query parameters. + --http-header strings Headers to add to requests (in format key=value) + --include strings Comma separated Href references to expand in results, may be dotted three levels deep + -o, --output string Output format (*table, json, yaml). env output formats are (*sh, terraform, capp). + --search string Search keyword for use in 'get' actions. Search is not supported by all resources. + --sort-by string Sort fields for use in 'get' actions. Sort is not supported by all resources. + --sort-dir string Sort field direction for use in 'get' actions. Sort is not supported by all resources. + --token string Metal API Token (METAL_AUTH_TOKEN) +``` + +### SEE ALSO + +* [metal interconnections](metal_interconnections.md) - interconnections operations: create, get. + diff --git a/docs/metal_interconnections_get.md b/docs/metal_interconnections_get.md new file mode 100644 index 00000000..9d8f7793 --- /dev/null +++ b/docs/metal_interconnections_get.md @@ -0,0 +1,55 @@ +## metal interconnections get + +Retrieves interconnections for the current user, an organization, a project or the details of a specific interconnection. + +### Synopsis + +Retrieves interconnections for the current user, an organization, a project or the details of a specific interconnection. + +``` +metal interconnections get [flags] +``` + +### Examples + +``` + # Retrieve all interconnections of a current user:: + + # Retrieve the details of a specific interconnection: + metal interconnections get -i e9a969b3-8911-4667-9d99-57cd3dd4ef6f + + # Retrieve all the interconnection of an organization: + metal interconnections get -O c079178c-9557-48f2-9ce7-cfb927b81928 + + # Retrieve all interconnection of a project: + metal interconnections get -p 1867ee8f-6a11-470a-9505-952d6a324040 +``` + +### Options + +``` + -i, --connID string UUID of the interconnection + -h, --help help for get + -O, --organizationID string UUID of the organization + -p, --projectID string Project ID (METAL_PROJECT_ID) +``` + +### Options inherited from parent commands + +``` + --config string Path to JSON or YAML configuration file + --exclude strings Comma separated Href references to collapse in results, may be dotted three levels deep + --filter stringArray Filter 'get' actions with name value pairs. Filter is not supported by all resources and is implemented as request query parameters. + --http-header strings Headers to add to requests (in format key=value) + --include strings Comma separated Href references to expand in results, may be dotted three levels deep + -o, --output string Output format (*table, json, yaml). env output formats are (*sh, terraform, capp). + --search string Search keyword for use in 'get' actions. Search is not supported by all resources. + --sort-by string Sort fields for use in 'get' actions. Sort is not supported by all resources. + --sort-dir string Sort field direction for use in 'get' actions. Sort is not supported by all resources. + --token string Metal API Token (METAL_AUTH_TOKEN) +``` + +### SEE ALSO + +* [metal interconnections](metal_interconnections.md) - interconnections operations: create, get. + diff --git a/go.mod b/go.mod index 494b1316..2ac9efde 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/equinix/metal-cli go 1.19 require ( - github.com/equinix-labs/metal-go v0.23.1 + github.com/equinix-labs/metal-go v0.24.0 github.com/manifoldco/promptui v0.9.0 github.com/olekukonko/tablewriter v0.0.5 github.com/packethost/packngo v0.30.0 diff --git a/go.sum b/go.sum index ad899496..63f2c92a 100644 --- a/go.sum +++ b/go.sum @@ -62,8 +62,8 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/equinix-labs/metal-go v0.23.1 h1:u6rdCKW7ZN/ydxS63+cbPMjHk8wYiVPYJsb8LB1sXZM= -github.com/equinix-labs/metal-go v0.23.1/go.mod h1:SmxCklxW+KjmBLVMdEXgtFO5gD5/b4N0VxcNgUYbOH4= +github.com/equinix-labs/metal-go v0.24.0 h1:dxIZXG3P/KKHOLmFfiDpwxMmahfiwFqbzk/i0OPETvA= +github.com/equinix-labs/metal-go v0.24.0/go.mod h1:SmxCklxW+KjmBLVMdEXgtFO5gD5/b4N0VxcNgUYbOH4= github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= diff --git a/internal/interconnections/create.go b/internal/interconnections/create.go new file mode 100644 index 00000000..c086a79a --- /dev/null +++ b/internal/interconnections/create.go @@ -0,0 +1,71 @@ +package interconnections + +import ( + "context" + "fmt" + + metal "github.com/equinix-labs/metal-go/metal/v1" + "github.com/spf13/cobra" +) + +func (c *Client) Create() *cobra.Command { + var name, metro, redundancy, connType, projectID, organizationID string + var vrfs []string + + createInterconnectionsCmd := &cobra.Command{ + Use: `create -n [-m ] [-r ] [-t ] [-p ] | [-O ]`, + Short: "Creates an interconnection.", + Long: "Creates a new interconnection as per the organization ID or project ID ", + Example: ` # Creates a new interconnection named "it-interconnection": + metal interconnections create -n [-m ] [-r ] [-t "dedicated" ] [-p ] | [-O ] + + metal interconnections create -n [-m ] [-r ] [-t "shared" ] [-p ] | [-O ] -T + + metal interconnections create -n [-m ] [-r ] [-t "shared" ] [-p ] | [-O ] -T -v `, + + RunE: func(cmd *cobra.Command, args []string) error { + cmd.SilenceUsage = true + var interconn *metal.Interconnection + var err error + + createOrganizationInterconnectionRequest := metal.CreateOrganizationInterconnectionRequest{DedicatedPortCreateInput: metal.NewDedicatedPortCreateInput(metro, name, redundancy, metal.DedicatedPortCreateInputType(connType))} + if projectID != "" { + + interconn, _, err = c.Service.CreateProjectInterconnection(context.Background(), projectID).CreateOrganizationInterconnectionRequest(createOrganizationInterconnectionRequest).Execute() + if err != nil { + return fmt.Errorf("could not create interconnections: %w", err) + + } + } else if organizationID != "" { + interconn, _, err = c.Service.CreateOrganizationInterconnection(context.Background(), organizationID).CreateOrganizationInterconnectionRequest(createOrganizationInterconnectionRequest).Execute() + if err != nil { + return fmt.Errorf("could not create interconnections: %w", err) + } + } else { + return fmt.Errorf("Could you provide at least either of projectID OR organizationID") + } + + data := make([][]string, 1) + + data[0] = []string{interconn.GetId(), interconn.GetName(), string(interconn.GetType()), interconn.GetCreatedAt().String()} + header := []string{"ID", "Name", "Type", "Created"} + + return c.Out.Output(interconn, header, &data) + }, + } + + createInterconnectionsCmd.Flags().StringVarP(&name, "name", "n", "", "Name of the interconnection") + createInterconnectionsCmd.Flags().StringVarP(&metro, "metro", "m", "", "metro in the interconnection") + createInterconnectionsCmd.Flags().StringVarP(&redundancy, "redundancy", "r", "", "Website URL of the organization.") + createInterconnectionsCmd.Flags().StringVarP(&connType, "type", "t", "", "type of of interconnection.") + // createInterconnectionsCmd.Flags().StringVarP(&connType, "serviceTokentype", "T", "", "service token type for interconnection either fabric OR Metal builds") + createInterconnectionsCmd.Flags().StringSliceVarP(&vrfs, "vrfs", "v", []string{}, "Return only the specified vrfs.") + createInterconnectionsCmd.Flags().StringVarP(&projectID, "projectID", "p", "", "project ID") + createInterconnectionsCmd.Flags().StringVarP(&organizationID, "organizationID", "O", "", "Org ID") + + _ = createInterconnectionsCmd.MarkFlagRequired("name") + _ = createInterconnectionsCmd.MarkFlagRequired("metro") + _ = createInterconnectionsCmd.MarkFlagRequired("redundancy") + _ = createInterconnectionsCmd.MarkFlagRequired("type") + return createInterconnectionsCmd +} diff --git a/internal/interconnections/createvc.go b/internal/interconnections/createvc.go new file mode 100644 index 00000000..96f0fea1 --- /dev/null +++ b/internal/interconnections/createvc.go @@ -0,0 +1,85 @@ +package interconnections + +import ( + "context" + "fmt" + + metal "github.com/equinix-labs/metal-go/metal/v1" + "github.com/spf13/cobra" +) + +func (c *Client) CreateVirtualCricuit() *cobra.Command { + var connectionID, portID, name, description, projectID, vlanID string + var vlan, speed int + var tags []string + + createVirtualCricuitCmd := &cobra.Command{ + Use: `create-virtual-circuit [-i connection_id] [-p port_id] [-P ] --n [-d ] [-v ] [-t ] [-vlan ] [-speed ]`, + Short: "Creates an create-virtual-circuit for specific interconnection.", + Long: "Creates an create-virtual-circuit for specific interconnection", + Example: ` # Creates a new interconnection named "it-interconnection": + metal interconnections create-virtual-circuit [-i connection_id] [-p port_id] [-P ] --n [-d ] [-v ] [-t ] [-vlan ] [-speed ] + + metal interconnections create-virtual-circuit -n [-m ] [-r ] [-t "shared" ] [-p ] | [-O ] -T + + metal interconnections create-virtual-circuit -n [-m ] [-r ] [-t "shared" ] [-p ] | [-O ] -T -v `, + + RunE: func(cmd *cobra.Command, args []string) error { + cmd.SilenceUsage = true + vlanVirtualCircuitCreateInput := metal.NewVlanVirtualCircuitCreateInput(projectID) + virtualCircuitCreateInput := metal.VirtualCircuitCreateInput{VlanVirtualCircuitCreateInput: vlanVirtualCircuitCreateInput} + + if description != "" { + virtualCircuitCreateInput.VlanVirtualCircuitCreateInput.SetDescription(description) + } + + if name != "" { + virtualCircuitCreateInput.VlanVirtualCircuitCreateInput.SetName(name) + } + + if vlan > 0 { + virtualCircuitCreateInput.VlanVirtualCircuitCreateInput.SetNniVlan(int32(vlan)) + } + + if speed > 0 { + virtualCircuitCreateInput.VlanVirtualCircuitCreateInput.SetSpeed(int32(speed)) + } + + if len(tags) > 0 { + virtualCircuitCreateInput.VlanVirtualCircuitCreateInput.SetTags(tags) + } + + if vlanID != "" { + virtualCircuitCreateInput.VlanVirtualCircuitCreateInput.SetVnid(vlanID) + } + + vc, _, err := c.Service.CreateInterconnectionPortVirtualCircuit(context.Background(), connectionID, portID).VirtualCircuitCreateInput(virtualCircuitCreateInput).Execute() + if err != nil { + return fmt.Errorf("could not create interconnections: %w", err) + } + + data := make([][]string, 1) + + data[0] = []string{vc.VlanVirtualCircuit.GetId(), vc.VlanVirtualCircuit.GetName(), vc.VlanVirtualCircuit.GetDescription(), vc.VlanVirtualCircuit.GetCreatedAt().String()} + header := []string{"ID", "Name", "Description", "Created"} + + return c.Out.Output(vc.VlanVirtualCircuit, header, &data) + + }, + } + + createVirtualCricuitCmd.Flags().StringVarP(&connectionID, "id", "i", "", "The UUID of the interconnection.") + createVirtualCricuitCmd.Flags().StringVarP(&portID, "port", "p", "", "The UUID of the port.") + createVirtualCricuitCmd.Flags().StringVarP(&projectID, "projectId", "P", "", "The UUID of the projectID.") + createVirtualCricuitCmd.Flags().StringVarP(&name, "name", "n", "", "Name of the interconnection") + createVirtualCricuitCmd.Flags().StringVarP(&description, "description", "d", "", "Adds or updates the description for the interconnection.") + createVirtualCricuitCmd.Flags().StringVarP(&vlanID, "vID", "v", "", "The UUID of the VLAN.") + createVirtualCricuitCmd.Flags().IntVarP(&vlan, "vlan", "", 0, "Adds or updates vlan Must be between 2 and 3999") + createVirtualCricuitCmd.Flags().IntVarP(&speed, "speed", "", 0, "bps speed or string (e.g. 52 - '52m' or '100g' or '4 gbps')") + createVirtualCricuitCmd.Flags().StringSliceVarP(&tags, "tags", "t", []string{}, "Return only the specified tags.") + + _ = createVirtualCricuitCmd.MarkFlagRequired("id") + _ = createVirtualCricuitCmd.MarkFlagRequired("portId") + _ = createVirtualCricuitCmd.MarkFlagRequired("projectId") + return createVirtualCricuitCmd +} diff --git a/internal/interconnections/createvlanvc.go b/internal/interconnections/createvlanvc.go new file mode 100644 index 00000000..91c11ec6 --- /dev/null +++ b/internal/interconnections/createvlanvc.go @@ -0,0 +1,81 @@ +package interconnections + +import ( + "context" + "fmt" + + metal "github.com/equinix-labs/metal-go/metal/v1" + "github.com/spf13/cobra" +) + +func (c *Client) CreateVlanVirtualCricuit() *cobra.Command { + var connectionID, portID, name, description, projectID, vlanID string + var vlan, speed int + var tags []string + + createVirtualCricuitCmd := &cobra.Command{ + Use: `create-virtual-circuit [-i connection_id] [-p port_id] [-P ] --n [-d ] [-v ] [-t ] [-vlan ] [-speed ]`, + Short: "Creates an vlan create-virtual-circuit for specific interconnection.", + Long: "Creates an vlan create-virtual-circuit for specific interconnection", + Example: ` # Creates a new interconnection named "it-interconnection": + metal interconnections create-virtual-circuit [-i connection_id] [-p port_id] [-P ] --n [-d ] [-v ] [-t ] [-vlan ] [-speed ]`, + + RunE: func(cmd *cobra.Command, args []string) error { + cmd.SilenceUsage = true + vlanVirtualCircuitCreateInput := metal.NewVlanVirtualCircuitCreateInput(projectID) + virtualCircuitCreateInput := metal.VirtualCircuitCreateInput{VlanVirtualCircuitCreateInput: vlanVirtualCircuitCreateInput} + + if description != "" { + virtualCircuitCreateInput.VlanVirtualCircuitCreateInput.SetDescription(description) + } + + if name != "" { + virtualCircuitCreateInput.VlanVirtualCircuitCreateInput.SetName(name) + } + + if vlan > 0 { + virtualCircuitCreateInput.VlanVirtualCircuitCreateInput.SetNniVlan(int32(vlan)) + } + + if speed > 0 { + virtualCircuitCreateInput.VlanVirtualCircuitCreateInput.SetSpeed(int32(speed)) + } + + if len(tags) > 0 { + virtualCircuitCreateInput.VlanVirtualCircuitCreateInput.SetTags(tags) + } + + if vlanID != "" { + virtualCircuitCreateInput.VlanVirtualCircuitCreateInput.SetVnid(vlanID) + } + + vc, _, err := c.Service.CreateInterconnectionPortVirtualCircuit(context.Background(), connectionID, portID).VirtualCircuitCreateInput(virtualCircuitCreateInput).Execute() + if err != nil { + return fmt.Errorf("could not create interconnections: %w", err) + } + + data := make([][]string, 1) + + data[0] = []string{vc.VlanVirtualCircuit.GetId(), vc.VlanVirtualCircuit.GetName(), vc.VlanVirtualCircuit.GetDescription(), vc.VlanVirtualCircuit.GetCreatedAt().String()} + header := []string{"ID", "Name", "Description", "Created"} + + return c.Out.Output(vc.VlanVirtualCircuit, header, &data) + + }, + } + + createVirtualCricuitCmd.Flags().StringVarP(&connectionID, "id", "i", "", "The UUID of the interconnection.") + createVirtualCricuitCmd.Flags().StringVarP(&portID, "port", "p", "", "The UUID of the port.") + createVirtualCricuitCmd.Flags().StringVarP(&projectID, "projectId", "P", "", "The UUID of the projectID.") + createVirtualCricuitCmd.Flags().StringVarP(&name, "name", "n", "", "Name of the interconnection") + createVirtualCricuitCmd.Flags().StringVarP(&description, "description", "d", "", "Adds or updates the description for the interconnection.") + createVirtualCricuitCmd.Flags().StringVarP(&vlanID, "vID", "v", "", "The UUID of the VLAN.") + createVirtualCricuitCmd.Flags().IntVarP(&vlan, "vlan", "", 0, "Adds or updates vlan Must be between 2 and 3999") + createVirtualCricuitCmd.Flags().IntVarP(&speed, "speed", "", 0, "bps speed or string (e.g. 52 - '52m' or '100g' or '4 gbps')") + createVirtualCricuitCmd.Flags().StringSliceVarP(&tags, "tags", "t", []string{}, "Return only the specified tags.") + + _ = createVirtualCricuitCmd.MarkFlagRequired("id") + _ = createVirtualCricuitCmd.MarkFlagRequired("portId") + _ = createVirtualCricuitCmd.MarkFlagRequired("projectId") + return createVirtualCricuitCmd +} diff --git a/internal/interconnections/createvrfvc.go b/internal/interconnections/createvrfvc.go new file mode 100644 index 00000000..6997b18f --- /dev/null +++ b/internal/interconnections/createvrfvc.go @@ -0,0 +1,96 @@ +package interconnections + +import ( + "context" + "fmt" + + metal "github.com/equinix-labs/metal-go/metal/v1" + "github.com/spf13/cobra" +) + +func (c *Client) CreateVrfVirtualCricuit() *cobra.Command { + var connectionID, portID, name, description, projectID string + var customerIp, md5, metalIp, subnet, vrf string + var vlan, speed, peerAsn int + var tags []string + + createVirtualCricuitCmd := &cobra.Command{ + Use: `create-virtual-circuit [-i connection_id] [-p port_id] [-P ] --n [-d ] [-v ] [-t ] [-vlan ] [-speed ]`, + Short: "Creates an VRF create-virtual-circuit for specific interconnection.", + Long: "Creates an VRF create-virtual-circuit for specific interconnection", + Example: ` # Creates a new interconnection named "it-interconnection": + metal interconnections create-virtual-circuit [-i connection_id] [-p port_id] [-P ] --n [-d ] [-t ] [-vlan ] [-speed ]`, + + RunE: func(cmd *cobra.Command, args []string) error { + cmd.SilenceUsage = true + VrfVirtualCircuitCreateInput := metal.NewVrfVirtualCircuitCreateInput(int32(vlan), int32(peerAsn), projectID, subnet, vrf) + virtualCircuitCreateInput := metal.VirtualCircuitCreateInput{VrfVirtualCircuitCreateInput: VrfVirtualCircuitCreateInput} + + if description != "" { + virtualCircuitCreateInput.VrfVirtualCircuitCreateInput.SetDescription(description) + } + + if name != "" { + virtualCircuitCreateInput.VrfVirtualCircuitCreateInput.SetName(name) + } + + if metalIp != "" { + virtualCircuitCreateInput.VrfVirtualCircuitCreateInput.SetMetalIp(metalIp) + } + + if md5 != "" { + virtualCircuitCreateInput.VrfVirtualCircuitCreateInput.SetMd5(md5) + } + + if customerIp != "" { + virtualCircuitCreateInput.VrfVirtualCircuitCreateInput.SetCustomerIp(customerIp) + } + + if speed > 0 { + virtualCircuitCreateInput.VrfVirtualCircuitCreateInput.SetSpeed(int32(speed)) + } + + if len(tags) > 0 { + virtualCircuitCreateInput.VrfVirtualCircuitCreateInput.SetTags(tags) + } + + vc, _, err := c.Service.CreateInterconnectionPortVirtualCircuit(context.Background(), connectionID, portID).VirtualCircuitCreateInput(virtualCircuitCreateInput).Execute() + if err != nil { + return fmt.Errorf("could not create VRF interconnections: %w", err) + } + + data := make([][]string, 1) + + data[0] = []string{vc.VlanVirtualCircuit.GetId(), vc.VlanVirtualCircuit.GetName(), vc.VlanVirtualCircuit.GetDescription(), vc.VlanVirtualCircuit.GetCreatedAt().String()} + header := []string{"ID", "Name", "Description", "Created"} + + return c.Out.Output(vc.VlanVirtualCircuit, header, &data) + + }, + } + + createVirtualCricuitCmd.Flags().StringVarP(&connectionID, "id", "i", "", "The UUID of the interconnection.") + createVirtualCricuitCmd.Flags().StringVarP(&portID, "port", "p", "", "The UUID of the port.") + createVirtualCricuitCmd.Flags().StringVarP(&projectID, "projectId", "P", "", "The UUID of the projectID.") + createVirtualCricuitCmd.Flags().StringVarP(&name, "name", "n", "", "Name of the interconnection") + createVirtualCricuitCmd.Flags().StringVarP(&description, "description", "d", "", "Adds or updates the description for the interconnection.") + createVirtualCricuitCmd.Flags().StringVarP(&customerIp, "customerIp", "c", "", "Adds or updates the description for the interconnection.") + createVirtualCricuitCmd.Flags().StringVarP(&md5, "md5", "m", "", "The plaintext BGP peering password shared by neighbors as an MD5 checksum") + createVirtualCricuitCmd.Flags().StringVarP(&metalIp, "metalIp", "M", "", "An IP address from the subnet that will be used on the Metal side") + + createVirtualCricuitCmd.Flags().StringVarP(&subnet, "subnet", "s", "", "The /30 or /31 subnet of one of the VRF IP Blocks that will be used with the VRF ") + createVirtualCricuitCmd.Flags().IntVarP(&peerAsn, "peerAsn", "a", 0, "The peer ASN that will be used with the VRF on the Virtual Circuit.") + createVirtualCricuitCmd.Flags().IntVarP(&vlan, "vlan", "", 0, "Adds or updates vlan Must be between 2 and 3999") + createVirtualCricuitCmd.Flags().IntVarP(&speed, "speed", "", 0, "bps speed or string (e.g. 52 - '52m' or '100g' or '4 gbps')") + createVirtualCricuitCmd.Flags().StringSliceVarP(&tags, "tags", "t", []string{}, "Return only the specified tags.") + createVirtualCricuitCmd.Flags().StringVarP(&vrf, "vrf", "v", "", "The UUID of the VRF that will be associated with the Virtual Circuit.") + + _ = createVirtualCricuitCmd.MarkFlagRequired("id") + _ = createVirtualCricuitCmd.MarkFlagRequired("portId") + _ = createVirtualCricuitCmd.MarkFlagRequired("projectId") + _ = createVirtualCricuitCmd.MarkFlagRequired("subnet") + _ = createVirtualCricuitCmd.MarkFlagRequired("vlan") + _ = createVirtualCricuitCmd.MarkFlagRequired("peerAsn") + _ = createVirtualCricuitCmd.MarkFlagRequired("vrf") + return createVirtualCricuitCmd +} diff --git a/internal/interconnections/delete.go b/internal/interconnections/delete.go new file mode 100644 index 00000000..2a59a9c1 --- /dev/null +++ b/internal/interconnections/delete.go @@ -0,0 +1,37 @@ +package interconnections + +import ( + "context" + "fmt" + + "github.com/spf13/cobra" +) + +func (c *Client) Delete() *cobra.Command { + var connectionID string + + deleteConnectionCmd := &cobra.Command{ + Use: `delete -i `, + Short: "Deletes a interconnection.", + Long: "Deletes the specified interconnection.", + Example: ` # Deletes the specified interconnection: + metal interconnections delete -i 7ec86e23-8dcf-48ed-bd9b-c25c20958277`, + + RunE: func(cmd *cobra.Command, args []string) error { + cmd.SilenceUsage = true + + _, _, err := c.Service.DeleteInterconnection(context.Background(), connectionID).Execute() + if err != nil { + return err + } + fmt.Println("connection deletion initiated. Please check 'metal interconnections get -i", connectionID, "' for status") + + return nil + }, + } + + deleteConnectionCmd.Flags().StringVarP(&connectionID, "id", "i", "", "The UUID of the interconnection.") + _ = deleteConnectionCmd.MarkFlagRequired("id") + + return deleteConnectionCmd +} diff --git a/internal/interconnections/interconnections.go b/internal/interconnections/interconnections.go new file mode 100644 index 00000000..cf9ff838 --- /dev/null +++ b/internal/interconnections/interconnections.go @@ -0,0 +1,52 @@ +package interconnections + +import ( + metal "github.com/equinix-labs/metal-go/metal/v1" + "github.com/equinix/metal-cli/internal/outputs" + "github.com/spf13/cobra" +) + +type Client struct { + Servicer Servicer + Service metal.InterconnectionsApiService + Out outputs.Outputer +} + +func (c *Client) NewCommand() *cobra.Command { + cmd := &cobra.Command{ + Use: `interconnections`, + Aliases: []string{"conn"}, + Short: "interconnections operations: create, get.", + Long: "Get information on Metro locations. For more information on https://deploy.equinix.com/developers/docs/metal/interconnections.", + PersistentPreRun: func(cmd *cobra.Command, args []string) { + if root := cmd.Root(); root != nil { + if root.PersistentPreRun != nil { + root.PersistentPreRun(cmd, args) + } + } + c.Service = *c.Servicer.MetalAPI(cmd).InterconnectionsApi + }, + } + + cmd.AddCommand( + c.Retrieve(), + c.Create(), + c.Delete(), + ) + + return cmd +} + +type Servicer interface { + MetalAPI(*cobra.Command) *metal.APIClient + Filters() map[string]string + Includes(defaultIncludes []string) (incl []string) + Excludes(defaultExcludes []string) (excl []string) +} + +func NewClient(s Servicer, out outputs.Outputer) *Client { + return &Client{ + Servicer: s, + Out: out, + } +} diff --git a/internal/interconnections/retrieve.go b/internal/interconnections/retrieve.go new file mode 100644 index 00000000..81838277 --- /dev/null +++ b/internal/interconnections/retrieve.go @@ -0,0 +1,72 @@ +package interconnections + +import ( + "context" + "fmt" + + metal "github.com/equinix-labs/metal-go/metal/v1" + pager "github.com/equinix/metal-cli/internal/pagination" + "github.com/spf13/cobra" +) + +func (c *Client) Retrieve() *cobra.Command { + // metrosCmd represents the metros command + var projectID, organizationID, connID string + retrieveInterconnectionsCmd := &cobra.Command{ + Use: "get", + Aliases: []string{"list"}, + Short: "Retrieves interconnections for the current user, an organization, a project or the details of a specific interconnection.", + Long: "Retrieves interconnections for the current user, an organization, a project or the details of a specific interconnection.", + Example: ` # Retrieve all interconnections of a current user:: + + # Retrieve the details of a specific interconnection: + metal interconnections get -i e9a969b3-8911-4667-9d99-57cd3dd4ef6f + + # Retrieve all the interconnection of an organization: + metal interconnections get -O c079178c-9557-48f2-9ce7-cfb927b81928 + + # Retrieve all interconnection of a project: + metal interconnections get -p 1867ee8f-6a11-470a-9505-952d6a324040 `, + + RunE: func(cmd *cobra.Command, args []string) error { + cmd.SilenceUsage = true + var interConnections []metal.Interconnection + var proerr error + inc := []string{} + exc := []string{} + header := []string{"ID", "Name", "Code", "Type", "Created"} + if connID != "" && projectID != "" && organizationID != "" { + return fmt.Errorf("projectID, connID, and organizationID parameters are mutually exclusive") + } else if organizationID != "" { + interConnectionsList, _, err := c.Service.OrganizationListInterconnections(context.Background(), organizationID).Include(inc).Exclude(exc).Execute() + if err != nil { + return fmt.Errorf("could not list Organization Interconnections: %w", err) + } + interConnections = interConnectionsList.GetInterconnections() + } else if projectID != "" { + interConnections, proerr = pager.GetAllProjectInterconnections(c.Service, projectID, inc, exc) + if proerr != nil { + return fmt.Errorf("could not list Project Interconnections: %w", proerr) + } + } else if connID != "" { + interConnection, _, err := c.Service.GetInterconnection(context.Background(), connID).Include(inc).Exclude(exc).Execute() + if err != nil { + return fmt.Errorf("could not list Organization Interconnections: %w", err) + } + data := make([][]string, 1) + data[0] = []string{interConnection.GetId(), interConnection.GetName(), string(interConnection.GetType()), interConnection.GetCreatedAt().String()} + return c.Out.Output(interConnections, header, &data) + } + data := make([][]string, len(interConnections)) + + for i, interConn := range interConnections { + data[i] = []string{interConn.GetId(), interConn.GetName(), string(interConn.GetType()), interConn.GetCreatedAt().String()} + } + return c.Out.Output(interConnections, header, &data) + }, + } + retrieveInterconnectionsCmd.Flags().StringVarP(&projectID, "projectID", "p", "", "Project ID (METAL_PROJECT_ID)") + retrieveInterconnectionsCmd.Flags().StringVarP(&connID, "connID", "i", "", "UUID of the interconnection") + retrieveInterconnectionsCmd.Flags().StringVarP(&organizationID, "organizationID", "O", "", "UUID of the organization") + return retrieveInterconnectionsCmd +} diff --git a/internal/interconnections/update.go b/internal/interconnections/update.go new file mode 100644 index 00000000..9197ad2d --- /dev/null +++ b/internal/interconnections/update.go @@ -0,0 +1,84 @@ +package interconnections + +import ( + "context" + "fmt" + + metal "github.com/equinix-labs/metal-go/metal/v1" + "github.com/spf13/cobra" +) + +func (c *Client) Update() *cobra.Command { + var ( + description string + mode string + name string + contactEmail string + redundancy string + connectionID string + tags []string + ) + + // updateConnectionCmd represents the updateConnectionCmd command + updateConnectionCmd := &cobra.Command{ + Use: `update -i `, + Short: "Updates a connection.", + Long: "Updates a specified connection.", + Example: ` # Updates a specified connection.: + metal interconnections update --id 30c15082-a06e-4c43-bfc3-252616b46eba`, + + RunE: func(cmd *cobra.Command, args []string) error { + cmd.SilenceUsage = true + interconnectionUpdateInput := metal.NewInterconnectionUpdateInput() + + if description != "" { + interconnectionUpdateInput.SetDescription(description) + } + + if name != "" { + interconnectionUpdateInput.SetName(name) + } + // TO-DO + var v metal.InterconnectionMode + + if mode != "" { + + interconnectionUpdateInput.SetMode(v) + } + + if redundancy != "" { + interconnectionUpdateInput.SetRedundancy(redundancy) + } + + if contactEmail != "" { + interconnectionUpdateInput.SetContactEmail(contactEmail) + } + + if len(tags) > 0 { + interconnectionUpdateInput.SetTags(tags) + } + + interconn, _, err := c.Service.UpdateInterconnection(context.Background(), connectionID).InterconnectionUpdateInput(*interconnectionUpdateInput).Execute() + if err != nil { + return fmt.Errorf("could not update interconnection: %w", err) + } + data := make([][]string, 1) + + data[0] = []string{interconn.GetId(), interconn.GetName(), string(interconn.GetType()), interconn.GetCreatedAt().String()} + header := []string{"ID", "Name", "Type", "Created"} + + return c.Out.Output(interconn, header, &data) + }, + } + + updateConnectionCmd.Flags().StringVarP(&connectionID, "id", "i", "", "The UUID of the interconnection.") + updateConnectionCmd.Flags().StringVarP(&name, "name", "n", "", "The new name of the interconnection.") + updateConnectionCmd.Flags().StringVarP(&description, "description", "d", "", "Adds or updates the description for the interconnection.") + updateConnectionCmd.Flags().StringVarP(&mode, "mode", "m", "", "Adds or updates the mode for the interconnection.") + updateConnectionCmd.Flags().StringVarP(&contactEmail, "contactEmail", "e", "", "adds or updates the Email") + updateConnectionCmd.Flags().StringSliceVarP(&tags, "tags", "t", []string{}, `Adds or updates the tags for the connection --tags="tag1,tag2".`) + updateConnectionCmd.Flags().StringVarP(&redundancy, "redundancy", "r", "", "Updating from 'redundant' to 'primary' will remove a secondary port, while updating from 'primary' to 'redundant' will add one.") + + _ = updateConnectionCmd.MarkFlagRequired("id") + return updateConnectionCmd +} diff --git a/internal/pagination/pager.go b/internal/pagination/pager.go index 9272cf40..e2f27322 100644 --- a/internal/pagination/pager.go +++ b/internal/pagination/pager.go @@ -165,3 +165,23 @@ func GetAllIPReservations(s metal.IPAddressesApiService, projectId string, inc [ return ipReservations, nil } } + +func GetAllProjectInterconnections(s metal.InterconnectionsApiService, projectId string, include []string, exclude []string) ([]metal.Interconnection, error) { + var interConn []metal.Interconnection + + page := int32(1) // int32 | Page to return (optional) (default to 1) + perPage := int32(20) // int32 | Items returned per page (optional) (default to 10) + + for { + interConnPage, _, err := s.ProjectListInterconnections(context.Background(), projectId).Include(include).Exclude(exclude).Page(page).PerPage(perPage).Execute() + if err != nil { + return nil, err + } + interConn = append(interConn, interConnPage.GetInterconnections()...) + if interConnPage.Meta.GetLastPage() > interConnPage.Meta.GetCurrentPage() { + page = page + 1 + continue + } + return interConn, nil + } +}