common/controllers/operations.go (102 lines of code) (raw):
// Copyright 2018 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package controllers
import (
"context"
"strings"
"sync"
"time"
"github.com/go-logr/logr"
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/discovery"
"k8s.io/client-go/dynamic"
"k8s.io/client-go/rest"
cronanything "github.com/GoogleCloudPlatform/elcarro-oracle-operator/common/api/v1alpha1"
)
type realResourceControl struct {
dynClient dynamic.Interface
}
func (r *realResourceControl) Delete(resource schema.GroupVersionResource, namespace, name string) error {
deleteForeground := metav1.DeletePropagationForeground
return r.dynClient.Resource(resource).Namespace(namespace).Delete(context.TODO(), name, metav1.DeleteOptions{PropagationPolicy: &deleteForeground})
}
func (r *realResourceControl) Create(resource schema.GroupVersionResource, namespace string, template *unstructured.Unstructured) error {
_, err := r.dynClient.Resource(resource).Namespace(namespace).Create(context.TODO(), template, metav1.CreateOptions{})
return err
}
func (r *realResourceControl) List(resource schema.GroupVersionResource, cronAnythingName string) ([]*unstructured.Unstructured, error) {
res, err := r.dynClient.Resource(resource).List(context.TODO(), metav1.ListOptions{
LabelSelector: labels.SelectorFromSet(labels.Set{cronanything.CronAnythingCreatedByLabel: cronAnythingName}).String(),
})
if err != nil {
return []*unstructured.Unstructured{}, err
}
list, err := meta.ExtractList(res)
if err != nil {
return []*unstructured.Unstructured{}, err
}
returnList := make([]*unstructured.Unstructured, 0)
for _, obj := range list {
unstructuredResource, _ := obj.(*unstructured.Unstructured)
returnList = append(returnList, unstructuredResource)
}
return returnList, nil
}
// NewResourceResolver creates a resource resolver to find the corresponding
// group version resource for a given group version kind.
func NewResourceResolver(config *rest.Config) *realResourceResolver {
dc := discovery.NewDiscoveryClientForConfigOrDie(config)
return &realResourceResolver{
dc: dc,
}
}
type realResourceResolver struct {
mu sync.Mutex
dc *discovery.DiscoveryClient
resourceMapping map[schema.GroupVersionKind]schema.GroupVersionResource
}
func (r *realResourceResolver) Start(refreshInterval time.Duration, stopCh <-chan struct{}, log logr.Logger) {
go func() {
ticker := time.NewTicker(refreshInterval)
defer ticker.Stop()
for {
r.refresh(log)
select {
case <-stopCh:
return
case <-ticker.C:
}
}
}()
}
func (r *realResourceResolver) refresh(log logr.Logger) {
_, resources, err := r.dc.ServerGroupsAndResources()
if err != nil {
log.Error(err, "Unable to fetch server resources")
return
}
mapping := make(map[schema.GroupVersionKind]schema.GroupVersionResource)
for _, apiResourceList := range resources {
gv, err := schema.ParseGroupVersion(apiResourceList.GroupVersion)
if err != nil {
log.Error(err, "Error parsing group version", "groupVersion", apiResourceList.GroupVersion)
continue
}
for _, apiResource := range apiResourceList.APIResources {
gvk := gv.WithKind(apiResource.Kind)
gvr := gv.WithResource(apiResource.Name)
// temporary fix to avoid adding subResource. For example, backups and
// backups/status shared the same gvk.
if !strings.Contains(apiResource.Name, "/") {
mapping[gvk] = gvr
}
}
}
r.mu.Lock()
defer r.mu.Unlock()
r.resourceMapping = mapping
}
func (r *realResourceResolver) Resolve(gvk schema.GroupVersionKind) (schema.GroupVersionResource, bool) {
r.mu.Lock()
defer r.mu.Unlock()
item, found := r.resourceMapping[gvk]
return item, found
}