From 346776cd14902a6e0f24cc97c15f61adecf57895 Mon Sep 17 00:00:00 2001 From: yaomengjiao <729974012@qq.com> Date: Wed, 30 Oct 2024 19:52:58 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0agent=E5=92=8Capi=E7=9B=B8?= =?UTF-8?q?=E5=85=B3=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pkg/agent/agent.go | 420 ++++++++++++++++++ pkg/agent/config-interface.go | 115 +++++ pkg/agent/watch/object.go | 174 ++++++++ pkg/agent/watch/watch.go | 15 + pkg/apis/numaadj/v1alpha1/doc.go | 2 + pkg/apis/numaadj/v1alpha1/register.go | 37 ++ pkg/apis/numaadj/v1alpha1/types.go | 60 +++ .../numaadj/v1alpha1/zz_generated.deepcopy.go | 145 ++++++ 8 files changed, 968 insertions(+) create mode 100644 pkg/agent/agent.go create mode 100644 pkg/agent/config-interface.go create mode 100644 pkg/agent/watch/object.go create mode 100644 pkg/agent/watch/watch.go create mode 100644 pkg/apis/numaadj/v1alpha1/doc.go create mode 100644 pkg/apis/numaadj/v1alpha1/register.go create mode 100644 pkg/apis/numaadj/v1alpha1/types.go create mode 100644 pkg/apis/numaadj/v1alpha1/zz_generated.deepcopy.go diff --git a/pkg/agent/agent.go b/pkg/agent/agent.go new file mode 100644 index 0000000..20a7137 --- /dev/null +++ b/pkg/agent/agent.go @@ -0,0 +1,420 @@ +package agent + +import ( + "context" + "flag" + "fmt" + "os" + "strings" + "sync" + "time" + + "github.com/containerd/nri/pkg/api" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/kubernetes" + "k8s.io/client-go/rest" + "k8s.io/client-go/tools/clientcmd" + "k8s.io/klog/v2" + "numaadj.huawei.com/pkg/agent/watch" + "numaadj.huawei.com/pkg/apis/numaadj/v1alpha1" + "numaadj.huawei.com/pkg/policy" + nf "numaadj.huawei.com/pkg/policy/numafast" +) + +type Option func(*Agent) error + +var ( + defaultKubeconfig string + defaultConfigFile string + defaultCrdName string + defaultNamespace string + defaultGrpcIp string + defaultGrpcPort string + defaultReconcilerTime int +) + +func init() { + flag.StringVar(&defaultKubeconfig, "kubeconfig", "", "kubeconfig file path, if emptyt then use in-cluster configuration") + flag.StringVar(&defaultConfigFile, "config-file", "", "config file, used for monitor insetd of a CustomResources") + flag.StringVar(&defaultNamespace, "config-namespace", "kube-system", "namespace for configuration CustomResources") + flag.StringVar(&defaultCrdName, "config-crdname", "podafi", "name for configuration CustomerResouces") + flag.StringVar(&defaultGrpcIp, "grpc-ip", "127.0.0.1", "the ip address of grpc server for numafast") + flag.StringVar(&defaultGrpcPort, "grpc-port", "9090", "the port of grpc server for numafast") + flag.IntVar(&defaultReconcilerTime, "reconcile-time", 300, "the reconcile time of numafast(seconds)") +} + +// ConfigInterface is used bu the agent to access config custom resources. +type ConfigInterface interface { + SetKubeClient(cfg *rest.Config) error + CreateWatch(ctx context.Context, ns, name string) (watch.Interface, error) + GetConfigCrd(ctx context.Context, ns, name string) (*unstructured.Unstructured, error) + UpdateConfigCrd(ctx context.Context, ns string, un *unstructured.Unstructured) (*unstructured.Unstructured, error) + CreateConfigCrd(ctx context.Context, name, ns string) error +} + +func CrdConfigInterface() ConfigInterface { + return &configIf{ + kind: 1, + } +} + +func New(cfgIf ConfigInterface, options ...Option) (*Agent, error) { + a := &Agent{ + nodeName: os.Getenv("NODE_NAME"), + kubeconfig: defaultKubeconfig, + configFile: defaultConfigFile, + namespace: defaultNamespace, + crdname: defaultCrdName, + cfgIf: cfgIf, + stopC: make(chan struct{}), + } + + for _, o := range options { + if err := o(a); err != nil { + return nil, fmt.Errorf("failed to create agent: %w", err) + } + } + + if a.nodeName == "" && a.configFile == "" { + return nil, fmt.Errorf("failed to create agent: neither node name nor config file set") + } + + return a, nil +} + +func (a *Agent) Start(notifyFn NotifyFn) error { + a.notifyFn = notifyFn + + err := a.setupClients() + if err != nil { + return err + } + + err = a.setupCrdWatch() + if err != nil { + return err + } + + err = a.setupGrpc() + if err != nil { + return err + } + + err = a.setupConfigCrd() + if err != nil { + klog.Warningf("faile to create config crd: %v\n", err) + } else { + klog.Info("create config crd success") + } + + eventChanOf := func(w watch.Interface) <-chan watch.Event { + if w == nil { + return nil + } + return w.ResultChan() + } + + klog.Info("initialization configuration complete, starting up now...") + + //TODO: 这里定时器指定了5分钟调用一次numafast, 怎么改成动态配置定时器的时间,或者配置定时策略? + tick := time.Tick(time.Second * time.Duration(defaultReconcilerTime)) + + for { + select { + case <-a.stopC: + a.cleanUpWatches() + return nil + + case <-tick: + if err := a.updateByNumafastAware(); err != nil { + klog.Warningf("failed to update by numafaster Aware: %v", err) + } + + case e, ok := <-eventChanOf(a.crdWatch): + klog.Info("cra watch ^-^") + if !ok { + klog.Warningf("can't accept event to handle crd config update, error: %v", e.Object) + break + } + if e.Type == watch.Added || e.Type == watch.Modified { + if err := a.updateByCrdConfig(e.Object); err != nil { + klog.Warningf("failed to update by crd config: %v", err) + } + } + } + } +} + +func (a *Agent) Stop() { + a.stopLock.Lock() + defer a.stopLock.Unlock() + + if a.stopC != nil { + close(a.stopC) + _ = <-a.doneC + a.stopC = nil + } +} + +func (a *Agent) updateByNumafastAware() error { + klog.Info("update pod node resource by numafast aware ...") + + un, err := a.cfgIf.GetConfigCrd(context.Background(), a.namespace, a.crdname) + if err != nil { + return err + } + + oenuma := &v1alpha1.Oenuma{} + err = runtime.DefaultUnstructuredConverter.FromUnstructured(un.UnstructuredContent(), oenuma) + if err != nil { + return err + } + + var targetNode *v1alpha1.Node = nil + for idx := 0; idx < len(oenuma.Spec.Node); idx++ { + if a.nodeName == oenuma.Spec.Node[idx].Name { // 只能维护插件所在的工作节点上的Pod + targetNode = &oenuma.Spec.Node[idx] + break + } + } + + // 如果工作节点上的Pod首次调整,新建一个Node的数据类型为其维护更新的内容和更新后的状态 + if targetNode == nil { + targetNode = &v1alpha1.Node{ + Name: a.nodeName, + PodAffinity: make([]v1alpha1.PodAffinity, 0), + Numa: make([]v1alpha1.Numa, 0), + } + numaInfo, err := a.grpcClient.GetNumaNodes() + if err != nil { + return err + } + for _, numa := range numaInfo.NumaNodes { + targetNode.Numa = append(targetNode.Numa, v1alpha1.Numa{ + NumaNum: int32(numa.NumaNumer), + Cpuset: numa.Cpuset, + Memset: numa.Memset, + }) + } + + if oenuma.Spec.Node == nil { + oenuma.Spec.Node = make([]v1alpha1.Node, 0) + } + oenuma.Spec.Node = append(oenuma.Spec.Node, *targetNode) + } + + podList, err := a.k8sCli.CoreV1().Pods("default").List(context.Background(), v1.ListOptions{}) + if err != nil { + return fmt.Errorf("get pods list error: %v", err) + } + + affiRelaship, err := a.grpcClient.GetPodAffinityRelationship(podList) + if err != nil { + return err + } + fmt.Println("-------------get pod affinity affiRelaship ----------------") + for _, group := range affiRelaship.AffinityGroup { + fmt.Printf("group.NumaNumer: %v\n", group.NumaNumer) + for _, pod := range group.Pods { + fmt.Printf("pod.PodName: %v\npod.namespace: %v\n", pod.PodName, pod.PodNamespace) + } + } + fmt.Println("-----------------------------------------------------------") + + for _, group := range affiRelaship.AffinityGroup { + for _, pod := range group.Pods { + var podsAdjusted bool = false + // 1. 检查当前的亲缘关系是否以存在该Pod,如果存在调整numa编号即可 + for idx := 0; idx < len(targetNode.PodAffinity); idx++ { + if targetNode.PodAffinity[idx].PodName == pod.PodName { + podsAdjusted = true + targetNode.PodAffinity[idx].NumaNum = int32(group.NumaNumer) + break + } + } + if !podsAdjusted { + targetNode.PodAffinity = append(targetNode.PodAffinity, v1alpha1.PodAffinity{ + NumaNum: int32(group.NumaNumer), + PodName: pod.PodName, + Namespace: pod.PodNamespace, + }) + } + } + } + + obj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(oenuma) + if err != nil { + return err + } + un.Object = obj + _, err = a.cfgIf.UpdateConfigCrd(context.Background(), a.namespace, un) + if err != nil { + return err + } + + return nil +} + +func (a *Agent) updateByCrdConfig(obj runtime.Object) error { + if obj != nil { + uobj, ok := obj.(*unstructured.Unstructured) + if !ok { + return fmt.Errorf("can not handle object %T, ignoring it.", obj) + } + + oenuma := &v1alpha1.Oenuma{} + err := runtime.DefaultUnstructuredConverter.FromUnstructured(uobj.UnstructuredContent(), oenuma) + if err != nil { + return fmt.Errorf("failed to convert unstructured obj.") + } + + config, err := a.createCrdConfigPolicy(oenuma) + if err != nil { + return fmt.Errorf("failer to create crd config policy.") + } + return a.notifyFn(config) + } + return nil +} + +func (a *Agent) createCrdConfigPolicy(oenuma *v1alpha1.Oenuma) (*policy.Config, error) { + config := &policy.Config{} + for _, node := range oenuma.Spec.Node { + if node.Name != a.nodeName { + continue //只更新本工作节点的pod + } + + for _, podAfi := range node.PodAffinity { + pod, err := a.k8sCli.CoreV1().Pods(podAfi.Namespace).Get(context.TODO(), podAfi.PodName, v1.GetOptions{}) + if err != nil { + klog.Errorf("can not found pod: %s in namespace: %s", podAfi.PodName, podAfi.Namespace) + continue + } + + for _, container := range pod.Status.ContainerStatuses { + sp := strings.Split(container.ContainerID, "/") + containerId := sp[len(sp)-1] + + containerUpdate := &api.ContainerUpdate{ + ContainerId: containerId, + Linux: &api.LinuxContainerUpdate{Resources: &api.LinuxResources{Cpu: &api.LinuxCPU{Cpus: "", Mems: ""}}}, + } + + idx := 0 + for idx < len(node.Numa) && node.Numa[idx].NumaNum != podAfi.NumaNum { + idx++ + } + if idx >= len(node.Numa) { + klog.Warning("can not found numa node affinity with pod") + continue + } + + containerUpdate.Linux.Resources.Cpu.Cpus = node.Numa[idx].Cpuset + containerUpdate.Linux.Resources.Cpu.Mems = node.Numa[idx].Memset + config.Push(containerUpdate) + } + } + } + return config, nil +} + +type NotifyFn func(cfg interface{}) error + +type Agent struct { + nodeName string + kubeconfig string + configFile string + namespace string + crdname string + + cfgIf ConfigInterface // custom resource access interface + k8sCli *kubernetes.Clientset + + notifyFn NotifyFn // config resource change notification callback + crdWatch watch.Interface + grpcClient *nf.GrpcClient + + stopLock sync.Mutex + stopC chan struct{} + doneC chan struct{} +} + +func (a *Agent) setupClients() error { + cfg, err := a.getK8sConfig() + if err != nil { + return err + } + + a.k8sCli, err = kubernetes.NewForConfig(cfg) + if err != nil { + return fmt.Errorf("failed to setup kubernetes client: %v", err) + } + + err = a.cfgIf.SetKubeClient(cfg) + if err != nil { + return fmt.Errorf("failed to setup config resource client: %v", err) + } + + return nil +} + +func (a *Agent) getK8sConfig() (*rest.Config, error) { + var ( + cfg *rest.Config + err error + ) + + if a.kubeconfig == "" { + cfg, err = rest.InClusterConfig() + } else { + cfg, err = clientcmd.BuildConfigFromFlags("", a.kubeconfig) + } + + if err != nil { + return nil, fmt.Errorf("failed to get kuberneters config: %v", err) + } + + return cfg, nil +} + +func (a *Agent) setupCrdWatch() error { + crdWatch, err := watch.Object(context.Background(), a.namespace, a.crdname, + func(ctx context.Context, ns, name string) (watch.Interface, error) { + return a.cfgIf.CreateWatch(ctx, ns, name) + }, + ) + + if err != nil { + return fmt.Errorf("failed to setup crd watch: %v", err) + } + + a.crdWatch = crdWatch + + return nil +} + +func (a *Agent) cleanUpWatches() { + if a.crdWatch != nil { + a.crdWatch.Stop() + a.crdWatch = nil + } +} + +func (a *Agent) setupGrpc() error { + grpcClient, err := nf.NewGrpcClient(defaultGrpcIp, defaultGrpcPort) + if err != nil { + return fmt.Errorf("can not set up grpc client") + } + a.grpcClient = grpcClient + return nil +} + +func (a *Agent) setupConfigCrd() error { + err := a.cfgIf.CreateConfigCrd(context.Background(), a.crdname, a.namespace) + if err != nil { + return err + } + return nil +} diff --git a/pkg/agent/config-interface.go b/pkg/agent/config-interface.go new file mode 100644 index 0000000..f15d392 --- /dev/null +++ b/pkg/agent/config-interface.go @@ -0,0 +1,115 @@ +package agent + +import ( + "context" + "fmt" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/watch" + "k8s.io/client-go/dynamic" + "k8s.io/client-go/rest" + "k8s.io/klog/v2" + "numaadj.huawei.com/pkg/apis/numaadj/v1alpha1" +) + +type configKind int + +type configIf struct { + kind configKind + cfg *rest.Config + cli *dynamic.DynamicClient +} + +func newConfigIf(kind configKind) *configIf { + return &configIf{ + kind: kind, + } +} + +func (cif *configIf) SetKubeClient(cfg *rest.Config) error { + cif.cfg = cfg + cli, err := dynamic.NewForConfig(cfg) + if err != nil { + return fmt.Errorf("failed to create client kuebclient: %v", err) + } + cif.cli = cli + return nil +} + +func (cif *configIf) CreateWatch(ctx context.Context, ns, name string) (watch.Interface, error) { + selector := metav1.ListOptions{ + FieldSelector: "metadata.name=" + name, + } + + return cif.cli.Resource(schema.GroupVersionResource{ + Group: v1alpha1.SchemeGroupVersion.Group, + Version: "v1alpha1", + Resource: "oenumas", + }).Namespace(ns).Watch(ctx, selector) +} + +func (cif *configIf) GetConfigCrd(ctx context.Context, ns, name string) (*unstructured.Unstructured, error) { + un, err := cif.cli.Resource(schema.GroupVersionResource{ + Group: v1alpha1.SchemeGroupVersion.Group, + Version: "v1alpha1", + Resource: "oenumas", + }).Namespace(ns).Get(ctx, name, v1.GetOptions{}) + + if err != nil { + return nil, fmt.Errorf("get configed crd error: %v", err) + } + + return un, err +} + +func (cif *configIf) UpdateConfigCrd(ctx context.Context, ns string, un *unstructured.Unstructured) (*unstructured.Unstructured, error) { + updated, err := cif.cli.Resource(schema.GroupVersionResource{ + Group: v1alpha1.SchemeGroupVersion.Group, + Version: "v1alpha1", + Resource: "oenumas", + }).Namespace(ns).Update(context.Background(), un, v1.UpdateOptions{}) + if err != nil { + return nil, fmt.Errorf("update config crd error%v", err) + } + return updated, nil +} + +func (cif *configIf) CreateConfigCrd(ctx context.Context, name, ns string) error { + gvr := schema.GroupVersionResource{ + Group: v1alpha1.SchemeGroupVersion.Group, + Version: "v1alpha1", + Resource: "oenumas", + } + + _, err := cif.cli.Resource(gvr).Namespace(ns).Get(ctx, name, v1.GetOptions{}) + if err == nil { + return fmt.Errorf("the target crd: oenuma already exists.") + } else { + klog.Info("the target crd not exists, automatically create crd: oenuma") + } + + crd := &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "resource.sop.huawei.com/v1alpha1", + "kind": "Oenuma", + "metadata": map[string]interface{}{ + "name": name, + "namespace": ns, + }, + "spec": map[string]interface{}{ + "name": "testapp1", + "replicas": 1, + }, + }, + } + + _, err = cif.cli.Resource(gvr).Namespace(ns).Create(ctx, crd, v1.CreateOptions{}) + if err != nil { + klog.Error(err) + return fmt.Errorf("unable to automatically create crd: oenuma, please try to creating it manually.") + } + return nil +} diff --git a/pkg/agent/watch/object.go b/pkg/agent/watch/object.go new file mode 100644 index 0000000..cc14944 --- /dev/null +++ b/pkg/agent/watch/object.go @@ -0,0 +1,174 @@ +package watch + +import ( + "context" + "sync" + "time" + + "k8s.io/apimachinery/pkg/watch" + "k8s.io/klog/v2" +) + +type CreateFn func(ctx context.Context, ns, name string) (watch.Interface, error) + +const ( + reopenDelay = 5 * time.Second +) + +type ObjectWatch struct { + create CreateFn + ctx context.Context + namespace string + name string + resultC chan watch.Event + wif watch.Interface + reopenC <-chan time.Time + failing bool + + stopLock sync.Mutex + stopC chan struct{} + doneC chan struct{} +} + +func Object(ctx context.Context, ns, name string, create CreateFn) (watch.Interface, error) { + w := &ObjectWatch{ + create: create, + ctx: ctx, + namespace: ns, + name: name, + resultC: make(chan watch.Event, watch.DefaultChanSize), + stopC: make(chan struct{}), + doneC: make(chan struct{}), + } + + if err := w.run(); err != nil { + return nil, err + } + return w, nil +} + +func (w *ObjectWatch) Stop() { + w.stopLock.Lock() + defer w.stopLock.Unlock() + + if w.stopC != nil { + close(w.stopC) + _ = <-w.doneC + w.stopC = nil + } +} + +func (w *ObjectWatch) ResultChan() <-chan watch.Event { + return w.resultC +} + +func (w *ObjectWatch) eventChan() <-chan watch.Event { + if w.wif == nil { + return nil + } + return w.wif.ResultChan() +} + +func (w *ObjectWatch) run() error { + err := w.open() + if err != nil { + return err + } + + go func() { + for { + select { + case <-w.stopC: + w.Stop() + close(w.resultC) + close(w.doneC) + return + + case e, ok := <-w.eventChan(): + if !ok { + klog.Warningf("watch %s expired", w.watchname()) + w.reopen() + continue + } + if e.Type == watch.Error { + w.markFailing() + w.stop() + } + select { + case w.resultC <- e: + default: + w.markFailing() + w.stop() + w.scheduleReopen() + } + + case <-w.reopenC: + w.reopenC = nil + w.reopen() + } + } + }() + + return nil +} + +func (w *ObjectWatch) open() error { + if w.wif != nil { + w.wif.Stop() + w.wif = nil + } + + wif, err := w.create(w.ctx, w.namespace, w.name) + if err != nil { + return err + } + + w.wif = wif + w.markRunning() + return nil +} + +func (w *ObjectWatch) reopen() error { + if err := w.open(); err != nil { + w.scheduleReopen() + } else { + klog.Infof("watch %s reopened", w.watchname()) + w.markRunning() + } + return nil +} + +func (w *ObjectWatch) stop() { + if w.wif != nil { + w.wif.Stop() + w.wif = nil + } +} + +func (w *ObjectWatch) scheduleReopen() { + if w.resultC != nil { + return + } + w.reopenC = time.After(reopenDelay) +} + +func (w *ObjectWatch) markFailing() { + if !w.failing { + klog.Errorf("watch %s is now failing", w.watchname()) + w.failing = true + } +} + +func (w *ObjectWatch) markRunning() { + if w.failing { + klog.Errorf("watch %s is now running", w.watchname()) + w.failing = false + } +} + +func (w *ObjectWatch) watchname() string { + if w.namespace != "" { + return w.namespace + "/" + w.name + } + return w.name +} diff --git a/pkg/agent/watch/watch.go b/pkg/agent/watch/watch.go new file mode 100644 index 0000000..a2ca8d1 --- /dev/null +++ b/pkg/agent/watch/watch.go @@ -0,0 +1,15 @@ +package watch + +import "k8s.io/apimachinery/pkg/watch" + +type ( + EventType = watch.EventType + Interface = watch.Interface + Event = watch.Event +) + +const ( + Added = watch.Added + Modified = watch.Modified + Error = watch.Error +) diff --git a/pkg/apis/numaadj/v1alpha1/doc.go b/pkg/apis/numaadj/v1alpha1/doc.go new file mode 100644 index 0000000..598b78e --- /dev/null +++ b/pkg/apis/numaadj/v1alpha1/doc.go @@ -0,0 +1,2 @@ +// +groupName=resource.sop.huawei.com +package v1alpha1 diff --git a/pkg/apis/numaadj/v1alpha1/register.go b/pkg/apis/numaadj/v1alpha1/register.go new file mode 100644 index 0000000..c88d450 --- /dev/null +++ b/pkg/apis/numaadj/v1alpha1/register.go @@ -0,0 +1,37 @@ +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +// SchemeGroupVersion is group version used to register these objects +var SchemeGroupVersion = schema.GroupVersion{Group: "resource.sop.huawei.com", Version: "v1alpha1"} + +// Kind takes an unqualified kind and returns back a Group qualified GroupKind +func Kind(kind string) schema.GroupKind { + return SchemeGroupVersion.WithKind(kind).GroupKind() +} + +// Resource takes an unqualified resource and returns a Group qualified GroupResource +func Resource(resource string) schema.GroupResource { + return SchemeGroupVersion.WithResource(resource).GroupResource() +} + +var ( + // SchemeBuilder initializes a scheme builder + SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) + // AddToScheme is a global function that registers this API group & version to a scheme + AddToScheme = SchemeBuilder.AddToScheme +) + +// Adds the list of known types to Scheme. +func addKnownTypes(scheme *runtime.Scheme) error { + scheme.AddKnownTypes(SchemeGroupVersion, + &Oenuma{}, + &OenumaList{}, + ) + metav1.AddToGroupVersion(scheme, SchemeGroupVersion) + return nil +} diff --git a/pkg/apis/numaadj/v1alpha1/types.go b/pkg/apis/numaadj/v1alpha1/types.go new file mode 100644 index 0000000..1ea38ba --- /dev/null +++ b/pkg/apis/numaadj/v1alpha1/types.go @@ -0,0 +1,60 @@ +package v1alpha1 + +import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + +// +k8s:deepcopy-gen=true +// OenumaSpec defines the desired state of Oenuma +type OenumaSpec struct { + // INSERT ADDITIONAL SPEC FIELDS -- desired state of cluster + Name string `json:"name,omitempty"` + Replicas int32 `json:"replicas,omitempty"` + Node []Node `json:"node,omitempty"` +} + +// +k8s:deepcopy-gen=true +type Node struct { + Name string `json:"name,omitempty"` + Numa []Numa `json:"numa,omitempty"` + PodAffinity []PodAffinity `json:"podAffinity,omitempty"` +} + +// +k8s:deepcopy-gen=true +type Numa struct { + NumaNum int32 `json:"numaNum,omitempty"` + Cpuset string `json:"cpuset,omitempty"` + Memset string `json:"memset,omitempty"` +} + +// +k8s:deepcopy-gen=true +type PodAffinity struct { + NumaNum int32 `json:"numaNum,omitempty"` + PodName string `json:"podName,omitempty"` + Namespace string `json:"namespace,omitempty"` +} + +// OenumaStatus defines the observed state of Oenuma. +// It should always be reconstructable from the state of the cluster and/or outside world. +type OenumaStatus struct { + // INSERT ADDITIONAL STATUS FIELDS -- observed state of cluster +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// Oenuma is the Schema for the oenumas API +// +k8s:openapi-gen=true +type Oenuma struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec OenumaSpec `json:"spec,omitempty"` + Status OenumaStatus `json:"status,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// OenumaList contains a list of Oenuma +type OenumaList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []Oenuma `json:"items"` +} diff --git a/pkg/apis/numaadj/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/numaadj/v1alpha1/zz_generated.deepcopy.go new file mode 100644 index 0000000..43befda --- /dev/null +++ b/pkg/apis/numaadj/v1alpha1/zz_generated.deepcopy.go @@ -0,0 +1,145 @@ +//go:build !ignore_autogenerated + +// Code generated by controller-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Node) DeepCopyInto(out *Node) { + *out = *in + if in.Numa != nil { + in, out := &in.Numa, &out.Numa + *out = make([]Numa, len(*in)) + copy(*out, *in) + } + if in.PodAffinity != nil { + in, out := &in.PodAffinity, &out.PodAffinity + *out = make([]PodAffinity, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Node. +func (in *Node) DeepCopy() *Node { + if in == nil { + return nil + } + out := new(Node) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Numa) DeepCopyInto(out *Numa) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Numa. +func (in *Numa) DeepCopy() *Numa { + if in == nil { + return nil + } + out := new(Numa) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Oenuma) DeepCopyInto(out *Oenuma) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + out.Status = in.Status +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Oenuma. +func (in *Oenuma) DeepCopy() *Oenuma { + if in == nil { + return nil + } + out := new(Oenuma) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Oenuma) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *OenumaList) DeepCopyInto(out *OenumaList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Oenuma, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OenumaList. +func (in *OenumaList) DeepCopy() *OenumaList { + if in == nil { + return nil + } + out := new(OenumaList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *OenumaList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *OenumaSpec) DeepCopyInto(out *OenumaSpec) { + *out = *in + if in.Node != nil { + in, out := &in.Node, &out.Node + *out = make([]Node, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OenumaSpec. +func (in *OenumaSpec) DeepCopy() *OenumaSpec { + if in == nil { + return nil + } + out := new(OenumaSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PodAffinity) DeepCopyInto(out *PodAffinity) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodAffinity. +func (in *PodAffinity) DeepCopy() *PodAffinity { + if in == nil { + return nil + } + out := new(PodAffinity) + in.DeepCopyInto(out) + return out +} -- Gitee