Skip to content

Commit

Permalink
refactoring for easy unit-test and cm-cli integration
Browse files Browse the repository at this point in the history
Signed-off-by: Dominique Vernier <[email protected]>
  • Loading branch information
itdove committed Jun 4, 2021
1 parent d6a8ab1 commit f99a6d5
Show file tree
Hide file tree
Showing 19 changed files with 209 additions and 61 deletions.
2 changes: 1 addition & 1 deletion VERSION.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.0.1
0.0.2
4 changes: 0 additions & 4 deletions pkg/cmd/accept/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,6 @@ var example = `
%[1]s accept --clusters <cluster_1>,<cluster_2>,...
`

const (
scenarioDirectory = "accept"
)

// NewCmd ...
func NewCmd(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra.Command {
o := newOptions(f, streams)
Expand Down
4 changes: 0 additions & 4 deletions pkg/cmd/init/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,6 @@ var example = `
%[1]s init
`

const (
scenarioDirectory = "init"
)

// NewCmd ...
func NewCmd(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra.Command {
o := newOptions(f, streams)
Expand Down
12 changes: 9 additions & 3 deletions pkg/cmd/init/exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@ package init

import (
"fmt"
"time"

"github.com/openshift/library-go/pkg/operator/resource/resourceapply"
"open-cluster-management.io/clusteradm/pkg/cmd/init/scenario"
"open-cluster-management.io/clusteradm/pkg/helpers"
"open-cluster-management.io/clusteradm/pkg/helpers/apply"

"github.com/spf13/cobra"

Expand Down Expand Up @@ -61,17 +63,21 @@ func (o *Options) run() error {
"init/service_account.yaml",
}

err = helpers.ApplyDirectly(clientHolder, reader, scenarioDirectory, o.values, files...)
err = apply.ApplyDirectly(clientHolder, reader, o.values, "", files...)
if err != nil {
return err
}

err = helpers.ApplyDeployment(kubeClient, reader, scenarioDirectory, o.values, "init/operator.yaml")
err = apply.ApplyDeployment(kubeClient, reader, o.values, "", "init/operator.yaml")
if err != nil {
return err
}
//quick fix for https://github.com/open-cluster-management-io/clusteradm/issues/12
fmt.Printf("Wait 10 sec... for the crd to be effective\n")
time.Sleep(10 * time.Second)

discoveryClient := discovery.NewDiscoveryClientForConfigOrDie(restConfig)
err = helpers.ApplyCustomResouces(dynamicClient, discoveryClient, reader, scenarioDirectory, o.values, "init/clustermanagers.cr.yaml")
err = apply.ApplyCustomResouces(dynamicClient, discoveryClient, reader, o.values, "", "init/clustermanagers.cr.yaml")
if err != nil {
return err
}
Expand Down
6 changes: 3 additions & 3 deletions pkg/cmd/init/scenario/resources.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ package scenario
import (
"embed"

"open-cluster-management.io/clusteradm/pkg/helpers"
"open-cluster-management.io/clusteradm/pkg/helpers/asset"
)

//go:embed init
var files embed.FS

func GetScenarioResourcesReader() *helpers.ScenarioResourcesReader {
return helpers.NewScenarioResourcesReader(&files)
func GetScenarioResourcesReader() *asset.ScenarioResourcesReader {
return asset.NewScenarioResourcesReader(&files)
}
4 changes: 0 additions & 4 deletions pkg/cmd/join/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,6 @@ var example = `
%[1]s join --hub-token <tokenID.tokenSecret> --hub-apiserver <hub_apiserveR_url> --name <cluster_name>
`

const (
scenarioDirectory = "join"
)

// NewCmd ...
func NewCmd(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra.Command {
o := newOptions(f, streams)
Expand Down
12 changes: 9 additions & 3 deletions pkg/cmd/join/exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package join

import (
"fmt"
"time"

"github.com/ghodss/yaml"
"github.com/openshift/library-go/pkg/operator/resource/resourceapply"
Expand All @@ -14,6 +15,7 @@ import (
clientcmdapiv1 "k8s.io/client-go/tools/clientcmd/api/v1"
"open-cluster-management.io/clusteradm/pkg/cmd/join/scenario"
"open-cluster-management.io/clusteradm/pkg/helpers"
"open-cluster-management.io/clusteradm/pkg/helpers/apply"

"github.com/spf13/cobra"
)
Expand Down Expand Up @@ -90,18 +92,22 @@ func (o *Options) run() error {
"join/service_account.yaml",
}

err = helpers.ApplyDirectly(clientHolder, reader, scenarioDirectory, o.values, files...)
err = apply.ApplyDirectly(clientHolder, reader, o.values, "", files...)
if err != nil {
return err
}

err = helpers.ApplyDeployment(kubeClient, reader, scenarioDirectory, o.values, "join/operator.yaml")
err = apply.ApplyDeployment(kubeClient, reader, o.values, "", "join/operator.yaml")
if err != nil {
return err
}

//quick fix for https://github.com/open-cluster-management-io/clusteradm/issues/12
fmt.Printf("Wait 10 sec... for the crd to be effective\n")
time.Sleep(10 * time.Second)

discoveryClient := discovery.NewDiscoveryClientForConfigOrDie(restConfig)
err = helpers.ApplyCustomResouces(dynamicClient, discoveryClient, reader, scenarioDirectory, o.values, "join/klusterlets.cr.yaml")
err = apply.ApplyCustomResouces(dynamicClient, discoveryClient, reader, o.values, "", "join/klusterlets.cr.yaml")
if err != nil {
return err
}
Expand Down
6 changes: 3 additions & 3 deletions pkg/cmd/join/scenario/resources.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ package scenario
import (
"embed"

"open-cluster-management.io/clusteradm/pkg/helpers"
"open-cluster-management.io/clusteradm/pkg/helpers/asset"
)

//go:embed join
var files embed.FS

func GetScenarioResourcesReader() *helpers.ScenarioResourcesReader {
return helpers.NewScenarioResourcesReader(&files)
func GetScenarioResourcesReader() *asset.ScenarioResourcesReader {
return asset.NewScenarioResourcesReader(&files)
}
93 changes: 61 additions & 32 deletions pkg/helpers/apply.go → pkg/helpers/apply/apply.go
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
// Copyright Contributors to the Open Cluster Management project
package helpers
package apply

import (
"bytes"
"context"
"fmt"
"regexp"
"strings"
"text/template"

"github.com/Masterminds/sprig"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"open-cluster-management.io/clusteradm/pkg/helpers"
"open-cluster-management.io/clusteradm/pkg/helpers/asset"

appsv1 "k8s.io/api/apps/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
Expand All @@ -27,6 +30,10 @@ import (
"github.com/openshift/library-go/pkg/operator/resource/resourceapply"
)

const (
ErrorEmptyAssetAfterTemplating = "ERROR_EMPTY_ASSET_AFTER_TEMPLATING"
)

var (
genericScheme = runtime.NewScheme()
genericCodecs = serializer.NewCodecFactory(genericScheme)
Expand All @@ -35,15 +42,18 @@ var (

func ApplyDeployment(
client kubernetes.Interface,
reader ScenarioReader,
templateName string,
reader asset.ScenarioReader,
values interface{},
headerFile string,
files ...string) error {
genericScheme.AddKnownTypes(appsv1.SchemeGroupVersion, &appsv1.Deployment{})
recorder := events.NewInMemoryRecorder(GetExampleHeader())
recorder := events.NewInMemoryRecorder(helpers.GetExampleHeader())
for _, name := range files {
deploymentBytes, err := MustTempalteAsset(name, templateName, reader, values)
deploymentBytes, err := MustTempalteAsset(name, headerFile, reader, values)
if err != nil {
if IsEmptyAsset(err) {
continue
}
return err
}
deployment, sch, err := genericCodec.Decode(deploymentBytes, nil, nil)
Expand All @@ -62,16 +72,16 @@ func ApplyDeployment(
}

func ApplyDirectly(clients *resourceapply.ClientHolder,
reader ScenarioReader,
templateName string,
reader asset.ScenarioReader,
values interface{},
headerFile string,
files ...string) error {
recorder := events.NewInMemoryRecorder(GetExampleHeader())
recorder := events.NewInMemoryRecorder(helpers.GetExampleHeader())
resourceResults := resourceapply.ApplyDirectly(clients, recorder, func(name string) ([]byte, error) {
return MustTempalteAsset(name, templateName, reader, values)
return MustTempalteAsset(name, headerFile, reader, values)
}, files...)
for _, result := range resourceResults {
if result.Error != nil {
if result.Error != nil && !IsEmptyAsset(result.Error) {
return fmt.Errorf("%q (%T): %v", result.File, result.Type, result.Error)
}
}
Expand All @@ -80,13 +90,16 @@ func ApplyDirectly(clients *resourceapply.ClientHolder,

func ApplyCustomResouces(client dynamic.Interface,
discoveryClient discovery.DiscoveryInterface,
reader ScenarioReader,
templateName string,
reader asset.ScenarioReader,
values interface{},
headerFile string,
files ...string) error {
for _, name := range files {
asset, err := MustTempalteAsset(name, templateName, reader, values)
asset, err := MustTempalteAsset(name, headerFile, reader, values)
if err != nil {
if IsEmptyAsset(err) {
continue
}
return err
}
u, err := bytesToUnstructured(reader, asset)
Expand Down Expand Up @@ -122,18 +135,7 @@ func ApplyCustomResouces(client dynamic.Interface,
return nil
}

func getResource(kind string) (string, error) {
switch kind {
case "ClusterManager":
return "clustermanagers", nil
case "Klusterlet":
return "klusterlets", nil
default:
return "", fmt.Errorf("kind: %s not supported", kind)
}
}

func bytesToUnstructured(reader ScenarioReader, asset []byte) (*unstructured.Unstructured, error) {
func bytesToUnstructured(reader asset.ScenarioReader, asset []byte) (*unstructured.Unstructured, error) {
j, err := reader.ToJSON(asset)
if err != nil {
return nil, err
Expand All @@ -159,8 +161,18 @@ func getTemplate(templateName string) *template.Template {
return tmpl
}

func MustTempalteAsset(name, templateName string, reader ScenarioReader, values interface{}) ([]byte, error) {
tmpl := getTemplate(templateName)
//MustTempalteAsset generates textual output for an file name.
//If a headerFile is specified it will be added as a header of the file.
func MustTempalteAsset(name, headerFile string, reader asset.ScenarioReader, values interface{}) ([]byte, error) {
tmpl := getTemplate(name)
h := []byte{}
var err error
if headerFile != "" {
h, err = reader.Asset(headerFile)
if err != nil {
return nil, err
}
}
b, err := reader.Asset(name)
if err != nil {
return nil, err
Expand All @@ -170,17 +182,34 @@ func MustTempalteAsset(name, templateName string, reader ScenarioReader, values
if err != nil {
return nil, err
}
tmplParsed, err = tmplParsed.Parse(string(h))
if err != nil {
return nil, err
}

err = tmplParsed.Execute(&buf, values)
if err != nil {
return nil, err
}

// recorder.Eventf("templated:\n%s\n---", buf.String())
trim := strings.TrimSuffix(buf.String(), "\n")
trim = strings.TrimSpace(trim)
if len(trim) == 0 {
return nil, nil
if isEmpty(buf.Bytes()) {
return nil, fmt.Errorf("asset %s becomes %s", name, ErrorEmptyAssetAfterTemplating)
}

return buf.Bytes(), nil
}

func isEmpty(body []byte) bool {
//Remove comments
re := regexp.MustCompile("#.*")
bodyNoComment := re.ReplaceAll(body, nil)
//Remove blank lines
trim := strings.TrimSuffix(string(bodyNoComment), "\n")
trim = strings.TrimSpace(trim)

return len(trim) == 0
}

func IsEmptyAsset(err error) bool {
return strings.Contains(err.Error(), ErrorEmptyAssetAfterTemplating)
}
Loading

0 comments on commit f99a6d5

Please sign in to comment.