Skip to content

Commit afd8fd0

Browse files
OKE addon support (#287)
* Add support for OKE addons
1 parent e5676d6 commit afd8fd0

File tree

15 files changed

+959
-10
lines changed

15 files changed

+959
-10
lines changed

cloud/scope/managed_control_plane.go

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -591,6 +591,7 @@ func setControlPlaneSpecDefaults(spec *infrav2exp.OCIManagedControlPlaneSpec) {
591591
if spec.ClusterType == "" {
592592
spec.ClusterType = infrav2exp.BasicClusterType
593593
}
594+
spec.Addons = nil
594595
if spec.ImagePolicyConfig == nil {
595596
spec.ImagePolicyConfig = &infrav2exp.ImagePolicyConfig{
596597
IsPolicyEnabled: common.Bool(false),
@@ -615,6 +616,7 @@ func (s *ManagedControlPlaneScope) getSpecFromActual(cluster *oke.Cluster) *infr
615616
Version: cluster.KubernetesVersion,
616617
KmsKeyId: cluster.KmsKeyId,
617618
ID: cluster.Id,
619+
Addons: nil,
618620
}
619621
if cluster.ImagePolicyConfig != nil {
620622
keys := make([]infrav2exp.KeyDetails, 0)
@@ -673,6 +675,183 @@ func (s *ManagedControlPlaneScope) getSpecFromActual(cluster *oke.Cluster) *infr
673675
return &spec
674676
}
675677

678+
// ReconcileAddons reconciles addons which have been specified in the spec on the OKE cluster
679+
func (s *ManagedControlPlaneScope) ReconcileAddons(ctx context.Context, okeCluster *oke.Cluster) error {
680+
addonSpec := s.OCIManagedControlPlane.Spec.Addons
681+
// go through the list of addons present in the spec and reconcile them, reconcile can be 2 ways, either
682+
// install the addon if it has not been installed till now, or update the addon
683+
for _, addon := range addonSpec {
684+
resp, err := s.ContainerEngineClient.GetAddon(ctx, oke.GetAddonRequest{
685+
ClusterId: okeCluster.Id,
686+
AddonName: addon.Name,
687+
})
688+
if err != nil {
689+
// addon is not present, hence install it
690+
if ociutil.IsNotFound(err) {
691+
s.Info(fmt.Sprintf("Install addon %s", *addon.Name))
692+
_, err = s.ContainerEngineClient.InstallAddon(ctx, oke.InstallAddonRequest{
693+
ClusterId: okeCluster.Id,
694+
InstallAddonDetails: oke.InstallAddonDetails{
695+
Version: addon.Version,
696+
Configurations: getAddonConfigurations(addon.Configurations),
697+
AddonName: addon.Name,
698+
},
699+
})
700+
if err != nil {
701+
return err
702+
}
703+
// add it to status, details will be reconciled in next loop
704+
status := infrav2exp.AddonStatus{
705+
LifecycleState: common.String(string(oke.AddonLifecycleStateCreating)),
706+
}
707+
s.OCIManagedControlPlane.SetAddonStatus(*addon.Name, status)
708+
} else {
709+
return err
710+
}
711+
} else {
712+
s.OCIManagedControlPlane.SetAddonStatus(*addon.Name, s.getStatus(resp.Addon))
713+
// addon present, update it
714+
err = s.handleExistingAddon(ctx, okeCluster, resp.Addon, addon)
715+
if err != nil {
716+
return err
717+
}
718+
}
719+
}
720+
// for addons which are present in the status object but not in the spec, the possibility
721+
// is that user deleted it from the spec. Hence disable the addon
722+
for k, _ := range s.OCIManagedControlPlane.Status.AddonStatus {
723+
// present in status but not in spec
724+
if getAddon(addonSpec, k) == nil {
725+
err := s.handleDeletedAddon(ctx, okeCluster, k)
726+
if err != nil {
727+
return err
728+
}
729+
}
730+
}
731+
return nil
732+
}
733+
734+
func (s *ManagedControlPlaneScope) getStatus(addon oke.Addon) infrav2exp.AddonStatus {
735+
// update status of the addon
736+
status := infrav2exp.AddonStatus{
737+
LifecycleState: common.String(string(addon.LifecycleState)),
738+
CurrentlyInstalledVersion: addon.CurrentInstalledVersion,
739+
}
740+
if addon.AddonError != nil {
741+
status.AddonError = &infrav2exp.AddonError{
742+
Status: addon.AddonError.Status,
743+
Code: addon.AddonError.Code,
744+
Message: addon.AddonError.Message,
745+
}
746+
}
747+
return status
748+
}
749+
750+
func (s *ManagedControlPlaneScope) handleExistingAddon(ctx context.Context, okeCluster *oke.Cluster, addon oke.Addon, addonInSpec infrav2exp.Addon) error {
751+
// if the addon can be updated do so
752+
// if the addon is already in updating state, or in failed state, do not update
753+
s.Info(fmt.Sprintf("Reconciling addon %s with lifecycle state %s", *addon.Name, string(addon.LifecycleState)))
754+
if !(addon.LifecycleState == oke.AddonLifecycleStateUpdating ||
755+
addon.LifecycleState == oke.AddonLifecycleStateFailed) {
756+
addonConfigurationsActual := getActualAddonConfigurations(addon.Configurations)
757+
// if the version changed or the configuration changed, update the addon
758+
// if the lifecycle state is needs attention, try to update
759+
if addon.LifecycleState == oke.AddonLifecycleStateNeedsAttention ||
760+
!reflect.DeepEqual(addonInSpec.Version, addon.Version) ||
761+
!reflect.DeepEqual(addonConfigurationsActual, addonInSpec.Configurations) {
762+
s.Info(fmt.Sprintf("Updating addon %s", *addon.Name))
763+
_, err := s.ContainerEngineClient.UpdateAddon(ctx, oke.UpdateAddonRequest{
764+
ClusterId: okeCluster.Id,
765+
AddonName: addon.Name,
766+
UpdateAddonDetails: oke.UpdateAddonDetails{
767+
Version: addonInSpec.Version,
768+
Configurations: getAddonConfigurations(addonInSpec.Configurations),
769+
},
770+
})
771+
if err != nil {
772+
return err
773+
}
774+
}
775+
}
776+
return nil
777+
}
778+
779+
func (s *ManagedControlPlaneScope) handleDeletedAddon(ctx context.Context, okeCluster *oke.Cluster, addonName string) error {
780+
resp, err := s.ContainerEngineClient.GetAddon(ctx, oke.GetAddonRequest{
781+
ClusterId: okeCluster.Id,
782+
AddonName: common.String(addonName),
783+
})
784+
if err != nil {
785+
if ociutil.IsNotFound(err) {
786+
s.OCIManagedControlPlane.RemoveAddonStatus(addonName)
787+
return nil
788+
} else {
789+
return err
790+
}
791+
}
792+
addonState := resp.LifecycleState
793+
switch addonState {
794+
// nothing to do if addon is in deleting state
795+
case oke.AddonLifecycleStateDeleting:
796+
s.Info(fmt.Sprintf("Addon %s is in deleting state", addonName))
797+
break
798+
case oke.AddonLifecycleStateDeleted:
799+
// delete addon from status if addon has been deleted
800+
s.Info(fmt.Sprintf("Addon %s is in deleted state", addonName))
801+
s.OCIManagedControlPlane.RemoveAddonStatus(addonName)
802+
break
803+
default:
804+
// else delete the addon
805+
// delete addon is called disable addon with remove flag turned on
806+
_, err := s.ContainerEngineClient.DisableAddon(ctx, oke.DisableAddonRequest{
807+
ClusterId: okeCluster.Id,
808+
AddonName: common.String(addonName),
809+
IsRemoveExistingAddOn: common.Bool(true),
810+
})
811+
if err != nil {
812+
return err
813+
}
814+
}
815+
return nil
816+
}
817+
818+
func getAddonConfigurations(configurations []infrav2exp.AddonConfiguration) []oke.AddonConfiguration {
819+
if len(configurations) == 0 {
820+
return nil
821+
}
822+
config := make([]oke.AddonConfiguration, len(configurations))
823+
for i, c := range configurations {
824+
config[i] = oke.AddonConfiguration{
825+
Key: c.Key,
826+
Value: c.Value,
827+
}
828+
}
829+
return config
830+
}
831+
832+
func getActualAddonConfigurations(addonConfigurations []oke.AddonConfiguration) []infrav2exp.AddonConfiguration {
833+
if len(addonConfigurations) == 0 {
834+
return nil
835+
}
836+
config := make([]infrav2exp.AddonConfiguration, len(addonConfigurations))
837+
for i, c := range addonConfigurations {
838+
config[i] = infrav2exp.AddonConfiguration{
839+
Key: c.Key,
840+
Value: c.Value,
841+
}
842+
}
843+
return config
844+
}
845+
846+
func getAddon(addons []infrav2exp.Addon, name string) *infrav2exp.Addon {
847+
for i, addon := range addons {
848+
if *addon.Name == name {
849+
return &addons[i]
850+
}
851+
}
852+
return nil
853+
}
854+
676855
func getKubeConfigUserName(clusterName string, isUser bool) string {
677856
if isUser {
678857
return fmt.Sprintf("%s-user", clusterName)

0 commit comments

Comments
 (0)