Skip to content

Commit 176af45

Browse files
authored
chore: align instance api config status (#10145)
1 parent cf10be1 commit 176af45

16 files changed

Lines changed: 1659 additions & 171 deletions

apis/workloads/v1/instance_types.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,11 @@ type InstanceSpec struct {
128128
// +optional
129129
LifecycleActions *LifecycleActions `json:"lifecycleActions,omitempty"`
130130

131+
// Configs define the desired config templates applied to this instance.
132+
//
133+
// +optional
134+
Configs []ConfigTemplate `json:"configs,omitempty"`
135+
131136
// Assistant objects that are necessary to run the instance.
132137
//
133138
// +optional
@@ -187,6 +192,11 @@ type InstanceStatus2 struct {
187192
//
188193
// +optional
189194
VolumeExpansion bool `json:"volumeExpansion,omitempty"`
195+
196+
// Represents the config status observed from the running pod of this instance.
197+
//
198+
// +optional
199+
Configs []InstanceConfigStatus `json:"configs,omitempty"`
190200
}
191201

192202
type InstanceAssistantObject struct {

apis/workloads/v1/zz_generated.deepcopy.go

Lines changed: 14 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

config/crd/bases/workloads.kubeblocks.io_instances.yaml

Lines changed: 479 additions & 0 deletions
Large diffs are not rendered by default.

controllers/workloads/instance_controller_test.go

Lines changed: 228 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ package workloads
2121

2222
import (
2323
"context"
24+
"encoding/json"
2425
"fmt"
2526
"strings"
2627
"time"
@@ -143,6 +144,44 @@ var _ = Describe("Instance Controller", func() {
143144
})).Should(Succeed())
144145
})
145146

147+
It("status - configs", func() {
148+
createInstObj(instName, func(f *testapps.MockInstanceFactory) {
149+
f.AddConfigs(
150+
workloads.ConfigTemplate{
151+
Name: "log",
152+
ConfigHash: ptr.To("123456"),
153+
},
154+
workloads.ConfigTemplate{
155+
Name: "server",
156+
ConfigHash: ptr.To("654321"),
157+
},
158+
)
159+
})
160+
161+
podKey := instKey
162+
Eventually(testapps.CheckObj(&testCtx, podKey, func(g Gomega, pod *corev1.Pod) {
163+
expectConfigHashAnnotation(g, pod, map[string]string{
164+
"log": "123456",
165+
"server": "654321",
166+
})
167+
})).Should(Succeed())
168+
169+
mockPodReady(instObj.Namespace, instObj.Name)
170+
171+
Eventually(testapps.CheckObj(&testCtx, instKey, func(g Gomega, inst *workloads.Instance) {
172+
g.Expect(inst.Status.Configs).Should(Equal([]workloads.InstanceConfigStatus{
173+
{
174+
Name: "log",
175+
ConfigHash: ptr.To("123456"),
176+
},
177+
{
178+
Name: "server",
179+
ConfigHash: ptr.To("654321"),
180+
},
181+
}))
182+
})).Should(Succeed())
183+
})
184+
146185
It("status - available & role", func() {
147186
createInstObj(instName, func(f *testapps.MockInstanceFactory) {
148187
f.SetMinReadySeconds(minReadySeconds).
@@ -500,10 +539,188 @@ var _ = Describe("Instance Controller", func() {
500539
Expect(switchover).Should(BeTrue())
501540
})
502541

503-
// It("reconfigure", func() {
504-
// // TODO
505-
// })
506-
//
542+
It("reconfigure", func() {
543+
var (
544+
reconfigure string
545+
parameters map[string]string
546+
)
547+
testapps.MockKBAgentClient(func(recorder *kbacli.MockClientMockRecorder) {
548+
recorder.Action(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, req kbagentproto.ActionRequest) (kbagentproto.ActionResponse, error) {
549+
if req.Action == "reconfigure" {
550+
reconfigure = req.Action
551+
parameters = req.Parameters
552+
}
553+
return kbagentproto.ActionResponse{}, nil
554+
}).AnyTimes()
555+
})
556+
defer kbacli.UnsetMockClient()
557+
558+
createInstObj(instName, func(f *testapps.MockInstanceFactory) {
559+
f.AddConfigs(
560+
workloads.ConfigTemplate{
561+
Name: "log",
562+
ConfigHash: ptr.To("123456"),
563+
},
564+
workloads.ConfigTemplate{
565+
Name: "server",
566+
ConfigHash: ptr.To("123456"),
567+
},
568+
)
569+
})
570+
571+
mockPodReady(instObj.Namespace, instObj.Name)
572+
573+
Expect(testapps.GetAndChangeObj(&testCtx, instKey, func(inst *workloads.Instance) {
574+
inst.Spec.Configs[0].ConfigHash = ptr.To("abcdef")
575+
inst.Spec.Configs[0].Reconfigure = testapps.NewLifecycleAction("reconfigure")
576+
inst.Spec.Configs[0].Parameters = map[string]string{"foo": "bar"}
577+
})()).Should(Succeed())
578+
579+
Eventually(func(g Gomega) {
580+
g.Expect(reconfigure).Should(Equal("reconfigure"))
581+
g.Expect(parameters).Should(HaveKeyWithValue("foo", "bar"))
582+
}).Should(Succeed())
583+
584+
podKey := instKey
585+
Eventually(testapps.CheckObj(&testCtx, podKey, func(g Gomega, pod *corev1.Pod) {
586+
expectConfigHashAnnotation(g, pod, map[string]string{
587+
"log": "abcdef",
588+
"server": "123456",
589+
})
590+
})).Should(Succeed())
591+
592+
Eventually(testapps.CheckObj(&testCtx, instKey, func(g Gomega, inst *workloads.Instance) {
593+
g.Expect(inst.Status.Configs).Should(Equal([]workloads.InstanceConfigStatus{
594+
{
595+
Name: "log",
596+
ConfigHash: ptr.To("abcdef"),
597+
},
598+
{
599+
Name: "server",
600+
ConfigHash: ptr.To("123456"),
601+
},
602+
}))
603+
})).Should(Succeed())
604+
})
605+
606+
It("restart on config update", func() {
607+
createInstObj(instName, func(f *testapps.MockInstanceFactory) {
608+
f.AddConfigs(
609+
workloads.ConfigTemplate{
610+
Name: "log",
611+
ConfigHash: ptr.To("123456"),
612+
},
613+
workloads.ConfigTemplate{
614+
Name: "server",
615+
ConfigHash: ptr.To("123456"),
616+
},
617+
)
618+
})
619+
620+
mockPodReady(instObj.Namespace, instObj.Name)
621+
podKey := instKey
622+
podObj := &corev1.Pod{}
623+
Expect(k8sClient.Get(ctx, podKey, podObj)).Should(Succeed())
624+
625+
Expect(testapps.GetAndChangeObj(&testCtx, instKey, func(inst *workloads.Instance) {
626+
inst.Spec.Configs[0].ConfigHash = ptr.To("abcdef")
627+
inst.Spec.Configs[0].Restart = ptr.To(true)
628+
})()).Should(Succeed())
629+
630+
Eventually(testapps.CheckObj(&testCtx, podKey, func(g Gomega, pod *corev1.Pod) {
631+
g.Expect(pod.UID).ShouldNot(Equal(podObj.UID))
632+
expectConfigHashAnnotation(g, pod, map[string]string{
633+
"log": "abcdef",
634+
"server": "123456",
635+
})
636+
})).Should(Succeed())
637+
638+
Eventually(testapps.CheckObj(&testCtx, instKey, func(g Gomega, inst *workloads.Instance) {
639+
g.Expect(inst.Status.Configs).Should(Equal([]workloads.InstanceConfigStatus{
640+
{
641+
Name: "log",
642+
ConfigHash: ptr.To("abcdef"),
643+
},
644+
{
645+
Name: "server",
646+
ConfigHash: ptr.To("123456"),
647+
},
648+
}))
649+
})).Should(Succeed())
650+
})
651+
652+
It("reconfigure and restart", func() {
653+
var (
654+
reconfigure string
655+
parameters map[string]string
656+
reconfigureTimestamp time.Time
657+
)
658+
testapps.MockKBAgentClient(func(recorder *kbacli.MockClientMockRecorder) {
659+
recorder.Action(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, req kbagentproto.ActionRequest) (kbagentproto.ActionResponse, error) {
660+
if req.Action == "reconfigure" {
661+
reconfigure = req.Action
662+
parameters = req.Parameters
663+
reconfigureTimestamp = time.Now()
664+
time.Sleep(1200 * time.Millisecond)
665+
}
666+
return kbagentproto.ActionResponse{}, nil
667+
}).AnyTimes()
668+
})
669+
defer kbacli.UnsetMockClient()
670+
671+
createInstObj(instName, func(f *testapps.MockInstanceFactory) {
672+
f.AddConfigs(
673+
workloads.ConfigTemplate{
674+
Name: "log",
675+
ConfigHash: ptr.To("123456"),
676+
},
677+
workloads.ConfigTemplate{
678+
Name: "server",
679+
ConfigHash: ptr.To("123456"),
680+
},
681+
)
682+
})
683+
684+
mockPodReady(instObj.Namespace, instObj.Name)
685+
podKey := instKey
686+
podObj := &corev1.Pod{}
687+
Expect(k8sClient.Get(ctx, podKey, podObj)).Should(Succeed())
688+
689+
Expect(testapps.GetAndChangeObj(&testCtx, instKey, func(inst *workloads.Instance) {
690+
inst.Spec.Configs[0].ConfigHash = ptr.To("abcdef")
691+
inst.Spec.Configs[0].Restart = ptr.To(true)
692+
inst.Spec.Configs[0].Reconfigure = testapps.NewLifecycleAction("reconfigure")
693+
inst.Spec.Configs[0].Parameters = map[string]string{"foo": "bar"}
694+
})()).Should(Succeed())
695+
696+
Eventually(func(g Gomega) {
697+
g.Expect(reconfigure).Should(Equal("reconfigure"))
698+
g.Expect(parameters).Should(HaveKeyWithValue("foo", "bar"))
699+
}).Should(Succeed())
700+
701+
Eventually(testapps.CheckObj(&testCtx, podKey, func(g Gomega, pod *corev1.Pod) {
702+
g.Expect(pod.UID).ShouldNot(Equal(podObj.UID))
703+
g.Expect(pod.CreationTimestamp.Time.After(reconfigureTimestamp)).Should(BeTrue())
704+
expectConfigHashAnnotation(g, pod, map[string]string{
705+
"log": "abcdef",
706+
"server": "123456",
707+
})
708+
})).Should(Succeed())
709+
710+
Eventually(testapps.CheckObj(&testCtx, instKey, func(g Gomega, inst *workloads.Instance) {
711+
g.Expect(inst.Status.Configs).Should(Equal([]workloads.InstanceConfigStatus{
712+
{
713+
Name: "log",
714+
ConfigHash: ptr.To("abcdef"),
715+
},
716+
{
717+
Name: "server",
718+
ConfigHash: ptr.To("123456"),
719+
},
720+
}))
721+
})).Should(Succeed())
722+
})
723+
507724
// It("member join", func() {
508725
// // TODO
509726
// })
@@ -566,3 +783,10 @@ func mockPodReadyNAvailableWithRole(namespace, podName, role string, minReadySec
566783
pod.Labels[constant.RoleLabelKey] = role
567784
})()).Should(Succeed())
568785
}
786+
787+
func expectConfigHashAnnotation(g Gomega, pod *corev1.Pod, expected map[string]string) {
788+
g.Expect(pod.Annotations).Should(HaveKey(constant.CMInsConfigurationHashLabelKey))
789+
actual := make(map[string]string)
790+
g.Expect(json.Unmarshal([]byte(pod.Annotations[constant.CMInsConfigurationHashLabelKey]), &actual)).Should(Succeed())
791+
g.Expect(actual).Should(Equal(expected))
792+
}

controllers/workloads/instanceset_controller_2_test.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,39 @@ var _ = Describe("InstanceSet Controller 2", func() {
183183
})).Should(Succeed())
184184
})
185185

186+
It("instance status - configs", func() {
187+
createITSObj(itsName, func(f *testapps.MockInstanceSetFactory) {
188+
f.AddConfigs(
189+
workloads.ConfigTemplate{
190+
Name: "log",
191+
ConfigHash: ptr.To("123456"),
192+
},
193+
workloads.ConfigTemplate{
194+
Name: "server",
195+
ConfigHash: ptr.To("654321"),
196+
},
197+
)
198+
})
199+
200+
mockPodsReady()
201+
202+
Eventually(testapps.CheckObj(&testCtx, itsKey, func(g Gomega, its *workloads.InstanceSet) {
203+
g.Expect(its.Status.InstanceStatus).Should(HaveLen(int(replicas)))
204+
for i := range its.Status.InstanceStatus {
205+
g.Expect(its.Status.InstanceStatus[i].Configs).Should(Equal([]workloads.InstanceConfigStatus{
206+
{
207+
Name: "log",
208+
ConfigHash: ptr.To("123456"),
209+
},
210+
{
211+
Name: "server",
212+
ConfigHash: ptr.To("654321"),
213+
},
214+
}))
215+
}
216+
})).Should(Succeed())
217+
})
218+
186219
It("pod management - ordered ready", func() {
187220
createITSObj(itsName, func(f *testapps.MockInstanceSetFactory) {
188221
f.SetPodManagementPolicy(appsv1.OrderedReadyPodManagement)

0 commit comments

Comments
 (0)