Skip to content

Commit 7cd4a7d

Browse files
committed
refactor(target): unify target setters and make overlays idempotent
Direct setters (TargetGarden/Project/Seed/Shoot/ControlPlane) and pattern targeting now converge on a single applyOverlay path that performs merge, validation, enrichment, and access-restriction prompts. The separate target_builder is removed. Command-lifetime idempotency moves from the provider into the manager: CurrentTarget caches the effective target and writes update the cache through one updateTarget path, so repeated reads no longer reapply CLI flags onto freshly written state. Pattern targeting reads the raw persisted target once, merges CLI and pattern flags into one overlay with conflict detection, and runs validation a single time on the finalized target.
1 parent 404a065 commit 7cd4a7d

12 files changed

Lines changed: 787 additions & 468 deletions

File tree

internal/fake/target_provider.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,12 @@ func (p *TargetProvider) Read() (target.Target, error) {
3535
return p.Target, nil
3636
}
3737

38+
// ReadPersisted returns the target as persisted. The fake provider has no
39+
// command-local overlays, so this is identical to Read.
40+
func (p *TargetProvider) ReadPersisted() (target.Target, error) {
41+
return p.Read()
42+
}
43+
3844
// Write takes a target and saves it permanently.
3945
func (p *TargetProvider) Write(t target.Target) error {
4046
p.Target = t

internal/util/factory.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,10 @@ type FactoryImpl struct {
8181
// targetFlags can be used to completely override the target configuration
8282
// stored on the filesystem via a CLI flags.
8383
targetFlags target.TargetFlags
84+
85+
// ClientProvider overrides the Kubernetes client provider used by Manager.
86+
// If unset, Manager uses the real provider.
87+
ClientProvider internalclient.Provider
8488
}
8589

8690
var _ Factory = &FactoryImpl{}
@@ -133,7 +137,11 @@ func (f *FactoryImpl) Manager() (target.Manager, error) {
133137
}
134138

135139
targetProvider := target.NewTargetProvider(filepath.Join(sessionDirectory, "target.yaml"), f.targetFlags)
136-
clientProvider := internalclient.NewProvider()
140+
141+
clientProvider := f.ClientProvider
142+
if clientProvider == nil {
143+
clientProvider = internalclient.NewProvider()
144+
}
137145

138146
return target.NewManager(cfg, targetProvider, clientProvider, sessionDirectory, f.KubeconfigAccessLevel)
139147
}

pkg/cmd/providerenv/options.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,7 @@ func (o *options) Run(f util.Factory) error {
348348
}
349349

350350
requiresAccessRestrictionConfirmation := false
351+
351352
if o.TargetFlags != nil {
352353
controlPlaneRequested := o.TargetFlags.ControlPlane().Provided() && o.TargetFlags.ControlPlane().Value()
353354
requiresAccessRestrictionConfirmation = o.TargetFlags.ShootName() != "" || controlPlaneRequested

pkg/cmd/target/target_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,7 @@ var _ = Describe("Target Command", func() {
281281
Expect(err).NotTo(HaveOccurred())
282282
Expect(currentTarget.GardenName()).To(Equal(gardenName))
283283
Expect(currentTarget.ProjectName()).To(Equal(projectName))
284-
Expect(currentTarget.SeedName()).To(BeEmpty())
284+
Expect(currentTarget.SeedName()).To(Equal(seedName))
285285
Expect(currentTarget.ShootName()).To(Equal(shootName))
286286
Expect(currentTarget.ControlPlane()).To(BeTrue())
287287
})

pkg/flags/target_test.go

Lines changed: 49 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -265,10 +265,22 @@ var _ = Describe("Target flags", func() {
265265
})
266266

267267
Describe("Depending on the factory implementation", func() {
268-
var factory *util.FactoryImpl
268+
var (
269+
ctrl *gomock.Controller
270+
clientProvider *clientmocks.MockProvider
271+
factory *util.FactoryImpl
272+
)
269273

270274
BeforeEach(func() {
275+
ctrl = gomock.NewController(GinkgoT())
276+
clientProvider = clientmocks.NewMockProvider(ctrl)
277+
271278
factory = util.NewFactoryImpl()
279+
factory.ClientProvider = clientProvider
280+
})
281+
282+
AfterEach(func() {
283+
ctrl.Finish()
272284
})
273285

274286
Context("when wrapping completion functions", func() {
@@ -312,7 +324,36 @@ var _ = Describe("Target flags", func() {
312324

313325
Context("when running a command with target flags", func() {
314326
It("should override current target", func() {
327+
seedName := "test-seed1"
315328
shootName := "newshoot"
329+
testProject := &gardencorev1beta1.Project{
330+
ObjectMeta: metav1.ObjectMeta{
331+
Name: projectName,
332+
UID: "00000000-0000-0000-0000-000000000000",
333+
},
334+
Spec: gardencorev1beta1.ProjectSpec{
335+
Namespace: ptr.To("garden-" + projectName),
336+
},
337+
}
338+
testSeed := &gardencorev1beta1.Seed{
339+
ObjectMeta: metav1.ObjectMeta{
340+
Name: seedName,
341+
UID: "00000000-0000-0000-0000-000000000000",
342+
},
343+
}
344+
testShoot := &gardencorev1beta1.Shoot{
345+
ObjectMeta: metav1.ObjectMeta{
346+
Name: shootName,
347+
Namespace: *testProject.Spec.Namespace,
348+
UID: "00000000-0000-0000-0000-000000000000",
349+
},
350+
Spec: gardencorev1beta1.ShootSpec{
351+
SeedName: ptr.To(seedName),
352+
},
353+
}
354+
gardenClient := fake.NewClientWithObjects(testProject, testSeed, testShoot)
355+
clientProvider.EXPECT().FromClientConfig(gomock.Any()).Return(gardenClient, nil).AnyTimes()
356+
316357
args := []string{
317358
fmt.Sprintf("--shoot=%s", shootName),
318359
"target",
@@ -326,23 +367,24 @@ var _ = Describe("Target flags", func() {
326367
Expect(factory.ConfigFile).To(Equal(configFile))
327368
Expect(factory.GardenHomeDirectory).To(Equal(gardenHomeDir))
328369

329-
manager, err := factory.Manager()
330-
Expect(err).NotTo(HaveOccurred())
331-
332370
// check target flags values
333371
tf := factory.TargetFlags()
334372
Expect(tf.GardenName()).To(BeEmpty())
335373
Expect(tf.ProjectName()).To(BeEmpty())
336374
Expect(tf.SeedName()).To(BeEmpty())
337375
Expect(tf.ShootName()).To(Equal(shootName))
376+
Expect(tf.ControlPlane().Provided()).To(BeFalse())
377+
Expect(tf.ControlPlane().Value()).To(BeFalse())
338378

339-
// check current target values
340-
current, err := manager.CurrentTarget()
379+
// check persisted target values
380+
targetProvider := target.NewTargetProvider(filepath.Join(sessionDir, "target.yaml"), nil)
381+
current, err := targetProvider.Read()
341382
Expect(err).NotTo(HaveOccurred())
342383
Expect(current.GardenName()).To(Equal(gardenName1))
343384
Expect(current.ProjectName()).To(Equal(projectName))
344-
Expect(current.SeedName()).To(BeEmpty())
385+
Expect(current.SeedName()).To(Equal(seedName))
345386
Expect(current.ShootName()).To(Equal(shootName))
387+
Expect(current.ControlPlane()).To(BeTrue())
346388
})
347389
})
348390
})

0 commit comments

Comments
 (0)