You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@camel.apache.org by GitBox <gi...@apache.org> on 2018/12/14 13:26:01 UTC

[GitHub] lburgazzoli closed pull request #294: Allow to generate install resources if needed

lburgazzoli closed pull request #294: Allow to generate install resources if needed
URL: https://github.com/apache/camel-k/pull/294
 
 
   

This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:

As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):

diff --git a/pkg/client/cmd/install.go b/pkg/client/cmd/install.go
index 0de2ed21..2100908b 100644
--- a/pkg/client/cmd/install.go
+++ b/pkg/client/cmd/install.go
@@ -19,6 +19,8 @@ package cmd
 
 import (
 	"fmt"
+	"github.com/apache/camel-k/pkg/util/kubernetes"
+
 	"time"
 
 	"github.com/apache/camel-k/pkg/install"
@@ -40,8 +42,10 @@ func newCmdInstall(rootCmdOptions *RootCmdOptions) *cobra.Command {
 	}
 
 	cmd.Flags().BoolVar(&options.clusterSetupOnly, "cluster-setup", false, "Execute cluster-wide operations only (may require admin rights)")
+	cmd.Flags().BoolVar(&options.skipClusterSetup, "skip-cluster-setup", false, "Skip the cluster-setup phase")
 	cmd.Flags().BoolVar(&options.exampleSetup, "example", false, "Install example integration")
 	cmd.Flags().StringVar(&options.registry, "registry", "", "A Docker registry that can be used to publish images")
+	cmd.Flags().StringVarP(&options.outputFormat, "output", "o", "", "Output format. One of: json|yaml")
 	cmd.Flags().StringVar(&options.organization, "organization", "", "A organization on the Docker registry that can be used to publish images")
 	cmd.Flags().StringVar(&options.pushSecret, "push-secret", "", "A secret used to push images to the Docker registry")
 
@@ -51,8 +55,10 @@ func newCmdInstall(rootCmdOptions *RootCmdOptions) *cobra.Command {
 type installCmdOptions struct {
 	*RootCmdOptions
 	clusterSetupOnly bool
+	skipClusterSetup bool
 	exampleSetup     bool
 	registry         string
+	outputFormat     string
 	organization     string
 	pushSecret       string
 }
@@ -61,37 +67,74 @@ func (o *installCmdOptions) install(cmd *cobra.Command, args []string) error {
 	// Let's use a fast refresh period when running with the CLI
 	k8sclient.ResetCacheEvery(8 * time.Second)
 
-	err := install.SetupClusterwideResources()
-	if err != nil && k8serrors.IsForbidden(err) {
-		fmt.Println("Current user is not authorized to create cluster-wide objects like custom resource definitions or cluster roles: ", err)
-		return errors.New("please login as cluster-admin and execute \"kamel install --cluster-setup\" to install cluster-wide " +
-			"resources (one-time operation)")
+	var collection *kubernetes.Collection
+	if o.outputFormat != "" {
+		collection = kubernetes.NewCollection()
+	}
+
+	if !o.skipClusterSetup {
+		err := install.SetupClusterwideResourcesOrCollect(collection)
+		if err != nil && k8serrors.IsForbidden(err) {
+			fmt.Println("Current user is not authorized to create cluster-wide objects like custom resource definitions or cluster roles: ", err)
+			return errors.New("please login as cluster-admin and execute \"kamel install --cluster-setup\" to install cluster-wide resources (one-time operation)")
+		} else if err != nil {
+			return err
+		}
 	}
 
 	if o.clusterSetupOnly {
-		fmt.Println("Camel K cluster setup completed successfully")
+		if collection == nil {
+			fmt.Println("Camel K cluster setup completed successfully")
+		}
 	} else {
 		namespace := o.Namespace
 
-		err = install.Operator(namespace)
+		err := install.OperatorOrCollect(namespace, collection)
 		if err != nil {
 			return err
 		}
 
-		err = install.Platform(namespace, o.registry, o.organization, o.pushSecret)
+		err = install.PlatformOrCollect(namespace, o.registry, o.organization, o.pushSecret, collection)
 		if err != nil {
 			return err
 		}
 
 		if o.exampleSetup {
-			err = install.Example(namespace)
+			err = install.ExampleOrCollect(namespace, collection)
 			if err != nil {
 				return err
 			}
 		}
 
-		fmt.Println("Camel K installed in namespace", namespace)
+		if collection == nil {
+			fmt.Println("Camel K installed in namespace", namespace)
+		}
 	}
 
+	if collection != nil {
+		return o.printOutput(collection)
+	}
+
+	return nil
+}
+
+func (o *installCmdOptions) printOutput(collection *kubernetes.Collection) error {
+	lst := collection.AsKubernetesList()
+	switch o.outputFormat {
+	case "yaml":
+		data, err := kubernetes.ToYAML(lst)
+		if err != nil {
+			return err
+		}
+		fmt.Print(string(data))
+	case "json":
+		data, err := kubernetes.ToJSON(lst)
+		if err != nil {
+			return err
+		}
+		fmt.Print(string(data))
+	default:
+		return errors.New("unknown output format: " + o.outputFormat)
+	}
 	return nil
 }
diff --git a/pkg/client/cmd/run.go b/pkg/client/cmd/run.go
index 6b3bb8b5..de784b9f 100644
--- a/pkg/client/cmd/run.go
+++ b/pkg/client/cmd/run.go
@@ -341,7 +341,6 @@ func (o *runCmdOptions) updateIntegrationCode(sources []string) (*v1alpha1.Integ
 		if err != nil {
 			return nil, err
 		}
-
 		fmt.Print(string(data))
 		return nil, nil
 
diff --git a/pkg/install/cluster.go b/pkg/install/cluster.go
index dea1dee9..314de5ee 100644
--- a/pkg/install/cluster.go
+++ b/pkg/install/cluster.go
@@ -31,19 +31,24 @@ import (
 
 // SetupClusterwideResources --
 func SetupClusterwideResources() error {
+	return SetupClusterwideResourcesOrCollect(nil)
+}
+
+// SetupClusterwideResourcesOrCollect --
+func SetupClusterwideResourcesOrCollect(collection *kubernetes.Collection) error {
 
 	// Install CRD for Integration Platform (if needed)
-	if err := installCRD("IntegrationPlatform", "crd-integration-platform.yaml"); err != nil {
+	if err := installCRD("IntegrationPlatform", "crd-integration-platform.yaml", collection); err != nil {
 		return err
 	}
 
 	// Install CRD for Integration Context (if needed)
-	if err := installCRD("IntegrationContext", "crd-integration-context.yaml"); err != nil {
+	if err := installCRD("IntegrationContext", "crd-integration-context.yaml", collection); err != nil {
 		return err
 	}
 
 	// Install CRD for Integration (if needed)
-	if err := installCRD("Integration", "crd-integration.yaml"); err != nil {
+	if err := installCRD("Integration", "crd-integration.yaml", collection); err != nil {
 		return err
 	}
 
@@ -52,8 +57,8 @@ func SetupClusterwideResources() error {
 	if err != nil {
 		return err
 	}
-	if !clusterRoleInstalled {
-		err := installClusterRole()
+	if !clusterRoleInstalled || collection != nil {
+		err := installClusterRole(collection)
 		if err != nil {
 			return err
 		}
@@ -78,7 +83,17 @@ func IsCRDInstalled(kind string) (bool, error) {
 	return false, nil
 }
 
-func installCRD(kind string, resourceName string) error {
+func installCRD(kind string, resourceName string, collection *kubernetes.Collection) error {
+	crd := []byte(deploy.Resources[resourceName])
+	if collection != nil {
+		unstr, err := kubernetes.LoadRawResourceFromYaml(string(crd))
+		if err != nil {
+			return err
+		}
+		collection.Add(unstr)
+		return nil
+	}
+
 	// Installing Integration CRD
 	installed, err := IsCRDInstalled(kind)
 	if err != nil {
@@ -88,7 +103,6 @@ func installCRD(kind string, resourceName string) error {
 		return nil
 	}
 
-	crd := []byte(deploy.Resources[resourceName])
 	crdJSON, err := yaml.ToJSON(crd)
 	if err != nil {
 		return err
@@ -131,11 +145,15 @@ func IsClusterRoleInstalled() (bool, error) {
 	return true, nil
 }
 
-func installClusterRole() error {
+func installClusterRole(collection *kubernetes.Collection) error {
 	obj, err := kubernetes.LoadResourceFromYaml(deploy.Resources["user-cluster-role.yaml"])
 	if err != nil {
 		return err
 	}
 
+	if collection != nil {
+		collection.Add(obj)
+		return nil
+	}
 	return sdk.Create(obj)
 }
diff --git a/pkg/install/common.go b/pkg/install/common.go
index 6d7c61fe..ea11af12 100644
--- a/pkg/install/common.go
+++ b/pkg/install/common.go
@@ -29,8 +29,12 @@ import (
 
 // Resources installs named resources from the project resource directory
 func Resources(namespace string, names ...string) error {
+	return ResourcesOrCollect(namespace, nil, names...)
+}
+
+func ResourcesOrCollect(namespace string, collection *kubernetes.Collection, names ...string) error {
 	for _, name := range names {
-		if err := Resource(namespace, name); err != nil {
+		if err := ResourceOrCollect(namespace, collection, name); err != nil {
 			return err
 		}
 	}
@@ -39,16 +43,30 @@ func Resources(namespace string, names ...string) error {
 
 // Resource installs a single named resource from the project resource directory
 func Resource(namespace string, name string) error {
+	return ResourceOrCollect(namespace, nil, name)
+}
+
+func ResourceOrCollect(namespace string, collection *kubernetes.Collection, name string) error {
 	obj, err := kubernetes.LoadResourceFromYaml(deploy.Resources[name])
 	if err != nil {
 		return err
 	}
 
-	return RuntimeObject(namespace, obj)
+	return RuntimeObjectOrCollect(namespace, collection, obj)
 }
 
 // RuntimeObject installs a single runtime object
 func RuntimeObject(namespace string, obj runtime.Object) error {
+	return RuntimeObjectOrCollect(namespace, nil, obj)
+}
+
+func RuntimeObjectOrCollect(namespace string, collection *kubernetes.Collection, obj runtime.Object) error {
+	if collection != nil {
+		// Adding to the collection before setting the namespace
+		collection.Add(obj)
+		return nil
+	}
+
 	if metaObject, ok := obj.(metav1.Object); ok {
 		metaObject.SetNamespace(namespace)
 	}
diff --git a/pkg/install/operator.go b/pkg/install/operator.go
index 147bbb52..953625f5 100644
--- a/pkg/install/operator.go
+++ b/pkg/install/operator.go
@@ -31,18 +31,23 @@ import (
 	"github.com/operator-framework/operator-sdk/pkg/sdk"
 )
 
-// Operator --
+// Operator installs the operator resources in the given namespace
 func Operator(namespace string) error {
+	return OperatorOrCollect(namespace, nil)
+}
+
+// OperatorOrCollect installs the operator resources or adds them to the collector if present
+func OperatorOrCollect(namespace string, collection *kubernetes.Collection) error {
 	isOpenshift, err := openshift.IsOpenShift()
 	if err != nil {
 		return err
 	}
 	if isOpenshift {
-		if err := installOpenshift(namespace); err != nil {
+		if err := installOpenshift(namespace, collection); err != nil {
 			return err
 		}
 	} else {
-		if err := installKubernetes(namespace); err != nil {
+		if err := installKubernetes(namespace, collection); err != nil {
 			return err
 		}
 	}
@@ -52,13 +57,13 @@ func Operator(namespace string) error {
 		return err
 	}
 	if isKnative {
-		return installKnative(namespace)
+		return installKnative(namespace, collection)
 	}
 	return nil
 }
 
-func installOpenshift(namespace string) error {
-	return Resources(namespace,
+func installOpenshift(namespace string, collection *kubernetes.Collection) error {
+	return ResourcesOrCollect(namespace, collection,
 		"operator-service-account.yaml",
 		"operator-role-openshift.yaml",
 		"operator-role-binding.yaml",
@@ -67,8 +72,8 @@ func installOpenshift(namespace string) error {
 	)
 }
 
-func installKubernetes(namespace string) error {
-	return Resources(namespace,
+func installKubernetes(namespace string, collection *kubernetes.Collection) error {
+	return ResourcesOrCollect(namespace, collection,
 		"operator-service-account.yaml",
 		"operator-role-kubernetes.yaml",
 		"operator-role-binding.yaml",
@@ -78,8 +83,8 @@ func installKubernetes(namespace string) error {
 	)
 }
 
-func installKnative(namespace string) error {
-	return Resources(namespace,
+func installKnative(namespace string, collection *kubernetes.Collection) error {
+	return ResourcesOrCollect(namespace, collection,
 		"operator-role-knative.yaml",
 		"operator-role-binding-knative.yaml",
 	)
@@ -87,6 +92,11 @@ func installKnative(namespace string) error {
 
 // Platform installs the platform custom resource
 func Platform(namespace string, registry string, organization string, pushSecret string) error {
+	return PlatformOrCollect(namespace, registry, organization, pushSecret, nil)
+}
+
+// PlatformOrCollect --
+func PlatformOrCollect(namespace string, registry string, organization string, pushSecret string, collection *kubernetes.Collection) error {
 	if err := waitForPlatformCRDAvailable(namespace, 25*time.Second); err != nil {
 		return err
 	}
@@ -127,7 +137,7 @@ func Platform(namespace string, registry string, organization string, pushSecret
 		pl.Spec.Profile = v1alpha1.TraitProfileKnative
 	}
 
-	return RuntimeObject(namespace, pl)
+	return RuntimeObjectOrCollect(namespace, collection, pl)
 }
 
 func waitForPlatformCRDAvailable(namespace string, timeout time.Duration) error {
@@ -146,7 +156,12 @@ func waitForPlatformCRDAvailable(namespace string, timeout time.Duration) error
 
 // Example --
 func Example(namespace string) error {
-	return Resources(namespace,
+	return ExampleOrCollect(namespace, nil)
+}
+
+// ExampleOrCollect --
+func ExampleOrCollect(namespace string, collection *kubernetes.Collection) error {
+	return ResourcesOrCollect(namespace, collection,
 		"cr-example.yaml",
 	)
 }
diff --git a/pkg/util/kubernetes/collection.go b/pkg/util/kubernetes/collection.go
index 46655757..54b340bd 100644
--- a/pkg/util/kubernetes/collection.go
+++ b/pkg/util/kubernetes/collection.go
@@ -48,6 +48,24 @@ func (c *Collection) Items() []runtime.Object {
 	return c.items
 }
 
+// AsKubernetesList returns all resources wrapped in a Kubernetes list
+func (c *Collection) AsKubernetesList() *corev1.List {
+	lst := corev1.List{
+		TypeMeta: metav1.TypeMeta{
+			Kind: "List",
+			APIVersion: "v1",
+		},
+		Items: make([]runtime.RawExtension, 0, len(c.items)),
+	}
+	for _, res := range c.items {
+		raw := runtime.RawExtension{
+			Object: res,
+		}
+		lst.Items = append(lst.Items, raw)
+	}
+	return &lst
+}
+
 // Add adds a resource to the collection
 func (c *Collection) Add(resource runtime.Object) {
 	c.items = append(c.items, resource)
diff --git a/pkg/util/kubernetes/loader.go b/pkg/util/kubernetes/loader.go
index fdc1fb88..cd830da3 100644
--- a/pkg/util/kubernetes/loader.go
+++ b/pkg/util/kubernetes/loader.go
@@ -18,6 +18,7 @@ limitations under the License.
 package kubernetes
 
 import (
+	"encoding/json"
 	"github.com/operator-framework/operator-sdk/pkg/util/k8sutil"
 	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
 	"k8s.io/apimachinery/pkg/runtime"
@@ -26,16 +27,32 @@ import (
 
 // LoadResourceFromYaml loads a k8s resource from a yaml definition
 func LoadResourceFromYaml(data string) (runtime.Object, error) {
-	role := []byte(data)
-	roleJSON, err := yaml.ToJSON(role)
+	source := []byte(data)
+	jsonSource, err := yaml.ToJSON(source)
 	if err != nil {
 		return nil, err
 	}
 	u := unstructured.Unstructured{}
-	err = u.UnmarshalJSON(roleJSON)
+	err = u.UnmarshalJSON(jsonSource)
 	if err != nil {
 		return nil, err
 	}
 
 	return k8sutil.RuntimeObjectFromUnstructured(&u)
 }
+
+// LoadRawResourceFromYaml loads a k8s resource from a yaml definition without making assumptions on the underlying type
+func LoadRawResourceFromYaml(data string) (runtime.Object, error) {
+	source := []byte(data)
+	jsonSource, err := yaml.ToJSON(source)
+	if err != nil {
+		return nil, err
+	}
+	var objmap map[string]interface{}
+	if err = json.Unmarshal(jsonSource, &objmap); err != nil {
+		return nil, err
+	}
+	return &unstructured.Unstructured{
+		Object: objmap,
+	}, nil
+}


 

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services