Skip to content
This repository was archived by the owner on Aug 12, 2025. It is now read-only.

Commit f272f16

Browse files
committed
Finish basic implmeentation of 'upgrade cloudprovider' and fix image version checking for 'migration providerid'
1 parent 53318bb commit f272f16

File tree

5 files changed

+445
-87
lines changed

5 files changed

+445
-87
lines changed

cmd/helper/base/tool.go

Lines changed: 23 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,10 @@ func ClusterToKey(c *clusterv1.Cluster) string {
3232
}
3333

3434
type Tool struct {
35-
// TODO: make this private
36-
Clusters []*clusterv1.Cluster
37-
38-
kubeconfig string
39-
MgmtClient client.Client
40-
41-
mu sync.Mutex
35+
kubeconfig string
36+
MgmtClient client.Client
37+
baseMutex sync.Mutex
38+
clusters []*clusterv1.Cluster
4239
workloadClients map[string]client.Client
4340
errors map[string]error
4441
outputBuffers map[string]*bytes.Buffer
@@ -48,11 +45,16 @@ type Tool struct {
4845
var ErrMissingKubeConfig = errors.New("kubeconfig was nil")
4946

5047
func (t *Tool) GetClusters() []*clusterv1.Cluster {
51-
// TODO: should this lock???
52-
return t.Clusters
48+
t.baseMutex.Lock()
49+
defer t.baseMutex.Unlock()
50+
51+
return t.clusters
5352
}
5453

5554
func (t *Tool) Initialize(ctx context.Context, kubeconfig *string) error {
55+
t.baseMutex.Lock()
56+
defer t.baseMutex.Unlock()
57+
5658
if kubeconfig == nil {
5759
return ErrMissingKubeConfig
5860
}
@@ -79,7 +81,7 @@ func (t *Tool) Initialize(ctx context.Context, kubeconfig *string) error {
7981
clusters = append(clusters, cluster)
8082
}
8183

82-
t.Clusters = clusters
84+
t.clusters = clusters
8385
t.workloadClients = make(map[string]client.Client, size)
8486
t.errors = make(map[string]error, size)
8587
t.outputBuffers = make(map[string]*bytes.Buffer, size)
@@ -93,8 +95,8 @@ func (t *Tool) HasError(c *clusterv1.Cluster) bool {
9395
}
9496

9597
func (t *Tool) GetErrorFor(c *clusterv1.Cluster) error {
96-
t.mu.Lock()
97-
defer t.mu.Unlock()
98+
t.baseMutex.Lock()
99+
defer t.baseMutex.Unlock()
98100

99101
if t.errors == nil {
100102
return nil
@@ -104,17 +106,17 @@ func (t *Tool) GetErrorFor(c *clusterv1.Cluster) error {
104106
}
105107

106108
func (t *Tool) GetOutputFor(c *clusterv1.Cluster) string {
107-
t.mu.Lock()
108-
defer t.mu.Unlock()
109+
t.baseMutex.Lock()
110+
defer t.baseMutex.Unlock()
109111

110112
t.flushBuffers()
111113

112114
return t.outputContents[ClusterToKey(c)]
113115
}
114116

115117
func (t *Tool) AddErrorFor(c *clusterv1.Cluster, err error) {
116-
t.mu.Lock()
117-
defer t.mu.Unlock()
118+
t.baseMutex.Lock()
119+
defer t.baseMutex.Unlock()
118120

119121
if t.errors == nil {
120122
t.errors = make(map[string]error)
@@ -124,8 +126,8 @@ func (t *Tool) AddErrorFor(c *clusterv1.Cluster, err error) {
124126
}
125127

126128
func (t *Tool) GetBufferFor(c *clusterv1.Cluster) *bytes.Buffer {
127-
t.mu.Lock()
128-
defer t.mu.Unlock()
129+
t.baseMutex.Lock()
130+
defer t.baseMutex.Unlock()
129131

130132
if t.outputBuffers == nil {
131133
t.outputBuffers = make(map[string]*bytes.Buffer)
@@ -163,6 +165,9 @@ func (t *Tool) GetWorkloadClient(
163165
ctx context.Context,
164166
cluster *clusterv1.Cluster,
165167
) (client.Client, error) {
168+
t.baseMutex.Lock()
169+
defer t.baseMutex.Unlock()
170+
166171
if t.workloadClients == nil {
167172
t.workloadClients = make(map[string]client.Client)
168173
}

cmd/helper/migrate/providerid/migrator/migrator.go

Lines changed: 59 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,14 @@ import (
2121
"sync"
2222

2323
"github.com/blang/semver"
24+
"github.com/docker/distribution/reference"
2425
appsv1 "k8s.io/api/apps/v1"
2526
corev1 "k8s.io/api/core/v1"
2627
apierrors "k8s.io/apimachinery/pkg/api/errors"
2728
"k8s.io/client-go/util/retry"
2829
"sigs.k8s.io/cluster-api-provider-packet/cmd/helper/base"
2930
clusterv1 "sigs.k8s.io/cluster-api/api/v1alpha3"
3031
capiutil "sigs.k8s.io/cluster-api/util"
31-
containerutil "sigs.k8s.io/cluster-api/util/container"
3232
"sigs.k8s.io/controller-runtime/pkg/client"
3333
)
3434

@@ -53,9 +53,13 @@ func (m *Migrator) Initialize(ctx context.Context, kubeconfig *string) error {
5353
return err
5454
}
5555

56-
m.nodeStatus = make(map[string]map[string]bool, len(m.Clusters))
56+
// Initialize the node status
57+
m.mu.Lock()
58+
clusters := m.GetClusters()
59+
m.nodeStatus = make(map[string]map[string]bool, len(clusters))
60+
m.mu.Unlock()
5761

58-
for _, c := range m.Clusters {
62+
for _, c := range clusters {
5963
nodes, err := m.getNodes(ctx, c)
6064
if err != nil {
6165
m.AddErrorFor(c, err)
@@ -74,8 +78,9 @@ func (m *Migrator) Initialize(ctx context.Context, kubeconfig *string) error {
7478
func (m *Migrator) CheckPrerequisites(ctx context.Context) error {
7579
wg := new(sync.WaitGroup)
7680

77-
for i := range m.Clusters {
78-
c := m.Clusters[i]
81+
clusters := m.GetClusters()
82+
for i := range clusters {
83+
c := clusters[i]
7984

8085
wg.Add(1)
8186

@@ -90,18 +95,20 @@ func (m *Migrator) CheckPrerequisites(ctx context.Context) error {
9095

9196
wg.Wait()
9297

93-
cappDeployment, err := getDeployment(
98+
cappDeployment := new(appsv1.Deployment)
99+
if err := m.MgmtClient.Get(
94100
ctx,
95-
m.MgmtClient,
96-
"cluster-api-provider-packet-system",
97-
"cluster-api-provider-packet-controller-manager",
98-
)
99-
if err != nil {
100-
return fmt.Errorf("failed to get CAPP deployment: %w", err)
101-
}
101+
client.ObjectKey{
102+
Namespace: "cluster-api-provider-packet-system",
103+
Name: "cluster-api-provider-packet-controller-manager",
104+
},
105+
cappDeployment,
106+
); err != nil {
107+
if apierrors.IsNotFound(err) {
108+
return ErrMissingCAPPDeployment
109+
}
102110

103-
if cappDeployment == nil {
104-
return ErrMissingCAPPDeployment
111+
return fmt.Errorf("failed to get CAPP deployment: %w", err)
105112
}
106113

107114
ok, err := containerImageGTE(cappDeployment.Spec.Template.Spec.Containers[0], semver.MustParse("0.4.0"))
@@ -117,12 +124,16 @@ func (m *Migrator) CheckPrerequisites(ctx context.Context) error {
117124
}
118125

119126
func containerImageGTE(container corev1.Container, version semver.Version) (bool, error) {
120-
image, err := containerutil.ImageFromString(container.Image)
127+
ref, err := reference.ParseNormalizedNamed(container.Image)
121128
if err != nil {
122-
return false, fmt.Errorf("failed to get image from container: %w", err)
129+
return false, fmt.Errorf("failed to parse container reference %s: %w", container.Image, err)
123130
}
124131

125-
imageVersion, err := capiutil.ParseMajorMinorPatch(image.Tag)
132+
ref = reference.TagNameOnly(ref)
133+
tagged, _ := ref.(reference.Tagged)
134+
tag := tagged.Tag()
135+
136+
imageVersion, err := capiutil.ParseMajorMinorPatch(tag)
126137
if err != nil {
127138
return false, fmt.Errorf("failed to get version from image: %w", err)
128139
}
@@ -141,22 +152,36 @@ func (m *Migrator) validateCloudProviderForCluster(ctx context.Context, c *clust
141152
return err
142153
}
143154

144-
packetCCMDeployment, err := getDeployment(ctx, workloadClient, "kube-system", "packet-cloud-controller-manager")
145-
if err != nil {
146-
return err
147-
}
148-
149-
if packetCCMDeployment != nil {
155+
packetCCMDeployment := new(appsv1.Deployment)
156+
if err := workloadClient.Get(
157+
ctx,
158+
client.ObjectKey{Namespace: "kube-system", Name: "packet-cloud-controller-manager"},
159+
packetCCMDeployment,
160+
); err != nil {
161+
if !apierrors.IsNotFound(err) {
162+
// Ignore IsNotFound errors, since this is what we want to proceed
163+
// We hit an unexpected error
164+
return fmt.Errorf("failed to get deployment: %w", err)
165+
}
166+
} else {
167+
// If we successfully retrieved the deployment, that means that the prerequisite step
168+
// for upgrading the Cloud Provider has not been run yet
150169
return ErrPacketCloudProviderFound
151170
}
152171

153-
cpemDeployment, err := getDeployment(ctx, workloadClient, "kube-system", "cloud-provider-equinix-metal")
154-
if err != nil {
155-
return err
156-
}
172+
cpemDeployment := new(appsv1.Deployment)
173+
if err := workloadClient.Get(
174+
ctx,
175+
client.ObjectKey{Namespace: "kube-system", Name: "cloud-provider-equinix-metal"},
176+
cpemDeployment,
177+
); err != nil {
178+
if apierrors.IsNotFound(err) {
179+
// Missing expected CPEM deployment
180+
return ErrMissingCPEMDeployment
181+
}
157182

158-
if cpemDeployment == nil {
159-
return ErrMissingCPEMDeployment
183+
// We hit an unexpected error
184+
return fmt.Errorf("failed to get deployment: %w", err)
160185
}
161186

162187
ok, err := containerImageGTE(cpemDeployment.Spec.Template.Spec.Containers[0], semver.MustParse("3.1.0"))
@@ -171,25 +196,6 @@ func (m *Migrator) validateCloudProviderForCluster(ctx context.Context, c *clust
171196
return nil
172197
}
173198

174-
func getDeployment(
175-
ctx context.Context,
176-
workloadClient client.Client,
177-
namespace, name string,
178-
) (*appsv1.Deployment, error) {
179-
deployment := new(appsv1.Deployment)
180-
key := client.ObjectKey{Namespace: namespace, Name: name}
181-
182-
if err := workloadClient.Get(ctx, key, deployment); err != nil {
183-
if apierrors.IsNotFound(err) {
184-
return nil, nil
185-
}
186-
187-
return nil, fmt.Errorf("failed to get deployment: %w", err)
188-
}
189-
190-
return deployment, nil
191-
}
192-
193199
func (m *Migrator) CalculatePercentage() float64 {
194200
m.mu.Lock()
195201
defer m.mu.Unlock()
@@ -200,7 +206,7 @@ func (m *Migrator) CalculatePercentage() float64 {
200206

201207
var totalNodes, doneNodes int
202208

203-
for _, c := range m.Clusters {
209+
for _, c := range m.GetClusters() {
204210
clusterKey := base.ClusterToKey(c)
205211

206212
if m.nodeStatus[clusterKey] == nil {
@@ -226,8 +232,9 @@ func (m *Migrator) CalculatePercentage() float64 {
226232
func (m *Migrator) Run(ctx context.Context) {
227233
wg := new(sync.WaitGroup)
228234

229-
for i := range m.Clusters {
230-
c := m.Clusters[i]
235+
clusters := m.GetClusters()
236+
for i := range clusters {
237+
c := clusters[i]
231238

232239
wg.Add(1)
233240

cmd/helper/ui/base.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"github.com/charmbracelet/bubbles/progress"
2222
tea "github.com/charmbracelet/bubbletea"
2323
"github.com/charmbracelet/lipgloss"
24+
"github.com/muesli/reflow/wordwrap"
2425
clusterv1 "sigs.k8s.io/cluster-api/api/v1alpha3"
2526
)
2627

@@ -58,6 +59,8 @@ type Model struct {
5859
progress *progress.Model
5960
percent float64
6061
err error
62+
height int
63+
width int
6164
}
6265

6366
type TickMsg time.Time
@@ -92,6 +95,8 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
9295
cmd = cleanQuit
9396
}
9497
case tea.WindowSizeMsg:
98+
m.width = msg.Width
99+
m.height = msg.Height
95100
m.progress.Width = msg.Width - padding*2 - 4 //nolint: gomnd
96101
if m.progress.Width > maxWidth {
97102
m.progress.Width = maxWidth
@@ -145,7 +150,7 @@ func (m Model) View() string {
145150
}
146151
}
147152

148-
return s
153+
return wordwrap.String(s, m.width)
149154
}
150155

151156
func cleanQuit() tea.Msg {

0 commit comments

Comments
 (0)