mirror of
https://github.com/rancher/os.git
synced 2025-09-08 18:20:32 +00:00
Add operator
This commit is contained in:
80
pkg/controllers/inventory/inventory.go
Normal file
80
pkg/controllers/inventory/inventory.go
Normal file
@@ -0,0 +1,80 @@
|
||||
package inventory
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
v1 "github.com/rancher/os/pkg/apis/rancheros.cattle.io/v1"
|
||||
"github.com/rancher/os/pkg/clients"
|
||||
ranchercontrollers "github.com/rancher/os/pkg/generated/controllers/management.cattle.io/v3"
|
||||
provcontrollers "github.com/rancher/os/pkg/generated/controllers/provisioning.cattle.io/v1"
|
||||
v12 "github.com/rancher/os/pkg/generated/controllers/rancheros.cattle.io/v1"
|
||||
v3 "github.com/rancher/rancher/pkg/apis/management.cattle.io/v3"
|
||||
"github.com/rancher/wrangler/pkg/name"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
type handler struct {
|
||||
clusterCache provcontrollers.ClusterCache
|
||||
clusterRegistrationTokenCache ranchercontrollers.ClusterRegistrationTokenCache
|
||||
clusterRegistrationTokenClient ranchercontrollers.ClusterRegistrationTokenClient
|
||||
}
|
||||
|
||||
func Register(ctx context.Context, clients *clients.Clients) {
|
||||
h := &handler{
|
||||
clusterCache: clients.Provisioning.Cluster().Cache(),
|
||||
clusterRegistrationTokenCache: clients.Rancher.ClusterRegistrationToken().Cache(),
|
||||
clusterRegistrationTokenClient: clients.Rancher.ClusterRegistrationToken(),
|
||||
}
|
||||
|
||||
clients.OS.MachineInventory().OnRemove(ctx, "machine-inventory-remove", h.OnMachineInventoryRemove)
|
||||
v12.RegisterMachineInventoryStatusHandler(ctx, clients.OS.MachineInventory(), "", "machine-inventory", h.OnMachineInventory)
|
||||
}
|
||||
|
||||
func (h *handler) OnMachineInventoryRemove(key string, machine *v1.MachineInventory) (*v1.MachineInventory, error) {
|
||||
if machine.Status.ClusterRegistrationTokenName != "" && machine.Status.ClusterRegistrationTokenNamespace != "" {
|
||||
err := h.clusterRegistrationTokenClient.Delete(machine.Status.ClusterRegistrationTokenNamespace, machine.Status.ClusterRegistrationTokenName, nil)
|
||||
if !apierrors.IsNotFound(err) && err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return machine, nil
|
||||
}
|
||||
|
||||
func (h *handler) OnMachineInventory(machine *v1.MachineInventory, status v1.MachineInventoryStatus) (v1.MachineInventoryStatus, error) {
|
||||
if machine == nil {
|
||||
return status, nil
|
||||
}
|
||||
|
||||
cluster, err := h.clusterCache.Get(machine.Namespace, machine.Spec.ClusterName)
|
||||
if err != nil {
|
||||
return status, err
|
||||
}
|
||||
|
||||
if cluster.Status.ClusterName == "" {
|
||||
return status, fmt.Errorf("waiting for mgmt cluster to be created for prov cluster %s/%s", machine.Namespace, machine.Spec.ClusterName)
|
||||
}
|
||||
|
||||
crtName := name.SafeConcatName(cluster.Status.ClusterName, machine.Name, "-token")
|
||||
_, err = h.clusterRegistrationTokenCache.Get(cluster.Status.ClusterName, crtName)
|
||||
if apierrors.IsNotFound(err) {
|
||||
_, err = h.clusterRegistrationTokenClient.Create(&v3.ClusterRegistrationToken{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: crtName,
|
||||
Namespace: cluster.Status.ClusterName,
|
||||
},
|
||||
Spec: v3.ClusterRegistrationTokenSpec{
|
||||
ClusterName: cluster.Status.ClusterName,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return status, err
|
||||
}
|
||||
|
||||
status.ClusterRegistrationTokenName = crtName
|
||||
status.ClusterRegistrationTokenNamespace = cluster.Status.ClusterName
|
||||
return status, nil
|
||||
}
|
104
pkg/controllers/managedos/managedos.go
Normal file
104
pkg/controllers/managedos/managedos.go
Normal file
@@ -0,0 +1,104 @@
|
||||
package managedos
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/rancher/fleet/pkg/apis/fleet.cattle.io/v1alpha1"
|
||||
provv1 "github.com/rancher/os/pkg/apis/rancheros.cattle.io/v1"
|
||||
"github.com/rancher/os/pkg/clients"
|
||||
fleetcontrollers "github.com/rancher/os/pkg/generated/controllers/fleet.cattle.io/v1alpha1"
|
||||
ranchercontrollers "github.com/rancher/os/pkg/generated/controllers/management.cattle.io/v3"
|
||||
oscontrollers "github.com/rancher/os/pkg/generated/controllers/rancheros.cattle.io/v1"
|
||||
"github.com/rancher/wrangler/pkg/name"
|
||||
"github.com/rancher/wrangler/pkg/relatedresource"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
func Register(ctx context.Context, clients *clients.Clients) {
|
||||
h := &handler{
|
||||
bundleCache: clients.Fleet.Bundle().Cache(),
|
||||
settingsCache: clients.Rancher.Setting().Cache(),
|
||||
}
|
||||
|
||||
relatedresource.Watch(ctx,
|
||||
"mcc-from-bundle-trigger",
|
||||
relatedresource.OwnerResolver(true, provv1.SchemeGroupVersion.String(), "ManagedOSImage"),
|
||||
clients.OS.ManagedOSImage(),
|
||||
clients.Fleet.Bundle())
|
||||
oscontrollers.RegisterManagedOSImageGeneratingHandler(ctx,
|
||||
clients.OS.ManagedOSImage(),
|
||||
clients.Apply.
|
||||
WithSetOwnerReference(true, true).
|
||||
WithCacheTypes(
|
||||
clients.OS.ManagedOSImage(),
|
||||
clients.Fleet.Bundle()),
|
||||
"Defined",
|
||||
"mos-bundle",
|
||||
h.OnChange,
|
||||
nil)
|
||||
}
|
||||
|
||||
type handler struct {
|
||||
bundleCache fleetcontrollers.BundleCache
|
||||
settingsCache ranchercontrollers.SettingCache
|
||||
}
|
||||
|
||||
func (h *handler) defaultRegistry() (string, error) {
|
||||
setting, err := h.settingsCache.Get("system-default-registry")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if setting.Value == "" {
|
||||
return setting.Default, nil
|
||||
}
|
||||
return setting.Value, nil
|
||||
}
|
||||
|
||||
func (h *handler) OnChange(mos *provv1.ManagedOSImage, status provv1.ManagedOSImageStatus) ([]runtime.Object, provv1.ManagedOSImageStatus, error) {
|
||||
if mos.Spec.OSImage == "" {
|
||||
return nil, status, nil
|
||||
}
|
||||
|
||||
prefix, err := h.defaultRegistry()
|
||||
if err != nil {
|
||||
return nil, status, err
|
||||
}
|
||||
|
||||
resources, err := ToResources(objects(mos, prefix))
|
||||
if err != nil {
|
||||
return nil, status, err
|
||||
}
|
||||
|
||||
bundle := &v1alpha1.Bundle{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name.SafeConcatName("mos", mos.Name),
|
||||
Namespace: mos.Namespace,
|
||||
},
|
||||
Spec: v1alpha1.BundleSpec{
|
||||
Resources: resources,
|
||||
BundleDeploymentOptions: v1alpha1.BundleDeploymentOptions{},
|
||||
Paused: mos.Spec.Paused,
|
||||
RolloutStrategy: mos.Spec.ClusterRolloutStrategy,
|
||||
Targets: mos.Spec.Targets,
|
||||
},
|
||||
}
|
||||
|
||||
status, err = h.updateStatus(status, bundle)
|
||||
return []runtime.Object{
|
||||
bundle,
|
||||
}, status, err
|
||||
}
|
||||
|
||||
func (h *handler) updateStatus(status provv1.ManagedOSImageStatus, bundle *v1alpha1.Bundle) (provv1.ManagedOSImageStatus, error) {
|
||||
bundle, err := h.bundleCache.Get(bundle.Namespace, bundle.Name)
|
||||
if apierrors.IsNotFound(err) {
|
||||
return status, nil
|
||||
} else if err != nil {
|
||||
return status, err
|
||||
}
|
||||
|
||||
status.BundleStatus = bundle.Status
|
||||
return status, nil
|
||||
}
|
46
pkg/controllers/managedos/resource.go
Normal file
46
pkg/controllers/managedos/resource.go
Normal file
@@ -0,0 +1,46 @@
|
||||
package managedos
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/rancher/fleet/pkg/apis/fleet.cattle.io/v1alpha1"
|
||||
"github.com/rancher/wrangler/pkg/gvk"
|
||||
"github.com/rancher/wrangler/pkg/name"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
func ToResources(objs []runtime.Object) (result []v1alpha1.BundleResource, err error) {
|
||||
for _, obj := range objs {
|
||||
obj = obj.DeepCopyObject()
|
||||
if err := gvk.Set(obj); err != nil {
|
||||
return nil, fmt.Errorf("failed to set gvk: %w", err)
|
||||
}
|
||||
|
||||
typeMeta, err := meta.TypeAccessor(obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
meta, err := meta.Accessor(obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
data, err := json.Marshal(obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
digest := sha256.Sum256(data)
|
||||
filename := name.SafeConcatName(typeMeta.GetKind(), meta.GetNamespace(), meta.GetName(), hex.EncodeToString(digest[:])[:12]) + ".yaml"
|
||||
result = append(result, v1alpha1.BundleResource{
|
||||
Name: filename,
|
||||
Content: string(data),
|
||||
})
|
||||
}
|
||||
return
|
||||
}
|
105
pkg/controllers/managedos/template.go
Normal file
105
pkg/controllers/managedos/template.go
Normal file
@@ -0,0 +1,105 @@
|
||||
package managedos
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
osv1 "github.com/rancher/os/pkg/apis/rancheros.cattle.io/v1"
|
||||
"github.com/rancher/os/pkg/clients"
|
||||
upgradev1 "github.com/rancher/system-upgrade-controller/pkg/apis/upgrade.cattle.io/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
rbacv1 "k8s.io/api/rbac/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
func objects(mos *osv1.ManagedOSImage, prefix string) []runtime.Object {
|
||||
concurrency := int64(1)
|
||||
if mos.Spec.Concurrency != nil {
|
||||
concurrency = *mos.Spec.Concurrency
|
||||
}
|
||||
|
||||
cordon := true
|
||||
if mos.Spec.Cordon != nil {
|
||||
cordon = *mos.Spec.Cordon
|
||||
}
|
||||
|
||||
image := strings.SplitN(mos.Spec.OSImage, ":", 2)
|
||||
version := "latest"
|
||||
if len(image) == 2 {
|
||||
version = image[1]
|
||||
}
|
||||
|
||||
selector := mos.Spec.NodeSelector
|
||||
if selector == nil {
|
||||
selector = &metav1.LabelSelector{}
|
||||
}
|
||||
|
||||
return []runtime.Object{
|
||||
&rbacv1.ClusterRole{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "os-upgrader",
|
||||
},
|
||||
Rules: []rbacv1.PolicyRule{{
|
||||
Verbs: []string{"update", "get", "list", "watch", "patch"},
|
||||
APIGroups: []string{""},
|
||||
Resources: []string{"nodes"},
|
||||
}},
|
||||
},
|
||||
&rbacv1.ClusterRoleBinding{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "os-upgrader",
|
||||
},
|
||||
Subjects: []rbacv1.Subject{{
|
||||
Kind: "ServiceAccount",
|
||||
Name: "os-upgrader",
|
||||
Namespace: clients.SystemNamespace,
|
||||
}},
|
||||
RoleRef: rbacv1.RoleRef{
|
||||
APIGroup: rbacv1.GroupName,
|
||||
Kind: "ClusterRole",
|
||||
Name: "os-upgrader",
|
||||
},
|
||||
},
|
||||
&corev1.ServiceAccount{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "os-upgrader",
|
||||
Namespace: clients.SystemNamespace,
|
||||
},
|
||||
},
|
||||
&upgradev1.Plan{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "Plan",
|
||||
APIVersion: "upgrade.cattle.io/v1",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "os-upgrader",
|
||||
Namespace: clients.SystemNamespace,
|
||||
},
|
||||
Spec: upgradev1.PlanSpec{
|
||||
Concurrency: concurrency,
|
||||
Version: version,
|
||||
Tolerations: []corev1.Toleration{{
|
||||
Operator: corev1.TolerationOpExists,
|
||||
}},
|
||||
ServiceAccountName: "os-upgrader",
|
||||
NodeSelector: selector,
|
||||
Cordon: cordon,
|
||||
Drain: mos.Spec.Drain,
|
||||
Prepare: mos.Spec.Prepare,
|
||||
Upgrade: &upgradev1.ContainerSpec{
|
||||
Image: PrefixPrivateRegistry(image[0], prefix),
|
||||
Command: []string{
|
||||
"/usr/sbin/suc-upgrade",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func PrefixPrivateRegistry(image, prefix string) string {
|
||||
if prefix == "" {
|
||||
return image
|
||||
}
|
||||
return prefix + "/" + image
|
||||
}
|
Reference in New Issue
Block a user