Implement render method for clusterctl executor
Change-Id: If3d66baa8eec27f51705c813f17854ad7ef23a26 Signed-off-by: Ruslan Aliev <raliev@mirantis.com>
This commit is contained in:
parent
cc25bcf52e
commit
0f44ad9a7c
@ -15,8 +15,11 @@
|
|||||||
package client
|
package client
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3"
|
||||||
clusterctlclient "sigs.k8s.io/cluster-api/cmd/clusterctl/client"
|
clusterctlclient "sigs.k8s.io/cluster-api/cmd/clusterctl/client"
|
||||||
clusterctlconfig "sigs.k8s.io/cluster-api/cmd/clusterctl/client/config"
|
clusterctlconfig "sigs.k8s.io/cluster-api/cmd/clusterctl/client/config"
|
||||||
|
"sigs.k8s.io/cluster-api/cmd/clusterctl/client/repository"
|
||||||
|
"sigs.k8s.io/cluster-api/cmd/clusterctl/client/yamlprocessor"
|
||||||
clog "sigs.k8s.io/cluster-api/cmd/clusterctl/log"
|
clog "sigs.k8s.io/cluster-api/cmd/clusterctl/log"
|
||||||
|
|
||||||
airshipv1 "opendev.org/airship/airshipctl/pkg/api/v1alpha1"
|
airshipv1 "opendev.org/airship/airshipctl/pkg/api/v1alpha1"
|
||||||
@ -26,11 +29,23 @@ import (
|
|||||||
|
|
||||||
var _ Interface = &Client{}
|
var _ Interface = &Client{}
|
||||||
|
|
||||||
|
const (
|
||||||
|
// BootstrapProviderType is a local copy of appropriate type from cluster-api
|
||||||
|
BootstrapProviderType = v1alpha3.BootstrapProviderType
|
||||||
|
// CoreProviderType is a local copy of appropriate type from cluster-api
|
||||||
|
CoreProviderType = v1alpha3.CoreProviderType
|
||||||
|
// ControlPlaneProviderType is a local copy of appropriate type from cluster-api
|
||||||
|
ControlPlaneProviderType = v1alpha3.ControlPlaneProviderType
|
||||||
|
// InfrastructureProviderType is a local copy of appropriate type from cluster-api
|
||||||
|
InfrastructureProviderType = v1alpha3.InfrastructureProviderType
|
||||||
|
)
|
||||||
|
|
||||||
// Interface is abstraction to Clusterctl
|
// Interface is abstraction to Clusterctl
|
||||||
type Interface interface {
|
type Interface interface {
|
||||||
Init(kubeconfigPath, kubeconfigContext string) error
|
Init(kubeconfigPath, kubeconfigContext string) error
|
||||||
Move(fromKubeconfigPath, fromKubeconfigContext, toKubeconfigPath, toKubeconfigContext, namespace string) error
|
Move(fromKubeconfigPath, fromKubeconfigContext, toKubeconfigPath, toKubeconfigContext, namespace string) error
|
||||||
GetKubeconfig(options *GetKubeconfigOptions) (string, error)
|
GetKubeconfig(options *GetKubeconfigOptions) (string, error)
|
||||||
|
Render(options RenderOptions) ([]byte, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Client Implements interface to Clusterctl
|
// Client Implements interface to Clusterctl
|
||||||
@ -38,6 +53,14 @@ type Client struct {
|
|||||||
clusterctlClient clusterctlclient.Client
|
clusterctlClient clusterctlclient.Client
|
||||||
initOptions clusterctlclient.InitOptions
|
initOptions clusterctlclient.InitOptions
|
||||||
moveOptions clusterctlclient.MoveOptions
|
moveOptions clusterctlclient.MoveOptions
|
||||||
|
repoFactory RepositoryFactory
|
||||||
|
}
|
||||||
|
|
||||||
|
// RenderOptions is used to get providers from RepoFactory for Render method
|
||||||
|
type RenderOptions struct {
|
||||||
|
ProviderName string
|
||||||
|
ProviderVersion string
|
||||||
|
ProviderType string
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetKubeconfigOptions carries all the options to retrieve kubeconfig from parent cluster
|
// GetKubeconfigOptions carries all the options to retrieve kubeconfig from parent cluster
|
||||||
@ -69,11 +92,11 @@ func NewClient(root string, debug bool, options *airshipv1.Clusterctl) (Interfac
|
|||||||
ControlPlaneProviders: initOptions.ControlPlaneProviders,
|
ControlPlaneProviders: initOptions.ControlPlaneProviders,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cclient, err := newClusterctlClient(root, options)
|
cclient, rf, err := newClusterctlClient(root, options)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &Client{clusterctlClient: cclient, initOptions: cio}, nil
|
return &Client{clusterctlClient: cclient, initOptions: cio, repoFactory: rf}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Init implements interface to Clusterctl
|
// Init implements interface to Clusterctl
|
||||||
@ -90,10 +113,6 @@ func (c *Client) Init(kubeconfigPath, kubeconfigContext string) error {
|
|||||||
// newConfig returns clusterctl config client
|
// newConfig returns clusterctl config client
|
||||||
func newConfig(options *airshipv1.Clusterctl, root string) (clusterctlconfig.Client, error) {
|
func newConfig(options *airshipv1.Clusterctl, root string) (clusterctlconfig.Client, error) {
|
||||||
for _, provider := range options.Providers {
|
for _, provider := range options.Providers {
|
||||||
// this is a workaround as clusterctl validates if URL is empty, even though it is not
|
|
||||||
// used anywhere outside repository factory which we override
|
|
||||||
// TODO (kkalynovskyi) we need to create issue for this in clusterctl, and remove URL
|
|
||||||
// validation and move it to be an error during repository interface initialization
|
|
||||||
if !provider.IsClusterctlRepository {
|
if !provider.IsClusterctlRepository {
|
||||||
provider.URL = root
|
provider.URL = root
|
||||||
}
|
}
|
||||||
@ -105,11 +124,13 @@ func newConfig(options *airshipv1.Clusterctl, root string) (clusterctlconfig.Cli
|
|||||||
return clusterctlconfig.New("", clusterctlconfig.InjectReader(reader))
|
return clusterctlconfig.New("", clusterctlconfig.InjectReader(reader))
|
||||||
}
|
}
|
||||||
|
|
||||||
func newClusterctlClient(root string, options *airshipv1.Clusterctl) (clusterctlclient.Client, error) {
|
func newClusterctlClient(root string, options *airshipv1.Clusterctl) (clusterctlclient.Client,
|
||||||
|
RepositoryFactory, error) {
|
||||||
cconf, err := newConfig(options, root)
|
cconf, err := newConfig(options, root)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, RepositoryFactory{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
rf := RepositoryFactory{
|
rf := RepositoryFactory{
|
||||||
Options: options,
|
Options: options,
|
||||||
ConfigClient: cconf,
|
ConfigClient: cconf,
|
||||||
@ -120,7 +141,32 @@ func newClusterctlClient(root string, options *airshipv1.Clusterctl) (clusterctl
|
|||||||
orf := clusterctlclient.InjectRepositoryFactory(rf.ClientRepositoryFactory())
|
orf := clusterctlclient.InjectRepositoryFactory(rf.ClientRepositoryFactory())
|
||||||
// options cluster client factory
|
// options cluster client factory
|
||||||
occf := clusterctlclient.InjectClusterClientFactory(rf.ClusterClientFactory())
|
occf := clusterctlclient.InjectClusterClientFactory(rf.ClusterClientFactory())
|
||||||
return clusterctlclient.New("", ocf, orf, occf)
|
client, err := clusterctlclient.New("", ocf, orf, occf)
|
||||||
|
return client, rf, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render returns requested components as yaml
|
||||||
|
func (c *Client) Render(renderOptions RenderOptions) ([]byte, error) {
|
||||||
|
provider, err := c.repoFactory.ConfigClient.Providers().Get(renderOptions.ProviderName,
|
||||||
|
v1alpha3.ProviderType(renderOptions.ProviderType))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
crf := c.repoFactory.ClientRepositoryFactory()
|
||||||
|
repoClient, err := crf(clusterctlclient.RepositoryClientFactoryInput{
|
||||||
|
Provider: provider,
|
||||||
|
Processor: yamlprocessor.NewSimpleProcessor(),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
components, err := repoClient.Components().Get(repository.ComponentsOptions{Version: renderOptions.ProviderVersion})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return components.Yaml()
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetKubeconfig is a wrapper for related cluster-api function
|
// GetKubeconfig is a wrapper for related cluster-api function
|
||||||
|
@ -15,11 +15,14 @@
|
|||||||
package executors
|
package executors
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"io"
|
"io"
|
||||||
|
"strings"
|
||||||
|
|
||||||
airshipv1 "opendev.org/airship/airshipctl/pkg/api/v1alpha1"
|
airshipv1 "opendev.org/airship/airshipctl/pkg/api/v1alpha1"
|
||||||
"opendev.org/airship/airshipctl/pkg/cluster/clustermap"
|
"opendev.org/airship/airshipctl/pkg/cluster/clustermap"
|
||||||
"opendev.org/airship/airshipctl/pkg/clusterctl/client"
|
"opendev.org/airship/airshipctl/pkg/clusterctl/client"
|
||||||
|
"opendev.org/airship/airshipctl/pkg/document"
|
||||||
"opendev.org/airship/airshipctl/pkg/errors"
|
"opendev.org/airship/airshipctl/pkg/errors"
|
||||||
"opendev.org/airship/airshipctl/pkg/events"
|
"opendev.org/airship/airshipctl/pkg/events"
|
||||||
"opendev.org/airship/airshipctl/pkg/k8s/kubeconfig"
|
"opendev.org/airship/airshipctl/pkg/k8s/kubeconfig"
|
||||||
@ -162,8 +165,44 @@ func (c *ClusterctlExecutor) Validate() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Render executor documents
|
// Render executor documents
|
||||||
func (c *ClusterctlExecutor) Render(w io.Writer, _ ifc.RenderOptions) error {
|
func (c *ClusterctlExecutor) Render(w io.Writer, ro ifc.RenderOptions) error {
|
||||||
// will be implemented later
|
dataAll := bytes.NewBuffer([]byte{})
|
||||||
_, err := w.Write([]byte{})
|
typeMap := map[string][]string{
|
||||||
return err
|
string(client.BootstrapProviderType): c.options.InitOptions.BootstrapProviders,
|
||||||
|
string(client.ControlPlaneProviderType): c.options.InitOptions.ControlPlaneProviders,
|
||||||
|
string(client.InfrastructureProviderType): c.options.InitOptions.InfrastructureProviders,
|
||||||
|
string(client.CoreProviderType): (map[bool][]string{true: {c.options.InitOptions.CoreProvider},
|
||||||
|
false: {}})[c.options.InitOptions.CoreProvider != ""],
|
||||||
|
}
|
||||||
|
for prvType, prvList := range typeMap {
|
||||||
|
for _, prv := range prvList {
|
||||||
|
res := strings.Split(prv, ":")
|
||||||
|
if len(res) != 2 {
|
||||||
|
return ErrUnableParseProvider{
|
||||||
|
Provider: prv,
|
||||||
|
ProviderType: prvType,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
data, err := c.Interface.Render(client.RenderOptions{
|
||||||
|
ProviderName: res[0],
|
||||||
|
ProviderVersion: res[1],
|
||||||
|
ProviderType: prvType,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
dataAll.Write(data)
|
||||||
|
dataAll.Write([]byte("\n---\n"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bundle, err := document.NewBundleFromBytes(dataAll.Bytes())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
filtered, err := bundle.SelectBundle(ro.FilterSelector)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return filtered.Write(w)
|
||||||
}
|
}
|
||||||
|
@ -44,7 +44,7 @@ metadata:
|
|||||||
name: clusterctl-v1
|
name: clusterctl-v1
|
||||||
action: %s
|
action: %s
|
||||||
init-options:
|
init-options:
|
||||||
core-provider: "cluster-api:v0.3.3"
|
core-provider: "cluster-api:v0.3.2"
|
||||||
kubeConfigRef:
|
kubeConfigRef:
|
||||||
apiVersion: airshipit.org/v1alpha1
|
apiVersion: airshipit.org/v1alpha1
|
||||||
kind: KubeConfig
|
kind: KubeConfig
|
||||||
@ -53,7 +53,19 @@ providers:
|
|||||||
- name: "cluster-api"
|
- name: "cluster-api"
|
||||||
type: "CoreProvider"
|
type: "CoreProvider"
|
||||||
versions:
|
versions:
|
||||||
v0.3.3: manifests/function/capi/v0.3.3`
|
v0.3.2: functions/capi/infrastructure/v0.3.2`
|
||||||
|
|
||||||
|
renderedDocs = `---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
cluster.x-k8s.io/provider: cluster-api
|
||||||
|
clusterctl.cluster.x-k8s.io: ""
|
||||||
|
control-plane: controller-manager
|
||||||
|
name: version-two
|
||||||
|
...
|
||||||
|
`
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestNewExecutor(t *testing.T) {
|
func TestNewExecutor(t *testing.T) {
|
||||||
@ -202,6 +214,6 @@ func TestExecutorRender(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
actualOut := &bytes.Buffer{}
|
actualOut := &bytes.Buffer{}
|
||||||
actualErr := executor.Render(actualOut, ifc.RenderOptions{})
|
actualErr := executor.Render(actualOut, ifc.RenderOptions{})
|
||||||
assert.Len(t, actualOut.Bytes(), 0)
|
assert.Equal(t, renderedDocs, actualOut.String())
|
||||||
assert.NoError(t, actualErr)
|
assert.NoError(t, actualErr)
|
||||||
}
|
}
|
||||||
|
@ -47,3 +47,13 @@ type ErrUnknownExecutorName struct {
|
|||||||
func (e ErrUnknownExecutorName) Error() string {
|
func (e ErrUnknownExecutorName) Error() string {
|
||||||
return fmt.Sprintf("unknown executor name '%s'", e.ExecutorName)
|
return fmt.Sprintf("unknown executor name '%s'", e.ExecutorName)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ErrUnableParseProvider is returned when it's impossible to parse provider's name and version
|
||||||
|
type ErrUnableParseProvider struct {
|
||||||
|
Provider string
|
||||||
|
ProviderType string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e ErrUnableParseProvider) Error() string {
|
||||||
|
return fmt.Sprintf("unable to parse name and version of '%s' type, '%s' provider", e.ProviderType, e.Provider)
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user