lburgazzoli closed pull request #6: Adding install and get commands
URL: https://github.com/apache/camel-k/pull/6
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/build/Makefile b/build/Makefile
index d8d2b7a..eb1a16c 100644
--- a/build/Makefile
+++ b/build/Makefile
@@ -1,6 +1,6 @@
VERSION := $(shell ./build/get_version.sh)
-build: build-runtime build-operator build-kamel
+build: build-runtime build-embed-resources build-operator build-kamel
build-operator:
go build -o camel-k-operator ./cmd/camel-k-operator/*.go
@@ -8,6 +8,9 @@ build-operator:
build-kamel:
go build -o kamel ./cmd/kamel/*.go
+build-embed-resources:
+ ./build/embed_resources.sh deploy
+
build-runtime:
mvn clean install -f ./runtime/pom.xml
diff --git a/build/embed_resources.sh b/build/embed_resources.sh
new file mode 100755
index 0000000..3ca6385
--- /dev/null
+++ b/build/embed_resources.sh
@@ -0,0 +1,47 @@
+#!/bin/sh
+
+if [[ $# -ne 1 ]] ; then
+ echo "Error invoking embed_resources.sh: directory argument required"
+ exit 1
+fi
+
+location=$(dirname $0)
+destdir=$location/../$1
+destfile=$location/../$1/resources.go
+
+cat > $destfile << EOM
+/*
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements. See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You 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.
+*/
+
+// Code generated by build/embed_resources.sh. DO NOT EDIT.
+
+package deploy
+
+var Resources map[string]string
+
+func init() {
+ Resources = make(map[string]string)
+
+EOM
+
+for f in $(ls $destdir | grep ".yaml"); do
+ printf "Resources[\"$f\"] =\n\`\n" >> $destfile
+ cat $destdir/$f >> $destfile
+ printf "\n\`\n" >> $destfile
+done
+
+printf "\n}\n" >> $destfile
\ No newline at end of file
diff --git a/deploy/operator-role-binding.yaml
b/deploy/operator-role-binding.yaml
new file mode 100644
index 0000000..eb4c712
--- /dev/null
+++ b/deploy/operator-role-binding.yaml
@@ -0,0 +1,11 @@
+kind: RoleBinding
+apiVersion: rbac.authorization.k8s.io/v1beta1
+metadata:
+ name: camel-k-operator
+subjects:
+- kind: ServiceAccount
+ name: camel-k-operator
+roleRef:
+ kind: Role
+ name: camel-k-operator
+ apiGroup: rbac.authorization.k8s.io
\ No newline at end of file
diff --git a/deploy/rbac.yaml b/deploy/operator-role.yaml
similarity index 60%
rename from deploy/rbac.yaml
rename to deploy/operator-role.yaml
index e1cb15f..7dea8d3 100644
--- a/deploy/rbac.yaml
+++ b/deploy/operator-role.yaml
@@ -1,7 +1,7 @@
kind: Role
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
- name: camel-k
+ name: camel-k-operator
rules:
- apiGroups:
- camel.apache.org
@@ -29,18 +29,4 @@ rules:
- replicasets
- statefulsets
verbs:
- - "*"
-
----
-
-kind: RoleBinding
-apiVersion: rbac.authorization.k8s.io/v1beta1
-metadata:
- name: default-account-camel-k
-subjects:
-- kind: ServiceAccount
- name: default
-roleRef:
- kind: Role
- name: camel-k
- apiGroup: rbac.authorization.k8s.io
+ - "*"
\ No newline at end of file
diff --git a/deploy/operator-service-account.yaml
b/deploy/operator-service-account.yaml
new file mode 100644
index 0000000..eb771aa
--- /dev/null
+++ b/deploy/operator-service-account.yaml
@@ -0,0 +1,4 @@
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+ name: camel-k-operator
\ No newline at end of file
diff --git a/deploy/operator.yaml b/deploy/operator.yaml
index 863b21c..265b76d 100644
--- a/deploy/operator.yaml
+++ b/deploy/operator.yaml
@@ -2,6 +2,8 @@ apiVersion: apps/v1
kind: Deployment
metadata:
name: camel-k-operator
+ labels:
+ app: "camel-k"
spec:
replicas: 1
selector:
@@ -12,6 +14,7 @@ spec:
labels:
name: camel-k-operator
spec:
+ serviceAccountName: camel-k-operator
containers:
- name: camel-k-operator
image: docker.io/apache/camel-k:0.0.1-SNAPSHOT
@@ -20,7 +23,7 @@ spec:
name: metrics
command:
- camel-k-operator
- imagePullPolicy: Always
+ imagePullPolicy: IfNotPresent
env:
- name: WATCH_NAMESPACE
valueFrom:
diff --git a/deploy/resources.go b/deploy/resources.go
new file mode 100644
index 0000000..1048333
--- /dev/null
+++ b/deploy/resources.go
@@ -0,0 +1,180 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements. See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You 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.
+*/
+
+// Code generated by build/embed_resources.sh. DO NOT EDIT.
+
+package deploy
+
+var Resources map[string]string
+
+func init() {
+ Resources = make(map[string]string)
+
+Resources["crd.yaml"] =
+`
+apiVersion: apiextensions.k8s.io/v1beta1
+kind: CustomResourceDefinition
+metadata:
+ name: integrations.camel.apache.org
+spec:
+ group: camel.apache.org
+ names:
+ kind: Integration
+ listKind: IntegrationList
+ plural: integrations
+ singular: integration
+ scope: Namespaced
+ version: v1alpha1
+
+`
+Resources["cr.yaml"] =
+`
+apiVersion: "camel.apache.org/v1alpha1"
+kind: "Integration"
+metadata:
+ name: "example"
+spec:
+ replicas: 1
+ source:
+ code: |-
+ package kamel;
+
+ import org.apache.camel.builder.RouteBuilder;
+
+ public class Routes extends RouteBuilder {
+
+ @Override
+ public void configure() throws Exception {
+ from("timer:tick")
+ .setBody(constant("Hello World!!!"))
+ .to("log:info");
+ }
+
+ }
+
+`
+Resources["operator-role-binding.yaml"] =
+`
+kind: RoleBinding
+apiVersion: rbac.authorization.k8s.io/v1beta1
+metadata:
+ name: camel-k-operator
+subjects:
+- kind: ServiceAccount
+ name: camel-k-operator
+roleRef:
+ kind: Role
+ name: camel-k-operator
+ apiGroup: rbac.authorization.k8s.io
+`
+Resources["operator-role.yaml"] =
+`
+kind: Role
+apiVersion: rbac.authorization.k8s.io/v1beta1
+metadata:
+ name: camel-k-operator
+rules:
+- apiGroups:
+ - camel.apache.org
+ resources:
+ - "*"
+ verbs:
+ - "*"
+- apiGroups:
+ - ""
+ resources:
+ - pods
+ - services
+ - endpoints
+ - persistentvolumeclaims
+ - events
+ - configmaps
+ - secrets
+ verbs:
+ - "*"
+- apiGroups:
+ - apps
+ resources:
+ - deployments
+ - daemonsets
+ - replicasets
+ - statefulsets
+ verbs:
+ - "*"
+`
+Resources["operator-service-account.yaml"] =
+`
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+ name: camel-k-operator
+`
+Resources["operator.yaml"] =
+`
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: camel-k-operator
+ labels:
+ app: "camel-k"
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ name: camel-k-operator
+ template:
+ metadata:
+ labels:
+ name: camel-k-operator
+ spec:
+ serviceAccountName: camel-k-operator
+ containers:
+ - name: camel-k-operator
+ image: docker.io/apache/camel-k:0.0.1-SNAPSHOT
+ ports:
+ - containerPort: 60000
+ name: metrics
+ command:
+ - camel-k-operator
+ imagePullPolicy: IfNotPresent
+ env:
+ - name: WATCH_NAMESPACE
+ valueFrom:
+ fieldRef:
+ fieldPath: metadata.namespace
+ - name: OPERATOR_NAME
+ value: "camel-k-operator"
+
+`
+Resources["user-cluster-role.yaml"] =
+`
+kind: ClusterRole
+apiVersion: rbac.authorization.k8s.io/v1
+metadata:
+ name: camel-k:edit
+ labels:
+ # Add these permissions to the "admin" and "edit" default roles.
+ rbac.authorization.k8s.io/aggregate-to-admin: "true"
+ rbac.authorization.k8s.io/aggregate-to-edit: "true"
+rules:
+- apiGroups: ["camel.apache.org"]
+ resources: ["*"]
+ verbs: ["*"]
+
+`
+
+}
diff --git a/deploy/user-cluster-role.yaml b/deploy/user-cluster-role.yaml
new file mode 100644
index 0000000..2fde6d1
--- /dev/null
+++ b/deploy/user-cluster-role.yaml
@@ -0,0 +1,12 @@
+kind: ClusterRole
+apiVersion: rbac.authorization.k8s.io/v1
+metadata:
+ name: camel-k:edit
+ labels:
+ # Add these permissions to the "admin" and "edit" default roles.
+ rbac.authorization.k8s.io/aggregate-to-admin: "true"
+ rbac.authorization.k8s.io/aggregate-to-edit: "true"
+rules:
+- apiGroups: ["camel.apache.org"]
+ resources: ["*"]
+ verbs: ["*"]
diff --git a/pkg/build/local/local_builder.go b/pkg/build/local/local_builder.go
index 98830d6..d37a56e 100644
--- a/pkg/build/local/local_builder.go
+++ b/pkg/build/local/local_builder.go
@@ -27,9 +27,6 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/api/core/v1"
"github.com/operator-framework/operator-sdk/pkg/sdk"
- "k8s.io/client-go/rest"
- "github.com/operator-framework/operator-sdk/pkg/k8sclient"
- "k8s.io/apimachinery/pkg/runtime/schema"
imagev1 "github.com/openshift/api/image/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"github.com/operator-framework/operator-sdk/pkg/util/k8sutil"
@@ -39,6 +36,7 @@ import (
"github.com/apache/camel-k/pkg/util/kubernetes"
"github.com/apache/camel-k/version"
"github.com/apache/camel-k/pkg/util/maven"
+ "github.com/apache/camel-k/pkg/util/kubernetes/customclient"
)
type localBuilder struct {
@@ -203,34 +201,17 @@ func (b *localBuilder) publish(tarFile string, source
build.BuildSource) (string
return "", errors.Wrap(err, "cannot create image stream")
}
- inConfig := k8sclient.GetKubeConfig()
- config := rest.CopyConfig(inConfig)
- config.GroupVersion = &schema.GroupVersion{
- Group: "build.openshift.io",
- Version: "v1",
- }
- config.APIPath = "/apis"
- config.AcceptContentTypes = "application/json"
- config.ContentType = "application/json"
-
- // this gets used for discovery and error handling types
- config.NegotiatedSerializer = basicNegotiatedSerializer{}
- if config.UserAgent == "" {
- config.UserAgent = rest.DefaultKubernetesUserAgent()
- }
-
- restClient, err := rest.RESTClientFor(config)
+ resource, err := ioutil.ReadFile(tarFile)
if err != nil {
- return "", err
+ return "", errors.Wrap(err, "cannot fully read tar file
"+tarFile)
}
- resource, err := ioutil.ReadFile(tarFile)
+ restClient, err := customclient.GetClientFor("build.openshift.io", "v1")
if err != nil {
- return "", errors.Wrap(err, "cannot fully read tar file
"+tarFile)
+ return "", err
}
- result := restClient.
- Post().
+ result := restClient.Post().
Namespace(b.namespace).
Body(resource).
Resource("buildconfigs").
diff --git a/pkg/client/cmd/get.go b/pkg/client/cmd/get.go
new file mode 100644
index 0000000..39a45d9
--- /dev/null
+++ b/pkg/client/cmd/get.go
@@ -0,0 +1,64 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements. See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You 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 cmd
+
+import (
+ "github.com/spf13/cobra"
+ "text/tabwriter"
+ "os"
+ "fmt"
+ "github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "github.com/operator-framework/operator-sdk/pkg/sdk"
+)
+
+func NewCmdGet() *cobra.Command {
+ cmd := cobra.Command{
+ Use: "get",
+ Short: "Get all integrations deployed on Kubernetes",
+ Long: `Get the status of all integrations deployed on on
Kubernetes.`,
+ RunE: run,
+ }
+
+ return &cmd
+}
+
+func run(cmd *cobra.Command, args []string) error {
+ integrationList := v1alpha1.IntegrationList{
+ TypeMeta: metav1.TypeMeta{
+ APIVersion: v1alpha1.SchemeGroupVersion.String(),
+ Kind: "Integration",
+ },
+ }
+
+ namespace := cmd.Flag("namespace").Value.String()
+
+ err := sdk.List(namespace, &integrationList)
+ if err != nil {
+ return err
+ }
+
+ w := tabwriter.NewWriter(os.Stdout, 0, 8, 0, '\t', 0)
+ fmt.Fprintln(w, "NAME\tSTATUS")
+ for _, integration := range integrationList.Items {
+ fmt.Fprintln(w,
integration.Name+"\t"+string(integration.Status.Phase))
+ }
+ w.Flush()
+
+ return nil
+}
diff --git a/pkg/client/cmd/install.go b/pkg/client/cmd/install.go
new file mode 100644
index 0000000..edeece4
--- /dev/null
+++ b/pkg/client/cmd/install.go
@@ -0,0 +1,58 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements. See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You 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 cmd
+
+import (
+ "github.com/spf13/cobra"
+ installutils "github.com/apache/camel-k/pkg/install"
+ "fmt"
+ "k8s.io/apimachinery/pkg/api/errors"
+)
+
+type InstallCmdOptions struct {
+}
+
+func NewCmdInstall() *cobra.Command {
+ options := InstallCmdOptions{}
+ cmd := cobra.Command{
+ Use: "install",
+ Short: "Install Camel K on a Kubernetes cluster",
+ Long: `Installs Camel K on a Kubernetes or Openshift cluster.`,
+ RunE: options.install,
+ }
+ return &cmd
+}
+
+func (o *InstallCmdOptions) install(cmd *cobra.Command, args []string) error {
+ err := installutils.SetupClusterwideResources()
+ if err != nil && errors.IsForbidden(err) {
+ // TODO explain that this is a one time operation and add a
flag to do cluster-level operations only when logged as admin
+ fmt.Println("Current user is not authorized to create
cluster-wide objects like custom resource definitions or cluster roles: ", err)
+ fmt.Println("Please login as cluster-admin to continue the
installation.")
+ return nil // TODO better error handling: if here we return err
the help page is shown
+ }
+
+ namespace := cmd.Flag("namespace").Value.String()
+
+ err = installutils.InstallOperator(namespace)
+ if err != nil {
+ return err
+ }
+ fmt.Println("Camel K installed in namespace", namespace)
+ return nil
+}
diff --git a/pkg/client/cmd/root.go b/pkg/client/cmd/root.go
index e49da28..f310f10 100644
--- a/pkg/client/cmd/root.go
+++ b/pkg/client/cmd/root.go
@@ -18,21 +18,42 @@ limitations under the License.
package cmd
import (
+ "os"
+
"github.com/spf13/cobra"
+ "github.com/apache/camel-k/pkg/util/kubernetes"
+ "github.com/pkg/errors"
)
+type rootCmdOptions struct {
+ KubeConfig string
+ Namespace string
+}
+
func NewKamelCommand() (*cobra.Command, error) {
+ options := rootCmdOptions{}
var cmd = cobra.Command{
Use: "kamel",
Short: "Kamel is a awesome client tool for running Apache Camel
integrations natively on Kubernetes",
Long: "Apache Camel K (a.k.a. Kamel) is a lightweight
integration framework\nbuilt from Apache Camel that runs natively on Kubernetes
and is\nspecifically designed for serverless and microservice architectures.",
}
- var kubeconfig string
- cmd.PersistentFlags().StringVar(&kubeconfig, "config", "", "Path to the
config file to use for CLI requests")
+ cmd.PersistentFlags().StringVar(&options.KubeConfig, "config", "",
"Path to the config file to use for CLI requests")
+ cmd.PersistentFlags().StringVarP(&options.Namespace, "namespace", "n",
"", "Namespace to use for all operations")
+
+ // Parse the flags before setting the defaults
+ cmd.ParseFlags(os.Args)
+
+ if options.Namespace == "" {
+ current, err :=
kubernetes.GetClientCurrentNamespace(options.KubeConfig)
+ if err != nil {
+ return nil, errors.Wrap(err, "cannot get current
namespace")
+ }
+ cmd.Flag("namespace").Value.Set(current)
+ }
// Initialize the Kubernetes client to allow using the operator-sdk
- err := initKubeClient(&cmd)
+ err := kubernetes.InitKubeClient(options.KubeConfig)
if err != nil {
return nil, err
}
@@ -40,6 +61,8 @@ func NewKamelCommand() (*cobra.Command, error) {
cmd.AddCommand(NewCmdCompletion())
cmd.AddCommand(NewCmdVersion())
cmd.AddCommand(NewCmdRun())
+ cmd.AddCommand(NewCmdGet())
+ cmd.AddCommand(NewCmdInstall())
return &cmd, nil
}
diff --git a/pkg/client/cmd/run.go b/pkg/client/cmd/run.go
index ca0872a..1fb90d4 100644
--- a/pkg/client/cmd/run.go
+++ b/pkg/client/cmd/run.go
@@ -32,27 +32,27 @@ import (
"k8s.io/apimachinery/pkg/apis/meta/v1"
)
-func NewCmdRun() *cobra.Command {
- impl := runCmd{}
+type RunCmdOptions struct {
+ Language string
+}
+func NewCmdRun() *cobra.Command {
+ options := RunCmdOptions{}
cmd := cobra.Command{
Use: "run [file to run]",
Short: "Run a integration on Kubernetes",
Long: `Deploys and execute a integration pod on Kubernetes.`,
- Args: impl.validateArgs,
- RunE: impl.execute,
+ Args: options.validateArgs,
+ RunE: options.run,
}
- cmd.Flags().StringVarP(&impl.language, "language", "l", "",
"Programming Language used to write the file")
+ cmd.Flags().StringVarP(&options.Language, "language", "l", "",
"Programming Language used to write the file")
+ cmd.ParseFlags(os.Args)
return &cmd
}
-type runCmd struct {
- language string
-}
-
-func (target runCmd) validateArgs(cmd *cobra.Command, args []string) error {
+func (*RunCmdOptions) validateArgs(cmd *cobra.Command, args []string) error {
if len(args) != 1 {
return errors.New("accepts 1 arg, received " +
strconv.Itoa(len(args)))
}
@@ -65,12 +65,14 @@ func (target runCmd) validateArgs(cmd *cobra.Command, args
[]string) error {
return nil
}
-func (target runCmd) execute(cmd *cobra.Command, args []string) error {
- code, err := target.loadCode(args[0])
+func (o *RunCmdOptions) run(cmd *cobra.Command, args []string) error {
+ code, err := o.loadCode(args[0])
if err != nil {
return err
}
+ namespace := cmd.Flag("namespace").Value.String()
+
name := kubernetes.SanitizeName(args[0])
if name == "" {
name = "integration"
@@ -82,7 +84,7 @@ func (target runCmd) execute(cmd *cobra.Command, args
[]string) error {
APIVersion: v1alpha1.SchemeGroupVersion.String(),
},
ObjectMeta: v1.ObjectMeta{
- Namespace: "test", // TODO discover current namespace
dynamically (and with command option)
+ Namespace: namespace,
Name: name,
},
Spec: v1alpha1.IntegrationSpec{
@@ -117,7 +119,7 @@ func (target runCmd) execute(cmd *cobra.Command, args
[]string) error {
return nil
}
-func (target runCmd) loadCode(fileName string) (string, error) {
+func (*RunCmdOptions) loadCode(fileName string) (string, error) {
content, err := ioutil.ReadFile(fileName)
if err != nil {
return "", err
diff --git a/pkg/install/cluster.go b/pkg/install/cluster.go
new file mode 100644
index 0000000..a6b60d5
--- /dev/null
+++ b/pkg/install/cluster.go
@@ -0,0 +1,124 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements. See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You 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 install
+
+import (
+ "github.com/operator-framework/operator-sdk/pkg/k8sclient"
+ "github.com/apache/camel-k/deploy"
+ "k8s.io/apimachinery/pkg/util/yaml"
+ "github.com/apache/camel-k/pkg/util/kubernetes/customclient"
+ "k8s.io/apimachinery/pkg/api/errors"
+ "github.com/apache/camel-k/pkg/util/kubernetes"
+ "github.com/operator-framework/operator-sdk/pkg/sdk"
+ "k8s.io/api/rbac/v1"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+)
+
+func SetupClusterwideResources() error {
+ // Installing CRD
+ crdInstalled, err := isCRDInstalled()
+ if err != nil {
+ return err
+ }
+ if !crdInstalled {
+ if err := installCRD(); err != nil {
+ return err
+ }
+ }
+
+ // Installing ClusterRole
+ clusterRoleInstalled, err := isClusterRoleInstalled()
+ if err != nil {
+ return err
+ }
+ if !clusterRoleInstalled {
+ err := installClusterRole()
+ if err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
+func isCRDInstalled() (bool, error) {
+ lst, err :=
k8sclient.GetKubeClient().Discovery().ServerResourcesForGroupVersion("camel.apache.org/v1alpha1")
+ if err != nil && errors.IsNotFound(err) {
+ return false, nil
+ } else if err != nil {
+ return false, err
+ }
+ for _, res := range lst.APIResources {
+ if res.Kind == "Integration" {
+ return true, nil
+ }
+ }
+ return false, nil
+}
+
+func installCRD() error {
+ crd := []byte(deploy.Resources["crd.yaml"])
+ crdJson, err := yaml.ToJSON(crd)
+ if err != nil {
+ return err
+ }
+ restClient, err := customclient.GetClientFor("apiextensions.k8s.io",
"v1beta1")
+ if err != nil {
+ return err
+ }
+ // Post using dynamic client
+ result := restClient.
+ Post().
+ Body(crdJson).
+ Resource("customresourcedefinitions").
+ Do()
+ // Check result
+ if result.Error() != nil && !errors.IsAlreadyExists(result.Error()) {
+ return result.Error()
+ }
+
+ return nil
+}
+
+func isClusterRoleInstalled() (bool, error) {
+ clusterRole := v1.ClusterRole{
+ TypeMeta: metav1.TypeMeta{
+ Kind: "ClusterRole",
+ APIVersion: "rbac.authorization.k8s.io/v1",
+ },
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "camel-k:edit",
+ },
+ }
+ err := sdk.Get(&clusterRole)
+ if err != nil && errors.IsNotFound(err) {
+ return false, nil
+ } else if err != nil {
+ return false, err
+ }
+ return true, nil
+}
+
+func installClusterRole() error {
+ obj, err :=
kubernetes.LoadResourceFromYaml(deploy.Resources["user-cluster-role.yaml"])
+ if err != nil {
+ return err
+ }
+
+ return sdk.Create(obj)
+}
diff --git a/pkg/install/cluster_integration_test.go
b/pkg/install/cluster_integration_test.go
new file mode 100644
index 0000000..df9f93c
--- /dev/null
+++ b/pkg/install/cluster_integration_test.go
@@ -0,0 +1,36 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements. See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You 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 install
+
+import (
+ "testing"
+ "github.com/stretchr/testify/assert"
+)
+
+func TestInstallation(t *testing.T) {
+ err := SetupClusterwideResources()
+ assert.Nil(t, err)
+
+ installedCRD, err := isCRDInstalled()
+ assert.Nil(t, err)
+ assert.True(t, installedCRD)
+
+ installedClusterRole, err := isClusterRoleInstalled()
+ assert.Nil(t, err)
+ assert.True(t, installedClusterRole)
+}
diff --git a/pkg/install/operator.go b/pkg/install/operator.go
new file mode 100644
index 0000000..ad6d5d6
--- /dev/null
+++ b/pkg/install/operator.go
@@ -0,0 +1,61 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements. See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You 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 install
+
+import (
+ "github.com/apache/camel-k/deploy"
+ "github.com/operator-framework/operator-sdk/pkg/sdk"
+ "github.com/apache/camel-k/pkg/util/kubernetes"
+ "k8s.io/apimachinery/pkg/api/errors"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+)
+
+func InstallOperator(namespace string) error {
+ return installResources(namespace,
+ "operator-service-account.yaml",
+ "operator-role.yaml",
+ "operator-role-binding.yaml",
+ "operator.yaml",
+ )
+}
+
+func installResources(namespace string, names ...string) error {
+ for _, name := range names {
+ if err := installResource(namespace, name); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func installResource(namespace string, name string) error {
+ obj, err := kubernetes.LoadResourceFromYaml(deploy.Resources[name])
+ if err != nil {
+ return err
+ }
+
+ if kObj, ok := obj.(metav1.Object); ok {
+ kObj.SetNamespace(namespace)
+ }
+
+ err = sdk.Create(obj)
+ if err != nil && errors.IsAlreadyExists(err) {
+ return sdk.Update(obj)
+ }
+ return err
+}
diff --git a/pkg/client/cmd/config.go b/pkg/util/kubernetes/config.go
similarity index 79%
rename from pkg/client/cmd/config.go
rename to pkg/util/kubernetes/config.go
index f7b347b..f01a8de 100644
--- a/pkg/client/cmd/config.go
+++ b/pkg/util/kubernetes/config.go
@@ -15,26 +15,18 @@ See the License for the specific language governing
permissions and
limitations under the License.
*/
-package cmd
+package kubernetes
import (
"os/user"
"path/filepath"
-
- "github.com/operator-framework/operator-sdk/pkg/k8sclient"
- "github.com/spf13/cobra"
"k8s.io/client-go/tools/clientcmd"
+ "github.com/operator-framework/operator-sdk/pkg/k8sclient"
)
-func initKubeClient(cmd *cobra.Command) error {
- kubeconfig := cmd.Flag("config").Value.String()
+func InitKubeClient(kubeconfig string) error {
if kubeconfig == "" {
- usr, err := user.Current()
- if err != nil {
- return err
- }
-
- kubeconfig = filepath.Join(usr.HomeDir, ".kube", "config")
+ kubeconfig = GetDefaultKubeConfigFile()
}
// use the current context in kubeconfig
@@ -46,3 +38,12 @@ func initKubeClient(cmd *cobra.Command) error {
k8sclient.CustomConfig = config
return nil
}
+
+func GetDefaultKubeConfigFile() string {
+ usr, err := user.Current()
+ if err != nil {
+ panic(err) // TODO handle error
+ }
+
+ return filepath.Join(usr.HomeDir, ".kube", "config")
+}
diff --git a/pkg/util/kubernetes/customclient/customclient.go
b/pkg/util/kubernetes/customclient/customclient.go
new file mode 100644
index 0000000..9dc0735
--- /dev/null
+++ b/pkg/util/kubernetes/customclient/customclient.go
@@ -0,0 +1,44 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements. See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You 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 customclient
+
+import (
+ "k8s.io/client-go/rest"
+ "k8s.io/apimachinery/pkg/runtime/schema"
+ "github.com/operator-framework/operator-sdk/pkg/k8sclient"
+)
+
+func GetClientFor(group string, version string) (*rest.RESTClient, error) {
+ inConfig := k8sclient.GetKubeConfig()
+ config := rest.CopyConfig(inConfig)
+ config.GroupVersion = &schema.GroupVersion{
+ Group: group,
+ Version: version,
+ }
+ config.APIPath = "/apis"
+ config.AcceptContentTypes = "application/json"
+ config.ContentType = "application/json"
+
+ // this gets used for discovery and error handling types
+ config.NegotiatedSerializer = basicNegotiatedSerializer{}
+ if config.UserAgent == "" {
+ config.UserAgent = rest.DefaultKubernetesUserAgent()
+ }
+
+ return rest.RESTClientFor(config)
+}
diff --git a/pkg/util/kubernetes/customclient/scheme.go
b/pkg/util/kubernetes/customclient/scheme.go
new file mode 100644
index 0000000..f20496d
--- /dev/null
+++ b/pkg/util/kubernetes/customclient/scheme.go
@@ -0,0 +1,98 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+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 customclient
+
+import (
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/apimachinery/pkg/runtime/schema"
+ "k8s.io/apimachinery/pkg/runtime/serializer"
+ "k8s.io/apimachinery/pkg/runtime/serializer/json"
+ "k8s.io/apimachinery/pkg/runtime/serializer/versioning"
+)
+
+var watchScheme = runtime.NewScheme()
+var basicScheme = runtime.NewScheme()
+var deleteScheme = runtime.NewScheme()
+var parameterScheme = runtime.NewScheme()
+var deleteOptionsCodec = serializer.NewCodecFactory(deleteScheme)
+var dynamicParameterCodec = runtime.NewParameterCodec(parameterScheme)
+
+var versionV1 = schema.GroupVersion{Version: "v1"}
+
+func init() {
+ metav1.AddToGroupVersion(watchScheme, versionV1)
+ metav1.AddToGroupVersion(basicScheme, versionV1)
+ metav1.AddToGroupVersion(parameterScheme, versionV1)
+ metav1.AddToGroupVersion(deleteScheme, versionV1)
+}
+
+var watchJsonSerializerInfo = runtime.SerializerInfo{
+ MediaType: "application/json",
+ EncodesAsText: true,
+ Serializer: json.NewSerializer(json.DefaultMetaFactory,
watchScheme, watchScheme, false),
+ PrettySerializer: json.NewSerializer(json.DefaultMetaFactory,
watchScheme, watchScheme, true),
+ StreamSerializer: &runtime.StreamSerializerInfo{
+ EncodesAsText: true,
+ Serializer: json.NewSerializer(json.DefaultMetaFactory,
watchScheme, watchScheme, false),
+ Framer: json.Framer,
+ },
+}
+
+// watchNegotiatedSerializer is used to read the wrapper of the watch stream
+type watchNegotiatedSerializer struct{}
+
+var watchNegotiatedSerializerInstance = watchNegotiatedSerializer{}
+
+func (s watchNegotiatedSerializer) SupportedMediaTypes()
[]runtime.SerializerInfo {
+ return []runtime.SerializerInfo{watchJsonSerializerInfo}
+}
+
+func (s watchNegotiatedSerializer) EncoderForVersion(encoder runtime.Encoder,
gv runtime.GroupVersioner) runtime.Encoder {
+ return versioning.NewDefaultingCodecForScheme(watchScheme, encoder,
nil, gv, nil)
+}
+
+func (s watchNegotiatedSerializer) DecoderToVersion(decoder runtime.Decoder,
gv runtime.GroupVersioner) runtime.Decoder {
+ return versioning.NewDefaultingCodecForScheme(watchScheme, nil,
decoder, nil, gv)
+}
+
+// basicNegotiatedSerializer is used to handle discovery and error handling
serialization
+type basicNegotiatedSerializer struct{}
+
+func (s basicNegotiatedSerializer) SupportedMediaTypes()
[]runtime.SerializerInfo {
+ return []runtime.SerializerInfo{
+ {
+ MediaType: "application/json",
+ EncodesAsText: true,
+ Serializer:
json.NewSerializer(json.DefaultMetaFactory, basicScheme, basicScheme, false),
+ PrettySerializer:
json.NewSerializer(json.DefaultMetaFactory, basicScheme, basicScheme, true),
+ StreamSerializer: &runtime.StreamSerializerInfo{
+ EncodesAsText: true,
+ Serializer:
json.NewSerializer(json.DefaultMetaFactory, basicScheme, basicScheme, false),
+ Framer: json.Framer,
+ },
+ },
+ }
+}
+
+func (s basicNegotiatedSerializer) EncoderForVersion(encoder runtime.Encoder,
gv runtime.GroupVersioner) runtime.Encoder {
+ return versioning.NewDefaultingCodecForScheme(watchScheme, encoder,
nil, gv, nil)
+}
+
+func (s basicNegotiatedSerializer) DecoderToVersion(decoder runtime.Decoder,
gv runtime.GroupVersioner) runtime.Decoder {
+ return versioning.NewDefaultingCodecForScheme(watchScheme, nil,
decoder, nil, gv)
+}
\ No newline at end of file
diff --git a/pkg/util/kubernetes/loader.go b/pkg/util/kubernetes/loader.go
new file mode 100644
index 0000000..c1cfc5a
--- /dev/null
+++ b/pkg/util/kubernetes/loader.go
@@ -0,0 +1,40 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements. See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You 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 kubernetes
+
+import (
+ "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
+ "github.com/operator-framework/operator-sdk/pkg/util/k8sutil"
+ "k8s.io/apimachinery/pkg/util/yaml"
+ "k8s.io/apimachinery/pkg/runtime"
+)
+
+func LoadResourceFromYaml(data string) (runtime.Object, error) {
+ role := []byte(data)
+ roleJson, err := yaml.ToJSON(role)
+ if err != nil {
+ return nil, err
+ }
+ u := unstructured.Unstructured{}
+ err = u.UnmarshalJSON(roleJson)
+ if err != nil {
+ return nil, err
+ }
+
+ return k8sutil.RuntimeObjectFromUnstructured(&u)
+}
diff --git a/pkg/util/kubernetes/namespace.go b/pkg/util/kubernetes/namespace.go
new file mode 100644
index 0000000..116865d
--- /dev/null
+++ b/pkg/util/kubernetes/namespace.go
@@ -0,0 +1,56 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements. See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You 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 kubernetes
+
+import (
+ "k8s.io/client-go/tools/clientcmd"
+ clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
+ clientcmdlatest "k8s.io/client-go/tools/clientcmd/api/latest"
+ "io/ioutil"
+ "github.com/pkg/errors"
+ "k8s.io/apimachinery/pkg/runtime/schema"
+)
+
+func GetClientCurrentNamespace(kubeconfig string) (string, error) {
+ if kubeconfig == "" {
+ kubeconfig = GetDefaultKubeConfigFile()
+ }
+ if kubeconfig == "" {
+ return "default", nil
+ }
+
+ data, err := ioutil.ReadFile(kubeconfig)
+ if err != nil {
+ return "", err
+ }
+ config := clientcmdapi.NewConfig()
+ if len(data) == 0 {
+ return "", errors.New("kubernetes config file is empty")
+ }
+
+ decoded, _, err := clientcmdlatest.Codec.Decode(data,
&schema.GroupVersionKind{Version: clientcmdlatest.Version, Kind: "Config"},
config)
+ if err != nil {
+ return "", err
+ }
+
+ clientcmdconfig := decoded.(*clientcmdapi.Config)
+
+ cc := clientcmd.NewDefaultClientConfig(*clientcmdconfig,
&clientcmd.ConfigOverrides{})
+ ns, _, err := cc.Namespace()
+ return ns, err
+}
----------------------------------------------------------------
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:
[email protected]
With regards,
Apache Git Services