Skip to content

Commit

Permalink
Add remaining BGP configuration types
Browse files Browse the repository at this point in the history
  • Loading branch information
Rob Brockbank committed Jul 5, 2017
1 parent bbbeb8a commit 2704959
Show file tree
Hide file tree
Showing 18 changed files with 924 additions and 207 deletions.
239 changes: 206 additions & 33 deletions lib/backend/compat/compat.go

Large diffs are not rendered by default.

92 changes: 62 additions & 30 deletions lib/backend/k8s/k8s.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,15 @@ type KubeClient struct {
converter converter

// Clients for interacting with Calico resources.
globalBgpClient resources.K8sResourceClient
nodeBgpClient resources.K8sResourceClient
globalConfigClient resources.K8sResourceClient
ipPoolClient resources.K8sResourceClient
snpClient resources.K8sResourceClient
nodeClient resources.K8sResourceClient
globalBgpPeerClient resources.K8sResourceClient
nodeBgpPeerClient resources.K8sResourceClient
globalBgpConfigClient resources.K8sResourceClient
nodeBgpConfigClient resources.K8sResourceClient
globalFelixConfigClient resources.K8sResourceClient
nodeFelixConfigClient resources.K8sResourceClient
ipPoolClient resources.K8sResourceClient
snpClient resources.K8sResourceClient
nodeClient resources.K8sResourceClient
}

func NewKubeClient(kc *capi.KubeConfig) (*KubeClient, error) {
Expand Down Expand Up @@ -133,9 +136,11 @@ func NewKubeClient(kc *capi.KubeConfig) (*KubeClient, error) {
kubeClient.ipPoolClient = resources.NewIPPoolClient(cs, tprClientV1)
kubeClient.nodeClient = resources.NewNodeClient(cs, tprClientV1)
kubeClient.snpClient = resources.NewSystemNetworkPolicyClient(cs, tprClientV1alpha)
kubeClient.globalBgpClient = resources.NewGlobalBGPPeerClient(cs, tprClientV1)
kubeClient.nodeBgpClient = resources.NewNodeBGPPeerClient(cs)
kubeClient.globalConfigClient = resources.NewGlobalConfigClient(cs, tprClientV1)
kubeClient.globalBgpPeerClient = resources.NewGlobalBGPPeerClient(cs, tprClientV1)
kubeClient.nodeBgpPeerClient = resources.NewNodeBGPPeerClient(cs)
kubeClient.globalBgpConfigClient = resources.NewGlobalBGPConfigClient(cs, tprClientV1)
kubeClient.nodeBgpConfigClient = resources.NewNodeBGPConfigClient(cs)
kubeClient.globalFelixConfigClient = resources.NewGlobalConfigClient(cs, tprClientV1)

return kubeClient, nil
}
Expand Down Expand Up @@ -183,13 +188,14 @@ func (c *KubeClient) createThirdPartyResources() error {
done := make(chan error)
go func() { done <- c.ipPoolClient.EnsureInitialized() }()
go func() { done <- c.snpClient.EnsureInitialized() }()
go func() { done <- c.globalBgpClient.EnsureInitialized() }()
go func() { done <- c.globalConfigClient.EnsureInitialized() }()
go func() { done <- c.globalBgpPeerClient.EnsureInitialized() }()
go func() { done <- c.globalFelixConfigClient.EnsureInitialized() }()
go func() { done <- c.globalBgpConfigClient.EnsureInitialized() }()

// Wait for all 4 registrations to complete and keep track of the last
// error to return.
var lastErr error
for i := 0; i < 4; i++ {
for i := 0; i < 5; i++ {
if err := <-done; err != nil {
log.WithError(err).Error("Hit error initializing TPR")
lastErr = err
Expand Down Expand Up @@ -318,15 +324,19 @@ func (c *KubeClient) Create(d *model.KVPair) (*model.KVPair, error) {
log.Debugf("Performing 'Create' for %+v", d)
switch d.Key.(type) {
case model.GlobalConfigKey:
return c.globalConfigClient.Create(d)
return c.globalFelixConfigClient.Create(d)
case model.IPPoolKey:
return c.ipPoolClient.Create(d)
case model.NodeKey:
return c.nodeClient.Create(d)
case model.GlobalBGPPeerKey:
return c.globalBgpClient.Create(d)
return c.globalBgpPeerClient.Create(d)
case model.NodeBGPPeerKey:
return c.nodeBgpClient.Create(d)
return c.nodeBgpPeerClient.Create(d)
case model.GlobalBGPConfigKey:
return c.globalBgpConfigClient.Create(d)
case model.NodeBGPConfigKey:
return c.nodeBgpConfigClient.Create(d)
default:
log.Warn("Attempt to 'Create' using kubernetes backend is not supported.")
return nil, errors.ErrorOperationNotSupported{
Expand All @@ -342,15 +352,19 @@ func (c *KubeClient) Update(d *model.KVPair) (*model.KVPair, error) {
log.Debugf("Performing 'Update' for %+v", d)
switch d.Key.(type) {
case model.GlobalConfigKey:
return c.globalConfigClient.Update(d)
return c.globalFelixConfigClient.Update(d)
case model.IPPoolKey:
return c.ipPoolClient.Update(d)
case model.NodeKey:
return c.nodeClient.Update(d)
case model.GlobalBGPPeerKey:
return c.globalBgpClient.Update(d)
return c.globalBgpPeerClient.Update(d)
case model.NodeBGPPeerKey:
return c.nodeBgpClient.Update(d)
return c.nodeBgpPeerClient.Update(d)
case model.GlobalBGPConfigKey:
return c.globalBgpConfigClient.Update(d)
case model.NodeBGPConfigKey:
return c.nodeBgpConfigClient.Update(d)
default:
log.Warn("Attempt to 'Update' using kubernetes backend is not supported.")
return nil, errors.ErrorOperationNotSupported{
Expand All @@ -368,15 +382,19 @@ func (c *KubeClient) Apply(d *model.KVPair) (*model.KVPair, error) {
case model.WorkloadEndpointKey:
return c.applyWorkloadEndpoint(d)
case model.GlobalConfigKey:
return c.globalConfigClient.Apply(d)
return c.globalFelixConfigClient.Apply(d)
case model.IPPoolKey:
return c.ipPoolClient.Apply(d)
case model.NodeKey:
return c.nodeClient.Apply(d)
case model.GlobalBGPPeerKey:
return c.globalBgpClient.Apply(d)
return c.globalBgpPeerClient.Apply(d)
case model.NodeBGPPeerKey:
return c.nodeBgpClient.Apply(d)
return c.nodeBgpPeerClient.Apply(d)
case model.GlobalBGPConfigKey:
return c.globalBgpConfigClient.Apply(d)
case model.NodeBGPConfigKey:
return c.nodeBgpConfigClient.Apply(d)
case model.ActiveStatusReportKey, model.LastStatusReportKey,
model.HostEndpointStatusKey, model.WorkloadEndpointStatusKey:
// Felix periodically reports status to the datastore. This isn't supported
Expand All @@ -397,15 +415,19 @@ func (c *KubeClient) Delete(d *model.KVPair) error {
log.Debugf("Performing 'Delete' for %+v", d)
switch d.Key.(type) {
case model.GlobalConfigKey:
return c.globalConfigClient.Delete(d)
return c.globalFelixConfigClient.Delete(d)
case model.IPPoolKey:
return c.ipPoolClient.Delete(d)
case model.NodeKey:
return c.nodeClient.Delete(d)
case model.GlobalBGPPeerKey:
return c.globalBgpClient.Delete(d)
return c.globalBgpPeerClient.Delete(d)
case model.NodeBGPPeerKey:
return c.nodeBgpClient.Delete(d)
return c.nodeBgpPeerClient.Delete(d)
case model.GlobalBGPConfigKey:
return c.globalBgpConfigClient.Delete(d)
case model.NodeBGPConfigKey:
return c.nodeBgpConfigClient.Delete(d)
default:
log.Warn("Attempt to 'Delete' using kubernetes backend is not supported.")
return errors.ErrorOperationNotSupported{
Expand All @@ -428,17 +450,21 @@ func (c *KubeClient) Get(k model.Key) (*model.KVPair, error) {
case model.HostConfigKey:
return c.getHostConfig(k.(model.HostConfigKey))
case model.GlobalConfigKey:
return c.globalConfigClient.Get(k)
return c.globalFelixConfigClient.Get(k)
case model.ReadyFlagKey:
return c.getReadyStatus(k.(model.ReadyFlagKey))
case model.IPPoolKey:
return c.ipPoolClient.Get(k)
case model.NodeKey:
return c.nodeClient.Get(k.(model.NodeKey))
case model.GlobalBGPPeerKey:
return c.globalBgpClient.Get(k)
return c.globalBgpPeerClient.Get(k)
case model.NodeBGPPeerKey:
return c.nodeBgpClient.Get(k)
return c.nodeBgpPeerClient.Get(k)
case model.GlobalBGPConfigKey:
return c.globalBgpConfigClient.Get(k)
case model.NodeBGPConfigKey:
return c.nodeBgpConfigClient.Get(k)
default:
return nil, errors.ErrorOperationNotSupported{
Identifier: k,
Expand Down Expand Up @@ -467,13 +493,19 @@ func (c *KubeClient) List(l model.ListInterface) ([]*model.KVPair, error) {
k, _, err := c.nodeClient.List(l)
return k, err
case model.GlobalBGPPeerListOptions:
k, _, err := c.globalBgpClient.List(l)
k, _, err := c.globalBgpPeerClient.List(l)
return k, err
case model.NodeBGPPeerListOptions:
k, _, err := c.nodeBgpClient.List(l)
k, _, err := c.nodeBgpPeerClient.List(l)
return k, err
case model.GlobalConfigListOptions:
k, _, err := c.globalConfigClient.List(l)
k, _, err := c.globalFelixConfigClient.List(l)
return k, err
case model.GlobalBGPConfigListOptions:
k, _, err := c.globalBgpConfigClient.List(l)
return k, err
case model.NodeBGPConfigListOptions:
k, _, err := c.nodeBgpConfigClient.List(l)
return k, err
default:
return []*model.KVPair{}, nil
Expand Down
97 changes: 97 additions & 0 deletions lib/backend/k8s/resources/globalbgpconfig.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
// 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 resources

import (
"fmt"
"reflect"
"strings"

"github.com/projectcalico/libcalico-go/lib/backend/k8s/thirdparty"
"github.com/projectcalico/libcalico-go/lib/backend/model"

metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
)

const (
GlobalBgpConfigResourceName = "GlobalBgpConfigs"
GlobalBgpConfigTPRName = "global-bgp-config.projectcalico.org"
)

func NewGlobalBGPConfigClient(c *kubernetes.Clientset, r *rest.RESTClient) K8sResourceClient {
return &customK8sResourceClient{
clientSet: c,
restClient: r,
name: GlobalBgpConfigTPRName,
resource: GlobalBgpConfigResourceName,
description: "Calico Global Configuration",
k8sResourceType: reflect.TypeOf(thirdparty.GlobalBgpConfig{}),
k8sListType: reflect.TypeOf(thirdparty.GlobalBgpConfigList{}),
converter: GlobalBgpConfigConverter{},
}
}

// GlobalBgpConfigConverter implements the K8sResourceConverter interface.
type GlobalBgpConfigConverter struct {
}

func (_ GlobalBgpConfigConverter) ListInterfaceToKey(l model.ListInterface) model.Key {
pl := l.(model.GlobalBGPConfigListOptions)
if pl.Name != "" {
return model.GlobalBGPConfigKey{Name: pl.Name}
}
return nil
}

func (_ GlobalBgpConfigConverter) KeyToName(k model.Key) (string, error) {
return strings.ToLower(k.(model.GlobalBGPConfigKey).Name), nil
}

func (_ GlobalBgpConfigConverter) NameToKey(name string) (model.Key, error) {
return nil, fmt.Errorf("Mapping of Name to Key is not possible for global config")
}

func (c GlobalBgpConfigConverter) ToKVPair(r CustomK8sResource) (*model.KVPair, error) {
t := r.(*thirdparty.GlobalBgpConfig)
return &model.KVPair{
Key: model.GlobalBGPConfigKey{
Name: t.Spec.Name,
},
Value: t.Spec.Value,
Revision: t.Metadata.ResourceVersion,
}, nil
}

func (c GlobalBgpConfigConverter) FromKVPair(kvp *model.KVPair) (CustomK8sResource, error) {
name, err := c.KeyToName(kvp.Key)
if err != nil {
return nil, err
}
tpr := thirdparty.GlobalBgpConfig{
Metadata: metav1.ObjectMeta{
Name: name,
},
Spec: thirdparty.GlobalBgpConfigSpec{
Name: kvp.Key.(model.GlobalBGPConfigKey).Name,
Value: kvp.Value.(string),
},
}
if kvp.Revision != nil {
tpr.Metadata.ResourceVersion = kvp.Revision.(string)
}
return &tpr, nil
}
98 changes: 98 additions & 0 deletions lib/backend/k8s/resources/globalbgpconfig_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
// 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 resources_test

import (
"github.com/projectcalico/libcalico-go/lib/backend/k8s/resources"
"github.com/projectcalico/libcalico-go/lib/backend/k8s/thirdparty"
"github.com/projectcalico/libcalico-go/lib/backend/model"

metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)

var _ = Describe("Global BGP config conversion methods", func() {

converter := resources.GlobalBgpConfigConverter{}

// Define some useful test data.
listIncomplete := model.GlobalBGPConfigListOptions{}

// Compatible set of list, key and name (used for Key to Name conversion)
list1 := model.GlobalBGPConfigListOptions{
Name: "AbCd",
}
key1 := model.GlobalBGPConfigKey{
Name: "AbCd",
}
name1 := "abcd"

// Compatible set of KVPair and Kubernetes Resource.
value1 := "test"
kvp1 := &model.KVPair{
Key: key1,
Value: &value1,
Revision: "rv",
}
res1 := &thirdparty.GlobalBgpConfig{
Metadata: metav1.ObjectMeta{
Name: name1,
ResourceVersion: "rv",
},
Spec: thirdparty.GlobalBgpConfigSpec{
Name: key1.Name,
Value: value1,
},
}

It("should convert an incomplete ListInterface to no Key", func() {
Expect(converter.ListInterfaceToKey(listIncomplete)).To(BeNil())
})

It("should convert a qualified ListInterface to the equivalent Key", func() {
Expect(converter.ListInterfaceToKey(list1)).To(Equal(key1))
})

It("should convert a Key to the equivalent resource name", func() {
n, err := converter.KeyToName(key1)
Expect(err).NotTo(HaveOccurred())
Expect(n).To(Equal(name1))
})

It("should not convert a resource name to the equivalent Key - this is not possible due to case switching", func() {
_, err := converter.NameToKey("test")
Expect(err).To(HaveOccurred())
})

It("should convert between a KVPair and the equivalent Kubernetes resource", func() {
r, err := converter.FromKVPair(kvp1)
Expect(err).NotTo(HaveOccurred())
Expect(r.GetObjectMeta().GetName()).To(Equal(res1.Metadata.Name))
Expect(r.GetObjectMeta().GetResourceVersion()).To(Equal(res1.Metadata.ResourceVersion))
Expect(r).To(BeAssignableToTypeOf(&thirdparty.GlobalBgpConfig{}))
Expect(r.(*thirdparty.GlobalBgpConfig).Spec).To(Equal(res1.Spec))
})

It("should convert between a Kuberenetes resource and the equivalent KVPair", func() {
kvp, err := converter.ToKVPair(res1)
Expect(err).NotTo(HaveOccurred())
Expect(kvp.Key).To(Equal(kvp1.Key))
Expect(kvp.Revision).To(Equal(kvp1.Revision))
Expect(kvp.Value).To(BeAssignableToTypeOf(&value1))
Expect(kvp.Value).To(Equal(kvp1.Value))
})
})
Loading

0 comments on commit 2704959

Please sign in to comment.