Add the dynamic kubernetes client
The dynamic client will be needed to interact with any custom resource that airshipctl doesn't know about. It will be required for checking the health of a cluster, as well as any other operations that may need to be performed on generic objects. This also adds the pkg/k8s/client/fake package, which can be used to create a mock instance of a client for use in unit tests. Change-Id: Ia331ff4875a067045f6f9245daee109126fb1d33 Relates-To: #73 Relates-To: #20
This commit is contained in:
parent
906c2b2ec2
commit
ea9fba7278
@ -8,24 +8,15 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"k8s.io/client-go/kubernetes"
|
||||
|
||||
"opendev.org/airship/airshipctl/pkg/cluster/initinfra"
|
||||
"opendev.org/airship/airshipctl/pkg/document"
|
||||
"opendev.org/airship/airshipctl/pkg/environment"
|
||||
"opendev.org/airship/airshipctl/pkg/k8s/client"
|
||||
"opendev.org/airship/airshipctl/pkg/k8s/client/fake"
|
||||
"opendev.org/airship/airshipctl/pkg/k8s/kubectl"
|
||||
"opendev.org/airship/airshipctl/testutil/k8sutils"
|
||||
)
|
||||
|
||||
type TestClient struct {
|
||||
MockKubectl func() kubectl.Interface
|
||||
MockClientset func() kubernetes.Interface
|
||||
}
|
||||
|
||||
func (tc TestClient) ClientSet() kubernetes.Interface { return tc.MockClientset() }
|
||||
func (tc TestClient) Kubectl() kubectl.Interface { return tc.MockKubectl() }
|
||||
|
||||
const (
|
||||
kubeconfigPath = "testdata/kubeconfig.yaml"
|
||||
filenameRC = "testdata/primary/site/test-site/ephemeral/initinfra/replicationcontroller.yaml"
|
||||
@ -55,7 +46,7 @@ func TestDeploy(t *testing.T) {
|
||||
infra.FileSystem = document.NewDocumentFs()
|
||||
|
||||
kctl := kubectl.NewKubectl(tf)
|
||||
tc := TestClient{
|
||||
tc := fake.Client{
|
||||
MockKubectl: func() kubectl.Interface { return kctl },
|
||||
}
|
||||
|
||||
@ -66,7 +57,7 @@ func TestDeploy(t *testing.T) {
|
||||
expectedError error
|
||||
}{
|
||||
{
|
||||
client: TestClient{
|
||||
client: fake.Client{
|
||||
MockKubectl: func() kubectl.Interface {
|
||||
return kubectl.NewKubectl(k8sutils.
|
||||
NewMockKubectlFactory().
|
||||
|
@ -3,6 +3,7 @@ package client
|
||||
import (
|
||||
"path/filepath"
|
||||
|
||||
"k8s.io/client-go/dynamic"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
|
||||
"opendev.org/airship/airshipctl/pkg/environment"
|
||||
@ -15,25 +16,72 @@ const (
|
||||
buffDir = ".airship"
|
||||
)
|
||||
|
||||
// Interface provides an abstraction layer to interactions
|
||||
// with kubernetes clusters by getting Clientset which includes
|
||||
// all kubernetes core objects with standard operations and kubectl
|
||||
// interface that is built on top of kubectl libraries and implements
|
||||
// such kubectl subcommands as kubectl apply (more will be added)
|
||||
// Interface provides an abstraction layer to interactions with kubernetes
|
||||
// clusters by providing a ClientSet which includes all kubernetes core objects
|
||||
// with standard operations, a DynamicClient which provides interactions with
|
||||
// loosely typed kubernetes resources, and a Kubectl interface that is built on
|
||||
// top of kubectl libraries and implements such kubectl subcommands as kubectl
|
||||
// apply (more will be added)
|
||||
type Interface interface {
|
||||
ClientSet() kubernetes.Interface
|
||||
DynamicClient() dynamic.Interface
|
||||
|
||||
Kubectl() kubectl.Interface
|
||||
}
|
||||
|
||||
// Client is implementation of Cluster interface
|
||||
// Client is an implementation of Interface
|
||||
type Client struct {
|
||||
kubectl kubectl.Interface
|
||||
clientset kubernetes.Interface
|
||||
clientSet kubernetes.Interface
|
||||
dynamicClient dynamic.Interface
|
||||
|
||||
kubectl kubectl.Interface
|
||||
}
|
||||
|
||||
// ClientSet getter for Clientset interface
|
||||
// Client implements Interface
|
||||
var _ Interface = &Client{}
|
||||
|
||||
// NewClient returns Cluster interface with Kubectl
|
||||
// and ClientSet interfaces initialized
|
||||
func NewClient(settings *environment.AirshipCTLSettings) (Interface, error) {
|
||||
client := new(Client)
|
||||
var err error
|
||||
|
||||
f := k8sutils.FactoryFromKubeconfigPath(settings.KubeConfigPath())
|
||||
|
||||
pathToBufferDir := filepath.Join(filepath.Dir(settings.AirshipConfigPath()), buffDir)
|
||||
client.kubectl = kubectl.NewKubectl(f).WithBufferDir(pathToBufferDir)
|
||||
|
||||
client.clientSet, err = f.KubernetesClientSet()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
client.dynamicClient, err = f.DynamicClient()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return client, nil
|
||||
}
|
||||
|
||||
// ClientSet getter for ClientSet interface
|
||||
func (c *Client) ClientSet() kubernetes.Interface {
|
||||
return c.clientset
|
||||
return c.clientSet
|
||||
}
|
||||
|
||||
// SetClientSet setter for ClientSet interface
|
||||
func (c *Client) SetClientSet(clientSet kubernetes.Interface) {
|
||||
c.clientSet = clientSet
|
||||
}
|
||||
|
||||
// DynamicClient getter for DynamicClient interface
|
||||
func (c *Client) DynamicClient() dynamic.Interface {
|
||||
return c.dynamicClient
|
||||
}
|
||||
|
||||
// SetDynamicClient setter for DynamicClient interface
|
||||
func (c *Client) SetDynamicClient(dynamicClient dynamic.Interface) {
|
||||
c.dynamicClient = dynamicClient
|
||||
}
|
||||
|
||||
// Kubectl getter for Kubectl interface
|
||||
@ -41,27 +89,6 @@ func (c *Client) Kubectl() kubectl.Interface {
|
||||
return c.kubectl
|
||||
}
|
||||
|
||||
// NewClient returns Cluster interface with Kubectl
|
||||
// and Clientset interfaces initialized
|
||||
func NewClient(as *environment.AirshipCTLSettings) (Interface, error) {
|
||||
f := k8sutils.FactoryFromKubeconfigPath(as.KubeConfigPath())
|
||||
kctl := kubectl.NewKubectl(f).
|
||||
WithBufferDir(filepath.Dir(as.AirshipConfigPath()) + buffDir)
|
||||
clientSet, err := f.KubernetesClientSet()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
client := &Client{}
|
||||
client.SetClientset(clientSet)
|
||||
client.SetKubectl(kctl)
|
||||
return client, nil
|
||||
}
|
||||
|
||||
// SetClientset setter for Clientset interface
|
||||
func (c *Client) SetClientset(cs kubernetes.Interface) {
|
||||
c.clientset = cs
|
||||
}
|
||||
|
||||
// SetKubectl setter for Kubectl interface
|
||||
func (c *Client) SetKubectl(kctl kubectl.Interface) {
|
||||
c.kubectl = kctl
|
||||
|
62
pkg/k8s/client/fake/fake.go
Normal file
62
pkg/k8s/client/fake/fake.go
Normal file
@ -0,0 +1,62 @@
|
||||
package fake
|
||||
|
||||
import (
|
||||
"k8s.io/client-go/dynamic"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
|
||||
"opendev.org/airship/airshipctl/pkg/k8s/client"
|
||||
"opendev.org/airship/airshipctl/pkg/k8s/kubectl"
|
||||
)
|
||||
|
||||
// Client is an implementation of client.Interface meant for testing purposes.
|
||||
// Its member methods are intended to be implemented on a case-by-case basis
|
||||
// per test. Examples of implementations can be found with each interface
|
||||
// method.
|
||||
type Client struct {
|
||||
MockClientSet func() kubernetes.Interface
|
||||
MockDynamicClient func() dynamic.Interface
|
||||
MockKubectl func() kubectl.Interface
|
||||
}
|
||||
|
||||
var _ client.Interface = &Client{}
|
||||
|
||||
// ClientSet is used to get a mocked implementation of a kubernetes clientset.
|
||||
// To initialize the mocked clientset to be returned, the MockClientSet method
|
||||
// must be implemented, ideally returning a k8s.io/client-go/kubernetes/fake.Clientset.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// testClient := fake.Client {
|
||||
// MockClientSet: func() kubernetes.Interface {
|
||||
// return kubernetes_fake.NewSimpleClientset()
|
||||
// },
|
||||
// }
|
||||
func (c Client) ClientSet() kubernetes.Interface {
|
||||
return c.MockClientSet()
|
||||
}
|
||||
|
||||
// DynamicClient is used to get a mocked implementation of a dynamic client.
|
||||
// To initialize the mocked client to be returned, the MockDynamicClient method
|
||||
// must be implemented, ideally returning a k8s.io/client-go/dynamic/fake.FakeDynamicClient.
|
||||
//
|
||||
// Example:
|
||||
// Here, scheme is a k8s.io/apimachinery/pkg/runtime.Scheme, possibly created
|
||||
// via runtime.NewScheme()
|
||||
//
|
||||
// testClient := fake.Client {
|
||||
// MockDynamicClient: func() dynamic.Interface {
|
||||
// return dynamic_fake.NewSimpleDynamicClient(scheme)
|
||||
// },
|
||||
// }
|
||||
func (c Client) DynamicClient() dynamic.Interface {
|
||||
return c.MockDynamicClient()
|
||||
}
|
||||
|
||||
// Kubectl is used to get a mocked implementation of a Kubectl client.
|
||||
// To initialize the mocked client to be returned, the MockKubectl method
|
||||
// must be implemented.
|
||||
//
|
||||
// Example: TODO(howell)
|
||||
func (c Client) Kubectl() kubectl.Interface {
|
||||
return c.MockKubectl()
|
||||
}
|
Loading…
Reference in New Issue
Block a user