Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(eip): Refactor eip using egoscale v3 #642

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
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
94 changes: 52 additions & 42 deletions cmd/elastic_ip_create.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,35 +3,31 @@ package cmd
import (
"fmt"
"strings"
"time"

"github.com/spf13/cobra"

"github.com/exoscale/cli/pkg/account"
"github.com/exoscale/cli/pkg/globalstate"
"github.com/exoscale/cli/pkg/output"
"github.com/exoscale/cli/utils"
egoscale "github.com/exoscale/egoscale/v2"
exoapi "github.com/exoscale/egoscale/v2/api"
v3 "github.com/exoscale/egoscale/v3"
)

type elasticIPCreateCmd struct {
cliCommandSettings `cli-cmd:"-"`

_ bool `cli-cmd:"create"`

Description string `cli-usage:"Elastic IP description"`
IPv6 bool `cli-flag:"ipv6" cli-usage:"create Elastic IPv6 prefix"`
HealthcheckInterval int64 `cli-usage:"managed Elastic IP health checking interval in seconds"`
HealthcheckMode string `cli-usage:"managed Elastic IP health checking mode (tcp|http|https)"`
HealthcheckPort int64 `cli-usage:"managed Elastic IP health checking port"`
HealthcheckStrikesFail int64 `cli-usage:"number of failed attempts before considering a managed Elastic IP health check unhealthy"`
HealthcheckStrikesOK int64 `cli-usage:"number of successful attempts before considering a managed Elastic IP health check healthy"`
HealthcheckTLSSNI string `cli-flag:"healthcheck-tls-sni" cli-usage:"managed Elastic IP health checking server name to present with SNI in https mode"`
HealthcheckTLSSSkipVerify bool `cli-flag:"healthcheck-tls-skip-verify" cli-usage:"disable TLS certificate verification for managed Elastic IP health checking in https mode"`
HealthcheckTimeout int64 `cli-usage:"managed Elastic IP health checking timeout in seconds"`
HealthcheckURI string `cli-usage:"managed Elastic IP health checking URI (required in http(s) mode)"`
Zone string `cli-short:"z" cli-usage:"Elastic IP zone"`
Description string `cli-usage:"Elastic IP description"`
IPv6 bool `cli-flag:"ipv6" cli-usage:"create Elastic IPv6 prefix"`
HealthcheckInterval int64 `cli-usage:"managed Elastic IP health checking interval in seconds"`
HealthcheckMode string `cli-usage:"managed Elastic IP health checking mode (tcp|http|https)"`
HealthcheckPort int64 `cli-usage:"managed Elastic IP health checking port"`
HealthcheckStrikesFail int64 `cli-usage:"number of failed attempts before considering a managed Elastic IP health check unhealthy"`
HealthcheckStrikesOK int64 `cli-usage:"number of successful attempts before considering a managed Elastic IP health check healthy"`
HealthcheckTLSSNI string `cli-flag:"healthcheck-tls-sni" cli-usage:"managed Elastic IP health checking server name to present with SNI in https mode"`
HealthcheckTLSSSkipVerify bool `cli-flag:"healthcheck-tls-skip-verify" cli-usage:"disable TLS certificate verification for managed Elastic IP health checking in https mode"`
HealthcheckTimeout int64 `cli-usage:"managed Elastic IP health checking timeout in seconds"`
HealthcheckURI string `cli-usage:"managed Elastic IP health checking URI (required in http(s) mode)"`
Zone v3.ZoneName `cli-short:"z" cli-usage:"Elastic IP zone"`
}

func (c *elasticIPCreateCmd) cmdAliases() []string { return gCreateAlias }
Expand All @@ -53,56 +49,70 @@ func (c *elasticIPCreateCmd) cmdPreRun(cmd *cobra.Command, args []string) error
}

func (c *elasticIPCreateCmd) cmdRun(_ *cobra.Command, _ []string) error {
ctx := exoapi.WithEndpoint(gContext, exoapi.NewReqEndpoint(account.CurrentAccount.Environment, c.Zone))
ctx := gContext
client, err := switchClientZoneV3(ctx, globalstate.EgoscaleV3Client, c.Zone)
mlec1 marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
return err
}

var healthcheck *egoscale.ElasticIPHealthcheck
var healthcheck *v3.ElasticIPHealthcheck
if c.HealthcheckMode != "" {
port := uint16(c.HealthcheckPort)
interval := time.Duration(c.HealthcheckInterval) * time.Second
timeout := time.Duration(c.HealthcheckTimeout) * time.Second

healthcheck = &egoscale.ElasticIPHealthcheck{
Interval: &interval,
Mode: &c.HealthcheckMode,
Port: &port,
StrikesFail: &c.HealthcheckStrikesFail,
StrikesOK: &c.HealthcheckStrikesOK,
Timeout: &timeout,
URI: func() (v *string) {
healthcheck = &v3.ElasticIPHealthcheck{
Interval: c.HealthcheckInterval,
Mode: v3.ElasticIPHealthcheckMode(c.HealthcheckMode),
Port: c.HealthcheckPort,
StrikesFail: c.HealthcheckStrikesFail,
StrikesOk: c.HealthcheckStrikesOK,
Timeout: c.HealthcheckTimeout,
URI: func() (v string) {
if strings.HasPrefix(c.HealthcheckMode, "http") {
v = &c.HealthcheckURI
v = c.HealthcheckURI
}
return
}(),
}

if c.HealthcheckMode == "https" {
healthcheck.TLSSkipVerify = &c.HealthcheckTLSSSkipVerify
healthcheck.TLSSNI = utils.NonEmptyStringPtr(c.HealthcheckTLSSNI)
healthcheck.TlsSkipVerify = &c.HealthcheckTLSSSkipVerify
healthcheck.TlsSNI = c.HealthcheckTLSSNI
}
}

elasticIP := &egoscale.ElasticIP{
Description: utils.NonEmptyStringPtr(c.Description),
createElasticIPRequest := v3.CreateElasticIPRequest{
Description: c.Description,
Healthcheck: healthcheck,
}

if c.IPv6 {
elasticIP.AddressFamily = utils.NonEmptyStringPtr("inet6")
createElasticIPRequest.Addressfamily = v3.CreateElasticIPRequestAddressfamilyInet6
}

var err error
decorateAsyncOperation("Creating Elastic IP...", func() {
elasticIP, err = globalstate.EgoscaleClient.CreateElasticIP(ctx, c.Zone, elasticIP)
err = decorateAsyncOperations("Creating Elastic IP...", func() error {
op, err := client.CreateElasticIP(ctx, createElasticIPRequest)
if err != nil {
return fmt.Errorf("exoscale: error while creating Elastic IP: %w", err)
}

_, err = client.Wait(ctx, op, v3.OperationStateSuccess)
if err != nil {
return fmt.Errorf("exoscale: error while waiting for Elastic IP creation: %w", err)
}

return nil
})

mlec1 marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
return err
}

return (&elasticIPShowCmd{
cliCommandSettings: c.cliCommandSettings,
ElasticIP: *elasticIP.ID,
Zone: c.Zone,
// Comment for reviewer:
// Is there a way to get the created Elastic IP address or UUID ???
// Listing all of them and comparing Addressfamily, Description,... doesn't really garantee uniquess
// TODO: Remove comment before merging
ElasticIP: "",
Zone: c.Zone,
Comment on lines +105 to +110
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes you need to get the op after waiting and there is the op.Reference.ID check if reference not nil before using

}).cmdRun(nil, nil)
}

Expand Down
37 changes: 28 additions & 9 deletions cmd/elastic_ip_delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,8 @@ import (

"github.com/spf13/cobra"

"github.com/exoscale/cli/pkg/account"
"github.com/exoscale/cli/pkg/globalstate"
exoapi "github.com/exoscale/egoscale/v2/api"
v3 "github.com/exoscale/egoscale/v3"
)

type elasticIPDeleteCmd struct {
Expand All @@ -18,8 +17,8 @@ type elasticIPDeleteCmd struct {

ElasticIP string `cli-arg:"#" cli-usage:"IP-ADDRESS|ID"`

Force bool `cli-short:"f" cli-usage:"don't prompt for confirmation"`
Zone string `cli-short:"z" cli-usage:"Elastic IP zone"`
Force bool `cli-short:"f" cli-usage:"don't prompt for confirmation"`
Zone v3.ZoneName `cli-short:"z" cli-usage:"Elastic IP zone"`
}

func (c *elasticIPDeleteCmd) cmdAliases() []string { return gRemoveAlias }
Expand All @@ -36,11 +35,20 @@ func (c *elasticIPDeleteCmd) cmdPreRun(cmd *cobra.Command, args []string) error
}

func (c *elasticIPDeleteCmd) cmdRun(_ *cobra.Command, _ []string) error {
ctx := exoapi.WithEndpoint(gContext, exoapi.NewReqEndpoint(account.CurrentAccount.Environment, c.Zone))
ctx := gContext
client, err := switchClientZoneV3(ctx, globalstate.EgoscaleV3Client, c.Zone)
if err != nil {
return err
}

elasticIPResp, err := client.ListElasticIPS(ctx)
if err != nil {
return err
}

elasticIP, err := globalstate.EgoscaleClient.FindElasticIP(ctx, c.Zone, c.ElasticIP)
elasticIP, err := elasticIPResp.FindElasticIP(c.ElasticIP)
if err != nil {
if errors.Is(err, exoapi.ErrNotFound) {
if errors.Is(err, v3.ErrNotFound) {
return fmt.Errorf("resource not found in zone %q", c.Zone)
}
return err
Expand All @@ -52,9 +60,20 @@ func (c *elasticIPDeleteCmd) cmdRun(_ *cobra.Command, _ []string) error {
}
}

decorateAsyncOperation(fmt.Sprintf("Deleting Elastic IP %s...", c.ElasticIP), func() {
err = globalstate.EgoscaleClient.DeleteElasticIP(ctx, c.Zone, elasticIP)
err = decorateAsyncOperations(fmt.Sprintf("Deleting Elastic IP %s...", c.ElasticIP), func() error {
op, err := client.DeleteElasticIP(ctx, elasticIP.ID)
if err != nil {
return fmt.Errorf("exoscale: error while deleting Elastic IP: %w", err)
}

_, err = client.Wait(ctx, op, v3.OperationStateSuccess)
if err != nil {
return fmt.Errorf("exoscale: error while waiting for Elastic IP deletion: %w", err)
}

return nil
})

mlec1 marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
return err
}
Expand Down
75 changes: 35 additions & 40 deletions cmd/elastic_ip_list.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,16 @@ import (

"github.com/spf13/cobra"

"github.com/exoscale/cli/pkg/account"
"github.com/exoscale/cli/pkg/globalstate"
"github.com/exoscale/cli/pkg/output"
"github.com/exoscale/cli/utils"
exoapi "github.com/exoscale/egoscale/v2/api"
v3 "github.com/exoscale/egoscale/v3"
)

type elasticIPListItemOutput struct {
ID string `json:"id"`
IPAddress string `json:"ip_address"`
Zone string `json:"zone"`
ID v3.UUID `json:"id"`
IPAddress string `json:"ip_address"`
Zone string `json:"zone"`
Description string `json:description`
}

type elasticIPListOutput []elasticIPListItemOutput
Expand All @@ -31,7 +30,7 @@ type elasticIPListCmd struct {

_ bool `cli-cmd:"list"`

Zone string `cli-short:"z" cli-usage:"zone to filter results to"`
Zone v3.ZoneName `cli-short:"z" cli-usage:"zone to filter results to"`
}

func (c *elasticIPListCmd) cmdAliases() []string { return gListAlias }
Expand All @@ -50,51 +49,47 @@ func (c *elasticIPListCmd) cmdPreRun(cmd *cobra.Command, args []string) error {
}

func (c *elasticIPListCmd) cmdRun(_ *cobra.Command, _ []string) error {
var zones []string
client := globalstate.EgoscaleV3Client
ctx := gContext

resp, err := client.ListZones(ctx)
if err != nil {
return err
}
zones := resp.Zones

if c.Zone != "" {
zones = []string{c.Zone}
} else {
zones = utils.AllZones
endpoint, err := client.GetZoneAPIEndpoint(ctx, c.Zone)
if err != nil {
return err
}

zones = []v3.Zone{{APIEndpoint: endpoint}}
}

out := make(elasticIPListOutput, 0)
res := make(chan elasticIPListItemOutput)
done := make(chan struct{})
output := make(elasticIPListOutput, 0)

go func() {
for nlb := range res {
out = append(out, nlb)
}
done <- struct{}{}
}()
err := utils.ForEachZone(zones, func(zone string) error {
ctx := exoapi.WithEndpoint(gContext, exoapi.NewReqEndpoint(account.CurrentAccount.Environment, zone))
for _, zone := range zones {
c := client.WithEndpoint(zone.APIEndpoint)

list, err := globalstate.EgoscaleClient.ListElasticIPs(ctx, zone)
resp, err := c.ListElasticIPS(ctx)
if err != nil {
return fmt.Errorf("unable to list Elastic IP addresses in zone %s: %w", zone, err)
_, _ = fmt.Fprintf(os.Stderr,
"warning: errors during listing, results might be incomplete.\n%s\n", err) // nolint:golint
continue
}

for _, e := range list {
res <- elasticIPListItemOutput{
ID: *e.ID,
IPAddress: e.IPAddress.String(),
Zone: zone,
}
for _, elasticIP := range resp.ElasticIPS {
output = append(output, elasticIPListItemOutput{
ID: elasticIP.ID,
IPAddress: elasticIP.IP,
Zone: string(zone.Name),
mlec1 marked this conversation as resolved.
Show resolved Hide resolved
Description: elasticIP.Description,
})
}

return nil
})
if err != nil {
_, _ = fmt.Fprintf(os.Stderr,
"warning: errors during listing, results might be incomplete.\n%s\n", err) // nolint:golint
}

close(res)
<-done

return c.outputFunc(&out, nil)
return c.outputFunc(&output, nil)
}

func init() {
Expand Down
Loading