Skip to content

Commit

Permalink
fix: use --poll-interval flag (#660)
Browse files Browse the repository at this point in the history
The `--poll-interval` flag was ignored since a refactoring in #293
(released first in v1.21.0). This adds back the functionality that was
lost then.
  • Loading branch information
phm07 authored Jan 9, 2024
1 parent 2df5e92 commit b9328a6
Show file tree
Hide file tree
Showing 8 changed files with 265 additions and 71 deletions.
9 changes: 9 additions & 0 deletions internal/cli/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (
"github.com/hetznercloud/cli/internal/cmd/version"
"github.com/hetznercloud/cli/internal/cmd/volume"
"github.com/hetznercloud/cli/internal/state"
"github.com/hetznercloud/hcloud-go/v2/hcloud"
)

func NewRootCommand(s state.State) *cobra.Command {
Expand Down Expand Up @@ -63,5 +64,13 @@ func NewRootCommand(s state.State) *cobra.Command {
)
cmd.PersistentFlags().Duration("poll-interval", 500*time.Millisecond, "Interval at which to poll information, for example action progress")
cmd.SetOut(os.Stdout)
cmd.PersistentPreRunE = func(cmd *cobra.Command, args []string) error {
pollInterval, err := cmd.Flags().GetDuration("poll-interval")
if err != nil {
return err
}
s.Client().WithOpts(hcloud.WithPollBackoffFunc(hcloud.ConstantBackoff(pollInterval)))
return nil
}
return cmd
}
20 changes: 20 additions & 0 deletions internal/hcapi2/action.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package hcapi2

import (
"github.com/hetznercloud/hcloud-go/v2/hcloud"
)

// ActionClient embeds the Hetzner Cloud Action client
type ActionClient interface {
hcloud.IActionClient
}

func NewActionClient(client hcloud.IActionClient) ActionClient {
return &actionClient{
IActionClient: client,
}
}

type actionClient struct {
hcloud.IActionClient
}
146 changes: 89 additions & 57 deletions internal/hcapi2/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (

// Client makes all API clients accessible via a single interface.
type Client interface {
Action() ActionClient
Datacenter() DatacenterClient
Firewall() FirewallClient
FloatingIP() FloatingIPClient
Expand All @@ -25,10 +26,11 @@ type Client interface {
PlacementGroup() PlacementGroupClient
RDNS() RDNSClient
PrimaryIP() PrimaryIPClient
WithOpts(...hcloud.ClientOption)
}

type client struct {
client *hcloud.Client
type clientCache struct {
actionClient ActionClient
certificateClient CertificateClient
datacenterClient DatacenterClient
serverClient ServerClient
Expand All @@ -46,162 +48,192 @@ type client struct {
placementGroupClient PlacementGroupClient
rdnsClient RDNSClient
primaryIPClient PrimaryIPClient
}

type client struct {
client *hcloud.Client
cache clientCache

mu sync.Mutex
mu sync.Mutex
opts []hcloud.ClientOption
}

// NewClient creates a new CLI API client extending hcloud.Client.
func NewClient(c *hcloud.Client) Client {
return &client{
client: c,
func NewClient(opts ...hcloud.ClientOption) Client {
c := &client{
opts: opts,
}
c.update()
return c
}

func (c *client) WithOpts(opts ...hcloud.ClientOption) {
c.mu.Lock()
defer c.mu.Unlock()
c.opts = append(c.opts, opts...)
c.update()
}

func (c *client) update() {
c.client = hcloud.NewClient(c.opts...)
c.cache = clientCache{}
}

func (c *client) Action() ActionClient {
c.mu.Lock()
if c.cache.actionClient == nil {
c.cache.actionClient = NewActionClient(&c.client.Action)
}
defer c.mu.Unlock()
return c.cache.actionClient
}

func (c *client) Certificate() CertificateClient {
c.mu.Lock()
if c.certificateClient == nil {
c.certificateClient = NewCertificateClient(&c.client.Certificate)
if c.cache.certificateClient == nil {
c.cache.certificateClient = NewCertificateClient(&c.client.Certificate)
}
defer c.mu.Unlock()
return c.certificateClient
return c.cache.certificateClient
}

func (c *client) Datacenter() DatacenterClient {
c.mu.Lock()
if c.datacenterClient == nil {
c.datacenterClient = NewDatacenterClient(&c.client.Datacenter)
if c.cache.datacenterClient == nil {
c.cache.datacenterClient = NewDatacenterClient(&c.client.Datacenter)
}
defer c.mu.Unlock()
return c.datacenterClient
return c.cache.datacenterClient
}

func (c *client) Firewall() FirewallClient {
c.mu.Lock()
if c.firewallClient == nil {
c.firewallClient = NewFirewallClient(&c.client.Firewall)
if c.cache.firewallClient == nil {
c.cache.firewallClient = NewFirewallClient(&c.client.Firewall)
}
defer c.mu.Unlock()
return c.firewallClient
return c.cache.firewallClient
}

func (c *client) FloatingIP() FloatingIPClient {
c.mu.Lock()
if c.floatingIPClient == nil {
c.floatingIPClient = NewFloatingIPClient(&c.client.FloatingIP)
if c.cache.floatingIPClient == nil {
c.cache.floatingIPClient = NewFloatingIPClient(&c.client.FloatingIP)
}
defer c.mu.Unlock()
return c.floatingIPClient
return c.cache.floatingIPClient
}

func (c *client) PrimaryIP() PrimaryIPClient {
c.mu.Lock()
if c.primaryIPClient == nil {
c.primaryIPClient = NewPrimaryIPClient(&c.client.PrimaryIP)
if c.cache.primaryIPClient == nil {
c.cache.primaryIPClient = NewPrimaryIPClient(&c.client.PrimaryIP)
}
defer c.mu.Unlock()
return c.primaryIPClient
return c.cache.primaryIPClient
}

func (c *client) Image() ImageClient {
c.mu.Lock()
if c.imageClient == nil {
c.imageClient = NewImageClient(&c.client.Image)
if c.cache.imageClient == nil {
c.cache.imageClient = NewImageClient(&c.client.Image)
}
defer c.mu.Unlock()
return c.imageClient
return c.cache.imageClient
}

func (c *client) ISO() ISOClient {
c.mu.Lock()
if c.isoClient == nil {
c.isoClient = NewISOClient(&c.client.ISO)
if c.cache.isoClient == nil {
c.cache.isoClient = NewISOClient(&c.client.ISO)
}
defer c.mu.Unlock()
return c.isoClient
return c.cache.isoClient
}

func (c *client) Location() LocationClient {
c.mu.Lock()
if c.locationClient == nil {
c.locationClient = NewLocationClient(&c.client.Location)
if c.cache.locationClient == nil {
c.cache.locationClient = NewLocationClient(&c.client.Location)
}
defer c.mu.Unlock()
return c.locationClient
return c.cache.locationClient
}

func (c *client) LoadBalancer() LoadBalancerClient {
c.mu.Lock()
if c.loadBalancerClient == nil {
c.loadBalancerClient = NewLoadBalancerClient(&c.client.LoadBalancer)
if c.cache.loadBalancerClient == nil {
c.cache.loadBalancerClient = NewLoadBalancerClient(&c.client.LoadBalancer)
}
defer c.mu.Unlock()
return c.loadBalancerClient
return c.cache.loadBalancerClient
}
func (c *client) LoadBalancerType() LoadBalancerTypeClient {
c.mu.Lock()
if c.loadBalancerTypeClient == nil {
c.loadBalancerTypeClient = NewLoadBalancerTypeClient(&c.client.LoadBalancerType)
if c.cache.loadBalancerTypeClient == nil {
c.cache.loadBalancerTypeClient = NewLoadBalancerTypeClient(&c.client.LoadBalancerType)
}
defer c.mu.Unlock()
return c.loadBalancerTypeClient
return c.cache.loadBalancerTypeClient
}
func (c *client) Network() NetworkClient {
c.mu.Lock()
if c.networkClient == nil {
c.networkClient = NewNetworkClient(&c.client.Network)
if c.cache.networkClient == nil {
c.cache.networkClient = NewNetworkClient(&c.client.Network)
}
defer c.mu.Unlock()
return c.networkClient
return c.cache.networkClient
}

func (c *client) Server() ServerClient {
c.mu.Lock()
if c.serverClient == nil {
c.serverClient = NewServerClient(&c.client.Server)
if c.cache.serverClient == nil {
c.cache.serverClient = NewServerClient(&c.client.Server)
}
defer c.mu.Unlock()
return c.serverClient
return c.cache.serverClient
}

func (c *client) ServerType() ServerTypeClient {
c.mu.Lock()
if c.serverTypeClient == nil {
c.serverTypeClient = NewServerTypeClient(&c.client.ServerType)
if c.cache.serverTypeClient == nil {
c.cache.serverTypeClient = NewServerTypeClient(&c.client.ServerType)
}
defer c.mu.Unlock()
return c.serverTypeClient
return c.cache.serverTypeClient
}

func (c *client) SSHKey() SSHKeyClient {
c.mu.Lock()
if c.sshKeyClient == nil {
c.sshKeyClient = NewSSHKeyClient(&c.client.SSHKey)
if c.cache.sshKeyClient == nil {
c.cache.sshKeyClient = NewSSHKeyClient(&c.client.SSHKey)
}
defer c.mu.Unlock()
return c.sshKeyClient
return c.cache.sshKeyClient
}
func (c *client) RDNS() RDNSClient {
c.mu.Lock()
if c.rdnsClient == nil {
c.rdnsClient = NewRDNSClient(&c.client.RDNS)
if c.cache.rdnsClient == nil {
c.cache.rdnsClient = NewRDNSClient(&c.client.RDNS)
}
defer c.mu.Unlock()
return c.rdnsClient
return c.cache.rdnsClient
}

func (c *client) Volume() VolumeClient {
c.mu.Lock()
if c.volumeClient == nil {
c.volumeClient = NewVolumeClient(&c.client.Volume)
if c.cache.volumeClient == nil {
c.cache.volumeClient = NewVolumeClient(&c.client.Volume)
}
defer c.mu.Unlock()
return c.volumeClient
return c.cache.volumeClient
}

func (c *client) PlacementGroup() PlacementGroupClient {
c.mu.Lock()
if c.placementGroupClient == nil {
c.placementGroupClient = NewPlacementGroupClient(&c.client.PlacementGroup)
if c.cache.placementGroupClient == nil {
c.cache.placementGroupClient = NewPlacementGroupClient(&c.client.PlacementGroup)
}
defer c.mu.Unlock()
return c.placementGroupClient
return c.cache.placementGroupClient
}
13 changes: 13 additions & 0 deletions internal/hcapi2/mock/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ import (
"github.com/golang/mock/gomock"

"github.com/hetznercloud/cli/internal/hcapi2"
"github.com/hetznercloud/hcloud-go/v2/hcloud"
)

type MockClient struct {
ActionClient *MockActionClient
CertificateClient *MockCertificateClient
DatacenterClient *MockDatacenterClient
FirewallClient *MockFirewallClient
Expand All @@ -28,6 +30,7 @@ type MockClient struct {

func NewMockClient(ctrl *gomock.Controller) *MockClient {
return &MockClient{
ActionClient: NewMockActionClient(ctrl),
CertificateClient: NewMockCertificateClient(ctrl),
DatacenterClient: NewMockDatacenterClient(ctrl),
FirewallClient: NewMockFirewallClient(ctrl),
Expand All @@ -47,9 +50,15 @@ func NewMockClient(ctrl *gomock.Controller) *MockClient {
RDNSClient: NewMockRDNSClient(ctrl),
}
}

func (c *MockClient) Action() hcapi2.ActionClient {
return c.ActionClient
}

func (c *MockClient) Certificate() hcapi2.CertificateClient {
return c.CertificateClient
}

func (c *MockClient) Datacenter() hcapi2.DatacenterClient {
return c.DatacenterClient
}
Expand Down Expand Up @@ -112,3 +121,7 @@ func (c *MockClient) RDNS() hcapi2.RDNSClient {
func (c *MockClient) PlacementGroup() hcapi2.PlacementGroupClient {
return c.PlacementGroupClient
}

func (*MockClient) WithOpts(...hcloud.ClientOption) {
// no-op
}
1 change: 1 addition & 0 deletions internal/hcapi2/mock/mock_gen.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package hcapi2_mock

//go:generate mockgen -package hcapi2_mock -destination zz_action_client_mock.go github.com/hetznercloud/cli/internal/hcapi2 ActionClient
//go:generate mockgen -package hcapi2_mock -destination zz_certificate_client_mock.go github.com/hetznercloud/cli/internal/hcapi2 CertificateClient
//go:generate mockgen -package hcapi2_mock -destination zz_datacenter_client_mock.go github.com/hetznercloud/cli/internal/hcapi2 DatacenterClient
//go:generate mockgen -package hcapi2_mock -destination zz_image_client_mock.go github.com/hetznercloud/cli/internal/hcapi2 ImageClient
Expand Down
Loading

0 comments on commit b9328a6

Please sign in to comment.