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:
18
vendor/github.com/projectcalico/calico/libcalico-go/lib/backend/encap/doc.go
generated
vendored
Normal file
18
vendor/github.com/projectcalico/calico/libcalico-go/lib/backend/encap/doc.go
generated
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
// Copyright (c) 2016 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 encap implements a field type that represent different encap modes.
|
||||
*/
|
||||
package encap
|
||||
25
vendor/github.com/projectcalico/calico/libcalico-go/lib/backend/encap/ipip.go
generated
vendored
Normal file
25
vendor/github.com/projectcalico/calico/libcalico-go/lib/backend/encap/ipip.go
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
// Copyright (c) 2016 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 encap
|
||||
|
||||
type Mode string
|
||||
|
||||
const (
|
||||
Undefined Mode = ""
|
||||
Always = "always"
|
||||
CrossSubnet = "cross-subnet"
|
||||
)
|
||||
|
||||
const DefaultMode = Always
|
||||
47
vendor/github.com/projectcalico/calico/libcalico-go/lib/backend/k8s/conversion/constants.go
generated
vendored
Normal file
47
vendor/github.com/projectcalico/calico/libcalico-go/lib/backend/k8s/conversion/constants.go
generated
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
// 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 conversion
|
||||
|
||||
const (
|
||||
NamespaceLabelPrefix = "pcns."
|
||||
NamespaceProfileNamePrefix = "kns."
|
||||
K8sNetworkPolicyNamePrefix = "knp.default."
|
||||
ServiceAccountLabelPrefix = "pcsa."
|
||||
ServiceAccountProfileNamePrefix = "ksa."
|
||||
|
||||
// AnnotationPodIP is an annotation we apply to pods when assigning them an IP. It
|
||||
// duplicates the value of the Pod.Status.PodIP field, which is set by kubelet but,
|
||||
// since we write it ourselves, we can make sure that it is written synchronously
|
||||
// and quickly.
|
||||
//
|
||||
// We set this annotation to the empty string when the WEP is deleted by the CNI plugin.
|
||||
// That signals that the IP no longer belongs to this pod.
|
||||
AnnotationPodIP = "cni.projectcalico.org/podIP"
|
||||
|
||||
// AnnotationPodIPs is similar for the plural PodIPs field.
|
||||
AnnotationPodIPs = "cni.projectcalico.org/podIPs"
|
||||
|
||||
// AnnotationPodIPs is the annotation set by the Amazon VPC CNI plugin.
|
||||
AnnotationAWSPodIPs = "vpc.amazonaws.com/pod-ips"
|
||||
|
||||
// AnnotationContainerID stores the container ID of the pod. This allows us to disambiguate different pods
|
||||
// that have the same name and namespace. For example, stateful set pod that is restarted. May be missing
|
||||
// on older Pods.
|
||||
AnnotationContainerID = "cni.projectcalico.org/containerID"
|
||||
|
||||
// NameLabel is a label that can be used to match a serviceaccount or namespace
|
||||
// name exactly.
|
||||
NameLabel = "projectcalico.org/name"
|
||||
)
|
||||
811
vendor/github.com/projectcalico/calico/libcalico-go/lib/backend/k8s/conversion/conversion.go
generated
vendored
Normal file
811
vendor/github.com/projectcalico/calico/libcalico-go/lib/backend/k8s/conversion/conversion.go
generated
vendored
Normal file
@@ -0,0 +1,811 @@
|
||||
// Copyright (c) 2016-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 conversion
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
kapiv1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
discovery "k8s.io/api/discovery/v1"
|
||||
networkingv1 "k8s.io/api/networking/v1"
|
||||
"k8s.io/apimachinery/pkg/util/intstr"
|
||||
|
||||
apiv3 "github.com/projectcalico/api/pkg/apis/projectcalico/v3"
|
||||
"github.com/projectcalico/api/pkg/lib/numorstring"
|
||||
|
||||
"github.com/projectcalico/calico/libcalico-go/lib/backend/model"
|
||||
cerrors "github.com/projectcalico/calico/libcalico-go/lib/errors"
|
||||
"github.com/projectcalico/calico/libcalico-go/lib/names"
|
||||
cnet "github.com/projectcalico/calico/libcalico-go/lib/net"
|
||||
)
|
||||
|
||||
var (
|
||||
protoTCP = kapiv1.ProtocolTCP
|
||||
)
|
||||
|
||||
type selectorType int8
|
||||
|
||||
const (
|
||||
SelectorNamespace selectorType = iota
|
||||
SelectorPod
|
||||
)
|
||||
|
||||
type Converter interface {
|
||||
WorkloadEndpointConverter
|
||||
ParseWorkloadEndpointName(workloadName string) (names.WorkloadEndpointIdentifiers, error)
|
||||
NamespaceToProfile(ns *kapiv1.Namespace) (*model.KVPair, error)
|
||||
IsValidCalicoWorkloadEndpoint(pod *kapiv1.Pod) bool
|
||||
IsReadyCalicoPod(pod *kapiv1.Pod) bool
|
||||
IsScheduled(pod *kapiv1.Pod) bool
|
||||
IsHostNetworked(pod *kapiv1.Pod) bool
|
||||
HasIPAddress(pod *kapiv1.Pod) bool
|
||||
StagedKubernetesNetworkPolicyToStagedName(stagedK8sName string) string
|
||||
K8sNetworkPolicyToCalico(np *networkingv1.NetworkPolicy) (*model.KVPair, error)
|
||||
EndpointSliceToKVP(svc *discovery.EndpointSlice) (*model.KVPair, error)
|
||||
ServiceToKVP(service *kapiv1.Service) (*model.KVPair, error)
|
||||
ProfileNameToNamespace(profileName string) (string, error)
|
||||
ServiceAccountToProfile(sa *kapiv1.ServiceAccount) (*model.KVPair, error)
|
||||
ProfileNameToServiceAccount(profileName string) (ns, sa string, err error)
|
||||
JoinProfileRevisions(nsRev, saRev string) string
|
||||
SplitProfileRevision(rev string) (nsRev string, saRev string, err error)
|
||||
}
|
||||
|
||||
type converter struct {
|
||||
WorkloadEndpointConverter
|
||||
}
|
||||
|
||||
func NewConverter() Converter {
|
||||
return &converter{
|
||||
WorkloadEndpointConverter: NewWorkloadEndpointConverter(),
|
||||
}
|
||||
}
|
||||
|
||||
// ParseWorkloadName extracts the Node name, Orchestrator, Pod name and endpoint from the
|
||||
// given WorkloadEndpoint name.
|
||||
// The expected format for k8s is <node>-k8s-<pod>-<endpoint>
|
||||
func (c converter) ParseWorkloadEndpointName(workloadName string) (names.WorkloadEndpointIdentifiers, error) {
|
||||
return names.ParseWorkloadEndpointName(workloadName)
|
||||
}
|
||||
|
||||
// NamespaceToProfile converts a Namespace to a Calico Profile. The Profile stores
|
||||
// labels from the Namespace which are inherited by the WorkloadEndpoints within
|
||||
// the Profile. This Profile also has the default ingress and egress rules, which are both 'allow'.
|
||||
func (c converter) NamespaceToProfile(ns *kapiv1.Namespace) (*model.KVPair, error) {
|
||||
// Generate the labels to apply to the profile, using a special prefix
|
||||
// to indicate that these are the labels from the parent Kubernetes Namespace.
|
||||
labels := map[string]string{}
|
||||
for k, v := range ns.Labels {
|
||||
labels[NamespaceLabelPrefix+k] = v
|
||||
}
|
||||
|
||||
// Add a label for the namespace's name. This allows exact namespace matching
|
||||
// based on name within the namespaceSelector.
|
||||
labels[NamespaceLabelPrefix+NameLabel] = ns.Name
|
||||
|
||||
// Create the profile object.
|
||||
name := NamespaceProfileNamePrefix + ns.Name
|
||||
profile := apiv3.NewProfile()
|
||||
profile.ObjectMeta = metav1.ObjectMeta{
|
||||
Name: name,
|
||||
CreationTimestamp: ns.CreationTimestamp,
|
||||
UID: ns.UID,
|
||||
}
|
||||
profile.Spec = apiv3.ProfileSpec{
|
||||
Ingress: []apiv3.Rule{{Action: apiv3.Allow}},
|
||||
Egress: []apiv3.Rule{{Action: apiv3.Allow}},
|
||||
LabelsToApply: labels,
|
||||
}
|
||||
|
||||
// Embed the profile in a KVPair.
|
||||
kvp := model.KVPair{
|
||||
Key: model.ResourceKey{
|
||||
Name: name,
|
||||
Kind: apiv3.KindProfile,
|
||||
},
|
||||
Value: profile,
|
||||
Revision: c.JoinProfileRevisions(ns.ResourceVersion, ""),
|
||||
}
|
||||
return &kvp, nil
|
||||
}
|
||||
|
||||
// IsValidCalicoWorkloadEndpoint returns true if the pod should be shown as a workloadEndpoint
|
||||
// in the Calico API and false otherwise. Note: since we completely ignore notifications for
|
||||
// invalid Pods, it is important that pods can only transition from not-valid to valid and not
|
||||
// the other way. If they transition from valid to invalid, we'll fail to emit a deletion
|
||||
// event in the watcher.
|
||||
func (c converter) IsValidCalicoWorkloadEndpoint(pod *kapiv1.Pod) bool {
|
||||
if c.IsHostNetworked(pod) {
|
||||
log.WithField("pod", pod.Name).Debug("Pod is host networked.")
|
||||
return false
|
||||
} else if !c.IsScheduled(pod) {
|
||||
log.WithField("pod", pod.Name).Debug("Pod is not scheduled.")
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// IsReadyCalicoPod returns true if the pod is a valid Calico WorkloadEndpoint and has
|
||||
// an IP address assigned (i.e. it's ready for Calico networking).
|
||||
func (c converter) IsReadyCalicoPod(pod *kapiv1.Pod) bool {
|
||||
if !c.IsValidCalicoWorkloadEndpoint(pod) {
|
||||
return false
|
||||
} else if !c.HasIPAddress(pod) {
|
||||
log.WithField("pod", pod.Name).Debug("Pod does not have an IP address.")
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
const (
|
||||
// Completed is documented but doesn't seem to be in the API, it should be safe to include.
|
||||
// Maybe it's in an older version of the API?
|
||||
podCompleted kapiv1.PodPhase = "Completed"
|
||||
)
|
||||
|
||||
func IsFinished(pod *kapiv1.Pod) bool {
|
||||
if pod.DeletionTimestamp != nil {
|
||||
// Pod is being deleted but it may still be in its termination grace period. If Calico CNI
|
||||
// was used, then we use AnnotationPodIP to signal the moment that the pod actually loses its
|
||||
// IP by setting the annotation to "". (Otherwise, just fall back on the status of the pod.)
|
||||
if ip, ok := pod.Annotations[AnnotationPodIP]; ok && ip == "" {
|
||||
// AnnotationPodIP is explicitly set to empty string, Calico CNI has removed the network
|
||||
// from the pod.
|
||||
log.Debug("Pod is being deleted and IPs have been removed by Calico CNI.")
|
||||
return true
|
||||
} else if ips, ok := pod.Annotations[AnnotationAWSPodIPs]; ok && ips == "" {
|
||||
// AnnotationAWSPodIPs is explicitly set to empty string, AWS CNI has removed the network
|
||||
// from the pod.
|
||||
log.Debug("Pod is being deleted and IPs have been removed by AWS CNI.")
|
||||
return true
|
||||
}
|
||||
}
|
||||
switch pod.Status.Phase {
|
||||
case kapiv1.PodFailed, kapiv1.PodSucceeded, podCompleted:
|
||||
log.Debug("Pod phase is failed/succeeded/completed.")
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (c converter) IsScheduled(pod *kapiv1.Pod) bool {
|
||||
return pod.Spec.NodeName != ""
|
||||
}
|
||||
|
||||
func (c converter) IsHostNetworked(pod *kapiv1.Pod) bool {
|
||||
return pod.Spec.HostNetwork
|
||||
}
|
||||
|
||||
func (c converter) HasIPAddress(pod *kapiv1.Pod) bool {
|
||||
return pod.Status.PodIP != "" || pod.Annotations[AnnotationPodIP] != "" || pod.Annotations[AnnotationAWSPodIPs] != ""
|
||||
// Note: we don't need to check PodIPs and AnnotationPodIPs here, because those cannot be
|
||||
// non-empty if the corresponding singular field is empty.
|
||||
}
|
||||
|
||||
// getPodIPs extracts the IP addresses from a Kubernetes Pod. We support a single IPv4 address
|
||||
// and/or a single IPv6. getPodIPs loads the IPs either from the PodIPs and PodIP field, if
|
||||
// present, or the calico podIP annotation.
|
||||
func getPodIPs(pod *kapiv1.Pod) ([]*cnet.IPNet, error) {
|
||||
logc := log.WithFields(log.Fields{"pod": pod.Name, "namespace": pod.Namespace})
|
||||
var podIPs []string
|
||||
if ips := pod.Status.PodIPs; len(ips) != 0 {
|
||||
logc.WithField("ips", ips).Debug("PodIPs field filled in")
|
||||
for _, ip := range ips {
|
||||
podIPs = append(podIPs, ip.IP)
|
||||
}
|
||||
} else if ip := pod.Status.PodIP; ip != "" {
|
||||
logc.WithField("ip", ip).Debug("PodIP field filled in")
|
||||
podIPs = append(podIPs, ip)
|
||||
} else if ips := pod.Annotations[AnnotationPodIPs]; ips != "" {
|
||||
logc.WithField("ips", ips).Debug("No PodStatus IPs, use Calico plural annotation")
|
||||
podIPs = append(podIPs, strings.Split(ips, ",")...)
|
||||
} else if ip := pod.Annotations[AnnotationPodIP]; ip != "" {
|
||||
logc.WithField("ip", ip).Debug("No PodStatus IPs, use Calico singular annotation")
|
||||
podIPs = append(podIPs, ip)
|
||||
} else if ips := pod.Annotations[AnnotationAWSPodIPs]; ips != "" {
|
||||
logc.WithField("ips", ips).Debug("No PodStatus IPs, use AWS VPC annotation")
|
||||
podIPs = append(podIPs, strings.Split(ips, ",")...)
|
||||
} else {
|
||||
logc.Debug("Pod has no IP")
|
||||
return nil, nil
|
||||
}
|
||||
var podIPNets []*cnet.IPNet
|
||||
for _, ip := range podIPs {
|
||||
_, ipNet, err := cnet.ParseCIDROrIP(ip)
|
||||
if err != nil {
|
||||
logc.WithFields(log.Fields{"ip": ip}).WithError(err).Error("Failed to parse pod IP")
|
||||
return nil, err
|
||||
}
|
||||
podIPNets = append(podIPNets, ipNet)
|
||||
}
|
||||
return podIPNets, nil
|
||||
}
|
||||
|
||||
// StagedKubernetesNetworkPolicyToStagedName converts a StagedKubernetesNetworkPolicy name into a StagedNetworkPolicy name
|
||||
func (c converter) StagedKubernetesNetworkPolicyToStagedName(stagedK8sName string) string {
|
||||
return fmt.Sprintf(K8sNetworkPolicyNamePrefix + stagedK8sName)
|
||||
}
|
||||
|
||||
// EndpointSliceToKVP converts a k8s EndpointSlice to a model.KVPair.
|
||||
func (c converter) EndpointSliceToKVP(slice *discovery.EndpointSlice) (*model.KVPair, error) {
|
||||
return &model.KVPair{
|
||||
Key: model.ResourceKey{
|
||||
Name: slice.Name,
|
||||
Namespace: slice.Namespace,
|
||||
Kind: model.KindKubernetesEndpointSlice,
|
||||
},
|
||||
Value: slice.DeepCopy(),
|
||||
Revision: slice.ResourceVersion,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c converter) ServiceToKVP(service *kapiv1.Service) (*model.KVPair, error) {
|
||||
return &model.KVPair{
|
||||
Key: model.ResourceKey{
|
||||
Name: service.Name,
|
||||
Namespace: service.Namespace,
|
||||
Kind: model.KindKubernetesService,
|
||||
},
|
||||
Value: service.DeepCopy(),
|
||||
Revision: service.ResourceVersion,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// K8sNetworkPolicyToCalico converts a k8s NetworkPolicy to a model.KVPair.
|
||||
func (c converter) K8sNetworkPolicyToCalico(np *networkingv1.NetworkPolicy) (*model.KVPair, error) {
|
||||
// Pull out important fields.
|
||||
policyName := fmt.Sprintf(K8sNetworkPolicyNamePrefix + np.Name)
|
||||
|
||||
// We insert all the NetworkPolicy Policies at order 1000.0 after conversion.
|
||||
// This order might change in future.
|
||||
order := float64(1000.0)
|
||||
|
||||
errorTracker := cerrors.ErrorPolicyConversion{PolicyName: np.Name}
|
||||
|
||||
// Generate the ingress rules list.
|
||||
var ingressRules []apiv3.Rule
|
||||
for _, r := range np.Spec.Ingress {
|
||||
rules, err := c.k8sRuleToCalico(r.From, r.Ports, np.Namespace, true)
|
||||
if err != nil {
|
||||
log.WithError(err).Warn("dropping k8s rule that couldn't be converted.")
|
||||
// Add rule to conversion error slice
|
||||
errorTracker.BadIngressRule(&r, fmt.Sprintf("k8s rule couldn't be converted: %s", err))
|
||||
} else {
|
||||
ingressRules = append(ingressRules, rules...)
|
||||
}
|
||||
}
|
||||
|
||||
// Generate the egress rules list.
|
||||
var egressRules []apiv3.Rule
|
||||
for _, r := range np.Spec.Egress {
|
||||
rules, err := c.k8sRuleToCalico(r.To, r.Ports, np.Namespace, false)
|
||||
if err != nil {
|
||||
log.WithError(err).Warn("dropping k8s rule that couldn't be converted")
|
||||
// Add rule to conversion error slice
|
||||
errorTracker.BadEgressRule(&r, fmt.Sprintf("k8s rule couldn't be converted: %s", err))
|
||||
} else {
|
||||
egressRules = append(egressRules, rules...)
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate Types setting.
|
||||
ingress := false
|
||||
egress := false
|
||||
for _, policyType := range np.Spec.PolicyTypes {
|
||||
switch policyType {
|
||||
case networkingv1.PolicyTypeIngress:
|
||||
ingress = true
|
||||
case networkingv1.PolicyTypeEgress:
|
||||
egress = true
|
||||
}
|
||||
}
|
||||
types := []apiv3.PolicyType{}
|
||||
if ingress {
|
||||
types = append(types, apiv3.PolicyTypeIngress)
|
||||
}
|
||||
if egress {
|
||||
types = append(types, apiv3.PolicyTypeEgress)
|
||||
} else if len(egressRules) > 0 {
|
||||
// Egress was introduced at the same time as policyTypes. It shouldn't be possible to
|
||||
// receive a NetworkPolicy with an egress rule but without "Egress" specified in its types,
|
||||
// but we'll warn about it anyway.
|
||||
log.Warn("K8s PolicyTypes don't include 'egress', but NetworkPolicy has egress rules.")
|
||||
}
|
||||
|
||||
// If no types were specified in the policy, then we're running on a cluster that doesn't
|
||||
// include support for that field in the API. In that case, the correct behavior is for the policy
|
||||
// to apply to only ingress traffic.
|
||||
if len(types) == 0 {
|
||||
types = append(types, apiv3.PolicyTypeIngress)
|
||||
}
|
||||
|
||||
// Create the NetworkPolicy.
|
||||
policy := apiv3.NewNetworkPolicy()
|
||||
policy.ObjectMeta = metav1.ObjectMeta{
|
||||
Name: policyName,
|
||||
Namespace: np.Namespace,
|
||||
CreationTimestamp: np.CreationTimestamp,
|
||||
UID: np.UID,
|
||||
ResourceVersion: np.ResourceVersion,
|
||||
}
|
||||
policy.Spec = apiv3.NetworkPolicySpec{
|
||||
Order: &order,
|
||||
Selector: c.k8sSelectorToCalico(&np.Spec.PodSelector, SelectorPod),
|
||||
Ingress: ingressRules,
|
||||
Egress: egressRules,
|
||||
Types: types,
|
||||
}
|
||||
|
||||
// Build the KVPair.
|
||||
kvp := &model.KVPair{
|
||||
Key: model.ResourceKey{
|
||||
Name: policyName,
|
||||
Namespace: np.Namespace,
|
||||
Kind: apiv3.KindNetworkPolicy,
|
||||
},
|
||||
Value: policy,
|
||||
Revision: np.ResourceVersion,
|
||||
}
|
||||
|
||||
// Return the KVPair with conversion errors if applicable
|
||||
return kvp, errorTracker.GetError()
|
||||
}
|
||||
|
||||
// k8sSelectorToCalico takes a namespaced k8s label selector and returns the Calico
|
||||
// equivalent.
|
||||
func (c converter) k8sSelectorToCalico(s *metav1.LabelSelector, selectorType selectorType) string {
|
||||
// Only prefix pod selectors - this won't work for namespace selectors.
|
||||
selectors := []string{}
|
||||
if selectorType == SelectorPod {
|
||||
selectors = append(selectors, fmt.Sprintf("%s == 'k8s'", apiv3.LabelOrchestrator))
|
||||
}
|
||||
|
||||
if s == nil {
|
||||
return strings.Join(selectors, " && ")
|
||||
}
|
||||
|
||||
// For namespace selectors, if they are present but have no terms, it means "select all
|
||||
// namespaces". We use empty string to represent the nil namespace selector, so use all() to
|
||||
// represent all namespaces.
|
||||
if selectorType == SelectorNamespace && len(s.MatchLabels) == 0 && len(s.MatchExpressions) == 0 {
|
||||
return "all()"
|
||||
}
|
||||
|
||||
// matchLabels is a map key => value, it means match if (label[key] ==
|
||||
// value) for all keys.
|
||||
keys := make([]string, 0, len(s.MatchLabels))
|
||||
for k := range s.MatchLabels {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
for _, k := range keys {
|
||||
v := s.MatchLabels[k]
|
||||
selectors = append(selectors, fmt.Sprintf("%s == '%s'", k, v))
|
||||
}
|
||||
|
||||
// matchExpressions is a list of in/notin/exists/doesnotexist tests.
|
||||
for _, e := range s.MatchExpressions {
|
||||
valueList := strings.Join(e.Values, "', '")
|
||||
|
||||
// Each selector is formatted differently based on the operator.
|
||||
switch e.Operator {
|
||||
case metav1.LabelSelectorOpIn:
|
||||
selectors = append(selectors, fmt.Sprintf("%s in { '%s' }", e.Key, valueList))
|
||||
case metav1.LabelSelectorOpNotIn:
|
||||
selectors = append(selectors, fmt.Sprintf("%s not in { '%s' }", e.Key, valueList))
|
||||
case metav1.LabelSelectorOpExists:
|
||||
selectors = append(selectors, fmt.Sprintf("has(%s)", e.Key))
|
||||
case metav1.LabelSelectorOpDoesNotExist:
|
||||
selectors = append(selectors, fmt.Sprintf("! has(%s)", e.Key))
|
||||
}
|
||||
}
|
||||
|
||||
return strings.Join(selectors, " && ")
|
||||
}
|
||||
|
||||
func (c converter) k8sRuleToCalico(rPeers []networkingv1.NetworkPolicyPeer, rPorts []networkingv1.NetworkPolicyPort, ns string, ingress bool) ([]apiv3.Rule, error) {
|
||||
rules := []apiv3.Rule{}
|
||||
peers := []*networkingv1.NetworkPolicyPeer{}
|
||||
ports := []*networkingv1.NetworkPolicyPort{}
|
||||
|
||||
// Built up a list of the sources and a list of the destinations.
|
||||
for _, f := range rPeers {
|
||||
// We need to add a copy of the peer so all the rules don't
|
||||
// point to the same location.
|
||||
peers = append(peers, &networkingv1.NetworkPolicyPeer{
|
||||
NamespaceSelector: f.NamespaceSelector,
|
||||
PodSelector: f.PodSelector,
|
||||
IPBlock: f.IPBlock,
|
||||
})
|
||||
}
|
||||
for _, p := range rPorts {
|
||||
// We need to add a copy of the port so all the rules don't
|
||||
// point to the same location.
|
||||
port := networkingv1.NetworkPolicyPort{}
|
||||
if p.Port != nil {
|
||||
portval := intstr.FromString(p.Port.String())
|
||||
port.Port = &portval
|
||||
}
|
||||
if p.Protocol != nil {
|
||||
protval := kapiv1.Protocol(fmt.Sprintf("%s", *p.Protocol))
|
||||
port.Protocol = &protval
|
||||
} else {
|
||||
// TCP is the implicit default (as per the definition of NetworkPolicyPort).
|
||||
// Make the default explicit here because our data-model always requires
|
||||
// the protocol to be specified if we're doing a port match.
|
||||
port.Protocol = &protoTCP
|
||||
}
|
||||
|
||||
if p.EndPort != nil {
|
||||
port.EndPort = p.EndPort
|
||||
}
|
||||
ports = append(ports, &port)
|
||||
}
|
||||
|
||||
// If there no peers, or no ports, represent that as nil.
|
||||
if len(peers) == 0 {
|
||||
peers = []*networkingv1.NetworkPolicyPeer{nil}
|
||||
}
|
||||
if len(ports) == 0 {
|
||||
ports = []*networkingv1.NetworkPolicyPort{nil}
|
||||
}
|
||||
|
||||
protocolPorts := map[string][]numorstring.Port{}
|
||||
|
||||
for _, port := range ports {
|
||||
protocol, calicoPorts, err := c.k8sPortToCalicoFields(port)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse k8s port: %s", err)
|
||||
}
|
||||
|
||||
if protocol == nil && calicoPorts == nil {
|
||||
// If nil, no ports were specified, or an empty port struct was provided, which we translate to allowing all.
|
||||
// We want to use a nil protocol and a nil list of ports, which will allow any destination (for ingress).
|
||||
// Given we're gonna allow all, we may as well break here and keep only this rule
|
||||
protocolPorts = map[string][]numorstring.Port{"": nil}
|
||||
break
|
||||
}
|
||||
|
||||
pStr := protocol.String()
|
||||
// treat nil as 'all ports'
|
||||
if calicoPorts == nil {
|
||||
protocolPorts[pStr] = nil
|
||||
} else if _, ok := protocolPorts[pStr]; !ok || len(protocolPorts[pStr]) > 0 {
|
||||
// don't overwrite a nil (allow all ports) if present; if no ports yet for this protocol
|
||||
// or 1+ ports which aren't 'all ports', then add the present ports
|
||||
protocolPorts[pStr] = append(protocolPorts[pStr], calicoPorts...)
|
||||
}
|
||||
}
|
||||
|
||||
protocols := make([]string, 0, len(protocolPorts))
|
||||
for k := range protocolPorts {
|
||||
protocols = append(protocols, k)
|
||||
}
|
||||
// Ensure deterministic output
|
||||
sort.Strings(protocols)
|
||||
|
||||
// Combine destinations with sources to generate rules. We generate one rule per protocol,
|
||||
// with each rule containing all the allowed ports.
|
||||
for _, protocolStr := range protocols {
|
||||
calicoPorts := protocolPorts[protocolStr]
|
||||
calicoPorts = SimplifyPorts(calicoPorts)
|
||||
|
||||
var protocol *numorstring.Protocol
|
||||
if protocolStr != "" {
|
||||
p := numorstring.ProtocolFromString(protocolStr)
|
||||
protocol = &p
|
||||
}
|
||||
|
||||
for _, peer := range peers {
|
||||
selector, nsSelector, nets, notNets := c.k8sPeerToCalicoFields(peer, ns)
|
||||
if ingress {
|
||||
// Build inbound rule and append to list.
|
||||
rules = append(rules, apiv3.Rule{
|
||||
Action: "Allow",
|
||||
Protocol: protocol,
|
||||
Source: apiv3.EntityRule{
|
||||
Selector: selector,
|
||||
NamespaceSelector: nsSelector,
|
||||
Nets: nets,
|
||||
NotNets: notNets,
|
||||
},
|
||||
Destination: apiv3.EntityRule{
|
||||
Ports: calicoPorts,
|
||||
},
|
||||
})
|
||||
} else {
|
||||
// Build outbound rule and append to list.
|
||||
rules = append(rules, apiv3.Rule{
|
||||
Action: "Allow",
|
||||
Protocol: protocol,
|
||||
Destination: apiv3.EntityRule{
|
||||
Ports: calicoPorts,
|
||||
Selector: selector,
|
||||
NamespaceSelector: nsSelector,
|
||||
Nets: nets,
|
||||
NotNets: notNets,
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
return rules, nil
|
||||
}
|
||||
|
||||
// SimplifyPorts calculates a minimum set of port ranges that cover the given set of ports.
|
||||
// For example, if the input was [80, 81, 82, 9090, "foo"] the output would consist of
|
||||
// [80-82, 9090, "foo"] in some order.
|
||||
func SimplifyPorts(ports []numorstring.Port) []numorstring.Port {
|
||||
if len(ports) <= 1 {
|
||||
return ports
|
||||
}
|
||||
var numericPorts []int
|
||||
var outputPorts []numorstring.Port
|
||||
for _, p := range ports {
|
||||
if p.PortName != "" {
|
||||
// Pass named ports through immediately, there's nothing to be done for them.
|
||||
outputPorts = append(outputPorts, p)
|
||||
} else {
|
||||
// Work with ints to avoid overflow with the uint16 port type.
|
||||
// In practice, we currently only get single ports here so this
|
||||
// loop should run exactly once.
|
||||
for i := int(p.MinPort); i <= int(p.MaxPort); i++ {
|
||||
numericPorts = append(numericPorts, i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(numericPorts) <= 1 {
|
||||
// We have nothing to combine, short-circuit.
|
||||
return ports
|
||||
}
|
||||
|
||||
// Sort the ports so it will be easy to find ranges.
|
||||
sort.Ints(numericPorts)
|
||||
|
||||
// Each pass around this outer loop extracts one port range from the sorted slice
|
||||
// and it moves the slice along to the start of the next range.
|
||||
for len(numericPorts) > 0 {
|
||||
// Initialise the next range to the contain only the first port in the slice.
|
||||
firstPortInRange := numericPorts[0]
|
||||
lastPortInRange := firstPortInRange
|
||||
|
||||
// Scan ahead, looking for ports that can be combined into this range.
|
||||
numericPorts = numericPorts[1:]
|
||||
for len(numericPorts) > 0 {
|
||||
nextPort := numericPorts[0]
|
||||
if nextPort > lastPortInRange+1 {
|
||||
// This port can't be coalesced with the existing range, break out so
|
||||
// that we record the range; then we'll loop again and pick up this
|
||||
// port as the start of a new range.
|
||||
break
|
||||
}
|
||||
// The next port is either equal to the last port (due to a duplicate port
|
||||
// in the input) or it is exactly one greater. Extend the range to include
|
||||
// it.
|
||||
lastPortInRange = nextPort
|
||||
numericPorts = numericPorts[1:]
|
||||
}
|
||||
|
||||
// Record the port.
|
||||
outputPorts = appendPortRange(outputPorts, firstPortInRange, lastPortInRange)
|
||||
}
|
||||
|
||||
return outputPorts
|
||||
}
|
||||
|
||||
func appendPortRange(ports []numorstring.Port, first, last int) []numorstring.Port {
|
||||
portRange, err := numorstring.PortFromRange(uint16(first), uint16(last))
|
||||
if err != nil {
|
||||
log.WithError(err).Panic("Failed to make port range from ports that should have been pre-validated.")
|
||||
}
|
||||
return append(ports, portRange)
|
||||
}
|
||||
|
||||
func (c converter) k8sPortToCalicoFields(port *networkingv1.NetworkPolicyPort) (protocol *numorstring.Protocol, dstPorts []numorstring.Port, err error) {
|
||||
// If no port info, return zero values for all fields (protocol, dstPorts).
|
||||
if port == nil {
|
||||
return
|
||||
}
|
||||
// Port information available.
|
||||
dstPorts, err = c.k8sPortToCalico(*port)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
protocol = c.k8sProtocolToCalico(port.Protocol)
|
||||
return
|
||||
}
|
||||
|
||||
func (c converter) k8sProtocolToCalico(protocol *kapiv1.Protocol) *numorstring.Protocol {
|
||||
if protocol != nil {
|
||||
p := numorstring.ProtocolFromString(string(*protocol))
|
||||
return &p
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c converter) k8sPeerToCalicoFields(peer *networkingv1.NetworkPolicyPeer, ns string) (selector, nsSelector string, nets []string, notNets []string) {
|
||||
// If no peer, return zero values for all fields (selector, nets and !nets).
|
||||
if peer == nil {
|
||||
return
|
||||
}
|
||||
// Peer information available.
|
||||
// Determine the source selector for the rule.
|
||||
if peer.IPBlock != nil {
|
||||
// Convert the CIDR to include.
|
||||
_, ipNet, err := cnet.ParseCIDR(peer.IPBlock.CIDR)
|
||||
if err != nil {
|
||||
log.WithField("cidr", peer.IPBlock.CIDR).WithError(err).Error("Failed to parse CIDR")
|
||||
return
|
||||
}
|
||||
nets = []string{ipNet.String()}
|
||||
|
||||
// Convert the CIDRs to exclude.
|
||||
for _, exception := range peer.IPBlock.Except {
|
||||
_, ipNet, err = cnet.ParseCIDR(exception)
|
||||
if err != nil {
|
||||
log.WithField("cidr", exception).WithError(err).Error("Failed to parse CIDR")
|
||||
return
|
||||
}
|
||||
notNets = append(notNets, ipNet.String())
|
||||
}
|
||||
// If IPBlock is set, then PodSelector and NamespaceSelector cannot be.
|
||||
return
|
||||
}
|
||||
|
||||
// IPBlock is not set to get here.
|
||||
// Note that k8sSelectorToCalico() accepts nil values of the selector.
|
||||
selector = c.k8sSelectorToCalico(peer.PodSelector, SelectorPod)
|
||||
nsSelector = c.k8sSelectorToCalico(peer.NamespaceSelector, SelectorNamespace)
|
||||
return
|
||||
}
|
||||
|
||||
func (c converter) k8sPortToCalico(port networkingv1.NetworkPolicyPort) ([]numorstring.Port, error) {
|
||||
var portList []numorstring.Port
|
||||
if port.Port != nil {
|
||||
calicoPort := port.Port.String()
|
||||
if port.EndPort != nil {
|
||||
calicoPort = fmt.Sprintf("%s:%d", calicoPort, *port.EndPort)
|
||||
}
|
||||
p, err := numorstring.PortFromString(calicoPort)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid port %+v: %s", calicoPort, err)
|
||||
}
|
||||
return append(portList, p), nil
|
||||
}
|
||||
|
||||
// No ports - return empty list.
|
||||
return portList, nil
|
||||
}
|
||||
|
||||
// ProfileNameToNamespace extracts the Namespace name from the given Profile name.
|
||||
func (c converter) ProfileNameToNamespace(profileName string) (string, error) {
|
||||
// Profile objects backed by Namespaces have form "kns.<ns_name>"
|
||||
if !strings.HasPrefix(profileName, NamespaceProfileNamePrefix) {
|
||||
// This is not backed by a Kubernetes Namespace.
|
||||
return "", fmt.Errorf("Profile %s not backed by a Namespace", profileName)
|
||||
}
|
||||
|
||||
return strings.TrimPrefix(profileName, NamespaceProfileNamePrefix), nil
|
||||
}
|
||||
|
||||
// serviceAccountNameToProfileName creates a profile name that is a join
|
||||
// of 'ksa.' + namespace + "." + serviceaccount name.
|
||||
func serviceAccountNameToProfileName(sa, namespace string) string {
|
||||
// Need to incorporate the namespace into the name of the sa based profile
|
||||
// to make them globally unique
|
||||
if namespace == "" {
|
||||
namespace = "default"
|
||||
}
|
||||
return ServiceAccountProfileNamePrefix + namespace + "." + sa
|
||||
}
|
||||
|
||||
// ServiceAccountToProfile converts a ServiceAccount to a Calico Profile. The Profile stores
|
||||
// labels from the ServiceAccount which are inherited by the WorkloadEndpoints within
|
||||
// the Profile.
|
||||
func (c converter) ServiceAccountToProfile(sa *kapiv1.ServiceAccount) (*model.KVPair, error) {
|
||||
// Generate the labels to apply to the profile, using a special prefix
|
||||
// to indicate that these are the labels from the parent Kubernetes ServiceAccount.
|
||||
labels := map[string]string{}
|
||||
for k, v := range sa.ObjectMeta.Labels {
|
||||
labels[ServiceAccountLabelPrefix+k] = v
|
||||
}
|
||||
|
||||
// Add a label for the serviceaccount's name. This allows exact namespace matching
|
||||
// based on name within the serviceAccountSelector.
|
||||
labels[ServiceAccountLabelPrefix+NameLabel] = sa.Name
|
||||
|
||||
name := serviceAccountNameToProfileName(sa.Name, sa.Namespace)
|
||||
profile := apiv3.NewProfile()
|
||||
profile.ObjectMeta = metav1.ObjectMeta{
|
||||
Name: name,
|
||||
CreationTimestamp: sa.CreationTimestamp,
|
||||
UID: sa.UID,
|
||||
}
|
||||
profile.Spec.LabelsToApply = labels
|
||||
|
||||
// Embed the profile in a KVPair.
|
||||
kvp := model.KVPair{
|
||||
Key: model.ResourceKey{
|
||||
Name: name,
|
||||
Kind: apiv3.KindProfile,
|
||||
},
|
||||
Value: profile,
|
||||
Revision: c.JoinProfileRevisions("", sa.ResourceVersion),
|
||||
}
|
||||
return &kvp, nil
|
||||
}
|
||||
|
||||
// ProfileNameToServiceAccount extracts the ServiceAccount name from the given Profile name.
|
||||
func (c converter) ProfileNameToServiceAccount(profileName string) (ns, sa string, err error) {
|
||||
|
||||
// Profile objects backed by ServiceAccounts have form "ksa.<namespace>.<sa_name>"
|
||||
if !strings.HasPrefix(profileName, ServiceAccountProfileNamePrefix) {
|
||||
// This is not backed by a Kubernetes ServiceAccount.
|
||||
err = fmt.Errorf("Profile %s not backed by a ServiceAccount", profileName)
|
||||
return
|
||||
}
|
||||
|
||||
names := strings.SplitN(profileName, ".", 3)
|
||||
if len(names) != 3 {
|
||||
err = fmt.Errorf("Profile %s is not formatted correctly", profileName)
|
||||
return
|
||||
}
|
||||
|
||||
ns = names[1]
|
||||
sa = names[2]
|
||||
return
|
||||
}
|
||||
|
||||
// JoinProfileRevisions constructs the revision from the individual namespace and serviceaccount
|
||||
// revisions.
|
||||
// This is conditional on the feature flag for serviceaccount set or not.
|
||||
func (c converter) JoinProfileRevisions(nsRev, saRev string) string {
|
||||
return nsRev + "/" + saRev
|
||||
}
|
||||
|
||||
// SplitProfileRevision extracts the namespace and serviceaccount revisions from the combined
|
||||
// revision returned on the KDD service account based profile.
|
||||
// This is conditional on the feature flag for serviceaccount set or not.
|
||||
func (c converter) SplitProfileRevision(rev string) (nsRev string, saRev string, err error) {
|
||||
if rev == "" || rev == "0" {
|
||||
return
|
||||
}
|
||||
|
||||
revs := strings.Split(rev, "/")
|
||||
if len(revs) != 2 {
|
||||
err = fmt.Errorf("ResourceVersion is not valid: %s", rev)
|
||||
return
|
||||
}
|
||||
nsRev = revs[0]
|
||||
saRev = revs[1]
|
||||
return
|
||||
}
|
||||
|
||||
func stringsToIPNets(ipStrings []string) ([]*cnet.IPNet, error) {
|
||||
var podIPNets []*cnet.IPNet
|
||||
for _, ip := range ipStrings {
|
||||
_, ipNet, err := cnet.ParseCIDROrIP(ip)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
podIPNets = append(podIPNets, ipNet)
|
||||
}
|
||||
return podIPNets, nil
|
||||
}
|
||||
32
vendor/github.com/projectcalico/calico/libcalico-go/lib/backend/k8s/conversion/workload_endpoint.go
generated
vendored
Normal file
32
vendor/github.com/projectcalico/calico/libcalico-go/lib/backend/k8s/conversion/workload_endpoint.go
generated
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
// Copyright (c) 2016-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.
|
||||
|
||||
// TODO move the WorkloadEndpoint converters to is own package. Some refactoring of the annotation and label constants
|
||||
// is necessary to avoid circular imports, which is why this has been deferred.
|
||||
package conversion
|
||||
|
||||
import (
|
||||
kapiv1 "k8s.io/api/core/v1"
|
||||
|
||||
"github.com/projectcalico/calico/libcalico-go/lib/backend/model"
|
||||
)
|
||||
|
||||
type WorkloadEndpointConverter interface {
|
||||
VethNameForWorkload(namespace, podName string) string
|
||||
PodToWorkloadEndpoints(pod *kapiv1.Pod) ([]*model.KVPair, error)
|
||||
}
|
||||
|
||||
func NewWorkloadEndpointConverter() WorkloadEndpointConverter {
|
||||
return &defaultWorkloadEndpointConverter{}
|
||||
}
|
||||
285
vendor/github.com/projectcalico/calico/libcalico-go/lib/backend/k8s/conversion/workload_endpoint_default.go
generated
vendored
Normal file
285
vendor/github.com/projectcalico/calico/libcalico-go/lib/backend/k8s/conversion/workload_endpoint_default.go
generated
vendored
Normal file
@@ -0,0 +1,285 @@
|
||||
// Copyright (c) 2016-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 conversion
|
||||
|
||||
import (
|
||||
"crypto/sha1"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
kapiv1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
apiv3 "github.com/projectcalico/api/pkg/apis/projectcalico/v3"
|
||||
"github.com/projectcalico/api/pkg/lib/numorstring"
|
||||
|
||||
libapiv3 "github.com/projectcalico/calico/libcalico-go/lib/apis/v3"
|
||||
"github.com/projectcalico/calico/libcalico-go/lib/backend/model"
|
||||
"github.com/projectcalico/calico/libcalico-go/lib/json"
|
||||
"github.com/projectcalico/calico/libcalico-go/lib/names"
|
||||
cnet "github.com/projectcalico/calico/libcalico-go/lib/net"
|
||||
)
|
||||
|
||||
type defaultWorkloadEndpointConverter struct{}
|
||||
|
||||
// VethNameForWorkload returns a deterministic veth name
|
||||
// for the given Kubernetes workload (WEP) name and namespace.
|
||||
func (wc defaultWorkloadEndpointConverter) VethNameForWorkload(namespace, podname string) string {
|
||||
// A SHA1 is always 20 bytes long, and so is sufficient for generating the
|
||||
// veth name and mac addr.
|
||||
h := sha1.New()
|
||||
h.Write([]byte(fmt.Sprintf("%s.%s", namespace, podname)))
|
||||
prefix := os.Getenv("FELIX_INTERFACEPREFIX")
|
||||
if prefix == "" {
|
||||
// Prefix is not set. Default to "cali"
|
||||
prefix = "cali"
|
||||
} else {
|
||||
// Prefix is set - use the first value in the list.
|
||||
splits := strings.Split(prefix, ",")
|
||||
prefix = splits[0]
|
||||
}
|
||||
log.WithField("prefix", prefix).Debugf("Using prefix to create a WorkloadEndpoint veth name")
|
||||
return fmt.Sprintf("%s%s", prefix, hex.EncodeToString(h.Sum(nil))[:11])
|
||||
}
|
||||
|
||||
func (wc defaultWorkloadEndpointConverter) PodToWorkloadEndpoints(pod *kapiv1.Pod) ([]*model.KVPair, error) {
|
||||
wep, err := wc.podToDefaultWorkloadEndpoint(pod)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return []*model.KVPair{wep}, nil
|
||||
}
|
||||
|
||||
// PodToWorkloadEndpoint converts a Pod to a WorkloadEndpoint. It assumes the calling code
|
||||
// has verified that the provided Pod is valid to convert to a WorkloadEndpoint.
|
||||
// PodToWorkloadEndpoint requires a Pods Name and Node Name to be populated. It will
|
||||
// fail to convert from a Pod to WorkloadEndpoint otherwise.
|
||||
func (wc defaultWorkloadEndpointConverter) podToDefaultWorkloadEndpoint(pod *kapiv1.Pod) (*model.KVPair, error) {
|
||||
log.WithField("pod", pod).Debug("Converting pod to WorkloadEndpoint")
|
||||
// Get all the profiles that apply
|
||||
var profiles []string
|
||||
|
||||
// Pull out the Namespace based profile off the pod name and Namespace.
|
||||
profiles = append(profiles, NamespaceProfileNamePrefix+pod.Namespace)
|
||||
|
||||
// Pull out the Serviceaccount based profile off the pod SA and namespace
|
||||
if pod.Spec.ServiceAccountName != "" {
|
||||
profiles = append(profiles, serviceAccountNameToProfileName(pod.Spec.ServiceAccountName, pod.Namespace))
|
||||
}
|
||||
|
||||
wepids := names.WorkloadEndpointIdentifiers{
|
||||
Node: pod.Spec.NodeName,
|
||||
Orchestrator: apiv3.OrchestratorKubernetes,
|
||||
Endpoint: "eth0",
|
||||
Pod: pod.Name,
|
||||
}
|
||||
wepName, err := wepids.CalculateWorkloadEndpointName(false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
podIPNets, err := getPodIPs(pod)
|
||||
if err != nil {
|
||||
// IP address was present but malformed in some way, handle as an explicit failure.
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if IsFinished(pod) {
|
||||
// Pod is finished but not yet deleted. In this state the IP will have been freed and returned to the pool
|
||||
// so we need to make sure we don't let the caller believe it still belongs to this endpoint.
|
||||
// Pods with no IPs will get filtered out before they get to Felix in the watcher syncer cache layer.
|
||||
// We can't pretend the workload endpoint is deleted _here_ because that would confuse users of the
|
||||
// native v3 Watch() API.
|
||||
log.Debug("Pod is in a 'finished' state so no longer owns its IP(s).")
|
||||
podIPNets = nil
|
||||
}
|
||||
|
||||
ipNets := []string{}
|
||||
for _, ipNet := range podIPNets {
|
||||
ipNets = append(ipNets, ipNet.String())
|
||||
}
|
||||
|
||||
// Generate the interface name based on workload. This must match
|
||||
// the host-side veth configured by the CNI plugin.
|
||||
interfaceName := wc.VethNameForWorkload(pod.Namespace, pod.Name)
|
||||
|
||||
// Build the labels map. Start with the pod labels, and append two additional labels for
|
||||
// namespace and orchestrator matches.
|
||||
labels := pod.Labels
|
||||
if labels == nil {
|
||||
labels = make(map[string]string, 2)
|
||||
}
|
||||
labels[apiv3.LabelNamespace] = pod.Namespace
|
||||
labels[apiv3.LabelOrchestrator] = apiv3.OrchestratorKubernetes
|
||||
|
||||
if pod.Spec.ServiceAccountName != "" && len(pod.Spec.ServiceAccountName) < 63 {
|
||||
// For backwards compatibility, include the label if less than 63 characters.
|
||||
labels[apiv3.LabelServiceAccount] = pod.Spec.ServiceAccountName
|
||||
}
|
||||
|
||||
// Pull out floating IP annotation
|
||||
var floatingIPs []libapiv3.IPNAT
|
||||
if annotation, ok := pod.Annotations["cni.projectcalico.org/floatingIPs"]; ok && len(podIPNets) > 0 {
|
||||
|
||||
// Parse Annotation data
|
||||
var ips []string
|
||||
err := json.Unmarshal([]byte(annotation), &ips)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse '%s' as JSON: %s", annotation, err)
|
||||
}
|
||||
|
||||
// Get IPv4 and IPv6 targets for NAT
|
||||
var podnetV4, podnetV6 *cnet.IPNet
|
||||
for _, ipNet := range podIPNets {
|
||||
if ipNet.IP.To4() != nil {
|
||||
podnetV4 = ipNet
|
||||
netmask, _ := podnetV4.Mask.Size()
|
||||
if netmask != 32 {
|
||||
return nil, fmt.Errorf("PodIP %v is not a valid IPv4: Mask size is %d, not 32", ipNet, netmask)
|
||||
}
|
||||
} else {
|
||||
podnetV6 = ipNet
|
||||
netmask, _ := podnetV6.Mask.Size()
|
||||
if netmask != 128 {
|
||||
return nil, fmt.Errorf("PodIP %v is not a valid IPv6: Mask size is %d, not 128", ipNet, netmask)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, ip := range ips {
|
||||
if strings.Contains(ip, ":") {
|
||||
if podnetV6 != nil {
|
||||
floatingIPs = append(floatingIPs, libapiv3.IPNAT{
|
||||
InternalIP: podnetV6.IP.String(),
|
||||
ExternalIP: ip,
|
||||
})
|
||||
}
|
||||
} else {
|
||||
if podnetV4 != nil {
|
||||
floatingIPs = append(floatingIPs, libapiv3.IPNAT{
|
||||
InternalIP: podnetV4.IP.String(),
|
||||
ExternalIP: ip,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle source IP spoofing annotation
|
||||
var sourcePrefixes []string
|
||||
if annotation, ok := pod.Annotations["cni.projectcalico.org/allowedSourcePrefixes"]; ok && annotation != "" {
|
||||
// Parse Annotation data
|
||||
var requestedSourcePrefixes []string
|
||||
err := json.Unmarshal([]byte(annotation), &requestedSourcePrefixes)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse '%s' as JSON: %s", annotation, err)
|
||||
}
|
||||
|
||||
// Filter out any invalid entries and normalize the CIDRs.
|
||||
for _, prefix := range requestedSourcePrefixes {
|
||||
if _, n, err := cnet.ParseCIDR(prefix); err != nil {
|
||||
return nil, fmt.Errorf("failed to parse '%s' as a CIDR: %s", prefix, err)
|
||||
} else {
|
||||
sourcePrefixes = append(sourcePrefixes, n.String())
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Map any named ports through.
|
||||
var endpointPorts []libapiv3.WorkloadEndpointPort
|
||||
for _, container := range pod.Spec.Containers {
|
||||
for _, containerPort := range container.Ports {
|
||||
if containerPort.ContainerPort != 0 && (containerPort.HostPort != 0 || containerPort.Name != "") {
|
||||
var modelProto numorstring.Protocol
|
||||
switch containerPort.Protocol {
|
||||
case kapiv1.ProtocolUDP:
|
||||
modelProto = numorstring.ProtocolFromString("udp")
|
||||
case kapiv1.ProtocolSCTP:
|
||||
modelProto = numorstring.ProtocolFromString("sctp")
|
||||
case kapiv1.ProtocolTCP, kapiv1.Protocol("") /* K8s default is TCP. */ :
|
||||
modelProto = numorstring.ProtocolFromString("tcp")
|
||||
default:
|
||||
log.WithFields(log.Fields{
|
||||
"protocol": containerPort.Protocol,
|
||||
"pod": pod,
|
||||
"port": containerPort,
|
||||
}).Debug("Ignoring named port with unknown protocol")
|
||||
continue
|
||||
}
|
||||
|
||||
endpointPorts = append(endpointPorts, libapiv3.WorkloadEndpointPort{
|
||||
Name: containerPort.Name,
|
||||
Protocol: modelProto,
|
||||
Port: uint16(containerPort.ContainerPort),
|
||||
HostPort: uint16(containerPort.HostPort),
|
||||
HostIP: containerPort.HostIP,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get the container ID if present. This is used in the CNI plugin to distinguish different pods that have
|
||||
// the same name. For example, restarted stateful set pods.
|
||||
containerID := pod.Annotations[AnnotationContainerID]
|
||||
|
||||
// Create the workload endpoint.
|
||||
wep := libapiv3.NewWorkloadEndpoint()
|
||||
wep.ObjectMeta = metav1.ObjectMeta{
|
||||
Name: wepName,
|
||||
Namespace: pod.Namespace,
|
||||
CreationTimestamp: pod.CreationTimestamp,
|
||||
UID: pod.UID,
|
||||
Labels: labels,
|
||||
GenerateName: pod.GenerateName,
|
||||
}
|
||||
wep.Spec = libapiv3.WorkloadEndpointSpec{
|
||||
Orchestrator: "k8s",
|
||||
Node: pod.Spec.NodeName,
|
||||
Pod: pod.Name,
|
||||
ContainerID: containerID,
|
||||
Endpoint: "eth0",
|
||||
InterfaceName: interfaceName,
|
||||
Profiles: profiles,
|
||||
IPNetworks: ipNets,
|
||||
Ports: endpointPorts,
|
||||
IPNATs: floatingIPs,
|
||||
ServiceAccountName: pod.Spec.ServiceAccountName,
|
||||
AllowSpoofedSourcePrefixes: sourcePrefixes,
|
||||
}
|
||||
|
||||
if v, ok := pod.Annotations["k8s.v1.cni.cncf.io/network-status"]; ok {
|
||||
if wep.Annotations == nil {
|
||||
wep.Annotations = make(map[string]string)
|
||||
}
|
||||
wep.Annotations["k8s.v1.cni.cncf.io/network-status"] = v
|
||||
}
|
||||
|
||||
// Embed the workload endpoint into a KVPair.
|
||||
kvp := model.KVPair{
|
||||
Key: model.ResourceKey{
|
||||
Name: wepName,
|
||||
Namespace: pod.Namespace,
|
||||
Kind: libapiv3.KindWorkloadEndpoint,
|
||||
},
|
||||
Value: wep,
|
||||
Revision: pod.ResourceVersion,
|
||||
}
|
||||
return &kvp, nil
|
||||
}
|
||||
58
vendor/github.com/projectcalico/calico/libcalico-go/lib/backend/model/bgp_node.go
generated
vendored
Normal file
58
vendor/github.com/projectcalico/calico/libcalico-go/lib/backend/model/bgp_node.go
generated
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
// 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 model
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/projectcalico/calico/libcalico-go/lib/errors"
|
||||
)
|
||||
|
||||
var (
|
||||
typeBGPNode = reflect.TypeOf(BGPNode{})
|
||||
)
|
||||
|
||||
type BGPNodeKey struct {
|
||||
Host string
|
||||
}
|
||||
|
||||
func (key BGPNodeKey) defaultPath() (string, error) {
|
||||
if key.Host == "" {
|
||||
return "", errors.ErrorInsufficientIdentifiers{Name: "host"}
|
||||
}
|
||||
|
||||
k := "/calico/bgp/v1/host/" + key.Host
|
||||
return k, nil
|
||||
}
|
||||
|
||||
func (key BGPNodeKey) defaultDeletePath() (string, error) {
|
||||
return key.defaultPath()
|
||||
}
|
||||
|
||||
func (key BGPNodeKey) defaultDeleteParentPaths() ([]string, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (key BGPNodeKey) valueType() (reflect.Type, error) {
|
||||
return typeBGPNode, nil
|
||||
}
|
||||
|
||||
func (key BGPNodeKey) String() string {
|
||||
return fmt.Sprintf("BGPNodeKey(host=%s)", key.Host)
|
||||
}
|
||||
|
||||
type BGPNode struct {
|
||||
}
|
||||
162
vendor/github.com/projectcalico/calico/libcalico-go/lib/backend/model/bgpconfig.go
generated
vendored
Normal file
162
vendor/github.com/projectcalico/calico/libcalico-go/lib/backend/model/bgpconfig.go
generated
vendored
Normal file
@@ -0,0 +1,162 @@
|
||||
// Copyright (c) 2016 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 model
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"regexp"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/projectcalico/calico/libcalico-go/lib/errors"
|
||||
)
|
||||
|
||||
var (
|
||||
matchGlobalBGPConfig = regexp.MustCompile("^/?calico/bgp/v1/global/(.+)$")
|
||||
matchNodeBGPConfig = regexp.MustCompile("^/?calico/bgp/v1/host/([^/]+)/(.+)$")
|
||||
typeGlobalBGPConfig = rawStringType
|
||||
typeNodeBGPConfig = rawStringType
|
||||
)
|
||||
|
||||
type GlobalBGPConfigKey struct {
|
||||
// The name of the global BGP config key.
|
||||
Name string `json:"-" validate:"required,name"`
|
||||
}
|
||||
|
||||
func (key GlobalBGPConfigKey) defaultPath() (string, error) {
|
||||
return key.defaultDeletePath()
|
||||
}
|
||||
|
||||
func (key GlobalBGPConfigKey) defaultDeletePath() (string, error) {
|
||||
if key.Name == "" {
|
||||
return "", errors.ErrorInsufficientIdentifiers{Name: "name"}
|
||||
}
|
||||
e := fmt.Sprintf("/calico/bgp/v1/global/%s", key.Name)
|
||||
return e, nil
|
||||
}
|
||||
|
||||
func (key GlobalBGPConfigKey) defaultDeleteParentPaths() ([]string, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (key GlobalBGPConfigKey) valueType() (reflect.Type, error) {
|
||||
return typeGlobalBGPConfig, nil
|
||||
}
|
||||
|
||||
func (key GlobalBGPConfigKey) String() string {
|
||||
return fmt.Sprintf("GlobalBGPConfig(name=%s)", key.Name)
|
||||
}
|
||||
|
||||
type GlobalBGPConfigListOptions struct {
|
||||
Name string
|
||||
}
|
||||
|
||||
func (options GlobalBGPConfigListOptions) defaultPathRoot() string {
|
||||
k := "/calico/bgp/v1/global"
|
||||
if options.Name == "" {
|
||||
return k
|
||||
}
|
||||
k = k + fmt.Sprintf("/%s", options.Name)
|
||||
return k
|
||||
}
|
||||
|
||||
func (options GlobalBGPConfigListOptions) KeyFromDefaultPath(path string) Key {
|
||||
log.Debugf("Get GlobalFelixConfig key from %s", path)
|
||||
r := matchGlobalBGPConfig.FindAllStringSubmatch(path, -1)
|
||||
if len(r) != 1 {
|
||||
log.Debugf("Didn't match regex")
|
||||
return nil
|
||||
}
|
||||
name := r[0][1]
|
||||
if options.Name != "" && name != options.Name {
|
||||
log.Debugf("Didn't match name %s != %s", options.Name, name)
|
||||
return nil
|
||||
}
|
||||
return GlobalBGPConfigKey{Name: name}
|
||||
}
|
||||
|
||||
type NodeBGPConfigKey struct {
|
||||
// The hostname for the host specific BGP config
|
||||
Nodename string `json:"-" validate:"required,name"`
|
||||
|
||||
// The name of the host specific BGP config key.
|
||||
Name string `json:"-" validate:"required,name"`
|
||||
}
|
||||
|
||||
func (key NodeBGPConfigKey) defaultPath() (string, error) {
|
||||
return key.defaultDeletePath()
|
||||
}
|
||||
|
||||
func (key NodeBGPConfigKey) defaultDeletePath() (string, error) {
|
||||
if key.Nodename == "" {
|
||||
return "", errors.ErrorInsufficientIdentifiers{Name: "node"}
|
||||
}
|
||||
if key.Name == "" {
|
||||
return "", errors.ErrorInsufficientIdentifiers{Name: "name"}
|
||||
}
|
||||
e := fmt.Sprintf("/calico/bgp/v1/host/%s/%s", key.Nodename, key.Name)
|
||||
return e, nil
|
||||
}
|
||||
|
||||
func (key NodeBGPConfigKey) defaultDeleteParentPaths() ([]string, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (key NodeBGPConfigKey) valueType() (reflect.Type, error) {
|
||||
return typeNodeBGPConfig, nil
|
||||
}
|
||||
|
||||
func (key NodeBGPConfigKey) String() string {
|
||||
return fmt.Sprintf("HostBGPConfig(node=%s; name=%s)", key.Nodename, key.Name)
|
||||
}
|
||||
|
||||
type NodeBGPConfigListOptions struct {
|
||||
Nodename string
|
||||
Name string
|
||||
}
|
||||
|
||||
func (options NodeBGPConfigListOptions) defaultPathRoot() string {
|
||||
k := "/calico/bgp/v1/host/%s"
|
||||
if options.Nodename == "" {
|
||||
return k
|
||||
}
|
||||
k = k + fmt.Sprintf("/%s", options.Nodename)
|
||||
if options.Name == "" {
|
||||
return k
|
||||
}
|
||||
k = k + fmt.Sprintf("/%s", options.Name)
|
||||
return k
|
||||
}
|
||||
|
||||
func (options NodeBGPConfigListOptions) KeyFromDefaultPath(path string) Key {
|
||||
log.Debugf("Get HostConfig key from %s", path)
|
||||
r := matchNodeBGPConfig.FindAllStringSubmatch(path, -1)
|
||||
if len(r) != 1 {
|
||||
log.Debugf("Didn't match regex")
|
||||
return nil
|
||||
}
|
||||
nodename := r[0][1]
|
||||
name := r[0][2]
|
||||
if options.Nodename != "" && nodename != options.Nodename {
|
||||
log.Debugf("Didn't match nodename %s != %s", options.Nodename, nodename)
|
||||
return nil
|
||||
}
|
||||
if options.Name != "" && name != options.Name {
|
||||
log.Debugf("Didn't match name %s != %s", options.Name, name)
|
||||
return nil
|
||||
}
|
||||
return NodeBGPConfigKey{Nodename: nodename, Name: name}
|
||||
}
|
||||
230
vendor/github.com/projectcalico/calico/libcalico-go/lib/backend/model/bgppeer.go
generated
vendored
Normal file
230
vendor/github.com/projectcalico/calico/libcalico-go/lib/backend/model/bgppeer.go
generated
vendored
Normal file
@@ -0,0 +1,230 @@
|
||||
// Copyright (c) 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 model
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/projectcalico/api/pkg/lib/numorstring"
|
||||
|
||||
"github.com/projectcalico/calico/libcalico-go/lib/errors"
|
||||
"github.com/projectcalico/calico/libcalico-go/lib/net"
|
||||
)
|
||||
|
||||
var (
|
||||
matchGlobalBGPPeer = regexp.MustCompile("^/?calico/bgp/v1/global/peer_v./([^/]+)$")
|
||||
matchHostBGPPeer = regexp.MustCompile("^/?calico/bgp/v1/host/([^/]+)/peer_v./([^/]+)$")
|
||||
typeBGPPeer = reflect.TypeOf(BGPPeer{})
|
||||
ipPortSeparator = "-"
|
||||
defaultPort uint16 = 179
|
||||
)
|
||||
|
||||
type NodeBGPPeerKey struct {
|
||||
Nodename string `json:"-" validate:"omitempty"`
|
||||
PeerIP net.IP `json:"-" validate:"required"`
|
||||
Port uint16 `json:"-" validate:"omitempty"`
|
||||
}
|
||||
|
||||
func (key NodeBGPPeerKey) defaultPath() (string, error) {
|
||||
if key.PeerIP.IP == nil {
|
||||
return "", errors.ErrorInsufficientIdentifiers{Name: "peerIP"}
|
||||
}
|
||||
if key.Nodename == "" {
|
||||
return "", errors.ErrorInsufficientIdentifiers{Name: "node"}
|
||||
}
|
||||
e := fmt.Sprintf("/calico/bgp/v1/host/%s/peer_v%d/%s",
|
||||
key.Nodename, key.PeerIP.Version(), combineIPAndPort(key.PeerIP, key.Port))
|
||||
return e, nil
|
||||
}
|
||||
|
||||
func (key NodeBGPPeerKey) defaultDeletePath() (string, error) {
|
||||
return key.defaultPath()
|
||||
}
|
||||
|
||||
func (key NodeBGPPeerKey) defaultDeleteParentPaths() ([]string, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (key NodeBGPPeerKey) valueType() (reflect.Type, error) {
|
||||
return typeBGPPeer, nil
|
||||
}
|
||||
|
||||
func (key NodeBGPPeerKey) String() string {
|
||||
return fmt.Sprintf("BGPPeer(node=%s, ip=%s, port=%d)", key.Nodename, key.PeerIP, key.Port)
|
||||
}
|
||||
|
||||
type NodeBGPPeerListOptions struct {
|
||||
Nodename string
|
||||
PeerIP net.IP
|
||||
Port uint16
|
||||
}
|
||||
|
||||
func (options NodeBGPPeerListOptions) defaultPathRoot() string {
|
||||
if options.Nodename == "" {
|
||||
return "/calico/bgp/v1/host"
|
||||
} else if options.PeerIP.IP == nil {
|
||||
return fmt.Sprintf("/calico/bgp/v1/host/%s",
|
||||
options.Nodename)
|
||||
} else {
|
||||
return fmt.Sprintf("/calico/bgp/v1/host/%s/peer_v%d/%s",
|
||||
options.Nodename, options.PeerIP.Version(), combineIPAndPort(options.PeerIP, options.Port))
|
||||
}
|
||||
}
|
||||
|
||||
func (options NodeBGPPeerListOptions) KeyFromDefaultPath(path string) Key {
|
||||
log.Debugf("Get BGPPeer key from %s", path)
|
||||
nodename := ""
|
||||
var port uint16
|
||||
peerIP := net.IP{}
|
||||
ekeyb := []byte(path)
|
||||
if r := matchHostBGPPeer.FindAllSubmatch(ekeyb, -1); len(r) == 1 {
|
||||
var ipBytes []byte
|
||||
ipBytes, port = extractIPAndPort(string(r[0][2]))
|
||||
nodename = string(r[0][1])
|
||||
if err := peerIP.UnmarshalText(ipBytes); err != nil {
|
||||
log.WithError(err).WithField("PeerIP", r[0][2]).Error("Error unmarshalling GlobalBGPPeer IP address")
|
||||
return nil
|
||||
}
|
||||
} else {
|
||||
log.Debugf("%s didn't match regex", path)
|
||||
return nil
|
||||
}
|
||||
|
||||
if options.PeerIP.IP != nil && !options.PeerIP.Equal(peerIP.IP) {
|
||||
log.Debugf("Didn't match peerIP %s != %s", options.PeerIP.String(), peerIP.String())
|
||||
return nil
|
||||
}
|
||||
if options.Nodename != "" && nodename != options.Nodename {
|
||||
log.Debugf("Didn't match hostname %s != %s", options.Nodename, nodename)
|
||||
return nil
|
||||
}
|
||||
|
||||
if port == 0 {
|
||||
return NodeBGPPeerKey{PeerIP: peerIP, Nodename: nodename}
|
||||
}
|
||||
return NodeBGPPeerKey{PeerIP: peerIP, Nodename: nodename, Port: port}
|
||||
}
|
||||
|
||||
type GlobalBGPPeerKey struct {
|
||||
PeerIP net.IP `json:"-" validate:"required"`
|
||||
Port uint16 `json:"-" validate:"omitempty"`
|
||||
}
|
||||
|
||||
func (key GlobalBGPPeerKey) defaultPath() (string, error) {
|
||||
if key.PeerIP.IP == nil {
|
||||
return "", errors.ErrorInsufficientIdentifiers{Name: "peerIP"}
|
||||
}
|
||||
e := fmt.Sprintf("/calico/bgp/v1/global/peer_v%d/%s",
|
||||
key.PeerIP.Version(), combineIPAndPort(key.PeerIP, key.Port))
|
||||
return e, nil
|
||||
}
|
||||
|
||||
func (key GlobalBGPPeerKey) defaultDeletePath() (string, error) {
|
||||
return key.defaultPath()
|
||||
}
|
||||
|
||||
func (key GlobalBGPPeerKey) defaultDeleteParentPaths() ([]string, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (key GlobalBGPPeerKey) valueType() (reflect.Type, error) {
|
||||
return typeBGPPeer, nil
|
||||
}
|
||||
|
||||
func (key GlobalBGPPeerKey) String() string {
|
||||
return fmt.Sprintf("BGPPeer(global, ip=%s, port=%d)", key.PeerIP, key.Port)
|
||||
}
|
||||
|
||||
type GlobalBGPPeerListOptions struct {
|
||||
PeerIP net.IP
|
||||
Port uint16
|
||||
}
|
||||
|
||||
func (options GlobalBGPPeerListOptions) defaultPathRoot() string {
|
||||
if options.PeerIP.IP == nil {
|
||||
return "/calico/bgp/v1/global"
|
||||
} else {
|
||||
return fmt.Sprintf("/calico/bgp/v1/global/peer_v%d/%s",
|
||||
options.PeerIP.Version(), combineIPAndPort(options.PeerIP, options.Port))
|
||||
}
|
||||
}
|
||||
|
||||
func (options GlobalBGPPeerListOptions) KeyFromDefaultPath(path string) Key {
|
||||
log.Debugf("Get BGPPeer key from %s", path)
|
||||
peerIP := net.IP{}
|
||||
ekeyb := []byte(path)
|
||||
var port uint16
|
||||
|
||||
if r := matchGlobalBGPPeer.FindAllSubmatch(ekeyb, -1); len(r) == 1 {
|
||||
var ipBytes []byte
|
||||
ipBytes, port = extractIPAndPort(string(r[0][1]))
|
||||
if err := peerIP.UnmarshalText(ipBytes); err != nil {
|
||||
log.WithError(err).WithField("PeerIP", r[0][1]).Error("Error unmarshalling GlobalBGPPeer IP address")
|
||||
return nil
|
||||
}
|
||||
} else {
|
||||
log.Debugf("%s didn't match regex", path)
|
||||
return nil
|
||||
}
|
||||
|
||||
if options.PeerIP.IP != nil && !options.PeerIP.Equal(peerIP.IP) {
|
||||
log.Debugf("Didn't match peerIP %s != %s", options.PeerIP.String(), peerIP.String())
|
||||
return nil
|
||||
}
|
||||
|
||||
if port == 0 {
|
||||
return GlobalBGPPeerKey{PeerIP: peerIP, Port: port}
|
||||
}
|
||||
return GlobalBGPPeerKey{PeerIP: peerIP, Port: port}
|
||||
}
|
||||
|
||||
type BGPPeer struct {
|
||||
// PeerIP is the IP address of the BGP peer.
|
||||
PeerIP net.IP `json:"ip"`
|
||||
|
||||
// ASNum is the AS number of the peer. Note that we write out the
|
||||
// value as a string in to the backend, because confd templating
|
||||
// converts large uints to float e notation which breaks the BIRD
|
||||
// configuration.
|
||||
ASNum numorstring.ASNumber `json:"as_num,string"`
|
||||
}
|
||||
|
||||
func extractIPAndPort(ipPort string) ([]byte, uint16) {
|
||||
arr := strings.Split(ipPort, ipPortSeparator)
|
||||
if len(arr) == 2 {
|
||||
port, err := strconv.ParseUint(arr[1], 0, 16)
|
||||
if err != nil {
|
||||
log.Warningf("Error extracting port. %#v", err)
|
||||
return []byte(ipPort), defaultPort
|
||||
}
|
||||
return []byte(arr[0]), uint16(port)
|
||||
}
|
||||
return []byte(ipPort), defaultPort
|
||||
}
|
||||
|
||||
func combineIPAndPort(ip net.IP, port uint16) string {
|
||||
if port == 0 || port == defaultPort {
|
||||
return ip.String()
|
||||
} else {
|
||||
strPort := strconv.Itoa(int(port))
|
||||
return ip.String() + ipPortSeparator + strPort
|
||||
}
|
||||
}
|
||||
235
vendor/github.com/projectcalico/calico/libcalico-go/lib/backend/model/block.go
generated
vendored
Normal file
235
vendor/github.com/projectcalico/calico/libcalico-go/lib/backend/model/block.go
generated
vendored
Normal file
@@ -0,0 +1,235 @@
|
||||
// Copyright (c) 2016-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 model
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/projectcalico/calico/libcalico-go/lib/errors"
|
||||
"github.com/projectcalico/calico/libcalico-go/lib/net"
|
||||
)
|
||||
|
||||
const (
|
||||
// Common attributes which may be set on allocations by clients.
|
||||
IPAMBlockAttributePod = "pod"
|
||||
IPAMBlockAttributeNamespace = "namespace"
|
||||
IPAMBlockAttributeNode = "node"
|
||||
IPAMBlockAttributeType = "type"
|
||||
IPAMBlockAttributeTypeIPIP = "ipipTunnelAddress"
|
||||
IPAMBlockAttributeTypeVXLAN = "vxlanTunnelAddress"
|
||||
IPAMBlockAttributeTypeVXLANV6 = "vxlanV6TunnelAddress"
|
||||
IPAMBlockAttributeTypeWireguard = "wireguardTunnelAddress"
|
||||
IPAMBlockAttributeTypeWireguardV6 = "wireguardV6TunnelAddress"
|
||||
IPAMBlockAttributeTimestamp = "timestamp"
|
||||
)
|
||||
|
||||
var (
|
||||
matchBlock = regexp.MustCompile("^/?calico/ipam/v2/assignment/ipv./block/([^/]+)$")
|
||||
typeBlock = reflect.TypeOf(AllocationBlock{})
|
||||
)
|
||||
|
||||
type BlockKey struct {
|
||||
CIDR net.IPNet `json:"-" validate:"required,name"`
|
||||
}
|
||||
|
||||
func (key BlockKey) defaultPath() (string, error) {
|
||||
if key.CIDR.IP == nil {
|
||||
return "", errors.ErrorInsufficientIdentifiers{}
|
||||
}
|
||||
c := strings.Replace(key.CIDR.String(), "/", "-", 1)
|
||||
e := fmt.Sprintf("/calico/ipam/v2/assignment/ipv%d/block/%s", key.CIDR.Version(), c)
|
||||
return e, nil
|
||||
}
|
||||
|
||||
func (key BlockKey) defaultDeletePath() (string, error) {
|
||||
return key.defaultPath()
|
||||
}
|
||||
|
||||
func (key BlockKey) defaultDeleteParentPaths() ([]string, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (key BlockKey) valueType() (reflect.Type, error) {
|
||||
return typeBlock, nil
|
||||
}
|
||||
|
||||
func (key BlockKey) String() string {
|
||||
return fmt.Sprintf("BlockKey(cidr=%s)", key.CIDR.String())
|
||||
}
|
||||
|
||||
type BlockListOptions struct {
|
||||
IPVersion int `json:"-"`
|
||||
}
|
||||
|
||||
func (options BlockListOptions) defaultPathRoot() string {
|
||||
k := "/calico/ipam/v2/assignment/"
|
||||
if options.IPVersion != 0 {
|
||||
k = k + fmt.Sprintf("ipv%d/", options.IPVersion)
|
||||
}
|
||||
return k
|
||||
}
|
||||
|
||||
func (options BlockListOptions) KeyFromDefaultPath(path string) Key {
|
||||
log.Debugf("Get Block key from %s", path)
|
||||
r := matchBlock.FindAllStringSubmatch(path, -1)
|
||||
if len(r) != 1 {
|
||||
log.Debugf("%s didn't match regex", path)
|
||||
return nil
|
||||
}
|
||||
cidrStr := strings.Replace(r[0][1], "-", "/", 1)
|
||||
_, cidr, err := net.ParseCIDR(cidrStr)
|
||||
if err != nil {
|
||||
log.Debugf("find an invalid cidr %s for path=%v , info=%v ", r[0][1], path, err)
|
||||
return nil
|
||||
}
|
||||
return BlockKey{CIDR: *cidr}
|
||||
}
|
||||
|
||||
type AllocationBlock struct {
|
||||
// The block's CIDR.
|
||||
CIDR net.IPNet `json:"cidr"`
|
||||
|
||||
// Affinity of the block, if this block has one. If set, it will be of the form
|
||||
// "host:<hostname>". If not set, this block is not affine to a host.
|
||||
Affinity *string `json:"affinity"`
|
||||
|
||||
// Array of allocations in-use within this block. nil entries mean the allocation is free.
|
||||
// For non-nil entries at index i, the index is the ordinal of the allocation within this block
|
||||
// and the value is the index of the associated attributes in the Attributes array.
|
||||
Allocations []*int `json:"allocations"`
|
||||
|
||||
// Unallocated is an ordered list of allocations which are free in the block.
|
||||
Unallocated []int `json:"unallocated"`
|
||||
|
||||
// Attributes is an array of arbitrary metadata associated with allocations in the block. To find
|
||||
// attributes for a given allocation, use the value of the allocation's entry in the Allocations array
|
||||
// as the index of the element in this array.
|
||||
Attributes []AllocationAttribute `json:"attributes"`
|
||||
|
||||
// We store a sequence number that is updated each time the block is written.
|
||||
// Each allocation will also store the sequence number of the block at the time of its creation.
|
||||
// When releasing an IP, passing the sequence number associated with the allocation allows us
|
||||
// to protect against a race condition and ensure the IP hasn't been released and re-allocated
|
||||
// since the release request.
|
||||
SequenceNumber uint64 `json:"sequenceNumber"`
|
||||
|
||||
// Map of allocated ordinal within the block to sequence number of the block at
|
||||
// the time of allocation. Kubernetes does not allow numerical keys for maps, so
|
||||
// the key is cast to a string.
|
||||
SequenceNumberForAllocation map[string]uint64 `json:"sequenceNumberForAllocation"`
|
||||
|
||||
// Deleted is an internal boolean used to workaround a limitation in the Kubernetes API whereby
|
||||
// deletion will not return a conflict error if the block has been updated.
|
||||
Deleted bool `json:"deleted"`
|
||||
|
||||
// HostAffinity is deprecated in favor of Affinity.
|
||||
// This is only to keep compatibility with existing deployments.
|
||||
// The data format should be `Affinity: host:hostname` (not `hostAffinity: hostname`).
|
||||
HostAffinity *string `json:"hostAffinity,omitempty"`
|
||||
}
|
||||
|
||||
func (b *AllocationBlock) SetSequenceNumberForOrdinal(ordinal int) {
|
||||
if b.SequenceNumberForAllocation == nil {
|
||||
b.SequenceNumberForAllocation = map[string]uint64{}
|
||||
}
|
||||
b.SequenceNumberForAllocation[fmt.Sprintf("%d", ordinal)] = b.SequenceNumber
|
||||
}
|
||||
|
||||
func (b *AllocationBlock) GetSequenceNumberForOrdinal(ordinal int) uint64 {
|
||||
return b.SequenceNumberForAllocation[fmt.Sprintf("%d", ordinal)]
|
||||
}
|
||||
|
||||
func (b *AllocationBlock) ClearSequenceNumberForOrdinal(ordinal int) {
|
||||
delete(b.SequenceNumberForAllocation, fmt.Sprintf("%d", ordinal))
|
||||
}
|
||||
|
||||
func (b *AllocationBlock) MarkDeleted() {
|
||||
b.Deleted = true
|
||||
}
|
||||
|
||||
func (b *AllocationBlock) IsDeleted() bool {
|
||||
return b.Deleted
|
||||
}
|
||||
|
||||
func (b *AllocationBlock) Host() string {
|
||||
if b.Affinity != nil && strings.HasPrefix(*b.Affinity, "host:") {
|
||||
return strings.TrimPrefix(*b.Affinity, "host:")
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type Allocation struct {
|
||||
Addr net.IP
|
||||
Host string
|
||||
}
|
||||
|
||||
func (b *AllocationBlock) NonAffineAllocations() []Allocation {
|
||||
var allocs []Allocation
|
||||
myHost := b.Host()
|
||||
for ordinal, attrIdx := range b.Allocations {
|
||||
if attrIdx == nil {
|
||||
continue // Skip unallocated IPs.
|
||||
}
|
||||
if *attrIdx >= len(b.Attributes) {
|
||||
log.WithField("block", b).Warnf("Missing attributes for IP with ordinal %d", ordinal)
|
||||
continue
|
||||
}
|
||||
attrs := b.Attributes[*attrIdx]
|
||||
host := attrs.AttrSecondary[IPAMBlockAttributeNode]
|
||||
if myHost != "" && host == myHost {
|
||||
continue // Skip allocations that are affine to this block.
|
||||
}
|
||||
a := Allocation{
|
||||
Addr: b.OrdinalToIP(ordinal),
|
||||
Host: host,
|
||||
}
|
||||
allocs = append(allocs, a)
|
||||
}
|
||||
return allocs
|
||||
}
|
||||
|
||||
// Get number of addresses covered by the block
|
||||
func (b *AllocationBlock) NumAddresses() int {
|
||||
ones, size := b.CIDR.Mask.Size()
|
||||
numAddresses := 1 << uint(size-ones)
|
||||
return numAddresses
|
||||
}
|
||||
|
||||
// Find the ordinal (i.e. how far into the block) a given IP lies. Returns an error if the IP is outside the block.
|
||||
func (b *AllocationBlock) IPToOrdinal(ip net.IP) (int, error) {
|
||||
ipAsInt := net.IPToBigInt(ip)
|
||||
baseInt := net.IPToBigInt(net.IP{b.CIDR.IP})
|
||||
ord := big.NewInt(0).Sub(ipAsInt, baseInt).Int64()
|
||||
if ord < 0 || ord >= int64(b.NumAddresses()) {
|
||||
return 0, fmt.Errorf("IP %s not in block %s", ip, b.CIDR)
|
||||
}
|
||||
return int(ord), nil
|
||||
}
|
||||
|
||||
// Calculates the IP at the given position within the block. ord=0 gives the first IP in the block.
|
||||
func (b *AllocationBlock) OrdinalToIP(ord int) net.IP {
|
||||
return b.CIDR.NthIP(ord)
|
||||
}
|
||||
|
||||
type AllocationAttribute struct {
|
||||
AttrPrimary *string `json:"handle_id"`
|
||||
AttrSecondary map[string]string `json:"secondary"`
|
||||
}
|
||||
118
vendor/github.com/projectcalico/calico/libcalico-go/lib/backend/model/block_affinity.go
generated
vendored
Normal file
118
vendor/github.com/projectcalico/calico/libcalico-go/lib/backend/model/block_affinity.go
generated
vendored
Normal file
@@ -0,0 +1,118 @@
|
||||
// Copyright (c) 2016-2019 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 model
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/projectcalico/calico/libcalico-go/lib/errors"
|
||||
"github.com/projectcalico/calico/libcalico-go/lib/net"
|
||||
)
|
||||
|
||||
var (
|
||||
matchBlockAffinity = regexp.MustCompile("^/?calico/ipam/v2/host/([^/]+)/ipv./block/([^/]+)$")
|
||||
typeBlockAff = reflect.TypeOf(BlockAffinity{})
|
||||
)
|
||||
|
||||
type BlockAffinityState string
|
||||
|
||||
const (
|
||||
StateConfirmed BlockAffinityState = "confirmed"
|
||||
StatePending BlockAffinityState = "pending"
|
||||
StatePendingDeletion BlockAffinityState = "pendingDeletion"
|
||||
)
|
||||
|
||||
type BlockAffinityKey struct {
|
||||
CIDR net.IPNet `json:"-" validate:"required,name"`
|
||||
Host string `json:"-"`
|
||||
}
|
||||
|
||||
type BlockAffinity struct {
|
||||
State BlockAffinityState `json:"state"`
|
||||
Deleted bool `json:"deleted"`
|
||||
}
|
||||
|
||||
func (key BlockAffinityKey) defaultPath() (string, error) {
|
||||
if key.CIDR.IP == nil || key.Host == "" {
|
||||
return "", errors.ErrorInsufficientIdentifiers{}
|
||||
}
|
||||
c := strings.Replace(key.CIDR.String(), "/", "-", 1)
|
||||
e := fmt.Sprintf("/calico/ipam/v2/host/%s/ipv%d/block/%s", key.Host, key.CIDR.Version(), c)
|
||||
return e, nil
|
||||
}
|
||||
|
||||
func (key BlockAffinityKey) defaultDeletePath() (string, error) {
|
||||
return key.defaultPath()
|
||||
}
|
||||
|
||||
func (key BlockAffinityKey) defaultDeleteParentPaths() ([]string, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (key BlockAffinityKey) valueType() (reflect.Type, error) {
|
||||
return typeBlockAff, nil
|
||||
}
|
||||
|
||||
func (key BlockAffinityKey) String() string {
|
||||
return fmt.Sprintf("BlockAffinityKey(cidr=%s, host=%s)", key.CIDR, key.Host)
|
||||
}
|
||||
|
||||
type BlockAffinityListOptions struct {
|
||||
Host string
|
||||
IPVersion int
|
||||
}
|
||||
|
||||
func (options BlockAffinityListOptions) defaultPathRoot() string {
|
||||
k := "/calico/ipam/v2/host/"
|
||||
if options.Host != "" {
|
||||
k = k + options.Host
|
||||
|
||||
if options.IPVersion != 0 {
|
||||
k = k + fmt.Sprintf("/ipv%d/block", options.IPVersion)
|
||||
}
|
||||
}
|
||||
return k
|
||||
}
|
||||
|
||||
func (options BlockAffinityListOptions) KeyFromDefaultPath(path string) Key {
|
||||
log.Debugf("Get Block affinity key from %s", path)
|
||||
r := matchBlockAffinity.FindAllStringSubmatch(path, -1)
|
||||
if len(r) != 1 {
|
||||
log.Debugf("%s didn't match regex", path)
|
||||
return nil
|
||||
}
|
||||
cidrStr := strings.Replace(r[0][2], "-", "/", 1)
|
||||
_, cidr, _ := net.ParseCIDR(cidrStr)
|
||||
if cidr == nil {
|
||||
log.Debugf("Failed to parse CIDR in block affinity path: %q", path)
|
||||
return nil
|
||||
}
|
||||
host := r[0][1]
|
||||
|
||||
if options.Host != "" && options.Host != host {
|
||||
log.Debugf("Didn't match hostname: %s != %s", options.Host, host)
|
||||
return nil
|
||||
}
|
||||
if options.IPVersion != 0 && options.IPVersion != cidr.Version() {
|
||||
log.Debugf("Didn't match IP version. %d != %d", options.IPVersion, cidr.Version())
|
||||
return nil
|
||||
}
|
||||
return BlockAffinityKey{CIDR: *cidr, Host: host}
|
||||
}
|
||||
20
vendor/github.com/projectcalico/calico/libcalico-go/lib/backend/model/deletion.go
generated
vendored
Normal file
20
vendor/github.com/projectcalico/calico/libcalico-go/lib/backend/model/deletion.go
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
// Copyright (c) 2019 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 model
|
||||
|
||||
type DeletionMarker interface {
|
||||
MarkDeleted()
|
||||
IsDeleted() bool
|
||||
}
|
||||
183
vendor/github.com/projectcalico/calico/libcalico-go/lib/backend/model/felixconfig.go
generated
vendored
Normal file
183
vendor/github.com/projectcalico/calico/libcalico-go/lib/backend/model/felixconfig.go
generated
vendored
Normal file
@@ -0,0 +1,183 @@
|
||||
// Copyright (c) 2016-2018 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 model
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"regexp"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/projectcalico/calico/libcalico-go/lib/errors"
|
||||
)
|
||||
|
||||
var (
|
||||
matchGlobalConfig = regexp.MustCompile("^/?calico/v1/config/(.+)$")
|
||||
matchHostConfig = regexp.MustCompile("^/?calico/v1/host/([^/]+)/config/(.+)$")
|
||||
matchReadyFlag = regexp.MustCompile("^/calico/v1/Ready$")
|
||||
typeGlobalConfig = rawStringType
|
||||
typeHostConfig = rawStringType
|
||||
typeReadyFlag = rawBoolType
|
||||
)
|
||||
|
||||
type ReadyFlagKey struct {
|
||||
}
|
||||
|
||||
func (key ReadyFlagKey) defaultPath() (string, error) {
|
||||
return "/calico/v1/Ready", nil
|
||||
}
|
||||
|
||||
func (key ReadyFlagKey) defaultDeletePath() (string, error) {
|
||||
return key.defaultPath()
|
||||
}
|
||||
|
||||
func (key ReadyFlagKey) defaultDeleteParentPaths() ([]string, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (key ReadyFlagKey) valueType() (reflect.Type, error) {
|
||||
return typeReadyFlag, nil
|
||||
}
|
||||
|
||||
func (key ReadyFlagKey) String() string {
|
||||
return "ReadyFlagKey()"
|
||||
}
|
||||
|
||||
type GlobalConfigKey struct {
|
||||
Name string `json:"-" validate:"required,name"`
|
||||
}
|
||||
|
||||
func (key GlobalConfigKey) defaultPath() (string, error) {
|
||||
if key.Name == "" {
|
||||
return "", errors.ErrorInsufficientIdentifiers{Name: "name"}
|
||||
}
|
||||
e := fmt.Sprintf("/calico/v1/config/%s", key.Name)
|
||||
return e, nil
|
||||
}
|
||||
|
||||
func (key GlobalConfigKey) defaultDeletePath() (string, error) {
|
||||
return key.defaultPath()
|
||||
}
|
||||
|
||||
func (key GlobalConfigKey) defaultDeleteParentPaths() ([]string, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (key GlobalConfigKey) valueType() (reflect.Type, error) {
|
||||
return typeGlobalConfig, nil
|
||||
}
|
||||
|
||||
func (key GlobalConfigKey) String() string {
|
||||
return fmt.Sprintf("GlobalFelixConfig(name=%s)", key.Name)
|
||||
}
|
||||
|
||||
type GlobalConfigListOptions struct {
|
||||
Name string
|
||||
}
|
||||
|
||||
func (options GlobalConfigListOptions) defaultPathRoot() string {
|
||||
k := "/calico/v1/config"
|
||||
if options.Name == "" {
|
||||
return k
|
||||
}
|
||||
k = k + fmt.Sprintf("/%s", options.Name)
|
||||
return k
|
||||
}
|
||||
|
||||
func (options GlobalConfigListOptions) KeyFromDefaultPath(path string) Key {
|
||||
log.Debugf("Get GlobalConfig key from %s", path)
|
||||
r := matchGlobalConfig.FindAllStringSubmatch(path, -1)
|
||||
if len(r) != 1 {
|
||||
log.Debugf("Didn't match regex")
|
||||
return nil
|
||||
}
|
||||
name := r[0][1]
|
||||
if options.Name != "" && name != options.Name {
|
||||
log.Debugf("Didn't match name %s != %s", options.Name, name)
|
||||
return nil
|
||||
}
|
||||
return GlobalConfigKey{Name: name}
|
||||
}
|
||||
|
||||
type HostConfigKey struct {
|
||||
Hostname string `json:"-" validate:"required,name"`
|
||||
Name string `json:"-" validate:"required,name"`
|
||||
}
|
||||
|
||||
func (key HostConfigKey) defaultPath() (string, error) {
|
||||
if key.Name == "" {
|
||||
return "", errors.ErrorInsufficientIdentifiers{Name: "name"}
|
||||
}
|
||||
if key.Hostname == "" {
|
||||
return "", errors.ErrorInsufficientIdentifiers{Name: "node"}
|
||||
}
|
||||
e := fmt.Sprintf("/calico/v1/host/%s/config/%s", key.Hostname, key.Name)
|
||||
return e, nil
|
||||
}
|
||||
|
||||
func (key HostConfigKey) defaultDeletePath() (string, error) {
|
||||
return key.defaultPath()
|
||||
}
|
||||
|
||||
func (key HostConfigKey) defaultDeleteParentPaths() ([]string, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (key HostConfigKey) valueType() (reflect.Type, error) {
|
||||
return typeHostConfig, nil
|
||||
}
|
||||
|
||||
func (key HostConfigKey) String() string {
|
||||
return fmt.Sprintf("HostConfig(node=%s,name=%s)", key.Hostname, key.Name)
|
||||
}
|
||||
|
||||
type HostConfigListOptions struct {
|
||||
Hostname string
|
||||
Name string
|
||||
}
|
||||
|
||||
func (options HostConfigListOptions) defaultPathRoot() string {
|
||||
k := "/calico/v1/host"
|
||||
if options.Hostname == "" {
|
||||
return k
|
||||
}
|
||||
k = k + fmt.Sprintf("/%s/config", options.Hostname)
|
||||
if options.Name == "" {
|
||||
return k
|
||||
}
|
||||
k = k + fmt.Sprintf("/%s", options.Name)
|
||||
return k
|
||||
}
|
||||
|
||||
func (options HostConfigListOptions) KeyFromDefaultPath(path string) Key {
|
||||
log.Debugf("Get HostConfig key from %s", path)
|
||||
r := matchHostConfig.FindAllStringSubmatch(path, -1)
|
||||
if len(r) != 1 {
|
||||
log.Debugf("Didn't match regex")
|
||||
return nil
|
||||
}
|
||||
hostname := r[0][1]
|
||||
name := r[0][2]
|
||||
if options.Hostname != "" && hostname != options.Hostname {
|
||||
log.Debugf("Didn't match hostname %s != %s", options.Hostname, hostname)
|
||||
return nil
|
||||
}
|
||||
if options.Name != "" && name != options.Name {
|
||||
log.Debugf("Didn't match name %s != %s", options.Name, name)
|
||||
return nil
|
||||
}
|
||||
return HostConfigKey{Hostname: hostname, Name: name}
|
||||
}
|
||||
113
vendor/github.com/projectcalico/calico/libcalico-go/lib/backend/model/hostendpoint.go
generated
vendored
Normal file
113
vendor/github.com/projectcalico/calico/libcalico-go/lib/backend/model/hostendpoint.go
generated
vendored
Normal file
@@ -0,0 +1,113 @@
|
||||
// Copyright (c) 2016-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 model
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"regexp"
|
||||
|
||||
"reflect"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/projectcalico/calico/libcalico-go/lib/errors"
|
||||
"github.com/projectcalico/calico/libcalico-go/lib/net"
|
||||
)
|
||||
|
||||
var (
|
||||
matchHostEndpoint = regexp.MustCompile("^/?calico/v1/host/([^/]+)/endpoint/([^/]+)$")
|
||||
typeHostEndpoint = reflect.TypeOf(HostEndpoint{})
|
||||
)
|
||||
|
||||
type HostEndpointKey struct {
|
||||
Hostname string `json:"-" validate:"required,hostname"`
|
||||
EndpointID string `json:"-" validate:"required,namespacedName"`
|
||||
}
|
||||
|
||||
func (key HostEndpointKey) defaultPath() (string, error) {
|
||||
if key.Hostname == "" {
|
||||
return "", errors.ErrorInsufficientIdentifiers{Name: "node"}
|
||||
}
|
||||
if key.EndpointID == "" {
|
||||
return "", errors.ErrorInsufficientIdentifiers{Name: "name"}
|
||||
}
|
||||
e := fmt.Sprintf("/calico/v1/host/%s/endpoint/%s",
|
||||
key.Hostname, escapeName(key.EndpointID))
|
||||
return e, nil
|
||||
}
|
||||
|
||||
func (key HostEndpointKey) defaultDeletePath() (string, error) {
|
||||
return key.defaultPath()
|
||||
}
|
||||
|
||||
func (key HostEndpointKey) defaultDeleteParentPaths() ([]string, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (key HostEndpointKey) valueType() (reflect.Type, error) {
|
||||
return typeHostEndpoint, nil
|
||||
}
|
||||
|
||||
func (key HostEndpointKey) String() string {
|
||||
return fmt.Sprintf("HostEndpoint(node=%s, name=%s)", key.Hostname, key.EndpointID)
|
||||
}
|
||||
|
||||
type HostEndpointListOptions struct {
|
||||
Hostname string
|
||||
EndpointID string
|
||||
}
|
||||
|
||||
func (options HostEndpointListOptions) defaultPathRoot() string {
|
||||
k := "/calico/v1/host"
|
||||
if options.Hostname == "" {
|
||||
return k
|
||||
}
|
||||
k = k + fmt.Sprintf("/%s/endpoint", options.Hostname)
|
||||
if options.EndpointID == "" {
|
||||
return k
|
||||
}
|
||||
k = k + fmt.Sprintf("/%s", escapeName(options.EndpointID))
|
||||
return k
|
||||
}
|
||||
|
||||
func (options HostEndpointListOptions) KeyFromDefaultPath(path string) Key {
|
||||
log.Debugf("Get HostEndpoint key from %s", path)
|
||||
r := matchHostEndpoint.FindAllStringSubmatch(path, -1)
|
||||
if len(r) != 1 {
|
||||
log.Debugf("Didn't match regex")
|
||||
return nil
|
||||
}
|
||||
hostname := r[0][1]
|
||||
endpointID := unescapeName(r[0][2])
|
||||
if options.Hostname != "" && hostname != options.Hostname {
|
||||
log.Debugf("Didn't match hostname %s != %s", options.Hostname, hostname)
|
||||
return nil
|
||||
}
|
||||
if options.EndpointID != "" && endpointID != options.EndpointID {
|
||||
log.Debugf("Didn't match endpointID %s != %s", options.EndpointID, endpointID)
|
||||
return nil
|
||||
}
|
||||
return HostEndpointKey{Hostname: hostname, EndpointID: endpointID}
|
||||
}
|
||||
|
||||
type HostEndpoint struct {
|
||||
Name string `json:"name,omitempty" validate:"omitempty,interface"`
|
||||
ExpectedIPv4Addrs []net.IP `json:"expected_ipv4_addrs,omitempty" validate:"omitempty,dive,ipv4"`
|
||||
ExpectedIPv6Addrs []net.IP `json:"expected_ipv6_addrs,omitempty" validate:"omitempty,dive,ipv6"`
|
||||
Labels map[string]string `json:"labels,omitempty" validate:"omitempty,labels"`
|
||||
ProfileIDs []string `json:"profile_ids,omitempty" validate:"omitempty,dive,name"`
|
||||
Ports []EndpointPort `json:"ports,omitempty" validate:"dive"`
|
||||
}
|
||||
107
vendor/github.com/projectcalico/calico/libcalico-go/lib/backend/model/hostendpointstatus.go
generated
vendored
Normal file
107
vendor/github.com/projectcalico/calico/libcalico-go/lib/backend/model/hostendpointstatus.go
generated
vendored
Normal file
@@ -0,0 +1,107 @@
|
||||
// Copyright (c) 2016 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 model
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"regexp"
|
||||
|
||||
"reflect"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/projectcalico/calico/libcalico-go/lib/errors"
|
||||
)
|
||||
|
||||
var (
|
||||
matchHostEndpointStatus = regexp.MustCompile("^/?calico/felix/v1/host/([^/]+)/endpoint/([^/]+)$")
|
||||
typeHostEndpointStatus = reflect.TypeOf(HostEndpointStatus{})
|
||||
)
|
||||
|
||||
type HostEndpointStatusKey struct {
|
||||
Hostname string `json:"-" validate:"required,hostname"`
|
||||
EndpointID string `json:"-" validate:"required,namespacedName"`
|
||||
}
|
||||
|
||||
func (key HostEndpointStatusKey) defaultPath() (string, error) {
|
||||
if key.Hostname == "" {
|
||||
return "", errors.ErrorInsufficientIdentifiers{Name: "node"}
|
||||
}
|
||||
if key.EndpointID == "" {
|
||||
return "", errors.ErrorInsufficientIdentifiers{Name: "name"}
|
||||
}
|
||||
e := fmt.Sprintf("/calico/felix/v1/host/%s/endpoint/%s",
|
||||
key.Hostname, escapeName(key.EndpointID))
|
||||
return e, nil
|
||||
}
|
||||
|
||||
func (key HostEndpointStatusKey) defaultDeletePath() (string, error) {
|
||||
return key.defaultPath()
|
||||
}
|
||||
|
||||
func (key HostEndpointStatusKey) defaultDeleteParentPaths() ([]string, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (key HostEndpointStatusKey) valueType() (reflect.Type, error) {
|
||||
return typeHostEndpointStatus, nil
|
||||
}
|
||||
|
||||
func (key HostEndpointStatusKey) String() string {
|
||||
return fmt.Sprintf("HostEndpointStatus(hostname=%s, name=%s)", key.Hostname, key.EndpointID)
|
||||
}
|
||||
|
||||
type HostEndpointStatusListOptions struct {
|
||||
Hostname string
|
||||
EndpointID string
|
||||
}
|
||||
|
||||
func (options HostEndpointStatusListOptions) defaultPathRoot() string {
|
||||
k := "/calico/felix/v1/host"
|
||||
if options.Hostname == "" {
|
||||
return k
|
||||
}
|
||||
k = k + fmt.Sprintf("/%s/endpoint", options.Hostname)
|
||||
if options.EndpointID == "" {
|
||||
return k
|
||||
}
|
||||
k = k + fmt.Sprintf("/%s", escapeName(options.EndpointID))
|
||||
return k
|
||||
}
|
||||
|
||||
func (options HostEndpointStatusListOptions) KeyFromDefaultPath(ekey string) Key {
|
||||
log.Debugf("Get HostEndpointStatus key from %s", ekey)
|
||||
r := matchHostEndpointStatus.FindAllStringSubmatch(ekey, -1)
|
||||
if len(r) != 1 {
|
||||
log.Debugf("Didn't match regex")
|
||||
return nil
|
||||
}
|
||||
hostname := r[0][1]
|
||||
endpointID := unescapeName(r[0][2])
|
||||
if options.Hostname != "" && hostname != options.Hostname {
|
||||
log.Debugf("Didn't match hostname %s != %s", options.Hostname, hostname)
|
||||
return nil
|
||||
}
|
||||
if options.EndpointID != "" && endpointID != options.EndpointID {
|
||||
log.Debugf("Didn't match endpointID %s != %s", options.EndpointID, endpointID)
|
||||
return nil
|
||||
}
|
||||
return HostEndpointStatusKey{Hostname: hostname, EndpointID: endpointID}
|
||||
}
|
||||
|
||||
type HostEndpointStatus struct {
|
||||
Status string `json:"status"`
|
||||
}
|
||||
53
vendor/github.com/projectcalico/calico/libcalico-go/lib/backend/model/ipam_config.go
generated
vendored
Normal file
53
vendor/github.com/projectcalico/calico/libcalico-go/lib/backend/model/ipam_config.go
generated
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
// Copyright (c) 2016 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 model
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
)
|
||||
|
||||
const (
|
||||
IPAMConfigGlobalName = "default"
|
||||
)
|
||||
|
||||
var typeIPAMConfig = reflect.TypeOf(IPAMConfig{})
|
||||
|
||||
type IPAMConfigKey struct{}
|
||||
|
||||
func (key IPAMConfigKey) defaultPath() (string, error) {
|
||||
return "/calico/ipam/v2/config", nil
|
||||
}
|
||||
|
||||
func (key IPAMConfigKey) defaultDeletePath() (string, error) {
|
||||
return key.defaultPath()
|
||||
}
|
||||
|
||||
func (key IPAMConfigKey) defaultDeleteParentPaths() ([]string, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (key IPAMConfigKey) valueType() (reflect.Type, error) {
|
||||
return typeIPAMConfig, nil
|
||||
}
|
||||
|
||||
func (key IPAMConfigKey) String() string {
|
||||
return "IPAMConfigKey()"
|
||||
}
|
||||
|
||||
type IPAMConfig struct {
|
||||
StrictAffinity bool `json:"strict_affinity,omitempty"`
|
||||
AutoAllocateBlocks bool `json:"auto_allocate_blocks,omitempty"`
|
||||
MaxBlocksPerHost int `json:"maxBlocksPerHost,omitempty"`
|
||||
}
|
||||
84
vendor/github.com/projectcalico/calico/libcalico-go/lib/backend/model/ipam_handle.go
generated
vendored
Normal file
84
vendor/github.com/projectcalico/calico/libcalico-go/lib/backend/model/ipam_handle.go
generated
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
// Copyright (c) 2016,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 model
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"regexp"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/projectcalico/calico/libcalico-go/lib/errors"
|
||||
)
|
||||
|
||||
var (
|
||||
matchHandle = regexp.MustCompile("^/?calico/ipam/v2/handle/([^/]+)$")
|
||||
typeHandle = reflect.TypeOf(IPAMHandle{})
|
||||
)
|
||||
|
||||
type IPAMHandleKey struct {
|
||||
HandleID string `json:"id"`
|
||||
}
|
||||
|
||||
func (key IPAMHandleKey) defaultPath() (string, error) {
|
||||
if key.HandleID == "" {
|
||||
return "", errors.ErrorInsufficientIdentifiers{}
|
||||
}
|
||||
e := fmt.Sprintf("/calico/ipam/v2/handle/%s", key.HandleID)
|
||||
return e, nil
|
||||
}
|
||||
|
||||
func (key IPAMHandleKey) defaultDeletePath() (string, error) {
|
||||
return key.defaultPath()
|
||||
}
|
||||
|
||||
func (key IPAMHandleKey) defaultDeleteParentPaths() ([]string, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (key IPAMHandleKey) valueType() (reflect.Type, error) {
|
||||
return typeHandle, nil
|
||||
}
|
||||
|
||||
func (key IPAMHandleKey) String() string {
|
||||
return fmt.Sprintf("IPAMHandleKey(id=%s)", key.HandleID)
|
||||
}
|
||||
|
||||
type IPAMHandleListOptions struct {
|
||||
// TODO: Have some options here?
|
||||
}
|
||||
|
||||
func (options IPAMHandleListOptions) defaultPathRoot() string {
|
||||
k := "/calico/ipam/v2/handle/"
|
||||
// TODO: Allow filtering on individual host?
|
||||
return k
|
||||
}
|
||||
|
||||
func (options IPAMHandleListOptions) KeyFromDefaultPath(path string) Key {
|
||||
log.Debugf("Get IPAM handle key from %s", path)
|
||||
r := matchHandle.FindAllStringSubmatch(path, -1)
|
||||
if len(r) != 1 {
|
||||
log.Debugf("%s didn't match regex", path)
|
||||
return nil
|
||||
}
|
||||
return IPAMHandleKey{HandleID: r[0][1]}
|
||||
}
|
||||
|
||||
type IPAMHandle struct {
|
||||
HandleID string `json:"-"`
|
||||
Block map[string]int `json:"block"`
|
||||
Deleted bool `json:"deleted"`
|
||||
}
|
||||
58
vendor/github.com/projectcalico/calico/libcalico-go/lib/backend/model/ipam_host.go
generated
vendored
Normal file
58
vendor/github.com/projectcalico/calico/libcalico-go/lib/backend/model/ipam_host.go
generated
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
// Copyright (c) 2016 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 model
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/projectcalico/calico/libcalico-go/lib/errors"
|
||||
)
|
||||
|
||||
var (
|
||||
typeIPAMHost = reflect.TypeOf(IPAMHost{})
|
||||
)
|
||||
|
||||
type IPAMHostKey struct {
|
||||
Host string
|
||||
}
|
||||
|
||||
func (key IPAMHostKey) defaultPath() (string, error) {
|
||||
if key.Host == "" {
|
||||
return "", errors.ErrorInsufficientIdentifiers{Name: "host"}
|
||||
}
|
||||
|
||||
k := "/calico/ipam/v2/host/" + key.Host
|
||||
return k, nil
|
||||
}
|
||||
|
||||
func (key IPAMHostKey) defaultDeletePath() (string, error) {
|
||||
return key.defaultPath()
|
||||
}
|
||||
|
||||
func (key IPAMHostKey) defaultDeleteParentPaths() ([]string, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (key IPAMHostKey) valueType() (reflect.Type, error) {
|
||||
return typeIPAMHost, nil
|
||||
}
|
||||
|
||||
func (key IPAMHostKey) String() string {
|
||||
return fmt.Sprintf("IPAMHostKey(host=%s)", key.Host)
|
||||
}
|
||||
|
||||
type IPAMHost struct {
|
||||
}
|
||||
107
vendor/github.com/projectcalico/calico/libcalico-go/lib/backend/model/ippool.go
generated
vendored
Normal file
107
vendor/github.com/projectcalico/calico/libcalico-go/lib/backend/model/ippool.go
generated
vendored
Normal file
@@ -0,0 +1,107 @@
|
||||
// Copyright (c) 2016,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 model
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/projectcalico/calico/libcalico-go/lib/backend/encap"
|
||||
"github.com/projectcalico/calico/libcalico-go/lib/errors"
|
||||
"github.com/projectcalico/calico/libcalico-go/lib/net"
|
||||
)
|
||||
|
||||
var (
|
||||
matchIPPool = regexp.MustCompile("^/?calico/v1/ipam/v./pool/([^/]+)$")
|
||||
typeIPPool = reflect.TypeOf(IPPool{})
|
||||
)
|
||||
|
||||
type IPPoolKey struct {
|
||||
CIDR net.IPNet `json:"-" validate:"required,name"`
|
||||
}
|
||||
|
||||
func (key IPPoolKey) defaultPath() (string, error) {
|
||||
if key.CIDR.IP == nil {
|
||||
return "", errors.ErrorInsufficientIdentifiers{Name: "cidr"}
|
||||
}
|
||||
c := strings.Replace(key.CIDR.String(), "/", "-", 1)
|
||||
e := fmt.Sprintf("/calico/v1/ipam/v%d/pool/%s", key.CIDR.Version(), c)
|
||||
return e, nil
|
||||
}
|
||||
|
||||
func (key IPPoolKey) defaultDeletePath() (string, error) {
|
||||
return key.defaultPath()
|
||||
}
|
||||
|
||||
func (key IPPoolKey) defaultDeleteParentPaths() ([]string, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (key IPPoolKey) valueType() (reflect.Type, error) {
|
||||
return typeIPPool, nil
|
||||
}
|
||||
|
||||
func (key IPPoolKey) String() string {
|
||||
return fmt.Sprintf("IPPool(cidr=%s)", key.CIDR)
|
||||
}
|
||||
|
||||
type IPPoolListOptions struct {
|
||||
CIDR net.IPNet
|
||||
}
|
||||
|
||||
func (options IPPoolListOptions) defaultPathRoot() string {
|
||||
k := "/calico/v1/ipam/"
|
||||
if options.CIDR.IP == nil {
|
||||
return k
|
||||
}
|
||||
c := strings.Replace(options.CIDR.String(), "/", "-", 1)
|
||||
k = k + fmt.Sprintf("v%d/pool/", options.CIDR.Version()) + fmt.Sprintf("%s", c)
|
||||
return k
|
||||
}
|
||||
|
||||
func (options IPPoolListOptions) KeyFromDefaultPath(path string) Key {
|
||||
log.Debugf("Get Pool key from %s", path)
|
||||
r := matchIPPool.FindAllStringSubmatch(path, -1)
|
||||
if len(r) != 1 {
|
||||
log.Debugf("%s didn't match regex", path)
|
||||
return nil
|
||||
}
|
||||
cidrStr := strings.Replace(r[0][1], "-", "/", 1)
|
||||
_, cidr, err := net.ParseCIDR(cidrStr)
|
||||
if err != nil {
|
||||
log.WithError(err).Warningf("Failed to parse CIDR %s", cidrStr)
|
||||
return nil
|
||||
}
|
||||
if options.CIDR.IP != nil && !reflect.DeepEqual(*cidr, options.CIDR) {
|
||||
log.Debugf("Didn't match cidr %s != %s", options.CIDR.String(), cidr.String())
|
||||
return nil
|
||||
}
|
||||
return IPPoolKey{CIDR: *cidr}
|
||||
}
|
||||
|
||||
type IPPool struct {
|
||||
CIDR net.IPNet `json:"cidr"`
|
||||
IPIPInterface string `json:"ipip"`
|
||||
IPIPMode encap.Mode `json:"ipip_mode"`
|
||||
VXLANMode encap.Mode `json:"vxlan_mode"`
|
||||
Masquerade bool `json:"masquerade"`
|
||||
IPAM bool `json:"ipam"`
|
||||
Disabled bool `json:"disabled"`
|
||||
DisableBGPExport bool `json:"disableBGPExport"`
|
||||
}
|
||||
627
vendor/github.com/projectcalico/calico/libcalico-go/lib/backend/model/keys.go
generated
vendored
Normal file
627
vendor/github.com/projectcalico/calico/libcalico-go/lib/backend/model/keys.go
generated
vendored
Normal file
@@ -0,0 +1,627 @@
|
||||
// Copyright (c) 2016-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 model
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
net2 "net"
|
||||
"reflect"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
|
||||
"github.com/projectcalico/calico/libcalico-go/lib/json"
|
||||
"github.com/projectcalico/calico/libcalico-go/lib/namespace"
|
||||
"github.com/projectcalico/calico/libcalico-go/lib/net"
|
||||
)
|
||||
|
||||
// RawString is used a value type to indicate that the value is a bare non-JSON string
|
||||
type rawString string
|
||||
type rawBool bool
|
||||
type rawIP net.IP
|
||||
|
||||
var rawStringType = reflect.TypeOf(rawString(""))
|
||||
var rawBoolType = reflect.TypeOf(rawBool(true))
|
||||
var rawIPType = reflect.TypeOf(rawIP{})
|
||||
|
||||
// Key represents a parsed datastore key.
|
||||
type Key interface {
|
||||
// defaultPath() returns a common path representation of the object used by
|
||||
// etcdv3 and other datastores.
|
||||
defaultPath() (string, error)
|
||||
|
||||
// defaultDeletePath() returns a common path representation used by etcdv3
|
||||
// and other datastores to delete the object.
|
||||
defaultDeletePath() (string, error)
|
||||
|
||||
// defaultDeleteParentPaths() returns an ordered slice of paths that should
|
||||
// be removed after deleting the primary path (given by defaultDeletePath),
|
||||
// provided there are no child entries associated with those paths. This is
|
||||
// only used by directory based KV stores (such as etcdv3). With a directory
|
||||
// based KV store, creation of a resource may also create parent directory entries
|
||||
// that could be shared by multiple resources, and therefore the parent directories
|
||||
// can only be removed when there are no more resources under them. The list of
|
||||
// parent paths is ordered, and directories should be removed in the order supplied
|
||||
// in the slice and only if the directory is empty.
|
||||
defaultDeleteParentPaths() ([]string, error)
|
||||
|
||||
// valueType returns the object type associated with this key.
|
||||
valueType() (reflect.Type, error)
|
||||
|
||||
// String returns a unique string representation of this key. The string
|
||||
// returned by this method must uniquely identify this Key.
|
||||
String() string
|
||||
}
|
||||
|
||||
// Interface used to perform datastore lookups.
|
||||
type ListInterface interface {
|
||||
// defaultPathRoot() returns a default stringified root path, i.e. path
|
||||
// to the directory containing all the keys to be listed.
|
||||
defaultPathRoot() string
|
||||
|
||||
// BUG(smc) I think we should remove this and use the package KeyFromDefaultPath function.
|
||||
// KeyFromDefaultPath parses the default path representation of the
|
||||
// Key type for this list. It returns nil if passed a different kind
|
||||
// of path.
|
||||
KeyFromDefaultPath(key string) Key
|
||||
}
|
||||
|
||||
// KVPair holds a typed key and value object as well as datastore specific
|
||||
// revision information.
|
||||
//
|
||||
// The Value is dependent on the Key, but in general will be on of the following
|
||||
// types:
|
||||
// - A pointer to a struct
|
||||
// - A slice or map
|
||||
// - A bare string, boolean value or IP address (i.e. without quotes, so not
|
||||
// JSON format).
|
||||
type KVPair struct {
|
||||
Key Key
|
||||
Value interface{}
|
||||
Revision string
|
||||
UID *types.UID
|
||||
TTL time.Duration // For writes, if non-zero, key has a TTL.
|
||||
}
|
||||
|
||||
// KVPairList hosts a slice of KVPair structs and a Revision, returned from a Ls
|
||||
type KVPairList struct {
|
||||
KVPairs []*KVPair
|
||||
Revision string
|
||||
}
|
||||
|
||||
// KeyToDefaultPath converts one of the Keys from this package into a unique
|
||||
// '/'-delimited path, which is suitable for use as the key when storing the
|
||||
// value in a hierarchical (i.e. one with directories and leaves) key/value
|
||||
// datastore such as etcd v3.
|
||||
//
|
||||
// Each unique key returns a unique path.
|
||||
//
|
||||
// Keys with a hierarchical relationship share a common prefix. However, in
|
||||
// order to support datastores that do not support storing data at non-leaf
|
||||
// nodes in the hierarchy (such as etcd v3), the path returned for a "parent"
|
||||
// key, is not a direct ancestor of its children.
|
||||
func KeyToDefaultPath(key Key) (string, error) {
|
||||
return key.defaultPath()
|
||||
}
|
||||
|
||||
// KeyToDefaultDeletePath converts one of the Keys from this package into a
|
||||
// unique '/'-delimited path, which is suitable for use as the key when
|
||||
// (recursively) deleting the value from a hierarchical (i.e. one with
|
||||
// directories and leaves) key/value datastore such as etcd v3.
|
||||
//
|
||||
// KeyToDefaultDeletePath returns a different path to KeyToDefaultPath when
|
||||
// it is a passed a Key that represents a non-leaf which, for example, has its
|
||||
// own metadata but also contains other resource types as children.
|
||||
//
|
||||
// KeyToDefaultDeletePath returns the common prefix of the non-leaf key and
|
||||
// its children so that a recursive delete of that key would delete the
|
||||
// object itself and any children it has.
|
||||
func KeyToDefaultDeletePath(key Key) (string, error) {
|
||||
return key.defaultDeletePath()
|
||||
}
|
||||
|
||||
// KeyToDefaultDeleteParentPaths returns a slice of '/'-delimited
|
||||
// paths which are used to delete parent entries that may be auto-created
|
||||
// by directory-based KV stores (e.g. etcd v3). These paths should also be
|
||||
// removed provided they have no more child entries.
|
||||
//
|
||||
// The list of parent paths is ordered, and directories should be removed
|
||||
// in the order supplied in the slice and only if the directory is empty.
|
||||
//
|
||||
// For example,
|
||||
//
|
||||
// KeyToDefaultDeletePaths(WorkloadEndpointKey{
|
||||
// Nodename: "h",
|
||||
// OrchestratorID: "o",
|
||||
// WorkloadID: "w",
|
||||
// EndpointID: "e",
|
||||
// })
|
||||
//
|
||||
// returns
|
||||
//
|
||||
// ["/calico/v1/host/h/workload/o/w/endpoint",
|
||||
//
|
||||
// "/calico/v1/host/h/workload/o/w"]
|
||||
//
|
||||
// indicating that these paths should also be deleted when they are empty.
|
||||
// In this example it is equivalent to deleting the workload when there are
|
||||
// no more endpoints in the workload.
|
||||
func KeyToDefaultDeleteParentPaths(key Key) ([]string, error) {
|
||||
return key.defaultDeleteParentPaths()
|
||||
}
|
||||
|
||||
// ListOptionsToDefaultPathRoot converts list options struct into a
|
||||
// common-prefix path suitable for querying a datastore that uses the paths
|
||||
// returned by KeyToDefaultPath.
|
||||
func ListOptionsToDefaultPathRoot(listOptions ListInterface) string {
|
||||
return listOptions.defaultPathRoot()
|
||||
}
|
||||
|
||||
// ListOptionsIsFullyQualified returns true if the options actually specify a fully
|
||||
// qualified resource rather than a partial match.
|
||||
func ListOptionsIsFullyQualified(listOptions ListInterface) bool {
|
||||
// Construct the path prefix and then check to see if that actually corresponds to
|
||||
// the path of a resource instance.
|
||||
return listOptions.KeyFromDefaultPath(listOptions.defaultPathRoot()) != nil
|
||||
}
|
||||
|
||||
// IsListOptionsLastSegmentPrefix returns true if the final segment of the default path
|
||||
// root is a name prefix rather than the full name.
|
||||
func IsListOptionsLastSegmentPrefix(listOptions ListInterface) bool {
|
||||
// Only supported for ResourceListOptions.
|
||||
rl, ok := listOptions.(ResourceListOptions)
|
||||
return ok && rl.IsLastSegmentIsPrefix()
|
||||
}
|
||||
|
||||
// KeyFromDefaultPath parses the default path representation of a key into one
|
||||
// of our <Type>Key structs. Returns nil if the string doesn't match one of
|
||||
// our key types.
|
||||
func KeyFromDefaultPath(path string) Key {
|
||||
// "v3" resource keys strictly require a leading slash but older "v1" keys were permissive.
|
||||
// For ease of parsing, strip the slash off now but pass it down to keyFromDefaultPathInner so
|
||||
// it can check for it later.
|
||||
normalizedPath := path
|
||||
if strings.HasPrefix(normalizedPath, "/") {
|
||||
normalizedPath = normalizedPath[1:]
|
||||
}
|
||||
|
||||
parts := strings.Split(normalizedPath, "/")
|
||||
if len(parts) < 3 {
|
||||
// After removing the optional `/` prefix, should have at least 3 segments.
|
||||
return nil
|
||||
}
|
||||
|
||||
return keyFromDefaultPathInner(path, parts)
|
||||
}
|
||||
|
||||
func keyFromDefaultPathInner(path string, parts []string) Key {
|
||||
if parts[0] != "calico" {
|
||||
return nil
|
||||
}
|
||||
|
||||
switch parts[1] {
|
||||
case "v1":
|
||||
switch parts[2] {
|
||||
case "ipam":
|
||||
return IPPoolListOptions{}.KeyFromDefaultPath(path)
|
||||
case "config":
|
||||
return GlobalConfigKey{Name: strings.Join(parts[3:], "/")}
|
||||
case "host":
|
||||
if len(parts) < 5 {
|
||||
return nil
|
||||
}
|
||||
hostname := parts[3]
|
||||
switch parts[4] {
|
||||
case "workload":
|
||||
if len(parts) != 9 || parts[7] != "endpoint" {
|
||||
return nil
|
||||
}
|
||||
return WorkloadEndpointKey{
|
||||
Hostname: unescapeName(hostname),
|
||||
OrchestratorID: unescapeName(parts[5]),
|
||||
WorkloadID: unescapeName(parts[6]),
|
||||
EndpointID: unescapeName(parts[8]),
|
||||
}
|
||||
case "endpoint":
|
||||
if len(parts) != 6 {
|
||||
return nil
|
||||
}
|
||||
return HostEndpointKey{
|
||||
Hostname: unescapeName(hostname),
|
||||
EndpointID: unescapeName(parts[5]),
|
||||
}
|
||||
case "config":
|
||||
return HostConfigKey{
|
||||
Hostname: hostname,
|
||||
Name: strings.Join(parts[5:], "/"),
|
||||
}
|
||||
case "metadata":
|
||||
if len(parts) != 5 {
|
||||
return nil
|
||||
}
|
||||
return HostMetadataKey{
|
||||
Hostname: hostname,
|
||||
}
|
||||
case "bird_ip":
|
||||
if len(parts) != 5 {
|
||||
return nil
|
||||
}
|
||||
return HostIPKey{
|
||||
Hostname: hostname,
|
||||
}
|
||||
case "wireguard":
|
||||
if len(parts) != 5 {
|
||||
return nil
|
||||
}
|
||||
return WireguardKey{
|
||||
NodeName: hostname,
|
||||
}
|
||||
}
|
||||
case "netset":
|
||||
if len(parts) != 4 {
|
||||
return nil
|
||||
}
|
||||
return NetworkSetKey{
|
||||
Name: unescapeName(parts[3]),
|
||||
}
|
||||
case "Ready":
|
||||
if len(parts) > 3 || path[0] != '/' {
|
||||
return nil
|
||||
}
|
||||
return ReadyFlagKey{}
|
||||
case "policy":
|
||||
if len(parts) < 6 {
|
||||
return nil
|
||||
}
|
||||
switch parts[3] {
|
||||
case "tier":
|
||||
if len(parts) < 6 {
|
||||
return nil
|
||||
}
|
||||
switch parts[5] {
|
||||
case "policy":
|
||||
if len(parts) != 7 {
|
||||
return nil
|
||||
}
|
||||
return PolicyKey{
|
||||
Name: unescapeName(parts[6]),
|
||||
}
|
||||
}
|
||||
case "profile":
|
||||
pk := unescapeName(parts[4])
|
||||
switch parts[5] {
|
||||
case "rules":
|
||||
return ProfileRulesKey{ProfileKey: ProfileKey{pk}}
|
||||
case "labels":
|
||||
return ProfileLabelsKey{ProfileKey: ProfileKey{pk}}
|
||||
}
|
||||
}
|
||||
}
|
||||
case "bgp":
|
||||
switch parts[2] {
|
||||
case "v1":
|
||||
if len(parts) < 5 {
|
||||
return nil
|
||||
}
|
||||
switch parts[3] {
|
||||
case "global":
|
||||
return GlobalBGPConfigListOptions{}.KeyFromDefaultPath(path)
|
||||
case "host":
|
||||
if len(parts) < 6 {
|
||||
return nil
|
||||
}
|
||||
return NodeBGPConfigListOptions{}.KeyFromDefaultPath(path)
|
||||
}
|
||||
}
|
||||
case "ipam":
|
||||
if len(parts) < 5 {
|
||||
return nil
|
||||
}
|
||||
switch parts[2] {
|
||||
case "v2":
|
||||
switch parts[3] {
|
||||
case "assignment":
|
||||
return BlockListOptions{}.KeyFromDefaultPath(path)
|
||||
case "handle":
|
||||
if len(parts) > 5 {
|
||||
return nil
|
||||
}
|
||||
return IPAMHandleKey{
|
||||
HandleID: parts[4],
|
||||
}
|
||||
case "host":
|
||||
return BlockAffinityListOptions{}.KeyFromDefaultPath(path)
|
||||
}
|
||||
}
|
||||
case "resources":
|
||||
switch parts[2] {
|
||||
case "v3":
|
||||
// v3 resource keys strictly require the leading slash.
|
||||
if len(parts) < 6 || parts[3] != "projectcalico.org" || path[0] != '/' {
|
||||
return nil
|
||||
}
|
||||
switch len(parts) {
|
||||
case 6:
|
||||
ri, ok := resourceInfoByPlural[unescapeName(parts[4])]
|
||||
if !ok {
|
||||
log.Warnf("(BUG) unknown resource type: %v", path)
|
||||
return nil
|
||||
}
|
||||
if namespace.IsNamespaced(ri.kind) {
|
||||
log.Warnf("(BUG) Path is a global resource, but resource is namespaced: %v", path)
|
||||
return nil
|
||||
}
|
||||
log.Debugf("Path is a global resource: %v", path)
|
||||
return ResourceKey{
|
||||
Kind: ri.kind,
|
||||
Name: unescapeName(parts[5]),
|
||||
}
|
||||
case 7:
|
||||
ri, ok := resourceInfoByPlural[unescapeName(parts[4])]
|
||||
if !ok {
|
||||
log.Warnf("(BUG) unknown resource type: %v", path)
|
||||
return nil
|
||||
}
|
||||
if !namespace.IsNamespaced(ri.kind) {
|
||||
log.Warnf("(BUG) Path is a namespaced resource, but resource is global: %v", path)
|
||||
return nil
|
||||
}
|
||||
log.Debugf("Path is a namespaced resource: %v", path)
|
||||
return ResourceKey{
|
||||
Kind: ri.kind,
|
||||
Namespace: unescapeName(parts[5]),
|
||||
Name: unescapeName(parts[6]),
|
||||
}
|
||||
}
|
||||
}
|
||||
case "felix":
|
||||
if len(parts) < 4 {
|
||||
return nil
|
||||
}
|
||||
switch parts[2] {
|
||||
case "v1":
|
||||
switch parts[3] {
|
||||
case "host":
|
||||
if len(parts) != 7 || parts[5] != "endpoint" {
|
||||
return nil
|
||||
}
|
||||
return HostEndpointStatusKey{
|
||||
Hostname: parts[4],
|
||||
EndpointID: unescapeName(parts[6]),
|
||||
}
|
||||
}
|
||||
case "v2":
|
||||
if len(parts) < 7 {
|
||||
return nil
|
||||
}
|
||||
if parts[4] != "host" {
|
||||
return nil
|
||||
}
|
||||
switch parts[6] {
|
||||
case "status":
|
||||
return ActiveStatusReportListOptions{}.KeyFromDefaultPath(path)
|
||||
case "last_reported_status":
|
||||
return LastStatusReportListOptions{}.KeyFromDefaultPath(path)
|
||||
case "workload":
|
||||
return WorkloadEndpointStatusListOptions{}.KeyFromDefaultPath(path)
|
||||
}
|
||||
}
|
||||
}
|
||||
log.Debugf("Path is unknown: %v", path)
|
||||
return nil
|
||||
}
|
||||
|
||||
// OldKeyFromDefaultPath is the old, (slower) implementation of KeyFromDefaultPath. It is kept to allow
|
||||
// fuzzing the new version against it. Parses the default path representation of a key into one
|
||||
// of our <Type>Key structs. Returns nil if the string doesn't match one of
|
||||
// our key types.
|
||||
func OldKeyFromDefaultPath(path string) Key {
|
||||
if m := matchWorkloadEndpoint.FindStringSubmatch(path); m != nil {
|
||||
log.Debugf("Path is a workload endpoint: %v", path)
|
||||
return WorkloadEndpointKey{
|
||||
Hostname: unescapeName(m[1]),
|
||||
OrchestratorID: unescapeName(m[2]),
|
||||
WorkloadID: unescapeName(m[3]),
|
||||
EndpointID: unescapeName(m[4]),
|
||||
}
|
||||
} else if m := matchHostEndpoint.FindStringSubmatch(path); m != nil {
|
||||
log.Debugf("Path is a host endpoint: %v", path)
|
||||
return HostEndpointKey{
|
||||
Hostname: unescapeName(m[1]),
|
||||
EndpointID: unescapeName(m[2]),
|
||||
}
|
||||
} else if m := matchNetworkSet.FindStringSubmatch(path); m != nil {
|
||||
log.Debugf("Path is a network set: %v", path)
|
||||
return NetworkSetKey{
|
||||
Name: unescapeName(m[1]),
|
||||
}
|
||||
} else if m := matchGlobalResource.FindStringSubmatch(path); m != nil {
|
||||
ri, ok := resourceInfoByPlural[unescapeName(m[1])]
|
||||
if !ok {
|
||||
log.Warnf("(BUG) unknown resource type: %v", path)
|
||||
return nil
|
||||
}
|
||||
if namespace.IsNamespaced(ri.kind) {
|
||||
log.Warnf("(BUG) Path is a global resource, but resource is namespaced: %v", path)
|
||||
return nil
|
||||
}
|
||||
log.Debugf("Path is a global resource: %v", path)
|
||||
return ResourceKey{
|
||||
Kind: ri.kind,
|
||||
Name: unescapeName(m[2]),
|
||||
}
|
||||
} else if m := matchNamespacedResource.FindStringSubmatch(path); m != nil {
|
||||
ri, ok := resourceInfoByPlural[unescapeName(m[1])]
|
||||
if !ok {
|
||||
log.Warnf("(BUG) unknown resource type: %v", path)
|
||||
return nil
|
||||
}
|
||||
if !namespace.IsNamespaced(ri.kind) {
|
||||
log.Warnf("(BUG) Path is a namespaced resource, but resource is global: %v", path)
|
||||
return nil
|
||||
}
|
||||
log.Debugf("Path is a namespaced resource: %v", path)
|
||||
return ResourceKey{
|
||||
Kind: resourceInfoByPlural[unescapeName(m[1])].kind,
|
||||
Namespace: unescapeName(m[2]),
|
||||
Name: unescapeName(m[3]),
|
||||
}
|
||||
} else if m := matchPolicy.FindStringSubmatch(path); m != nil {
|
||||
log.Debugf("Path is a policy: %v", path)
|
||||
return PolicyKey{
|
||||
Name: unescapeName(m[2]),
|
||||
}
|
||||
} else if m := matchProfile.FindStringSubmatch(path); m != nil {
|
||||
log.Debugf("Path is a profile: %v (%v)", path, m[2])
|
||||
pk := ProfileKey{unescapeName(m[1])}
|
||||
switch m[2] {
|
||||
case "rules":
|
||||
log.Debugf("Profile rules")
|
||||
return ProfileRulesKey{ProfileKey: pk}
|
||||
case "labels":
|
||||
log.Debugf("Profile labels")
|
||||
return ProfileLabelsKey{ProfileKey: pk}
|
||||
}
|
||||
return nil
|
||||
} else if m := matchHostIp.FindStringSubmatch(path); m != nil {
|
||||
log.Debugf("Path is a host ID: %v", path)
|
||||
return HostIPKey{Hostname: m[1]}
|
||||
} else if m := matchWireguard.FindStringSubmatch(path); m != nil {
|
||||
log.Debugf("Path is a node name: %v", path)
|
||||
return WireguardKey{NodeName: m[1]}
|
||||
} else if m := matchIPPool.FindStringSubmatch(path); m != nil {
|
||||
log.Debugf("Path is a pool: %v", path)
|
||||
mungedCIDR := m[1]
|
||||
cidr := strings.Replace(mungedCIDR, "-", "/", 1)
|
||||
_, c, err := net.ParseCIDR(cidr)
|
||||
if err != nil {
|
||||
log.WithError(err).Warningf("Failed to parse CIDR %s", cidr)
|
||||
} else {
|
||||
return IPPoolKey{CIDR: *c}
|
||||
}
|
||||
} else if m := matchGlobalConfig.FindStringSubmatch(path); m != nil {
|
||||
log.Debugf("Path is a global felix config: %v", path)
|
||||
return GlobalConfigKey{Name: m[1]}
|
||||
} else if m := matchHostConfig.FindStringSubmatch(path); m != nil {
|
||||
log.Debugf("Path is a host config: %v", path)
|
||||
return HostConfigKey{Hostname: m[1], Name: m[2]}
|
||||
} else if matchReadyFlag.MatchString(path) {
|
||||
log.Debugf("Path is a ready flag: %v", path)
|
||||
return ReadyFlagKey{}
|
||||
} else if k := (NodeBGPConfigListOptions{}).KeyFromDefaultPath(path); k != nil {
|
||||
return k
|
||||
} else if k := (GlobalBGPConfigListOptions{}).KeyFromDefaultPath(path); k != nil {
|
||||
return k
|
||||
} else if k := (BlockAffinityListOptions{}).KeyFromDefaultPath(path); k != nil {
|
||||
return k
|
||||
} else if k := (BlockListOptions{}).KeyFromDefaultPath(path); k != nil {
|
||||
return k
|
||||
} else if k := (HostEndpointStatusListOptions{}).KeyFromDefaultPath(path); k != nil {
|
||||
return k
|
||||
} else if k := (WorkloadEndpointStatusListOptions{}).KeyFromDefaultPath(path); k != nil {
|
||||
return k
|
||||
} else if k := (ActiveStatusReportListOptions{}).KeyFromDefaultPath(path); k != nil {
|
||||
return k
|
||||
} else if k := (LastStatusReportListOptions{}).KeyFromDefaultPath(path); k != nil {
|
||||
return k
|
||||
} else {
|
||||
log.Debugf("Path is unknown: %v", path)
|
||||
}
|
||||
// Not a key we know about.
|
||||
return nil
|
||||
}
|
||||
|
||||
// ParseValue parses the default JSON representation of our data into one of
|
||||
// our value structs, according to the type of key. I.e. if passed a
|
||||
// PolicyKey as the first parameter, it will try to parse rawData into a
|
||||
// Policy struct.
|
||||
func ParseValue(key Key, rawData []byte) (interface{}, error) {
|
||||
valueType, err := key.valueType()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if valueType == rawStringType {
|
||||
return string(rawData), nil
|
||||
}
|
||||
if valueType == rawBoolType {
|
||||
return string(rawData) == "true", nil
|
||||
}
|
||||
if valueType == rawIPType {
|
||||
ip := net2.ParseIP(string(rawData))
|
||||
if ip == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return &net.IP{IP: ip}, nil
|
||||
}
|
||||
value := reflect.New(valueType)
|
||||
elem := value.Elem()
|
||||
if elem.Kind() == reflect.Struct && elem.NumField() > 0 {
|
||||
if elem.Field(0).Type() == reflect.ValueOf(key).Type() {
|
||||
elem.Field(0).Set(reflect.ValueOf(key))
|
||||
}
|
||||
}
|
||||
iface := value.Interface()
|
||||
err = json.Unmarshal(rawData, iface)
|
||||
if err != nil {
|
||||
// This is a special case to address backwards compatibility from the time when we had no state information as block affinity value.
|
||||
// example:
|
||||
// Key: "/calico/ipam/v2/host/myhost.io/ipv4/block/172.29.82.0-26"
|
||||
// Value: ""
|
||||
// In 3.0.7 we added block affinity state as the value, so old "" value is no longer a valid JSON, so for that
|
||||
// particular case we replace the "" with a "{}" so it can be parsed and we don't leak blocks after upgrade to Calico 3.0.7
|
||||
// See: https://github.com/projectcalico/calico/issues/1956
|
||||
if bytes.Equal(rawData, []byte(``)) && valueType == typeBlockAff {
|
||||
rawData = []byte(`{}`)
|
||||
if err = json.Unmarshal(rawData, iface); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
log.Warningf("Failed to unmarshal %#v into value %#v",
|
||||
string(rawData), value)
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if elem.Kind() != reflect.Struct {
|
||||
// Pointer to a map or slice, unwrap.
|
||||
iface = elem.Interface()
|
||||
}
|
||||
return iface, nil
|
||||
}
|
||||
|
||||
// SerializeValue serializes a value in the model to a []byte to be stored in the datastore. This
|
||||
// performs the opposite processing to ParseValue()
|
||||
func SerializeValue(d *KVPair) ([]byte, error) {
|
||||
valueType, err := d.Key.valueType()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if d.Value == nil {
|
||||
return json.Marshal(nil)
|
||||
}
|
||||
if valueType == rawStringType {
|
||||
return []byte(d.Value.(string)), nil
|
||||
}
|
||||
if valueType == rawBoolType {
|
||||
return []byte(fmt.Sprint(d.Value)), nil
|
||||
}
|
||||
if valueType == rawIPType {
|
||||
return []byte(fmt.Sprint(d.Value)), nil
|
||||
}
|
||||
return json.Marshal(d.Value)
|
||||
}
|
||||
19
vendor/github.com/projectcalico/calico/libcalico-go/lib/backend/model/kubeendpointslice.go
generated
vendored
Normal file
19
vendor/github.com/projectcalico/calico/libcalico-go/lib/backend/model/kubeendpointslice.go
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
// Copyright (c) 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 model
|
||||
|
||||
const (
|
||||
KindKubernetesEndpointSlice = "KubernetesEndpointSlice"
|
||||
)
|
||||
19
vendor/github.com/projectcalico/calico/libcalico-go/lib/backend/model/kubenetworkpolicy.go
generated
vendored
Normal file
19
vendor/github.com/projectcalico/calico/libcalico-go/lib/backend/model/kubenetworkpolicy.go
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
// Copyright (c) 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 model
|
||||
|
||||
const (
|
||||
KindKubernetesNetworkPolicy = "KubernetesNetworkPolicy"
|
||||
)
|
||||
19
vendor/github.com/projectcalico/calico/libcalico-go/lib/backend/model/kubeservice.go
generated
vendored
Normal file
19
vendor/github.com/projectcalico/calico/libcalico-go/lib/backend/model/kubeservice.go
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
// Copyright (c) 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 model
|
||||
|
||||
const (
|
||||
KindKubernetesService = "KubernetesService"
|
||||
)
|
||||
30
vendor/github.com/projectcalico/calico/libcalico-go/lib/backend/model/name.go
generated
vendored
Normal file
30
vendor/github.com/projectcalico/calico/libcalico-go/lib/backend/model/name.go
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
// Copyright (c) 2016 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 model
|
||||
|
||||
import "strings"
|
||||
|
||||
// escapeName removes any "/" from the name and URL encodes it to %2f,
|
||||
// and necessarily removes % and encodes to %25.
|
||||
func escapeName(name string) string {
|
||||
name = strings.Replace(name, "%", "%25", -1)
|
||||
return strings.Replace(name, "/", "%2f", -1)
|
||||
}
|
||||
|
||||
// unescapeName replaces %2f and %25 in the name back to be a / and %.
|
||||
func unescapeName(name string) string {
|
||||
name = strings.Replace(name, "%2f", "/", -1)
|
||||
return strings.Replace(name, "%25", "%", -1)
|
||||
}
|
||||
95
vendor/github.com/projectcalico/calico/libcalico-go/lib/backend/model/networkset.go
generated
vendored
Normal file
95
vendor/github.com/projectcalico/calico/libcalico-go/lib/backend/model/networkset.go
generated
vendored
Normal file
@@ -0,0 +1,95 @@
|
||||
// Copyright (c) 2017-2018 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 model
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"regexp"
|
||||
|
||||
"reflect"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/projectcalico/calico/libcalico-go/lib/errors"
|
||||
"github.com/projectcalico/calico/libcalico-go/lib/net"
|
||||
)
|
||||
|
||||
var (
|
||||
matchNetworkSet = regexp.MustCompile("^/?calico/v1/netset/([^/]+)$")
|
||||
typeNetworkSet = reflect.TypeOf(NetworkSet{})
|
||||
)
|
||||
|
||||
type NetworkSetKey struct {
|
||||
Name string `json:"-" validate:"required,namespacedName"`
|
||||
}
|
||||
|
||||
func (key NetworkSetKey) defaultPath() (string, error) {
|
||||
if key.Name == "" {
|
||||
return "", errors.ErrorInsufficientIdentifiers{Name: "name"}
|
||||
}
|
||||
e := fmt.Sprintf("/calico/v1/netset/%s", escapeName(key.Name))
|
||||
return e, nil
|
||||
}
|
||||
|
||||
func (key NetworkSetKey) defaultDeletePath() (string, error) {
|
||||
return key.defaultPath()
|
||||
}
|
||||
|
||||
func (key NetworkSetKey) defaultDeleteParentPaths() ([]string, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (key NetworkSetKey) valueType() (reflect.Type, error) {
|
||||
return typeNetworkSet, nil
|
||||
}
|
||||
|
||||
func (key NetworkSetKey) String() string {
|
||||
return fmt.Sprintf("NetworkSet(name=%s)", key.Name)
|
||||
}
|
||||
|
||||
type NetworkSetListOptions struct {
|
||||
Name string
|
||||
}
|
||||
|
||||
func (options NetworkSetListOptions) defaultPathRoot() string {
|
||||
k := "/calico/v1/netset"
|
||||
if options.Name == "" {
|
||||
return k
|
||||
}
|
||||
k = k + fmt.Sprintf("/%s", escapeName(options.Name))
|
||||
return k
|
||||
}
|
||||
|
||||
func (options NetworkSetListOptions) KeyFromDefaultPath(path string) Key {
|
||||
log.Debugf("Get NetworkSet key from %s", path)
|
||||
r := matchNetworkSet.FindAllStringSubmatch(path, -1)
|
||||
if len(r) != 1 {
|
||||
log.Debugf("Didn't match regex")
|
||||
return nil
|
||||
}
|
||||
name := unescapeName(r[0][1])
|
||||
if options.Name != "" && name != options.Name {
|
||||
log.Debugf("Didn't match name %s != %s", options.Name, name)
|
||||
return nil
|
||||
}
|
||||
return NetworkSetKey{Name: name}
|
||||
}
|
||||
|
||||
type NetworkSet struct {
|
||||
Nets []net.IPNet `json:"nets,omitempty" validate:"omitempty,dive,cidr"`
|
||||
Labels map[string]string `json:"labels,omitempty" validate:"omitempty,labels"`
|
||||
ProfileIDs []string `json:"profile_ids,omitempty" validate:"omitempty,dive,name"`
|
||||
}
|
||||
282
vendor/github.com/projectcalico/calico/libcalico-go/lib/backend/model/node.go
generated
vendored
Normal file
282
vendor/github.com/projectcalico/calico/libcalico-go/lib/backend/model/node.go
generated
vendored
Normal file
@@ -0,0 +1,282 @@
|
||||
// Copyright (c) 2016,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 model
|
||||
|
||||
import (
|
||||
goerrors "errors"
|
||||
"fmt"
|
||||
"regexp"
|
||||
|
||||
"reflect"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/projectcalico/api/pkg/lib/numorstring"
|
||||
|
||||
"github.com/projectcalico/calico/libcalico-go/lib/errors"
|
||||
"github.com/projectcalico/calico/libcalico-go/lib/net"
|
||||
)
|
||||
|
||||
var (
|
||||
typeNode = reflect.TypeOf(Node{})
|
||||
typeHostMetadata = reflect.TypeOf(HostMetadata{})
|
||||
typeOrchRefs = reflect.TypeOf([]OrchRef{})
|
||||
typeHostIp = rawIPType
|
||||
typeWireguard = reflect.TypeOf(Wireguard{})
|
||||
matchHostMetadata = regexp.MustCompile(`^/?calico/v1/host/([^/]+)/metadata$`)
|
||||
matchHostIp = regexp.MustCompile(`^/?calico/v1/host/([^/]+)/bird_ip$`)
|
||||
matchWireguard = regexp.MustCompile(`^/?calico/v1/host/([^/]+)/wireguard$`)
|
||||
)
|
||||
|
||||
type Node struct {
|
||||
// Felix specific configuration
|
||||
FelixIPv4 *net.IP
|
||||
|
||||
// Node specific labels
|
||||
Labels map[string]string `json:"labels,omitempty"`
|
||||
|
||||
// BGP specific configuration
|
||||
BGPIPv4Addr *net.IP
|
||||
BGPIPv6Addr *net.IP
|
||||
BGPIPv4Net *net.IPNet
|
||||
BGPIPv6Net *net.IPNet
|
||||
BGPASNumber *numorstring.ASNumber
|
||||
OrchRefs []OrchRef `json:"orchRefs,omitempty"`
|
||||
}
|
||||
|
||||
type OrchRef struct {
|
||||
Orchestrator string `json:"orchestrator,omitempty"`
|
||||
NodeName string `json:"nodeName,omitempty"`
|
||||
}
|
||||
|
||||
type Wireguard struct {
|
||||
InterfaceIPv4Addr *net.IP `json:"interfaceIPv4Addr,omitempty"`
|
||||
PublicKey string `json:"publicKey,omitempty"`
|
||||
InterfaceIPv6Addr *net.IP `json:"interfaceIPv6Addr,omitempty"`
|
||||
PublicKeyV6 string `json:"publicKeyV6,omitempty"`
|
||||
}
|
||||
|
||||
type NodeKey struct {
|
||||
Hostname string
|
||||
}
|
||||
|
||||
func (key NodeKey) defaultPath() (string, error) {
|
||||
return "", goerrors.New("Node is a composite type, so not handled with a single path")
|
||||
}
|
||||
|
||||
func (key NodeKey) defaultDeletePath() (string, error) {
|
||||
return "", goerrors.New("Node is a composite type, so not handled with a single path")
|
||||
}
|
||||
|
||||
func (key NodeKey) defaultDeleteParentPaths() ([]string, error) {
|
||||
return nil, goerrors.New("Node is composite type, so not handled with a single path")
|
||||
}
|
||||
|
||||
func (key NodeKey) valueType() (reflect.Type, error) {
|
||||
return typeNode, nil
|
||||
}
|
||||
|
||||
func (key NodeKey) String() string {
|
||||
return fmt.Sprintf("Node(name=%s)", key.Hostname)
|
||||
}
|
||||
|
||||
type NodeListOptions struct {
|
||||
Hostname string
|
||||
}
|
||||
|
||||
func (options NodeListOptions) defaultPathRoot() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (options NodeListOptions) KeyFromDefaultPath(path string) Key {
|
||||
return nil
|
||||
}
|
||||
|
||||
// The node is a composite of the following subcomponents:
|
||||
// - The host metadata. This is the primary subcomponent and is used to enumerate
|
||||
// hosts. However, for backwards compatibility, the etcd driver needs to handle
|
||||
// that this may not exist, and instead need to enumerate based on directory.
|
||||
// - The host IPv4 address used by Calico to lock down IPIP traffic.
|
||||
// - The BGP IPv4 and IPv6 addresses
|
||||
// - The BGP ASN.
|
||||
|
||||
type HostMetadata struct {
|
||||
}
|
||||
|
||||
type HostMetadataKey struct {
|
||||
Hostname string
|
||||
}
|
||||
|
||||
func (key HostMetadataKey) defaultPath() (string, error) {
|
||||
if key.Hostname == "" {
|
||||
return "", errors.ErrorInsufficientIdentifiers{Name: "name"}
|
||||
}
|
||||
return fmt.Sprintf("/calico/v1/host/%s/metadata", key.Hostname), nil
|
||||
}
|
||||
|
||||
func (key HostMetadataKey) defaultDeletePath() (string, error) {
|
||||
if key.Hostname == "" {
|
||||
return "", errors.ErrorInsufficientIdentifiers{Name: "name"}
|
||||
}
|
||||
return fmt.Sprintf("/calico/v1/host/%s", key.Hostname), nil
|
||||
}
|
||||
|
||||
func (key HostMetadataKey) defaultDeleteParentPaths() ([]string, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (key HostMetadataKey) valueType() (reflect.Type, error) {
|
||||
return typeHostMetadata, nil
|
||||
}
|
||||
|
||||
func (key HostMetadataKey) String() string {
|
||||
return fmt.Sprintf("Node(name=%s)", key.Hostname)
|
||||
}
|
||||
|
||||
type HostMetadataListOptions struct {
|
||||
Hostname string
|
||||
}
|
||||
|
||||
func (options HostMetadataListOptions) defaultPathRoot() string {
|
||||
if options.Hostname == "" {
|
||||
return "/calico/v1/host"
|
||||
} else {
|
||||
return fmt.Sprintf("/calico/v1/host/%s/metadata", options.Hostname)
|
||||
}
|
||||
}
|
||||
|
||||
func (options HostMetadataListOptions) KeyFromDefaultPath(path string) Key {
|
||||
log.Debugf("Get Node key from %s", path)
|
||||
if r := matchHostMetadata.FindAllStringSubmatch(path, -1); len(r) == 1 {
|
||||
return HostMetadataKey{Hostname: r[0][1]}
|
||||
} else {
|
||||
log.Debugf("%s didn't match regex", path)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// The Felix Host IP Key.
|
||||
type HostIPKey struct {
|
||||
Hostname string
|
||||
}
|
||||
|
||||
func (key HostIPKey) defaultPath() (string, error) {
|
||||
return fmt.Sprintf("/calico/v1/host/%s/bird_ip",
|
||||
key.Hostname), nil
|
||||
}
|
||||
|
||||
func (key HostIPKey) defaultDeletePath() (string, error) {
|
||||
return key.defaultPath()
|
||||
}
|
||||
|
||||
func (key HostIPKey) defaultDeleteParentPaths() ([]string, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (key HostIPKey) valueType() (reflect.Type, error) {
|
||||
return typeHostIp, nil
|
||||
}
|
||||
|
||||
func (key HostIPKey) String() string {
|
||||
return fmt.Sprintf("Node(name=%s)", key.Hostname)
|
||||
}
|
||||
|
||||
type OrchRefKey struct {
|
||||
Hostname string
|
||||
}
|
||||
|
||||
func (key OrchRefKey) defaultPath() (string, error) {
|
||||
return fmt.Sprintf("/calico/v1/host/%s/orchestrator_refs",
|
||||
key.Hostname), nil
|
||||
}
|
||||
|
||||
func (key OrchRefKey) defaultDeletePath() (string, error) {
|
||||
return key.defaultPath()
|
||||
}
|
||||
|
||||
func (key OrchRefKey) defaultDeleteParentPaths() ([]string, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (key OrchRefKey) valueType() (reflect.Type, error) {
|
||||
return typeOrchRefs, nil
|
||||
}
|
||||
|
||||
func (key OrchRefKey) String() string {
|
||||
return fmt.Sprintf("OrchRefs(nodename=%s)", key.Hostname)
|
||||
}
|
||||
|
||||
type OrchRefListOptions struct {
|
||||
Hostname string
|
||||
}
|
||||
|
||||
func (options OrchRefListOptions) defaultPathRoot() string {
|
||||
return fmt.Sprintf("/calico/v1/host/%s/orchestrator_refs", options.Hostname)
|
||||
}
|
||||
|
||||
func (options OrchRefListOptions) KeyFromDefaultPath(path string) Key {
|
||||
return OrchRefKey{Hostname: options.Hostname}
|
||||
}
|
||||
|
||||
// The Felix Wireguard Key.
|
||||
type WireguardKey struct {
|
||||
NodeName string
|
||||
}
|
||||
|
||||
func (key WireguardKey) defaultPath() (string, error) {
|
||||
if key.NodeName == "" {
|
||||
return "", errors.ErrorInsufficientIdentifiers{Name: "name"}
|
||||
}
|
||||
return fmt.Sprintf("/calico/v1/host/%s/wireguard",
|
||||
key.NodeName), nil
|
||||
}
|
||||
|
||||
func (key WireguardKey) defaultDeletePath() (string, error) {
|
||||
return key.defaultPath()
|
||||
}
|
||||
|
||||
func (key WireguardKey) defaultDeleteParentPaths() ([]string, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (key WireguardKey) valueType() (reflect.Type, error) {
|
||||
return typeWireguard, nil
|
||||
}
|
||||
|
||||
func (key WireguardKey) String() string {
|
||||
return fmt.Sprintf("Node(nodename=%s)", key.NodeName)
|
||||
}
|
||||
|
||||
type WireguardListOptions struct {
|
||||
NodeName string
|
||||
}
|
||||
|
||||
func (options WireguardListOptions) defaultPathRoot() string {
|
||||
if options.NodeName == "" {
|
||||
return "/calico/v1/host"
|
||||
} else {
|
||||
return fmt.Sprintf("/calico/v1/host/%s/wireguard", options.NodeName)
|
||||
}
|
||||
}
|
||||
|
||||
func (options WireguardListOptions) KeyFromDefaultPath(path string) Key {
|
||||
log.Debugf("Get Node key from %s", path)
|
||||
if r := matchWireguard.FindAllStringSubmatch(path, -1); len(r) == 1 {
|
||||
return WireguardKey{NodeName: r[0][1]}
|
||||
} else {
|
||||
log.Debugf("%s didn't match regex", path)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
126
vendor/github.com/projectcalico/calico/libcalico-go/lib/backend/model/policy.go
generated
vendored
Normal file
126
vendor/github.com/projectcalico/calico/libcalico-go/lib/backend/model/policy.go
generated
vendored
Normal file
@@ -0,0 +1,126 @@
|
||||
// Copyright (c) 2016-2018 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 model
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
|
||||
"reflect"
|
||||
|
||||
"strings"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/projectcalico/calico/libcalico-go/lib/errors"
|
||||
)
|
||||
|
||||
var (
|
||||
matchPolicy = regexp.MustCompile("^/?calico/v1/policy/tier/([^/]+)/policy/([^/]+)$")
|
||||
typePolicy = reflect.TypeOf(Policy{})
|
||||
)
|
||||
|
||||
type PolicyKey struct {
|
||||
Name string `json:"-" validate:"required,name"`
|
||||
}
|
||||
|
||||
func (key PolicyKey) defaultPath() (string, error) {
|
||||
if key.Name == "" {
|
||||
return "", errors.ErrorInsufficientIdentifiers{Name: "name"}
|
||||
}
|
||||
e := fmt.Sprintf("/calico/v1/policy/tier/default/policy/%s",
|
||||
escapeName(key.Name))
|
||||
return e, nil
|
||||
}
|
||||
|
||||
func (key PolicyKey) defaultDeletePath() (string, error) {
|
||||
return key.defaultPath()
|
||||
}
|
||||
|
||||
func (key PolicyKey) defaultDeleteParentPaths() ([]string, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (key PolicyKey) valueType() (reflect.Type, error) {
|
||||
return typePolicy, nil
|
||||
}
|
||||
|
||||
func (key PolicyKey) String() string {
|
||||
return fmt.Sprintf("Policy(name=%s)", key.Name)
|
||||
}
|
||||
|
||||
type PolicyListOptions struct {
|
||||
Name string
|
||||
}
|
||||
|
||||
func (options PolicyListOptions) defaultPathRoot() string {
|
||||
k := "/calico/v1/policy/tier/default/policy"
|
||||
if options.Name == "" {
|
||||
return k
|
||||
}
|
||||
k = k + fmt.Sprintf("/%s", escapeName(options.Name))
|
||||
return k
|
||||
}
|
||||
|
||||
func (options PolicyListOptions) KeyFromDefaultPath(path string) Key {
|
||||
log.Debugf("Get Policy key from %s", path)
|
||||
r := matchPolicy.FindAllStringSubmatch(path, -1)
|
||||
if len(r) != 1 {
|
||||
log.Debugf("Didn't match regex")
|
||||
return nil
|
||||
}
|
||||
name := unescapeName(r[0][2])
|
||||
if options.Name != "" && name != options.Name {
|
||||
log.Debugf("Didn't match name %s != %s", options.Name, name)
|
||||
return nil
|
||||
}
|
||||
return PolicyKey{Name: name}
|
||||
}
|
||||
|
||||
type Policy struct {
|
||||
Namespace string `json:"namespace,omitempty" validate:"omitempty"`
|
||||
Order *float64 `json:"order,omitempty" validate:"omitempty"`
|
||||
InboundRules []Rule `json:"inbound_rules,omitempty" validate:"omitempty,dive"`
|
||||
OutboundRules []Rule `json:"outbound_rules,omitempty" validate:"omitempty,dive"`
|
||||
Selector string `json:"selector" validate:"selector"`
|
||||
DoNotTrack bool `json:"untracked,omitempty"`
|
||||
Annotations map[string]string `json:"annotations,omitempty"`
|
||||
PreDNAT bool `json:"pre_dnat,omitempty"`
|
||||
ApplyOnForward bool `json:"apply_on_forward,omitempty"`
|
||||
Types []string `json:"types,omitempty"`
|
||||
}
|
||||
|
||||
func (p Policy) String() string {
|
||||
parts := make([]string, 0)
|
||||
if p.Order != nil {
|
||||
parts = append(parts, fmt.Sprintf("order:%v", *p.Order))
|
||||
}
|
||||
parts = append(parts, fmt.Sprintf("selector:%#v", p.Selector))
|
||||
inRules := make([]string, len(p.InboundRules))
|
||||
for ii, rule := range p.InboundRules {
|
||||
inRules[ii] = rule.String()
|
||||
}
|
||||
parts = append(parts, fmt.Sprintf("inbound:%v", strings.Join(inRules, ";")))
|
||||
outRules := make([]string, len(p.OutboundRules))
|
||||
for ii, rule := range p.OutboundRules {
|
||||
outRules[ii] = rule.String()
|
||||
}
|
||||
parts = append(parts, fmt.Sprintf("outbound:%v", strings.Join(outRules, ";")))
|
||||
parts = append(parts, fmt.Sprintf("untracked:%v", p.DoNotTrack))
|
||||
parts = append(parts, fmt.Sprintf("pre_dnat:%v", p.PreDNAT))
|
||||
parts = append(parts, fmt.Sprintf("apply_on_forward:%v", p.ApplyOnForward))
|
||||
parts = append(parts, fmt.Sprintf("types:%v", strings.Join(p.Types, ";")))
|
||||
return strings.Join(parts, ",")
|
||||
}
|
||||
208
vendor/github.com/projectcalico/calico/libcalico-go/lib/backend/model/profile.go
generated
vendored
Normal file
208
vendor/github.com/projectcalico/calico/libcalico-go/lib/backend/model/profile.go
generated
vendored
Normal file
@@ -0,0 +1,208 @@
|
||||
// Copyright (c) 2016 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 model
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
|
||||
"reflect"
|
||||
|
||||
"sort"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/projectcalico/calico/libcalico-go/lib/errors"
|
||||
)
|
||||
|
||||
var (
|
||||
matchProfile = regexp.MustCompile("^/?calico/v1/policy/profile/([^/]+)/(rules|labels)$")
|
||||
typeProfile = reflect.TypeOf(Profile{})
|
||||
)
|
||||
|
||||
// The profile key actually returns the common parent of the three separate entries.
|
||||
// It is useful to define this to re-use some of the common machinery, and can be used
|
||||
// for delete processing since delete needs to remove the common parent.
|
||||
type ProfileKey struct {
|
||||
Name string `json:"-" validate:"required,name"`
|
||||
}
|
||||
|
||||
func (key ProfileKey) defaultPath() (string, error) {
|
||||
if key.Name == "" {
|
||||
return "", errors.ErrorInsufficientIdentifiers{Name: "name"}
|
||||
}
|
||||
e := fmt.Sprintf("/calico/v1/policy/profile/%s", escapeName(key.Name))
|
||||
return e, nil
|
||||
}
|
||||
|
||||
func (key ProfileKey) defaultDeletePath() (string, error) {
|
||||
return key.defaultPath()
|
||||
}
|
||||
|
||||
func (key ProfileKey) defaultDeleteParentPaths() ([]string, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (key ProfileKey) valueType() (reflect.Type, error) {
|
||||
return typeProfile, nil
|
||||
}
|
||||
|
||||
func (key ProfileKey) String() string {
|
||||
return fmt.Sprintf("Profile(name=%s)", key.Name)
|
||||
}
|
||||
|
||||
// ProfileRulesKey implements the KeyInterface for the profile rules
|
||||
type ProfileRulesKey struct {
|
||||
ProfileKey
|
||||
}
|
||||
|
||||
func (key ProfileRulesKey) defaultPath() (string, error) {
|
||||
e, err := key.ProfileKey.defaultPath()
|
||||
return e + "/rules", err
|
||||
}
|
||||
|
||||
func (key ProfileRulesKey) valueType() (reflect.Type, error) {
|
||||
return reflect.TypeOf(ProfileRules{}), nil
|
||||
}
|
||||
|
||||
func (key ProfileRulesKey) String() string {
|
||||
return fmt.Sprintf("ProfileRules(name=%s)", key.Name)
|
||||
}
|
||||
|
||||
// ProfileLabelsKey implements the KeyInterface for the profile labels
|
||||
type ProfileLabelsKey struct {
|
||||
ProfileKey
|
||||
}
|
||||
|
||||
func (key ProfileLabelsKey) defaultPath() (string, error) {
|
||||
e, err := key.ProfileKey.defaultPath()
|
||||
return e + "/labels", err
|
||||
}
|
||||
|
||||
func (key ProfileLabelsKey) valueType() (reflect.Type, error) {
|
||||
return reflect.TypeOf(map[string]string{}), nil
|
||||
}
|
||||
|
||||
func (key ProfileLabelsKey) String() string {
|
||||
return fmt.Sprintf("ProfileLabels(name=%s)", key.Name)
|
||||
}
|
||||
|
||||
type ProfileListOptions struct {
|
||||
Name string
|
||||
}
|
||||
|
||||
func (options ProfileListOptions) defaultPathRoot() string {
|
||||
k := "/calico/v1/policy/profile"
|
||||
if options.Name == "" {
|
||||
return k
|
||||
}
|
||||
k = k + fmt.Sprintf("/%s", escapeName(options.Name))
|
||||
return k
|
||||
}
|
||||
|
||||
func (options ProfileListOptions) KeyFromDefaultPath(path string) Key {
|
||||
log.Debugf("Get Profile key from %s", path)
|
||||
r := matchProfile.FindAllStringSubmatch(path, -1)
|
||||
if len(r) != 1 {
|
||||
log.Debugf("Didn't match regex")
|
||||
return nil
|
||||
}
|
||||
name := unescapeName(r[0][1])
|
||||
kind := r[0][2]
|
||||
if options.Name != "" && name != options.Name {
|
||||
log.Debugf("Didn't match name %s != %s", options.Name, name)
|
||||
return nil
|
||||
}
|
||||
pk := ProfileKey{Name: name}
|
||||
switch kind {
|
||||
case "labels":
|
||||
return ProfileLabelsKey{ProfileKey: pk}
|
||||
case "rules":
|
||||
return ProfileRulesKey{ProfileKey: pk}
|
||||
}
|
||||
return pk
|
||||
}
|
||||
|
||||
// The profile structure is defined to allow the client to define a conversion interface
|
||||
// to map between the API and backend profiles. However, in the actual underlying
|
||||
// implementation the profile is written as three separate entries - rules, tags and labels.
|
||||
type Profile struct {
|
||||
Rules ProfileRules
|
||||
Tags []string
|
||||
Labels map[string]string
|
||||
}
|
||||
|
||||
type ProfileRules struct {
|
||||
InboundRules []Rule `json:"inbound_rules,omitempty" validate:"omitempty,dive"`
|
||||
OutboundRules []Rule `json:"outbound_rules,omitempty" validate:"omitempty,dive"`
|
||||
}
|
||||
|
||||
func (_ *ProfileListOptions) ListConvert(ds []*KVPair) []*KVPair {
|
||||
|
||||
profiles := make(map[string]*KVPair)
|
||||
var name string
|
||||
for _, d := range ds {
|
||||
switch t := d.Key.(type) {
|
||||
case ProfileLabelsKey:
|
||||
name = t.Name
|
||||
case ProfileRulesKey:
|
||||
name = t.Name
|
||||
default:
|
||||
panic(fmt.Errorf("Unexpected key type: %v", t))
|
||||
}
|
||||
|
||||
// Get the KVPair for the profile, initialising if just created.
|
||||
pd, ok := profiles[name]
|
||||
if !ok {
|
||||
log.Debugf("Initialise profile %v", name)
|
||||
pd = &KVPair{
|
||||
Value: &Profile{},
|
||||
Key: ProfileKey{Name: name},
|
||||
}
|
||||
profiles[name] = pd
|
||||
}
|
||||
|
||||
p := pd.Value.(*Profile)
|
||||
switch t := d.Value.(type) {
|
||||
case map[string]string: // must be labels
|
||||
log.Debugf("Store labels %v", t)
|
||||
p.Labels = t
|
||||
case *ProfileRules: // must be rules
|
||||
log.Debugf("Store rules %v", t)
|
||||
p.Rules = *t
|
||||
default:
|
||||
panic(fmt.Errorf("Unexpected type: %v", t))
|
||||
}
|
||||
pd.Value = p
|
||||
}
|
||||
|
||||
log.Debugf("Map of profiles: %v", profiles)
|
||||
|
||||
// To store the keys in slice in sorted order
|
||||
var keys []string
|
||||
for k := range profiles {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
|
||||
out := make([]*KVPair, len(keys))
|
||||
for i, k := range keys {
|
||||
out[i] = profiles[k]
|
||||
}
|
||||
|
||||
log.Debugf("Sorted groups of profiles: %v", out)
|
||||
|
||||
return out
|
||||
}
|
||||
34
vendor/github.com/projectcalico/calico/libcalico-go/lib/backend/model/region.go
generated
vendored
Normal file
34
vendor/github.com/projectcalico/calico/libcalico-go/lib/backend/model/region.go
generated
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
// Copyright (c) 2018 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 model
|
||||
|
||||
import "fmt"
|
||||
|
||||
const (
|
||||
NoRegion string = "no-region"
|
||||
RegionPrefix string = "region-"
|
||||
)
|
||||
|
||||
func RegionString(region string) string {
|
||||
if region != "" {
|
||||
return RegionPrefix + region
|
||||
} else {
|
||||
return NoRegion
|
||||
}
|
||||
}
|
||||
|
||||
func ErrorSlashInRegionString(regionString string) error {
|
||||
return fmt.Errorf("RegionString %v is invalid because it includes a slash", regionString)
|
||||
}
|
||||
321
vendor/github.com/projectcalico/calico/libcalico-go/lib/backend/model/resource.go
generated
vendored
Normal file
321
vendor/github.com/projectcalico/calico/libcalico-go/lib/backend/model/resource.go
generated
vendored
Normal file
@@ -0,0 +1,321 @@
|
||||
// Copyright (c) 2016-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 model
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
kapiv1 "k8s.io/api/core/v1"
|
||||
discovery "k8s.io/api/discovery/v1"
|
||||
|
||||
apiv3 "github.com/projectcalico/api/pkg/apis/projectcalico/v3"
|
||||
|
||||
libapiv3 "github.com/projectcalico/calico/libcalico-go/lib/apis/v3"
|
||||
"github.com/projectcalico/calico/libcalico-go/lib/namespace"
|
||||
)
|
||||
|
||||
// Name/type information about a single resource.
|
||||
type resourceInfo struct {
|
||||
typeOf reflect.Type
|
||||
plural string
|
||||
kindLower string
|
||||
kind string
|
||||
}
|
||||
|
||||
var (
|
||||
matchGlobalResource = regexp.MustCompile("^/calico/resources/v3/projectcalico[.]org/([^/]+)/([^/]+)$")
|
||||
matchNamespacedResource = regexp.MustCompile("^/calico/resources/v3/projectcalico[.]org/([^/]+)/([^/]+)/([^/]+)$")
|
||||
resourceInfoByKindLower = make(map[string]resourceInfo)
|
||||
resourceInfoByPlural = make(map[string]resourceInfo)
|
||||
)
|
||||
|
||||
func registerResourceInfo(kind string, plural string, typeOf reflect.Type) {
|
||||
kindLower := strings.ToLower(kind)
|
||||
plural = strings.ToLower(plural)
|
||||
ri := resourceInfo{
|
||||
typeOf: typeOf,
|
||||
kindLower: kindLower,
|
||||
kind: kind,
|
||||
plural: plural,
|
||||
}
|
||||
resourceInfoByKindLower[kindLower] = ri
|
||||
resourceInfoByPlural[plural] = ri
|
||||
}
|
||||
|
||||
func init() {
|
||||
registerResourceInfo(
|
||||
apiv3.KindBGPPeer,
|
||||
"bgppeers",
|
||||
reflect.TypeOf(apiv3.BGPPeer{}),
|
||||
)
|
||||
registerResourceInfo(
|
||||
apiv3.KindBGPConfiguration,
|
||||
"bgpconfigurations",
|
||||
reflect.TypeOf(apiv3.BGPConfiguration{}),
|
||||
)
|
||||
registerResourceInfo(
|
||||
apiv3.KindClusterInformation,
|
||||
"clusterinformations",
|
||||
reflect.TypeOf(apiv3.ClusterInformation{}),
|
||||
)
|
||||
registerResourceInfo(
|
||||
apiv3.KindFelixConfiguration,
|
||||
"felixconfigurations",
|
||||
reflect.TypeOf(apiv3.FelixConfiguration{}),
|
||||
)
|
||||
registerResourceInfo(
|
||||
apiv3.KindGlobalNetworkPolicy,
|
||||
"globalnetworkpolicies",
|
||||
reflect.TypeOf(apiv3.GlobalNetworkPolicy{}),
|
||||
)
|
||||
registerResourceInfo(
|
||||
apiv3.KindHostEndpoint,
|
||||
"hostendpoints",
|
||||
reflect.TypeOf(apiv3.HostEndpoint{}),
|
||||
)
|
||||
registerResourceInfo(
|
||||
apiv3.KindGlobalNetworkSet,
|
||||
"globalnetworksets",
|
||||
reflect.TypeOf(apiv3.GlobalNetworkSet{}),
|
||||
)
|
||||
registerResourceInfo(
|
||||
apiv3.KindIPPool,
|
||||
"ippools",
|
||||
reflect.TypeOf(apiv3.IPPool{}),
|
||||
)
|
||||
registerResourceInfo(
|
||||
apiv3.KindIPReservation,
|
||||
"ipreservations",
|
||||
reflect.TypeOf(apiv3.IPReservation{}),
|
||||
)
|
||||
registerResourceInfo(
|
||||
apiv3.KindNetworkPolicy,
|
||||
"networkpolicies",
|
||||
reflect.TypeOf(apiv3.NetworkPolicy{}),
|
||||
)
|
||||
registerResourceInfo(
|
||||
KindKubernetesNetworkPolicy,
|
||||
"kubernetesnetworkpolicies",
|
||||
reflect.TypeOf(apiv3.NetworkPolicy{}),
|
||||
)
|
||||
registerResourceInfo(
|
||||
KindKubernetesEndpointSlice,
|
||||
"kubernetesendpointslices",
|
||||
reflect.TypeOf(discovery.EndpointSlice{}),
|
||||
)
|
||||
registerResourceInfo(
|
||||
apiv3.KindNetworkSet,
|
||||
"networksets",
|
||||
reflect.TypeOf(apiv3.NetworkSet{}),
|
||||
)
|
||||
registerResourceInfo(
|
||||
libapiv3.KindNode,
|
||||
"nodes",
|
||||
reflect.TypeOf(libapiv3.Node{}),
|
||||
)
|
||||
registerResourceInfo(
|
||||
apiv3.KindCalicoNodeStatus,
|
||||
"caliconodestatuses",
|
||||
reflect.TypeOf(apiv3.CalicoNodeStatus{}),
|
||||
)
|
||||
registerResourceInfo(
|
||||
apiv3.KindProfile,
|
||||
"profiles",
|
||||
reflect.TypeOf(apiv3.Profile{}),
|
||||
)
|
||||
registerResourceInfo(
|
||||
libapiv3.KindWorkloadEndpoint,
|
||||
"workloadendpoints",
|
||||
reflect.TypeOf(libapiv3.WorkloadEndpoint{}),
|
||||
)
|
||||
registerResourceInfo(
|
||||
libapiv3.KindIPAMConfig,
|
||||
"ipamconfigs",
|
||||
reflect.TypeOf(libapiv3.IPAMConfig{}),
|
||||
)
|
||||
registerResourceInfo(
|
||||
apiv3.KindKubeControllersConfiguration,
|
||||
"kubecontrollersconfigurations",
|
||||
reflect.TypeOf(apiv3.KubeControllersConfiguration{}))
|
||||
registerResourceInfo(
|
||||
KindKubernetesService,
|
||||
"kubernetesservice",
|
||||
reflect.TypeOf(kapiv1.Service{}),
|
||||
)
|
||||
registerResourceInfo(
|
||||
libapiv3.KindBlockAffinity,
|
||||
"blockaffinities",
|
||||
reflect.TypeOf(libapiv3.BlockAffinity{}),
|
||||
)
|
||||
registerResourceInfo(
|
||||
apiv3.KindBGPFilter,
|
||||
"BGPFilters",
|
||||
reflect.TypeOf(apiv3.BGPFilter{}),
|
||||
)
|
||||
}
|
||||
|
||||
type ResourceKey struct {
|
||||
// The name of the resource.
|
||||
Name string
|
||||
// The namespace of the resource. Not required if the resource is not namespaced.
|
||||
Namespace string
|
||||
// The resource kind.
|
||||
Kind string
|
||||
}
|
||||
|
||||
func (key ResourceKey) defaultPath() (string, error) {
|
||||
return key.defaultDeletePath()
|
||||
}
|
||||
|
||||
func (key ResourceKey) defaultDeletePath() (string, error) {
|
||||
ri, ok := resourceInfoByKindLower[strings.ToLower(key.Kind)]
|
||||
if !ok {
|
||||
return "", fmt.Errorf("couldn't convert key: %+v", key)
|
||||
}
|
||||
if namespace.IsNamespaced(key.Kind) {
|
||||
return fmt.Sprintf("/calico/resources/v3/projectcalico.org/%s/%s/%s", ri.plural, key.Namespace, key.Name), nil
|
||||
}
|
||||
return fmt.Sprintf("/calico/resources/v3/projectcalico.org/%s/%s", ri.plural, key.Name), nil
|
||||
}
|
||||
|
||||
func (key ResourceKey) defaultDeleteParentPaths() ([]string, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (key ResourceKey) valueType() (reflect.Type, error) {
|
||||
ri, ok := resourceInfoByKindLower[strings.ToLower(key.Kind)]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("Unexpected resource kind: " + key.Kind)
|
||||
}
|
||||
return ri.typeOf, nil
|
||||
}
|
||||
|
||||
func (key ResourceKey) String() string {
|
||||
if namespace.IsNamespaced(key.Kind) {
|
||||
return fmt.Sprintf("%s(%s/%s)", key.Kind, key.Namespace, key.Name)
|
||||
}
|
||||
return fmt.Sprintf("%s(%s)", key.Kind, key.Name)
|
||||
}
|
||||
|
||||
type ResourceListOptions struct {
|
||||
// The name of the resource.
|
||||
Name string
|
||||
// The namespace of the resource. Not required if the resource is not namespaced.
|
||||
Namespace string
|
||||
// The resource kind.
|
||||
Kind string
|
||||
// Whether the name is prefix rather than the full name.
|
||||
Prefix bool
|
||||
}
|
||||
|
||||
// If the Kind, Namespace and Name are specified, but the Name is a prefix then the
|
||||
// last segment of this path is a prefix.
|
||||
func (options ResourceListOptions) IsLastSegmentIsPrefix() bool {
|
||||
return len(options.Kind) != 0 &&
|
||||
(len(options.Namespace) != 0 || !namespace.IsNamespaced(options.Kind)) &&
|
||||
len(options.Name) != 0 &&
|
||||
options.Prefix
|
||||
}
|
||||
|
||||
func (options ResourceListOptions) KeyFromDefaultPath(path string) Key {
|
||||
ri, ok := resourceInfoByKindLower[strings.ToLower(options.Kind)]
|
||||
if !ok {
|
||||
log.Panic("Unexpected resource kind: " + options.Kind)
|
||||
}
|
||||
|
||||
if namespace.IsNamespaced(options.Kind) {
|
||||
log.Debugf("Get Namespaced Resource key from %s", path)
|
||||
r := matchNamespacedResource.FindAllStringSubmatch(path, -1)
|
||||
if len(r) != 1 {
|
||||
log.Debugf("Didn't match regex")
|
||||
return nil
|
||||
}
|
||||
kindPlural := r[0][1]
|
||||
namespace := r[0][2]
|
||||
name := r[0][3]
|
||||
if len(options.Kind) == 0 {
|
||||
panic("Kind must be specified in List option but is not")
|
||||
}
|
||||
if kindPlural != ri.plural {
|
||||
log.Debugf("Didn't match kind %s != %s", kindPlural, kindPlural)
|
||||
return nil
|
||||
}
|
||||
if len(options.Namespace) != 0 && namespace != options.Namespace {
|
||||
log.Debugf("Didn't match namespace %s != %s", options.Namespace, namespace)
|
||||
return nil
|
||||
}
|
||||
if len(options.Name) != 0 {
|
||||
if options.Prefix && !strings.HasPrefix(name, options.Name) {
|
||||
log.Debugf("Didn't match name prefix %s != prefix(%s)", options.Name, name)
|
||||
return nil
|
||||
} else if !options.Prefix && name != options.Name {
|
||||
log.Debugf("Didn't match name %s != %s", options.Name, name)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return ResourceKey{Kind: options.Kind, Namespace: namespace, Name: name}
|
||||
}
|
||||
|
||||
log.Debugf("Get Global Resource key from %s", path)
|
||||
r := matchGlobalResource.FindAllStringSubmatch(path, -1)
|
||||
if len(r) != 1 {
|
||||
log.Debugf("Didn't match regex")
|
||||
return nil
|
||||
}
|
||||
kindPlural := r[0][1]
|
||||
name := r[0][2]
|
||||
if kindPlural != ri.plural {
|
||||
log.Debugf("Didn't match kind %s != %s", kindPlural, ri.plural)
|
||||
return nil
|
||||
}
|
||||
if len(options.Name) != 0 {
|
||||
if options.Prefix && !strings.HasPrefix(name, options.Name) {
|
||||
log.Debugf("Didn't match name prefix %s != prefix(%s)", options.Name, name)
|
||||
return nil
|
||||
} else if !options.Prefix && name != options.Name {
|
||||
log.Debugf("Didn't match name %s != %s", options.Name, name)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return ResourceKey{Kind: options.Kind, Name: name}
|
||||
}
|
||||
|
||||
func (options ResourceListOptions) defaultPathRoot() string {
|
||||
ri, ok := resourceInfoByKindLower[strings.ToLower(options.Kind)]
|
||||
if !ok {
|
||||
log.Panic("Unexpected resource kind: " + options.Kind)
|
||||
}
|
||||
|
||||
k := "/calico/resources/v3/projectcalico.org/" + ri.plural
|
||||
if namespace.IsNamespaced(options.Kind) {
|
||||
if options.Namespace == "" {
|
||||
return k
|
||||
}
|
||||
k = k + "/" + options.Namespace
|
||||
}
|
||||
if options.Name == "" {
|
||||
return k
|
||||
}
|
||||
return k + "/" + options.Name
|
||||
}
|
||||
|
||||
func (options ResourceListOptions) String() string {
|
||||
return options.Kind
|
||||
}
|
||||
268
vendor/github.com/projectcalico/calico/libcalico-go/lib/backend/model/rule.go
generated
vendored
Normal file
268
vendor/github.com/projectcalico/calico/libcalico-go/lib/backend/model/rule.go
generated
vendored
Normal file
@@ -0,0 +1,268 @@
|
||||
// Copyright (c) 2016-2018 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 model
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
apiv3 "github.com/projectcalico/api/pkg/apis/projectcalico/v3"
|
||||
"github.com/projectcalico/api/pkg/lib/numorstring"
|
||||
|
||||
"github.com/projectcalico/calico/libcalico-go/lib/net"
|
||||
)
|
||||
|
||||
type Rule struct {
|
||||
Action string `json:"action,omitempty"`
|
||||
|
||||
IPVersion *int `json:"ip_version,omitempty" validate:"omitempty,ipVersion"`
|
||||
|
||||
Protocol *numorstring.Protocol `json:"protocol,omitempty" validate:"omitempty"`
|
||||
NotProtocol *numorstring.Protocol `json:"!protocol,omitempty" validate:"omitempty"`
|
||||
|
||||
// ICMP validation notes: 0 is a valid (common) ICMP type and code. Type = 255 is not assigned
|
||||
// to any protocol and the Linux kernel doesn't support matching on it so we validate against
|
||||
// it.
|
||||
ICMPType *int `json:"icmp_type,omitempty" validate:"omitempty,gte=0,lt=255"`
|
||||
ICMPCode *int `json:"icmp_code,omitempty" validate:"omitempty,gte=0,lte=255"`
|
||||
NotICMPType *int `json:"!icmp_type,omitempty" validate:"omitempty,gte=0,lt=255"`
|
||||
NotICMPCode *int `json:"!icmp_code,omitempty" validate:"omitempty,gte=0,lte=255"`
|
||||
|
||||
SrcTag string `json:"src_tag,omitempty" validate:"omitempty,tag"`
|
||||
SrcNet *net.IPNet `json:"src_net,omitempty" validate:"omitempty"`
|
||||
SrcNets []*net.IPNet `json:"src_nets,omitempty" validate:"omitempty"`
|
||||
SrcSelector string `json:"src_selector,omitempty" validate:"omitempty,selector"`
|
||||
SrcPorts []numorstring.Port `json:"src_ports,omitempty" validate:"omitempty,dive"`
|
||||
SrcService string `json:"src_service,omitempty" validate:"omitempty"`
|
||||
SrcServiceNamespace string `json:"src_service_ns,omitempty" validate:"omitempty"`
|
||||
DstTag string `json:"dst_tag,omitempty" validate:"omitempty,tag"`
|
||||
DstSelector string `json:"dst_selector,omitempty" validate:"omitempty,selector"`
|
||||
DstNet *net.IPNet `json:"dst_net,omitempty" validate:"omitempty"`
|
||||
DstNets []*net.IPNet `json:"dst_nets,omitempty" validate:"omitempty"`
|
||||
DstPorts []numorstring.Port `json:"dst_ports,omitempty" validate:"omitempty,dive"`
|
||||
DstService string `json:"dst_service,omitempty" validate:"omitempty"`
|
||||
DstServiceNamespace string `json:"dst_service_ns,omitempty" validate:"omitempty"`
|
||||
|
||||
NotSrcTag string `json:"!src_tag,omitempty" validate:"omitempty,tag"`
|
||||
NotSrcNet *net.IPNet `json:"!src_net,omitempty" validate:"omitempty"`
|
||||
NotSrcNets []*net.IPNet `json:"!src_nets,omitempty" validate:"omitempty"`
|
||||
NotSrcSelector string `json:"!src_selector,omitempty" validate:"omitempty,selector"`
|
||||
NotSrcPorts []numorstring.Port `json:"!src_ports,omitempty" validate:"omitempty,dive"`
|
||||
NotDstTag string `json:"!dst_tag,omitempty" validate:"omitempty"`
|
||||
NotDstSelector string `json:"!dst_selector,omitempty" validate:"omitempty,selector"`
|
||||
NotDstNet *net.IPNet `json:"!dst_net,omitempty" validate:"omitempty"`
|
||||
NotDstNets []*net.IPNet `json:"!dst_nets,omitempty" validate:"omitempty"`
|
||||
NotDstPorts []numorstring.Port `json:"!dst_ports,omitempty" validate:"omitempty,dive"`
|
||||
|
||||
// These fields allow us to pass through the raw match criteria from the V3 datamodel unmodified.
|
||||
// The selectors above are formed in the update processor layer by combining the original
|
||||
// selectors, namespace selectors and service account selectors into one.
|
||||
OriginalSrcSelector string `json:"orig_src_selector,omitempty" validate:"omitempty,selector"`
|
||||
OriginalSrcNamespaceSelector string `json:"orig_src_namespace_selector,omitempty" validate:"omitempty,selector"`
|
||||
OriginalDstSelector string `json:"orig_dst_selector,omitempty" validate:"omitempty,selector"`
|
||||
OriginalDstNamespaceSelector string `json:"orig_dst_namespace_selector,omitempty" validate:"omitempty,selector"`
|
||||
OriginalNotSrcSelector string `json:"!orig_src_selector,omitempty" validate:"omitempty,selector"`
|
||||
OriginalNotDstSelector string `json:"!orig_dst_selector,omitempty" validate:"omitempty,selector"`
|
||||
OriginalSrcServiceAccountNames []string `json:"orig_src_service_acct_names,omitempty" validate:"omitempty"`
|
||||
OriginalSrcServiceAccountSelector string `json:"orig_src_service_acct_selector,omitempty" validate:"omitempty,selector"`
|
||||
OriginalDstServiceAccountNames []string `json:"orig_dst_service_acct_names,omitempty" validate:"omitempty"`
|
||||
OriginalDstServiceAccountSelector string `json:"orig_dst_service_acct_selector,omitempty" validate:"omitempty,selector"`
|
||||
|
||||
// These fields allow us to pass through application layer selectors from the V3 datamodel.
|
||||
HTTPMatch *HTTPMatch `json:"http,omitempty" validate:"omitempty"`
|
||||
|
||||
LogPrefix string `json:"log_prefix,omitempty" validate:"omitempty"`
|
||||
|
||||
Metadata *RuleMetadata `json:"metadata,omitempty" validate:"omitempty"`
|
||||
}
|
||||
|
||||
type HTTPMatch struct {
|
||||
Methods []string `json:"methods,omitempty" validate:"omitempty"`
|
||||
Paths []apiv3.HTTPPath `json:"paths,omitempty" validate:"omitempty"`
|
||||
}
|
||||
|
||||
type RuleMetadata struct {
|
||||
Annotations map[string]string `json:"annotations,omitempty"`
|
||||
}
|
||||
|
||||
func combineNets(n *net.IPNet, nets []*net.IPNet) []*net.IPNet {
|
||||
if n == nil {
|
||||
return nets
|
||||
}
|
||||
if len(nets) == 0 {
|
||||
return []*net.IPNet{n}
|
||||
}
|
||||
var combination = make([]*net.IPNet, len(nets)+1)
|
||||
copy(combination, nets)
|
||||
combination[len(nets)] = n
|
||||
return combination
|
||||
}
|
||||
|
||||
func (r Rule) AllSrcNets() []*net.IPNet {
|
||||
return combineNets(r.SrcNet, r.SrcNets)
|
||||
}
|
||||
|
||||
func (r Rule) AllDstNets() []*net.IPNet {
|
||||
return combineNets(r.DstNet, r.DstNets)
|
||||
}
|
||||
|
||||
func (r Rule) AllNotSrcNets() []*net.IPNet {
|
||||
return combineNets(r.NotSrcNet, r.NotSrcNets)
|
||||
}
|
||||
|
||||
func (r Rule) AllNotDstNets() []*net.IPNet {
|
||||
return combineNets(r.NotDstNet, r.NotDstNets)
|
||||
}
|
||||
|
||||
func joinNets(nets []*net.IPNet) string {
|
||||
parts := make([]string, len(nets))
|
||||
for i, n := range nets {
|
||||
parts[i] = n.String()
|
||||
}
|
||||
return strings.Join(parts, ",")
|
||||
}
|
||||
|
||||
func (r Rule) String() string {
|
||||
parts := make([]string, 0)
|
||||
// Action.
|
||||
if r.Action != "" {
|
||||
parts = append(parts, r.Action)
|
||||
} else {
|
||||
parts = append(parts, "Allow")
|
||||
}
|
||||
|
||||
// Global packet attributes that don't depend on direction.
|
||||
if r.Protocol != nil {
|
||||
parts = append(parts, r.Protocol.String())
|
||||
}
|
||||
if r.NotProtocol != nil {
|
||||
parts = append(parts, "!"+r.NotProtocol.String())
|
||||
}
|
||||
|
||||
if r.ICMPType != nil {
|
||||
parts = append(parts, "type", strconv.Itoa(*r.ICMPType))
|
||||
}
|
||||
if r.ICMPCode != nil {
|
||||
parts = append(parts, "code", strconv.Itoa(*r.ICMPCode))
|
||||
}
|
||||
if r.NotICMPType != nil {
|
||||
parts = append(parts, "!type", strconv.Itoa(*r.NotICMPType))
|
||||
}
|
||||
if r.NotICMPCode != nil {
|
||||
parts = append(parts, "!code", strconv.Itoa(*r.NotICMPCode))
|
||||
}
|
||||
|
||||
{
|
||||
// Source attributes. New block ensures that fromParts goes out-of-scope before
|
||||
// we calculate toParts. This prevents copy/paste errors.
|
||||
fromParts := make([]string, 0)
|
||||
if len(r.SrcPorts) > 0 {
|
||||
srcPorts := make([]string, len(r.SrcPorts))
|
||||
for ii, port := range r.SrcPorts {
|
||||
srcPorts[ii] = port.String()
|
||||
}
|
||||
fromParts = append(fromParts, "ports", strings.Join(srcPorts, ","))
|
||||
}
|
||||
if r.SrcTag != "" {
|
||||
fromParts = append(fromParts, "tag", r.SrcTag)
|
||||
}
|
||||
if r.SrcSelector != "" {
|
||||
fromParts = append(fromParts, "selector", fmt.Sprintf("%#v", r.SrcSelector))
|
||||
}
|
||||
srcNets := r.AllSrcNets()
|
||||
if len(srcNets) != 0 {
|
||||
fromParts = append(fromParts, "cidr", joinNets(srcNets))
|
||||
}
|
||||
if len(r.NotSrcPorts) > 0 {
|
||||
notSrcPorts := make([]string, len(r.NotSrcPorts))
|
||||
for ii, port := range r.NotSrcPorts {
|
||||
notSrcPorts[ii] = port.String()
|
||||
}
|
||||
fromParts = append(fromParts, "!ports", strings.Join(notSrcPorts, ","))
|
||||
}
|
||||
if r.NotSrcTag != "" {
|
||||
fromParts = append(fromParts, "!tag", r.NotSrcTag)
|
||||
}
|
||||
if r.NotSrcSelector != "" {
|
||||
fromParts = append(fromParts, "!selector", fmt.Sprintf("%#v", r.NotSrcSelector))
|
||||
}
|
||||
notSrcNets := r.AllNotSrcNets()
|
||||
if len(notSrcNets) != 0 {
|
||||
fromParts = append(fromParts, "!cidr", joinNets(notSrcNets))
|
||||
}
|
||||
|
||||
if len(fromParts) > 0 {
|
||||
parts = append(parts, "from")
|
||||
parts = append(parts, fromParts...)
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// Destination attributes.
|
||||
toParts := make([]string, 0)
|
||||
if len(r.DstPorts) > 0 {
|
||||
DstPorts := make([]string, len(r.DstPorts))
|
||||
for ii, port := range r.DstPorts {
|
||||
DstPorts[ii] = port.String()
|
||||
}
|
||||
toParts = append(toParts, "ports", strings.Join(DstPorts, ","))
|
||||
}
|
||||
if r.DstTag != "" {
|
||||
toParts = append(toParts, "tag", r.DstTag)
|
||||
}
|
||||
if r.DstSelector != "" {
|
||||
toParts = append(toParts, "selector", fmt.Sprintf("%#v", r.DstSelector))
|
||||
}
|
||||
dstNets := r.AllDstNets()
|
||||
if len(dstNets) != 0 {
|
||||
toParts = append(toParts, "cidr", joinNets(dstNets))
|
||||
}
|
||||
if len(r.NotDstPorts) > 0 {
|
||||
notDstPorts := make([]string, len(r.NotDstPorts))
|
||||
for ii, port := range r.NotDstPorts {
|
||||
notDstPorts[ii] = port.String()
|
||||
}
|
||||
toParts = append(toParts, "!ports", strings.Join(notDstPorts, ","))
|
||||
}
|
||||
if r.NotDstTag != "" {
|
||||
toParts = append(toParts, "!tag", r.NotDstTag)
|
||||
}
|
||||
if r.NotDstSelector != "" {
|
||||
toParts = append(toParts, "!selector", fmt.Sprintf("%#v", r.NotDstSelector))
|
||||
}
|
||||
notDstNets := r.AllNotDstNets()
|
||||
if len(notDstNets) != 0 {
|
||||
toParts = append(toParts, "!cidr", joinNets(notDstNets))
|
||||
}
|
||||
|
||||
// HTTPMatch are destination rules.
|
||||
if r.HTTPMatch != nil {
|
||||
if len(r.HTTPMatch.Methods) > 0 {
|
||||
toParts = append(toParts, "httpMethods", fmt.Sprintf("%+v", r.HTTPMatch.Methods))
|
||||
}
|
||||
if len(r.HTTPMatch.Paths) > 0 {
|
||||
toParts = append(toParts, "httpPaths", fmt.Sprintf("%+v", r.HTTPMatch.Paths))
|
||||
}
|
||||
}
|
||||
|
||||
if len(toParts) > 0 {
|
||||
parts = append(parts, "to")
|
||||
parts = append(parts, toParts...)
|
||||
}
|
||||
}
|
||||
|
||||
return strings.Join(parts, " ")
|
||||
}
|
||||
184
vendor/github.com/projectcalico/calico/libcalico-go/lib/backend/model/statusreports.go
generated
vendored
Normal file
184
vendor/github.com/projectcalico/calico/libcalico-go/lib/backend/model/statusreports.go
generated
vendored
Normal file
@@ -0,0 +1,184 @@
|
||||
// Copyright (c) 2016-2018 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 model
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/projectcalico/calico/libcalico-go/lib/errors"
|
||||
)
|
||||
|
||||
var (
|
||||
matchActiveStatusReport = regexp.MustCompile("^/?calico/felix/v2/([^/]+)/host/([^/]+)/status$")
|
||||
matchLastStatusReport = regexp.MustCompile("^/?calico/felix/v2/([^/]+)/host/([^/]+)/last_reported_status")
|
||||
typeStatusReport = reflect.TypeOf(StatusReport{})
|
||||
)
|
||||
|
||||
type ActiveStatusReportKey struct {
|
||||
Hostname string `json:"-" validate:"required,hostname"`
|
||||
RegionString string
|
||||
}
|
||||
|
||||
func (key ActiveStatusReportKey) defaultPath() (string, error) {
|
||||
return key.defaultDeletePath()
|
||||
}
|
||||
|
||||
func (key ActiveStatusReportKey) defaultDeletePath() (string, error) {
|
||||
if key.Hostname == "" {
|
||||
return "", errors.ErrorInsufficientIdentifiers{Name: "hostname"}
|
||||
}
|
||||
if key.RegionString == "" {
|
||||
return "", errors.ErrorInsufficientIdentifiers{Name: "regionString"}
|
||||
}
|
||||
if strings.Contains(key.RegionString, "/") {
|
||||
return "", ErrorSlashInRegionString(key.RegionString)
|
||||
}
|
||||
e := fmt.Sprintf("/calico/felix/v2/%s/host/%s/status", key.RegionString, key.Hostname)
|
||||
return e, nil
|
||||
}
|
||||
|
||||
func (key ActiveStatusReportKey) defaultDeleteParentPaths() ([]string, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (key ActiveStatusReportKey) valueType() (reflect.Type, error) {
|
||||
return typeStatusReport, nil
|
||||
}
|
||||
|
||||
func (key ActiveStatusReportKey) String() string {
|
||||
return fmt.Sprintf("StatusReport(hostname=%s)", key.Hostname)
|
||||
}
|
||||
|
||||
type ActiveStatusReportListOptions struct {
|
||||
Hostname string
|
||||
RegionString string
|
||||
}
|
||||
|
||||
func (options ActiveStatusReportListOptions) defaultPathRoot() string {
|
||||
k := "/calico/felix/v2/"
|
||||
if options.RegionString == "" {
|
||||
return k
|
||||
}
|
||||
k = k + options.RegionString + "/host"
|
||||
if options.Hostname == "" {
|
||||
return k
|
||||
}
|
||||
k = k + fmt.Sprintf("/%s/status", options.Hostname)
|
||||
return k
|
||||
}
|
||||
|
||||
func (options ActiveStatusReportListOptions) KeyFromDefaultPath(ekey string) Key {
|
||||
log.Debugf("Get StatusReport key from %s", ekey)
|
||||
r := matchActiveStatusReport.FindAllStringSubmatch(ekey, -1)
|
||||
if len(r) != 1 {
|
||||
log.Debugf("Didn't match regex")
|
||||
return nil
|
||||
}
|
||||
regionString := r[0][1]
|
||||
name := r[0][2]
|
||||
if options.RegionString != "" && regionString != options.RegionString {
|
||||
log.Debugf("Didn't match region %s != %s", options.RegionString, regionString)
|
||||
return nil
|
||||
}
|
||||
if options.Hostname != "" && name != options.Hostname {
|
||||
log.Debugf("Didn't match name %s != %s", options.Hostname, name)
|
||||
return nil
|
||||
}
|
||||
return ActiveStatusReportKey{Hostname: name, RegionString: regionString}
|
||||
}
|
||||
|
||||
type LastStatusReportKey struct {
|
||||
Hostname string `json:"-" validate:"required,hostname"`
|
||||
RegionString string
|
||||
}
|
||||
|
||||
func (key LastStatusReportKey) defaultPath() (string, error) {
|
||||
return key.defaultDeletePath()
|
||||
}
|
||||
|
||||
func (key LastStatusReportKey) defaultDeletePath() (string, error) {
|
||||
if key.Hostname == "" {
|
||||
return "", errors.ErrorInsufficientIdentifiers{Name: "hostname"}
|
||||
}
|
||||
if key.RegionString == "" {
|
||||
return "", errors.ErrorInsufficientIdentifiers{Name: "regionString"}
|
||||
}
|
||||
if strings.Contains(key.RegionString, "/") {
|
||||
return "", ErrorSlashInRegionString(key.RegionString)
|
||||
}
|
||||
e := fmt.Sprintf("/calico/felix/v2/%s/host/%s/last_reported_status", key.RegionString, key.Hostname)
|
||||
return e, nil
|
||||
}
|
||||
|
||||
func (key LastStatusReportKey) defaultDeleteParentPaths() ([]string, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (key LastStatusReportKey) valueType() (reflect.Type, error) {
|
||||
return typeStatusReport, nil
|
||||
}
|
||||
|
||||
func (key LastStatusReportKey) String() string {
|
||||
return fmt.Sprintf("StatusReport(hostname=%s)", key.Hostname)
|
||||
}
|
||||
|
||||
type LastStatusReportListOptions struct {
|
||||
Hostname string
|
||||
RegionString string
|
||||
}
|
||||
|
||||
func (options LastStatusReportListOptions) defaultPathRoot() string {
|
||||
k := "/calico/felix/v2/"
|
||||
if options.RegionString == "" {
|
||||
return k
|
||||
}
|
||||
k = k + options.RegionString + "/host"
|
||||
if options.Hostname == "" {
|
||||
return k
|
||||
}
|
||||
k = k + fmt.Sprintf("/%s/last_reported_status", options.Hostname)
|
||||
return k
|
||||
}
|
||||
|
||||
func (options LastStatusReportListOptions) KeyFromDefaultPath(ekey string) Key {
|
||||
log.Debugf("Get StatusReport key from %s", ekey)
|
||||
r := matchLastStatusReport.FindAllStringSubmatch(ekey, -1)
|
||||
if len(r) != 1 {
|
||||
log.Debugf("Didn't match regex")
|
||||
return nil
|
||||
}
|
||||
regionString := r[0][1]
|
||||
name := r[0][2]
|
||||
if options.RegionString != "" && regionString != options.RegionString {
|
||||
log.Debugf("Didn't match region %s != %s", options.RegionString, regionString)
|
||||
return nil
|
||||
}
|
||||
if options.Hostname != "" && name != options.Hostname {
|
||||
log.Debugf("Didn't match name %s != %s", options.Hostname, name)
|
||||
return nil
|
||||
}
|
||||
return LastStatusReportKey{Hostname: name, RegionString: regionString}
|
||||
}
|
||||
|
||||
type StatusReport struct {
|
||||
Timestamp string `json:"time"`
|
||||
UptimeSeconds float64 `json:"uptime"`
|
||||
FirstUpdate bool `json:"first_update"`
|
||||
}
|
||||
185
vendor/github.com/projectcalico/calico/libcalico-go/lib/backend/model/workloadendpoint.go
generated
vendored
Normal file
185
vendor/github.com/projectcalico/calico/libcalico-go/lib/backend/model/workloadendpoint.go
generated
vendored
Normal file
@@ -0,0 +1,185 @@
|
||||
// Copyright (c) 2016-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 model
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"regexp"
|
||||
|
||||
"reflect"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/projectcalico/api/pkg/lib/numorstring"
|
||||
|
||||
"github.com/projectcalico/calico/libcalico-go/lib/errors"
|
||||
"github.com/projectcalico/calico/libcalico-go/lib/net"
|
||||
)
|
||||
|
||||
var (
|
||||
matchWorkloadEndpoint = regexp.MustCompile("^/?calico/v1/host/([^/]+)/workload/([^/]+)/([^/]+)/endpoint/([^/]+)$")
|
||||
)
|
||||
|
||||
type WorkloadEndpointKey struct {
|
||||
Hostname string `json:"-"`
|
||||
OrchestratorID string `json:"-"`
|
||||
WorkloadID string `json:"-"`
|
||||
EndpointID string `json:"-"`
|
||||
}
|
||||
|
||||
func (key WorkloadEndpointKey) defaultPath() (string, error) {
|
||||
if key.Hostname == "" {
|
||||
return "", errors.ErrorInsufficientIdentifiers{Name: "node"}
|
||||
}
|
||||
if key.OrchestratorID == "" {
|
||||
return "", errors.ErrorInsufficientIdentifiers{Name: "orchestrator"}
|
||||
}
|
||||
if key.WorkloadID == "" {
|
||||
return "", errors.ErrorInsufficientIdentifiers{Name: "workload"}
|
||||
}
|
||||
if key.EndpointID == "" {
|
||||
return "", errors.ErrorInsufficientIdentifiers{Name: "name"}
|
||||
}
|
||||
return fmt.Sprintf("/calico/v1/host/%s/workload/%s/%s/endpoint/%s",
|
||||
key.Hostname, escapeName(key.OrchestratorID), escapeName(key.WorkloadID), escapeName(key.EndpointID)), nil
|
||||
}
|
||||
|
||||
func (key WorkloadEndpointKey) defaultDeletePath() (string, error) {
|
||||
return key.defaultPath()
|
||||
}
|
||||
|
||||
func (key WorkloadEndpointKey) defaultDeleteParentPaths() ([]string, error) {
|
||||
if key.Hostname == "" {
|
||||
return nil, errors.ErrorInsufficientIdentifiers{Name: "node"}
|
||||
}
|
||||
if key.OrchestratorID == "" {
|
||||
return nil, errors.ErrorInsufficientIdentifiers{Name: "orchestrator"}
|
||||
}
|
||||
if key.WorkloadID == "" {
|
||||
return nil, errors.ErrorInsufficientIdentifiers{Name: "workload"}
|
||||
}
|
||||
workload := fmt.Sprintf("/calico/v1/host/%s/workload/%s/%s",
|
||||
key.Hostname, escapeName(key.OrchestratorID), escapeName(key.WorkloadID))
|
||||
endpoints := workload + "/endpoint"
|
||||
return []string{endpoints, workload}, nil
|
||||
}
|
||||
|
||||
func (key WorkloadEndpointKey) valueType() (reflect.Type, error) {
|
||||
return reflect.TypeOf(WorkloadEndpoint{}), nil
|
||||
}
|
||||
|
||||
func (key WorkloadEndpointKey) String() string {
|
||||
return fmt.Sprintf("WorkloadEndpoint(node=%s, orchestrator=%s, workload=%s, name=%s)",
|
||||
key.Hostname, key.OrchestratorID, key.WorkloadID, key.EndpointID)
|
||||
}
|
||||
|
||||
type WorkloadEndpointListOptions struct {
|
||||
Hostname string
|
||||
OrchestratorID string
|
||||
WorkloadID string
|
||||
EndpointID string
|
||||
}
|
||||
|
||||
func (options WorkloadEndpointListOptions) defaultPathRoot() string {
|
||||
k := "/calico/v1/host"
|
||||
if options.Hostname == "" {
|
||||
return k
|
||||
}
|
||||
k = k + fmt.Sprintf("/%s/workload", options.Hostname)
|
||||
if options.OrchestratorID == "" {
|
||||
return k
|
||||
}
|
||||
k = k + fmt.Sprintf("/%s", escapeName(options.OrchestratorID))
|
||||
if options.WorkloadID == "" {
|
||||
return k
|
||||
}
|
||||
k = k + fmt.Sprintf("/%s/endpoint", escapeName(options.WorkloadID))
|
||||
if options.EndpointID == "" {
|
||||
return k
|
||||
}
|
||||
k = k + fmt.Sprintf("/%s", escapeName(options.EndpointID))
|
||||
return k
|
||||
}
|
||||
|
||||
func (options WorkloadEndpointListOptions) KeyFromDefaultPath(path string) Key {
|
||||
log.Debugf("Get WorkloadEndpoint key from %s", path)
|
||||
r := matchWorkloadEndpoint.FindAllStringSubmatch(path, -1)
|
||||
if len(r) != 1 {
|
||||
log.Debugf("Didn't match regex")
|
||||
return nil
|
||||
}
|
||||
hostname := r[0][1]
|
||||
orch := unescapeName(r[0][2])
|
||||
workload := unescapeName(r[0][3])
|
||||
endpointID := unescapeName(r[0][4])
|
||||
if options.Hostname != "" && hostname != options.Hostname {
|
||||
log.Debugf("Didn't match hostname %s != %s", options.Hostname, hostname)
|
||||
return nil
|
||||
}
|
||||
if options.OrchestratorID != "" && orch != options.OrchestratorID {
|
||||
log.Debugf("Didn't match orchestrator %s != %s", options.OrchestratorID, orch)
|
||||
return nil
|
||||
}
|
||||
if options.WorkloadID != "" && workload != options.WorkloadID {
|
||||
log.Debugf("Didn't match workload %s != %s", options.WorkloadID, workload)
|
||||
return nil
|
||||
}
|
||||
if options.EndpointID != "" && endpointID != options.EndpointID {
|
||||
log.Debugf("Didn't match endpoint ID %s != %s", options.EndpointID, endpointID)
|
||||
return nil
|
||||
}
|
||||
return WorkloadEndpointKey{
|
||||
Hostname: hostname,
|
||||
OrchestratorID: orch,
|
||||
WorkloadID: workload,
|
||||
EndpointID: endpointID,
|
||||
}
|
||||
}
|
||||
|
||||
type WorkloadEndpoint struct {
|
||||
State string `json:"state"`
|
||||
Name string `json:"name"`
|
||||
ActiveInstanceID string `json:"active_instance_id"`
|
||||
Mac *net.MAC `json:"mac"`
|
||||
ProfileIDs []string `json:"profile_ids"`
|
||||
IPv4Nets []net.IPNet `json:"ipv4_nets"`
|
||||
IPv6Nets []net.IPNet `json:"ipv6_nets"`
|
||||
IPv4NAT []IPNAT `json:"ipv4_nat,omitempty"`
|
||||
IPv6NAT []IPNAT `json:"ipv6_nat,omitempty"`
|
||||
Labels map[string]string `json:"labels,omitempty"`
|
||||
IPv4Gateway *net.IP `json:"ipv4_gateway,omitempty" validate:"omitempty,ipv4"`
|
||||
IPv6Gateway *net.IP `json:"ipv6_gateway,omitempty" validate:"omitempty,ipv6"`
|
||||
Ports []EndpointPort `json:"ports,omitempty" validate:"dive"`
|
||||
GenerateName string `json:"generate_name,omitempty"`
|
||||
AllowSpoofedSourcePrefixes []net.IPNet `json:"allow_spoofed_source_ips,omitempty"`
|
||||
Annotations map[string]string `json:"annotations,omitempty"`
|
||||
}
|
||||
|
||||
type EndpointPort struct {
|
||||
Name string `json:"name" validate:"name"`
|
||||
Protocol numorstring.Protocol `json:"protocol"`
|
||||
Port uint16 `json:"port" validate:"gt=0"`
|
||||
}
|
||||
|
||||
// IPNat contains a single NAT mapping for a WorkloadEndpoint resource.
|
||||
type IPNAT struct {
|
||||
// The internal IP address which must be associated with the owning endpoint via the
|
||||
// configured IPNetworks for the endpoint.
|
||||
IntIP net.IP `json:"int_ip" validate:"ip"`
|
||||
|
||||
// The external IP address.
|
||||
ExtIP net.IP `json:"ext_ip" validate:"ip"`
|
||||
}
|
||||
178
vendor/github.com/projectcalico/calico/libcalico-go/lib/backend/model/workloadendpointstatus.go
generated
vendored
Normal file
178
vendor/github.com/projectcalico/calico/libcalico-go/lib/backend/model/workloadendpointstatus.go
generated
vendored
Normal file
@@ -0,0 +1,178 @@
|
||||
// Copyright (c) 2016-2018 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 model
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"regexp"
|
||||
|
||||
"reflect"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/projectcalico/calico/libcalico-go/lib/errors"
|
||||
)
|
||||
|
||||
var (
|
||||
matchWorkloadEndpointStatus = regexp.MustCompile("^/?calico/felix/v2/([^/]+)/host/([^/]+)/workload/([^/]+)/([^/]+)/endpoint/([^/]+)$")
|
||||
)
|
||||
|
||||
type WorkloadEndpointStatusKey struct {
|
||||
Hostname string `json:"-"`
|
||||
OrchestratorID string `json:"-"`
|
||||
WorkloadID string `json:"-"`
|
||||
EndpointID string `json:"-"`
|
||||
RegionString string
|
||||
}
|
||||
|
||||
func (key WorkloadEndpointStatusKey) defaultPath() (string, error) {
|
||||
if key.Hostname == "" {
|
||||
return "", errors.ErrorInsufficientIdentifiers{Name: "hostname"}
|
||||
}
|
||||
if key.OrchestratorID == "" {
|
||||
return "", errors.ErrorInsufficientIdentifiers{Name: "orchestrator"}
|
||||
}
|
||||
if key.WorkloadID == "" {
|
||||
return "", errors.ErrorInsufficientIdentifiers{Name: "workload"}
|
||||
}
|
||||
if key.EndpointID == "" {
|
||||
return "", errors.ErrorInsufficientIdentifiers{Name: "endpoint"}
|
||||
}
|
||||
if key.RegionString == "" {
|
||||
return "", errors.ErrorInsufficientIdentifiers{Name: "regionString"}
|
||||
}
|
||||
if strings.Contains(key.RegionString, "/") {
|
||||
return "", ErrorSlashInRegionString(key.RegionString)
|
||||
}
|
||||
return fmt.Sprintf("/calico/felix/v2/%s/host/%s/workload/%s/%s/endpoint/%s",
|
||||
key.RegionString,
|
||||
key.Hostname, escapeName(key.OrchestratorID), escapeName(key.WorkloadID), escapeName(key.EndpointID)), nil
|
||||
}
|
||||
|
||||
func (key WorkloadEndpointStatusKey) defaultDeletePath() (string, error) {
|
||||
return key.defaultPath()
|
||||
}
|
||||
|
||||
func (key WorkloadEndpointStatusKey) defaultDeleteParentPaths() ([]string, error) {
|
||||
if key.Hostname == "" {
|
||||
return nil, errors.ErrorInsufficientIdentifiers{Name: "hostname"}
|
||||
}
|
||||
if key.OrchestratorID == "" {
|
||||
return nil, errors.ErrorInsufficientIdentifiers{Name: "orchestrator"}
|
||||
}
|
||||
if key.WorkloadID == "" {
|
||||
return nil, errors.ErrorInsufficientIdentifiers{Name: "workload"}
|
||||
}
|
||||
if key.RegionString == "" {
|
||||
return nil, errors.ErrorInsufficientIdentifiers{Name: "regionString"}
|
||||
}
|
||||
if strings.Contains(key.RegionString, "/") {
|
||||
return nil, ErrorSlashInRegionString(key.RegionString)
|
||||
}
|
||||
workload := fmt.Sprintf("/calico/felix/v2/%s/host/%s/workload/%s/%s",
|
||||
key.RegionString,
|
||||
key.Hostname, escapeName(key.OrchestratorID), escapeName(key.WorkloadID))
|
||||
endpoints := workload + "/endpoint"
|
||||
return []string{endpoints, workload}, nil
|
||||
}
|
||||
|
||||
func (key WorkloadEndpointStatusKey) valueType() (reflect.Type, error) {
|
||||
return reflect.TypeOf(WorkloadEndpointStatus{}), nil
|
||||
}
|
||||
|
||||
func (key WorkloadEndpointStatusKey) String() string {
|
||||
return fmt.Sprintf("WorkloadEndpointStatus(hostname=%s, orchestrator=%s, workload=%s, name=%s)",
|
||||
key.Hostname, key.OrchestratorID, key.WorkloadID, key.EndpointID)
|
||||
}
|
||||
|
||||
type WorkloadEndpointStatusListOptions struct {
|
||||
Hostname string
|
||||
OrchestratorID string
|
||||
WorkloadID string
|
||||
EndpointID string
|
||||
RegionString string
|
||||
}
|
||||
|
||||
func (options WorkloadEndpointStatusListOptions) defaultPathRoot() string {
|
||||
k := "/calico/felix/v2/"
|
||||
if options.RegionString == "" {
|
||||
return k
|
||||
}
|
||||
k = k + options.RegionString + "/host"
|
||||
if options.Hostname == "" {
|
||||
return k
|
||||
}
|
||||
k = k + fmt.Sprintf("/%s/workload", options.Hostname)
|
||||
if options.OrchestratorID == "" {
|
||||
return k
|
||||
}
|
||||
k = k + fmt.Sprintf("/%s", escapeName(options.OrchestratorID))
|
||||
if options.WorkloadID == "" {
|
||||
return k
|
||||
}
|
||||
k = k + fmt.Sprintf("/%s/endpoint", escapeName(options.WorkloadID))
|
||||
if options.EndpointID == "" {
|
||||
return k
|
||||
}
|
||||
k = k + fmt.Sprintf("/%s", escapeName(options.EndpointID))
|
||||
return k
|
||||
}
|
||||
|
||||
func (options WorkloadEndpointStatusListOptions) KeyFromDefaultPath(ekey string) Key {
|
||||
log.Debugf("Get WorkloadEndpoint key from %s", ekey)
|
||||
r := matchWorkloadEndpointStatus.FindAllStringSubmatch(ekey, -1)
|
||||
if len(r) != 1 {
|
||||
log.Debugf("Didn't match regex")
|
||||
return nil
|
||||
}
|
||||
regionString := r[0][1]
|
||||
hostname := r[0][2]
|
||||
orchID := unescapeName(r[0][3])
|
||||
workloadID := unescapeName(r[0][4])
|
||||
endpointID := unescapeName(r[0][5])
|
||||
if options.RegionString != "" && regionString != options.RegionString {
|
||||
log.Debugf("Didn't match region %s != %s", options.RegionString, regionString)
|
||||
return nil
|
||||
}
|
||||
if options.Hostname != "" && hostname != options.Hostname {
|
||||
log.Debugf("Didn't match hostname %s != %s", options.Hostname, hostname)
|
||||
return nil
|
||||
}
|
||||
if options.OrchestratorID != "" && orchID != options.OrchestratorID {
|
||||
log.Debugf("Didn't match orchestrator %s != %s", options.OrchestratorID, orchID)
|
||||
return nil
|
||||
}
|
||||
if options.WorkloadID != "" && workloadID != options.WorkloadID {
|
||||
log.Debugf("Didn't match workload %s != %s", options.WorkloadID, workloadID)
|
||||
return nil
|
||||
}
|
||||
if options.EndpointID != "" && endpointID != options.EndpointID {
|
||||
log.Debugf("Didn't match endpoint ID %s != %s", options.EndpointID, endpointID)
|
||||
return nil
|
||||
}
|
||||
return WorkloadEndpointStatusKey{
|
||||
Hostname: hostname,
|
||||
OrchestratorID: orchID,
|
||||
WorkloadID: workloadID,
|
||||
EndpointID: endpointID,
|
||||
RegionString: regionString,
|
||||
}
|
||||
}
|
||||
|
||||
type WorkloadEndpointStatus struct {
|
||||
Status string `json:"status"`
|
||||
}
|
||||
Reference in New Issue
Block a user