gomod: change projectcalico/calico to kubesphere/calico (#5557)

* chore(calico): update calico to 3.25.0

* chore(calico): replace projectcalico/calico to kubesphere/calico

Signed-off-by: root <renyunkang@kubesphere.io>

---------

Signed-off-by: root <renyunkang@kubesphere.io>
This commit is contained in:
Yunkang Ren
2023-02-28 17:03:36 +08:00
committed by GitHub
parent dc28a0917a
commit a3a6a1cd98
146 changed files with 11189 additions and 4663 deletions

View File

@@ -0,0 +1,296 @@
// Copyright (c) 2017 Tigera, Inc. All rights reserved.
//
// 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 cache
import (
"reflect"
"sync"
"time"
"github.com/patrickmn/go-cache"
log "github.com/sirupsen/logrus"
"k8s.io/client-go/util/workqueue"
)
// ResourceCache stores resources and queues updates when those resources
// are created, modified, or deleted. It de-duplicates updates by ensuring
// updates are only queued when an object has changed.
type ResourceCache interface {
// Set sets the key to the provided value, and generates an update
// on the queue the value has changed.
Set(key string, value interface{})
// Get gets the value associated with the given key. Returns nil
// if the key is not present.
Get(key string) (interface{}, bool)
// Prime sets the key to the provided value, but does not generate
// and update on the queue ever.
Prime(key string, value interface{})
// Delete deletes the value identified by the given key from the cache, and
// generates an update on the queue if a value was deleted.
Delete(key string)
// Clean removes the object identified by the given key from the cache.
// It does not generate an update on the queue.
Clean(key string)
// ListKeys lists the keys currently in the cache.
ListKeys() []string
// Run enables the generation of events on the output queue starts
// cache reconciliation.
Run(reconcilerPeriod string)
// GetQueue returns the cache's output queue, which emits a stream
// of any keys which have been created, modified, or deleted.
GetQueue() workqueue.RateLimitingInterface
}
// ResourceCacheArgs struct passed to constructor of ResourceCache.
// Groups togather all the arguments to pass in single struct.
type ResourceCacheArgs struct {
// ListFunc returns a mapping of keys to objects from the Calico datastore.
ListFunc func() (map[string]interface{}, error)
// ObjectType is the type of object which is to be stored in this cache.
ObjectType reflect.Type
// LogTypeDesc (optional) to log the type of object stored in the cache.
// If not provided it is derived from the ObjectType.
LogTypeDesc string
ReconcilerConfig ReconcilerConfig
}
// ReconcilerConfig contains configuration for the periodic reconciler.
type ReconcilerConfig struct {
// DisableUpdateOnChange disables the queuing of updates when the reconciler
// detects that a value has changed in the datastore.
DisableUpdateOnChange bool
// DisableMissingInDatastore disables queueing of updates when the reconciler
// detects that a value is no longer in the datastore but still exists in the cache.
DisableMissingInDatastore bool
// DisableMissingInCache disables queueing of updates when reconciler detects
// that a value that is still in the datastore no longer is in the cache.
DisableMissingInCache bool
}
// calicoCache implements the ResourceCache interface
type calicoCache struct {
threadSafeCache *cache.Cache
workqueue workqueue.RateLimitingInterface
ListFunc func() (map[string]interface{}, error)
ObjectType reflect.Type
log *log.Entry
running bool
mut *sync.Mutex
reconcilerConfig ReconcilerConfig
}
// NewResourceCache builds and returns a resource cache using the provided arguments.
func NewResourceCache(args ResourceCacheArgs) ResourceCache {
// Make sure logging is context aware.
return &calicoCache{
threadSafeCache: cache.New(cache.NoExpiration, cache.DefaultExpiration),
workqueue: workqueue.NewRateLimitingQueue(workqueue.DefaultControllerRateLimiter()),
ListFunc: args.ListFunc,
ObjectType: args.ObjectType,
log: func() *log.Entry {
if args.LogTypeDesc == "" {
return log.WithFields(log.Fields{"type": args.ObjectType})
}
return log.WithFields(log.Fields{"type": args.LogTypeDesc})
}(),
mut: &sync.Mutex{},
reconcilerConfig: args.ReconcilerConfig,
}
}
func (c *calicoCache) Set(key string, newObj interface{}) {
if reflect.TypeOf(newObj) != c.ObjectType {
c.log.Fatalf("Wrong object type received to store in cache. Expected: %s, Found: %s", c.ObjectType, reflect.TypeOf(newObj))
}
// Check if the object exists in the cache already. If it does and hasn't changed,
// then we don't need to send an update on the queue.
if existingObj, found := c.threadSafeCache.Get(key); found {
c.log.Debugf("%#v already exists in cache - comparing.", existingObj)
if !reflect.DeepEqual(existingObj, newObj) {
// The objects do not match - send an update over the queue.
c.threadSafeCache.Set(key, newObj, cache.NoExpiration)
if c.isRunning() {
c.log.Debugf("Queueing update - %#v and %#v do not match.", newObj, existingObj)
c.workqueue.Add(key)
}
}
} else {
c.threadSafeCache.Set(key, newObj, cache.NoExpiration)
if c.isRunning() {
c.log.Debugf("%#v not found in cache, adding it + queuing update.", newObj)
c.workqueue.Add(key)
}
}
}
func (c *calicoCache) Delete(key string) {
c.log.Debugf("Deleting %s from cache", key)
c.threadSafeCache.Delete(key)
c.workqueue.Add(key)
}
func (c *calicoCache) Clean(key string) {
c.log.Debugf("Cleaning %s from cache, no update required", key)
c.threadSafeCache.Delete(key)
}
func (c *calicoCache) Get(key string) (interface{}, bool) {
obj, found := c.threadSafeCache.Get(key)
if found {
return obj, true
}
return nil, false
}
// Prime adds the key and value to the cache but will never generate
// an update on the queue.
func (c *calicoCache) Prime(key string, value interface{}) {
c.threadSafeCache.Set(key, value, cache.NoExpiration)
}
// ListKeys returns a list of all the keys in the cache.
func (c *calicoCache) ListKeys() []string {
cacheItems := c.threadSafeCache.Items()
keys := make([]string, 0, len(cacheItems))
for k := range cacheItems {
keys = append(keys, k)
}
return keys
}
// GetQueue returns the output queue from the cache. Whenever a key/value pair
// is modified, an event will appear on this queue.
func (c *calicoCache) GetQueue() workqueue.RateLimitingInterface {
return c.workqueue
}
// Run starts the cache. Any Set() calls prior to calling Run() will
// prime the cache, but not trigger any updates on the output queue.
func (c *calicoCache) Run(reconcilerPeriod string) {
go c.reconcile(reconcilerPeriod)
// Indicate that the cache is running, and so updates
// can be queued.
c.mut.Lock()
c.running = true
c.mut.Unlock()
}
func (c *calicoCache) isRunning() bool {
c.mut.Lock()
defer c.mut.Unlock()
return c.running
}
// reconcile ensures a reconciliation is run every `reconcilerPeriod` in order to bring the datastore
// in sync with the cache. This is to correct any manual changes made in the datastore
// without the cache being aware.
func (c *calicoCache) reconcile(reconcilerPeriod string) {
duration, err := time.ParseDuration(reconcilerPeriod)
if err != nil {
c.log.Fatalf("Invalid time duration format for reconciler: %s. Some valid examples: 5m, 30s, 2m30s etc.", reconcilerPeriod)
}
// If user has set duration to 0 then disable the reconciler job.
if duration.Nanoseconds() == 0 {
c.log.Infof("Reconciler period set to %d. Disabling reconciler.", duration.Nanoseconds())
return
}
// Loop forever, performing a datastore reconciliation periodically.
for {
c.log.Debugf("Performing reconciliation")
err := c.performDatastoreSync()
if err != nil {
c.log.WithError(err).Error("Reconciliation failed")
continue
}
// Reconciliation was successful, sleep the configured duration.
c.log.Debugf("Reconciliation complete, %+v until next one.", duration)
time.Sleep(duration)
}
}
func (c *calicoCache) performDatastoreSync() error {
// Get all the objects we care about from the datastore using ListFunc.
objMap, err := c.ListFunc()
if err != nil {
c.log.WithError(err).Errorf("unable to list objects from datastore while reconciling.")
return err
}
// Build a map of existing keys in the datastore.
allKeys := map[string]bool{}
for key := range objMap {
allKeys[key] = true
}
// Also add all existing keys in the cache.
for _, key := range c.ListKeys() {
allKeys[key] = true
}
c.log.Debugf("Reconciling %d keys in total", len(allKeys))
for key := range allKeys {
cachedObj, existsInCache := c.Get(key)
if !existsInCache {
// Key does not exist in the cache, queue an update to
// remove it from the datastore if configured to do so.
if !c.reconcilerConfig.DisableMissingInCache {
c.log.WithField("key", key).Warn("Value for key should not exist, queueing update to remove")
c.workqueue.Add(key)
}
continue
}
obj, existsInDatastore := objMap[key]
if !existsInDatastore {
// Key exists in the cache but not in the datastore - queue an update
// to re-add it if configured to do so.
if !c.reconcilerConfig.DisableMissingInDatastore {
c.log.WithField("key", key).Warn("Value for key is missing in datastore, queueing update to reprogram")
c.workqueue.Add(key)
}
continue
}
if !reflect.DeepEqual(obj, cachedObj) {
// Objects differ - queue an update to re-program if configured to do so.
if !c.reconcilerConfig.DisableUpdateOnChange {
c.log.WithField("key", key).Warn("Value for key has changed, queueing update to reprogram")
c.log.Debugf("Cached: %#v", cachedObj)
c.log.Debugf("Updated: %#v", obj)
c.workqueue.Add(key)
}
continue
}
}
return nil
}

View File

@@ -0,0 +1,28 @@
// Copyright (c) 2017 Tigera, Inc. All rights reserved.
//
// 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 converter
// Converter Responsible for conversion of given kubernetes object to equivalent calico object
type Converter interface {
// Converts kubernetes object to calico representation of it.
Convert(k8sObj interface{}) (interface{}, error)
// Returns appropriate key for the object
GetKey(obj interface{}) string
// DeleteArgsFromKey returns name and namespace of the object to pass to Delete
// for the given key as generated by GetKey.
DeleteArgsFromKey(key string) (string, string)
}

View File

@@ -0,0 +1,73 @@
// Copyright (c) 2017-2021 Tigera, Inc. All rights reserved.
//
// 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 converter
import (
"fmt"
api "github.com/projectcalico/api/pkg/apis/projectcalico/v3"
"github.com/projectcalico/calico/libcalico-go/lib/backend/k8s/conversion"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/tools/cache"
)
type namespaceConverter struct {
}
// NewNamespaceConverter Constructor for namespaceConverter
func NewNamespaceConverter() Converter {
return &namespaceConverter{}
}
func (nc *namespaceConverter) Convert(k8sObj interface{}) (interface{}, error) {
c := conversion.NewConverter()
namespace, ok := k8sObj.(*v1.Namespace)
if !ok {
tombstone, ok := k8sObj.(cache.DeletedFinalStateUnknown)
if !ok {
return nil, fmt.Errorf("couldn't get object from tombstone %+v", k8sObj)
}
namespace, ok = tombstone.Obj.(*v1.Namespace)
if !ok {
return nil, fmt.Errorf("tombstone contained object that is not a Namespace %+v", k8sObj)
}
}
kvp, err := c.NamespaceToProfile(namespace)
if err != nil {
return nil, err
}
profile := kvp.Value.(*api.Profile)
// Isolate the metadata fields that we care about. ResourceVersion, CreationTimeStamp, etc are
// not relevant so we ignore them. This prevents unnecessary updates.
profile.ObjectMeta = metav1.ObjectMeta{Name: profile.Name}
return *profile, nil
}
// GetKey returns name of the Profile as its key. For Profiles
// backed by Kubernetes namespaces and managed by this controller, the name
// is of format `kns.name`.
func (nc *namespaceConverter) GetKey(obj interface{}) string {
profile := obj.(api.Profile)
return profile.Name
}
func (p *namespaceConverter) DeleteArgsFromKey(key string) (string, string) {
// Not namespaced, so just return the key, which is the profile name.
return "", key
}

View File

@@ -0,0 +1,82 @@
// Copyright (c) 2017-2021 Tigera, Inc. All rights reserved.
//
// 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 converter
import (
"errors"
"fmt"
"strings"
api "github.com/projectcalico/api/pkg/apis/projectcalico/v3"
"github.com/projectcalico/calico/libcalico-go/lib/backend/k8s/conversion"
cerrors "github.com/projectcalico/calico/libcalico-go/lib/errors"
networkingv1 "k8s.io/api/networking/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/tools/cache"
)
type policyConverter struct {
}
// NewPolicyConverter Constructor for policyConverter
func NewPolicyConverter() Converter {
return &policyConverter{}
}
// Convert takes a Kubernetes NetworkPolicy and returns a Calico api.NetworkPolicy representation.
func (p *policyConverter) Convert(k8sObj interface{}) (interface{}, error) {
np, ok := k8sObj.(*networkingv1.NetworkPolicy)
if !ok {
tombstone, ok := k8sObj.(cache.DeletedFinalStateUnknown)
if !ok {
return nil, fmt.Errorf("couldn't get object from tombstone %+v", k8sObj)
}
np, ok = tombstone.Obj.(*networkingv1.NetworkPolicy)
if !ok {
return nil, fmt.Errorf("tombstone contained object that is not a NetworkPolicy %+v", k8sObj)
}
}
c := conversion.NewConverter()
kvp, err := c.K8sNetworkPolicyToCalico(np)
// Silently ignore rule conversion errors. We don't expect any conversion errors
// since the data given to us here is validated by the Kubernetes API. The conversion
// code ignores any rules that it cannot parse, and we will pass the valid ones to Felix.
var e *cerrors.ErrorPolicyConversion
if err != nil && !errors.As(err, &e) {
return nil, err
}
cnp := kvp.Value.(*api.NetworkPolicy)
// Isolate the metadata fields that we care about. ResourceVersion, CreationTimeStamp, etc are
// not relevant so we ignore them. This prevents unnecessary updates.
cnp.ObjectMeta = metav1.ObjectMeta{Name: cnp.Name, Namespace: cnp.Namespace}
return *cnp, err
}
// GetKey returns the 'namespace/name' for the given Calico NetworkPolicy as its key.
func (p *policyConverter) GetKey(obj interface{}) string {
policy := obj.(api.NetworkPolicy)
return fmt.Sprintf("%s/%s", policy.Namespace, policy.Name)
}
func (p *policyConverter) DeleteArgsFromKey(key string) (string, string) {
splits := strings.SplitN(key, "/", 2)
return splits[0], splits[1]
}

View File

@@ -0,0 +1,146 @@
// Copyright (c) 2017-2020 Tigera, Inc. All rights reserved.
//
// 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 converter
import (
"errors"
"fmt"
"github.com/projectcalico/calico/libcalico-go/lib/backend/model"
log "github.com/sirupsen/logrus"
api "github.com/projectcalico/calico/libcalico-go/lib/apis/v3"
"github.com/projectcalico/calico/libcalico-go/lib/backend/k8s/conversion"
v1 "k8s.io/api/core/v1"
"k8s.io/client-go/tools/cache"
)
// WorkloadEndpointData is an internal struct used to store the various bits
// of information that the policy controller cares about on a workload endpoint.
type WorkloadEndpointData struct {
PodName string
Namespace string
Labels map[string]string
ServiceAccount string
}
type PodConverter interface {
Convert(k8sObj interface{}) ([]WorkloadEndpointData, error)
GetKey(obj WorkloadEndpointData) string
DeleteArgsFromKey(key string) (string, string)
}
type podConverter struct{}
// BuildWorkloadEndpointData generates the correct WorkloadEndpointData for the given
// list of WorkloadEndpoints, extracting fields that the policy controller is responsible
// for syncing.
func BuildWorkloadEndpointData(weps ...api.WorkloadEndpoint) []WorkloadEndpointData {
var retWEPs []WorkloadEndpointData
for _, wep := range weps {
retWEPs = append(retWEPs, WorkloadEndpointData{
PodName: wep.Spec.Pod,
Namespace: wep.Namespace,
Labels: wep.Labels,
ServiceAccount: wep.Spec.ServiceAccountName,
})
}
return retWEPs
}
// MergeWorkloadEndpointData applies the given WorkloadEndpointData to the provided
// WorkloadEndpoint, updating relevant fields with new values.
func MergeWorkloadEndpointData(wep *api.WorkloadEndpoint, upd WorkloadEndpointData) {
if wep.Spec.Pod != upd.PodName || wep.Namespace != upd.Namespace {
log.Fatalf("Bad attempt to merge data for %s/%s into wep %s/%s", upd.PodName, upd.Namespace, wep.Name, wep.Namespace)
}
wep.Labels = upd.Labels
wep.Spec.ServiceAccountName = upd.ServiceAccount
}
// NewPodConverter Constructor for podConverter
func NewPodConverter() PodConverter {
return &podConverter{}
}
func (p *podConverter) Convert(k8sObj interface{}) ([]WorkloadEndpointData, error) {
// Convert Pod into a workload endpoint.
c := conversion.NewConverter()
pod, err := ExtractPodFromUpdate(k8sObj)
if err != nil {
return nil, err
}
// The conversion logic always requires a node, but we don't always have one. We don't actually
// care about the value used for the node in this controller, so just dummy it out if it doesn't exist.
if pod.Spec.NodeName == "" {
pod.Spec.NodeName = "unknown.node"
}
kvps, err := c.PodToWorkloadEndpoints(pod)
if err != nil {
return nil, err
}
// Build and return a WorkloadEndpointData struct using the data.
return BuildWorkloadEndpointData(kvpsToWEPs(kvps)...), nil
}
func kvpsToWEPs(kvps []*model.KVPair) []api.WorkloadEndpoint {
var weps []api.WorkloadEndpoint
for _, kvp := range kvps {
wep := kvp.Value.(*api.WorkloadEndpoint)
if wep != nil {
weps = append(weps, *wep)
}
}
return weps
}
// GetKey takes a WorkloadEndpointData and returns the key which
// identifies it - namespace/name
func (p *podConverter) GetKey(obj WorkloadEndpointData) string {
return fmt.Sprintf("%s/%s", obj.Namespace, obj.PodName)
}
func (p *podConverter) DeleteArgsFromKey(key string) (string, string) {
// We don't have enough information to generate the delete args from the key that's used
// for Pods / WorkloadEndpoints, so just panic. This should never be called but is necessary
// to satisfy the interface.
log.Panicf("DeleteArgsFromKey call for WorkloadEndpoints is not allowed")
return "", ""
}
// ExtractPodFromUpdate takes an update as received from the informer and returns the pod object, if present.
// some updates (particularly deletes) can include tombstone placeholders rather than an exact pod object. This
// function should be called in order to safely handles those cases.
func ExtractPodFromUpdate(obj interface{}) (*v1.Pod, error) {
pod, ok := obj.(*v1.Pod)
if !ok {
tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
if !ok {
return nil, errors.New("couldn't get object from tombstone")
}
pod, ok = tombstone.Obj.(*v1.Pod)
if !ok {
return nil, errors.New("tombstone contained object that is not a Pod")
}
}
return pod, nil
}

View File

@@ -0,0 +1,74 @@
// Copyright (c) 2018-2020 Tigera, Inc. All rights reserved.
//
// 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 converter
import (
"fmt"
api "github.com/projectcalico/api/pkg/apis/projectcalico/v3"
"github.com/projectcalico/calico/libcalico-go/lib/backend/k8s/conversion"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/tools/cache"
)
type serviceAccountConverter struct {
}
// NewServiceaccountConverter Constructor to convert ServiceAccount to Profile
func NewServiceAccountConverter() Converter {
return &serviceAccountConverter{}
}
func (nc *serviceAccountConverter) Convert(k8sObj interface{}) (interface{}, error) {
c := conversion.NewConverter()
serviceAccount, ok := k8sObj.(*v1.ServiceAccount)
if !ok {
tombstone, ok := k8sObj.(cache.DeletedFinalStateUnknown)
if !ok {
return nil, fmt.Errorf("couldn't get object from tombstone %+v", k8sObj)
}
serviceAccount, ok = tombstone.Obj.(*v1.ServiceAccount)
if !ok {
return nil, fmt.Errorf("tombstone contained object that is not a Serviceaccount %+v", k8sObj)
}
}
kvp, err := c.ServiceAccountToProfile(serviceAccount)
if err != nil {
return nil, err
}
profile := kvp.Value.(*api.Profile)
// Isolate the metadata fields that we care about. ResourceVersion, CreationTimeStamp, etc are
// not relevant so we ignore them. This prevents unnecessary updates.
profile.ObjectMeta = metav1.ObjectMeta{Name: profile.Name}
return *profile, nil
}
// GetKey returns name of the Profile as its key. For Profiles
// backed by Kubernetes serviceaccounts and managed by this controller, the name
// is of format `ksa.namespace.name`.
func (nc *serviceAccountConverter) GetKey(obj interface{}) string {
profile := obj.(api.Profile)
return profile.Name
}
func (nc *serviceAccountConverter) DeleteArgsFromKey(key string) (string, string) {
// Not serviceaccount, so just return the key, which is the profile name.
return "", key
}