lburgazzoli closed pull request #126: Add IntegrationPlatform resource URL: https://github.com/apache/camel-k/pull/126
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/cmd/camel-k-operator/camel_k_operator.go b/cmd/camel-k-operator/camel_k_operator.go index 32ee754..79ae793 100644 --- a/cmd/camel-k-operator/camel_k_operator.go +++ b/cmd/camel-k-operator/camel_k_operator.go @@ -62,6 +62,7 @@ func main() { watch(resource, "Integration", namespace, resyncPeriod) watch(resource, "IntegrationContext", namespace, resyncPeriod) + watch(resource, "IntegrationPlatform", namespace, resyncPeriod) sdk.Handle(stub.NewHandler(ctx, namespace)) sdk.Run(ctx) diff --git a/deploy/crd-integration-platform.yaml b/deploy/crd-integration-platform.yaml new file mode 100644 index 0000000..ccba19c --- /dev/null +++ b/deploy/crd-integration-platform.yaml @@ -0,0 +1,17 @@ +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: integrationplatforms.camel.apache.org + labels: + app: "camel-k" +spec: + group: camel.apache.org + names: + kind: IntegrationPlatform + listKind: IntegrationPlatformList + plural: integrationplatforms + singular: integrationplatform + shortNames: + - ip + scope: Namespaced + version: v1alpha1 diff --git a/deploy/platform-cr.yaml b/deploy/platform-cr.yaml new file mode 100644 index 0000000..cdf13ff --- /dev/null +++ b/deploy/platform-cr.yaml @@ -0,0 +1,6 @@ +apiVersion: camel.apache.org/v1alpha1 +kind: IntegrationPlatform +metadata: + name: camel-k + labels: + app: "camel-k" diff --git a/deploy/resources.go b/deploy/resources.go index 7a9888f..7749be3 100644 --- a/deploy/resources.go +++ b/deploy/resources.go @@ -2122,6 +2122,27 @@ spec: scope: Namespaced version: v1alpha1 +` + Resources["crd-integration-platform.yaml"] = + ` +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: integrationplatforms.camel.apache.org + labels: + app: "camel-k" +spec: + group: camel.apache.org + names: + kind: IntegrationPlatform + listKind: IntegrationPlatformList + plural: integrationplatforms + singular: integrationplatform + shortNames: + - ip + scope: Namespaced + version: v1alpha1 + ` Resources["crd-integration.yaml"] = ` @@ -2435,6 +2456,16 @@ spec: status: loadBalancer: {} +` + Resources["platform-cr.yaml"] = + ` +apiVersion: camel.apache.org/v1alpha1 +kind: IntegrationPlatform +metadata: + name: camel-k + labels: + app: "camel-k" + ` Resources["platform-integration-context-core.yaml"] = ` diff --git a/docs/cluster-setup.adoc b/docs/cluster-setup.adoc index 2564b78..7e52648 100644 --- a/docs/cluster-setup.adoc +++ b/docs/cluster-setup.adoc @@ -7,7 +7,7 @@ There are various options for creating a development cluster: [[minishift]] == Minishift -You can run Camel K integrations on Openshift using the Minishift cluster creation tool. +You can run Camel K integrations on OpenShift using the Minishift cluster creation tool. Follow the instructions in the https://github.com/minishift/minishift#getting-started[getting started guide] for the installation. After installing the `minishift` binary, you need to enable the `admin-user` addon: @@ -16,6 +16,8 @@ After installing the `minishift` binary, you need to enable the `admin-user` add minishift addons enable admin-user ``` +NOTE: the admin user addon should be enabled before starting the cluster for the first time + Then you can start the cluster with: ``` diff --git a/docs/developers.adoc b/docs/developers.adoc index 983f15a..06bb10a 100644 --- a/docs/developers.adoc +++ b/docs/developers.adoc @@ -45,7 +45,7 @@ This is a high level overview of the project structure: | link:/docs[/docs] | Contains this documentation. | link:/pkg[/pkg] | This is where the code resides. The code is divided in multiple subpackages. | link:/runtime[/runtime] | The Java runtime code that is used inside the integration Docker containers. -| link:/test[/test] | Include integration tests to ensure that the software interacts correctly with Kubernetes and Openshift. +| link:/test[/test] | Include integration tests to ensure that the software interacts correctly with Kubernetes and OpenShift. | link:/tmp[/tmp] | Scripts and Docker configuration files used by the operator-sdk. | /vendor | Project dependencies (not staged in git). | link:/version[/version] | Contains the global version of the project. @@ -88,7 +88,7 @@ make images Unit tests are executed automatically as part of the build. They use the standard go testing framework. -Integration tests (aimed at ensuring that the code integrates correctly with Kubernetes and Openshift), need special care. +Integration tests (aimed at ensuring that the code integrates correctly with Kubernetes and OpenShift), need special care. The **convention** used in this repo is to name unit tests `xxx_test.go`, and name integration tests `yyy_integration_test.go`. Integration tests are all in the link:/test[/test] dir. @@ -102,7 +102,7 @@ integration tests. A integration test should start with the following line: Look into the link:/test[/test] directory for examples of integration tests. -Before running a integration test, you need to be connected to a Kubernetes/Openshift namespace. +Before running a integration test, you need to be connected to a Kubernetes/OpenShift namespace. After you log in into your cluster, you can run the following command to execute **all** integration tests: ``` @@ -144,7 +144,7 @@ It should be straightforward: just execute the link:/cmd/kamel/kamel.go[/cmd/kam It is a bit more complex (but not so much). -You are going to run the operator code **outside** Openshift in your IDE so, first of all, you need to **stop the operator running inside**: +You are going to run the operator code **outside** OpenShift in your IDE so, first of all, you need to **stop the operator running inside**: ``` // use kubectl in plain Kubernetes diff --git a/pkg/apis/camel/v1alpha1/register.go b/pkg/apis/camel/v1alpha1/register.go index 460dd4c..7ef6212 100644 --- a/pkg/apis/camel/v1alpha1/register.go +++ b/pkg/apis/camel/v1alpha1/register.go @@ -49,6 +49,8 @@ func addKnownTypes(scheme *runtime.Scheme) error { &IntegrationList{}, &IntegrationContext{}, &IntegrationContextList{}, + &IntegrationPlatform{}, + &IntegrationPlatformList{}, ) metav1.AddToGroupVersion(scheme, SchemeGroupVersion) return nil diff --git a/pkg/apis/camel/v1alpha1/types.go b/pkg/apis/camel/v1alpha1/types.go index 80ebe59..fa27617 100644 --- a/pkg/apis/camel/v1alpha1/types.go +++ b/pkg/apis/camel/v1alpha1/types.go @@ -150,3 +150,79 @@ const ( // IntegrationContextPhaseError -- IntegrationContextPhaseError IntegrationContextPhase = "Error" ) + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// IntegrationPlatformList -- +type IntegrationPlatformList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata"` + Items []IntegrationPlatform `json:"items"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// IntegrationPlatform -- +type IntegrationPlatform struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata"` + Spec IntegrationPlatformSpec `json:"spec"` + Status IntegrationPlatformStatus `json:"status,omitempty"` +} + +// IntegrationPlatformSpec -- +type IntegrationPlatformSpec struct { + Cluster IntegrationPlatformCluster `json:"cluster,omitempty"` + Build IntegrationPlatformBuildSpec `json:"build,omitempty"` +} + +// IntegrationPlatformCluster is the kind of orchestration cluster the platform is installed into +type IntegrationPlatformCluster string + +const ( + // IntegrationPlatformClusterOpenShift is used when targeting a OpenShift cluster + IntegrationPlatformClusterOpenShift = "OpenShift" + // IntegrationPlatformClusterKubernetes is used when targeting a Kubernetes cluster + IntegrationPlatformClusterKubernetes = "Kubernetes" +) + +// IntegrationPlatformBuildSpec contains platform related build information +type IntegrationPlatformBuildSpec struct { + PublishStrategy IntegrationPlatformBuildPublishStrategy `json:"publishStrategy,omitempty"` + Registry string `json:"registry,omitempty"` +} + +// IntegrationPlatformBuildPublishStrategy enumerates all implemented build strategies +type IntegrationPlatformBuildPublishStrategy string + +const ( + // IntegrationPlatformBuildPublishStrategyS2I performs a OpenShift binary S2I build + IntegrationPlatformBuildPublishStrategyS2I = "S2I" + + // IntegrationPlatformBuildPublishStrategyKaniko performs + IntegrationPlatformBuildPublishStrategyKaniko = "Kaniko" +) + +// IntegrationPlatformStatus -- +type IntegrationPlatformStatus struct { + Phase IntegrationPlatformPhase `json:"phase,omitempty"` +} + +// IntegrationPlatformPhase -- +type IntegrationPlatformPhase string + +const ( + // IntegrationPlatformKind -- + IntegrationPlatformKind string = "IntegrationPlatform" + + // IntegrationPlatformPhaseCreating -- + IntegrationPlatformPhaseCreating IntegrationPlatformPhase = "Creating" + // IntegrationPlatformPhaseStarting -- + IntegrationPlatformPhaseStarting IntegrationPlatformPhase = "Starting" + // IntegrationPlatformPhaseReady -- + IntegrationPlatformPhaseReady IntegrationPlatformPhase = "Ready" + // IntegrationPlatformPhaseError -- + IntegrationPlatformPhaseError IntegrationPlatformPhase = "Error" + // IntegrationPlatformPhaseDuplicate -- + IntegrationPlatformPhaseDuplicate IntegrationPlatformPhase = "Duplicate" +) diff --git a/pkg/apis/camel/v1alpha1/types_support.go b/pkg/apis/camel/v1alpha1/types_support.go index 39eb11d..fa4cceb 100644 --- a/pkg/apis/camel/v1alpha1/types_support.go +++ b/pkg/apis/camel/v1alpha1/types_support.go @@ -39,6 +39,16 @@ func (spec ConfigurationSpec) String() string { // // ********************************** +// NewIntegrationPlatformList -- +func NewIntegrationPlatformList() IntegrationPlatformList { + return IntegrationPlatformList{ + TypeMeta: metav1.TypeMeta{ + APIVersion: SchemeGroupVersion.String(), + Kind: IntegrationPlatformKind, + }, + } +} + // NewIntegrationList -- func NewIntegrationList() IntegrationList { return IntegrationList{ diff --git a/pkg/apis/camel/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/camel/v1alpha1/zz_generated.deepcopy.go index 0784edc..57ff452 100644 --- a/pkg/apis/camel/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/camel/v1alpha1/zz_generated.deepcopy.go @@ -210,6 +210,116 @@ func (in *IntegrationList) DeepCopyObject() runtime.Object { return nil } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *IntegrationPlatform) DeepCopyInto(out *IntegrationPlatform) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Spec = in.Spec + out.Status = in.Status + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IntegrationPlatform. +func (in *IntegrationPlatform) DeepCopy() *IntegrationPlatform { + if in == nil { + return nil + } + out := new(IntegrationPlatform) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *IntegrationPlatform) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *IntegrationPlatformBuildSpec) DeepCopyInto(out *IntegrationPlatformBuildSpec) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IntegrationPlatformBuildSpec. +func (in *IntegrationPlatformBuildSpec) DeepCopy() *IntegrationPlatformBuildSpec { + if in == nil { + return nil + } + out := new(IntegrationPlatformBuildSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *IntegrationPlatformList) DeepCopyInto(out *IntegrationPlatformList) { + *out = *in + out.TypeMeta = in.TypeMeta + out.ListMeta = in.ListMeta + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]IntegrationPlatform, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IntegrationPlatformList. +func (in *IntegrationPlatformList) DeepCopy() *IntegrationPlatformList { + if in == nil { + return nil + } + out := new(IntegrationPlatformList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *IntegrationPlatformList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *IntegrationPlatformSpec) DeepCopyInto(out *IntegrationPlatformSpec) { + *out = *in + out.Build = in.Build + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IntegrationPlatformSpec. +func (in *IntegrationPlatformSpec) DeepCopy() *IntegrationPlatformSpec { + if in == nil { + return nil + } + out := new(IntegrationPlatformSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *IntegrationPlatformStatus) DeepCopyInto(out *IntegrationPlatformStatus) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IntegrationPlatformStatus. +func (in *IntegrationPlatformStatus) DeepCopy() *IntegrationPlatformStatus { + if in == nil { + return nil + } + out := new(IntegrationPlatformStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *IntegrationSpec) DeepCopyInto(out *IntegrationSpec) { *out = *in diff --git a/pkg/client/cmd/install.go b/pkg/client/cmd/install.go index 2ca05ba..0d20021 100644 --- a/pkg/client/cmd/install.go +++ b/pkg/client/cmd/install.go @@ -35,7 +35,7 @@ func newCmdInstall(rootCmdOptions *RootCmdOptions) *cobra.Command { cmd := cobra.Command{ Use: "install", Short: "Install Camel K on a Kubernetes cluster", - Long: `Installs Camel K on a Kubernetes or Openshift cluster.`, + Long: `Installs Camel K on a Kubernetes or OpenShift cluster.`, RunE: options.install, } @@ -69,7 +69,7 @@ func (o *installCmdOptions) install(cmd *cobra.Command, args []string) error { return err } - err = install.PlatformContexts(namespace) + err = install.Platform(namespace) if err != nil { return err } diff --git a/pkg/install/cluster.go b/pkg/install/cluster.go index 855d8f6..dea1dee 100644 --- a/pkg/install/cluster.go +++ b/pkg/install/cluster.go @@ -32,6 +32,11 @@ import ( // SetupClusterwideResources -- func SetupClusterwideResources() error { + // Install CRD for Integration Platform (if needed) + if err := installCRD("IntegrationPlatform", "crd-integration-platform.yaml"); err != nil { + return err + } + // Install CRD for Integration Context (if needed) if err := installCRD("IntegrationContext", "crd-integration-context.yaml"); err != nil { return err diff --git a/pkg/install/common.go b/pkg/install/common.go new file mode 100644 index 0000000..bef7f6f --- /dev/null +++ b/pkg/install/common.go @@ -0,0 +1,66 @@ +/* +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/apache/camel-k/pkg/apis/camel/v1alpha1" + "github.com/apache/camel-k/pkg/util/kubernetes" + "github.com/operator-framework/operator-sdk/pkg/sdk" + "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// Resources installs named resources from the project resource directory +func Resources(namespace string, names ...string) error { + for _, name := range names { + if err := Resource(namespace, name); err != nil { + return err + } + } + return nil +} + +// Resource installs a single named resource from the project resource directory +func Resource(namespace string, name string) error { + obj, err := kubernetes.LoadResourceFromYaml(deploy.Resources[name]) + if err != nil { + return err + } + + if metaObject, ok := obj.(metav1.Object); ok { + metaObject.SetNamespace(namespace) + } + + err = sdk.Create(obj) + if err != nil && errors.IsAlreadyExists(err) { + // Don't recreate Service object + if obj.GetObjectKind().GroupVersionKind().Kind == "Service" { + return nil + } + // Don't recreate integration contexts or platforms + if obj.GetObjectKind().GroupVersionKind().Kind == v1alpha1.IntegrationContextKind { + return nil + } + if obj.GetObjectKind().GroupVersionKind().Kind == v1alpha1.IntegrationPlatformKind { + return nil + } + return sdk.Update(obj) + } + return err +} diff --git a/pkg/install/operator.go b/pkg/install/operator.go index 58aed65..0f6039c 100644 --- a/pkg/install/operator.go +++ b/pkg/install/operator.go @@ -17,18 +17,9 @@ limitations under the License. package install -import ( - "github.com/apache/camel-k/deploy" - "github.com/apache/camel-k/pkg/apis/camel/v1alpha1" - "github.com/apache/camel-k/pkg/util/kubernetes" - "github.com/operator-framework/operator-sdk/pkg/sdk" - "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - // Operator -- func Operator(namespace string) error { - return installResources(namespace, + return Resources(namespace, "operator-service-account.yaml", "operator-role-openshift.yaml", // TODO distinguish between Openshift and Kubernetes "operator-role-binding.yaml", @@ -37,51 +28,14 @@ func Operator(namespace string) error { ) } -// PlatformContexts -- -func PlatformContexts(namespace string) error { - return installResources(namespace, - "platform-integration-context-core.yaml", - "platform-integration-context-groovy.yaml", - ) +// Platform installs the platform custom resource +func Platform(namespace string) error { + return Resource(namespace,"platform-cr.yaml") } // Example -- func Example(namespace string) error { - return installResources(namespace, + return Resources(namespace, "cr-example.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 metaObject, ok := obj.(metav1.Object); ok { - metaObject.SetNamespace(namespace) - } - - err = sdk.Create(obj) - if err != nil && errors.IsAlreadyExists(err) { - // Don't recreate Service object - if obj.GetObjectKind().GroupVersionKind().Kind == "Service" { - return nil - } - // Don't recreate integration contexts - if obj.GetObjectKind().GroupVersionKind().Kind == v1alpha1.IntegrationContextKind { - return nil - } - return sdk.Update(obj) - } - return err -} diff --git a/pkg/platform/build.go b/pkg/platform/build.go new file mode 100644 index 0000000..994ced6 --- /dev/null +++ b/pkg/platform/build.go @@ -0,0 +1,91 @@ +/* +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 platform + +import ( + "context" + "errors" + "github.com/apache/camel-k/pkg/apis/camel/v1alpha1" + "github.com/apache/camel-k/pkg/build" + "github.com/apache/camel-k/pkg/build/assemble" + "github.com/apache/camel-k/pkg/build/publish" + "github.com/operator-framework/operator-sdk/pkg/sdk" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// buildManager is the current build manager +// Note: it cannot be changed at runtime, needs a operator restart +var buildManager *build.Manager + +// GetPlatformBuildManager returns a suitable build manager for the current platform +func GetPlatformBuildManager(ctx context.Context, namespace string) (*build.Manager, error) { + if buildManager != nil { + return buildManager, nil + } + pl, err := GetCurrentPlatform(namespace) + if err != nil { + return nil, err + } + + assembler := assemble.NewMavenAssembler(ctx) + if pl.Spec.Build.PublishStrategy == v1alpha1.IntegrationPlatformBuildPublishStrategyS2I { + publisher := publish.NewS2IIncrementalPublisher(ctx, namespace, newContextLister(namespace)) + buildManager = build.NewManager(ctx, assembler, publisher) + } + + if buildManager == nil { + return nil, errors.New("unsupported platform configuration") + } + return buildManager, nil +} + +// ================================================================= + +type contextLister struct { + namespace string +} + +func newContextLister(namespace string) contextLister { + return contextLister{ + namespace: namespace, + } +} + +func (l contextLister) ListPublishedImages() ([]publish.PublishedImage, error) { + list := v1alpha1.NewIntegrationContextList() + + err := sdk.List(l.namespace, &list, sdk.WithListOptions(&metav1.ListOptions{})) + if err != nil { + return nil, err + } + images := make([]publish.PublishedImage, 0) + for _, ctx := range list.Items { + if ctx.Status.Phase != v1alpha1.IntegrationContextPhaseReady || ctx.Labels == nil { + continue + } + if ctxType, present := ctx.Labels["camel.apache.org/context.type"]; !present || ctxType != "platform" { + continue + } + + images = append(images, publish.PublishedImage{ + Image: ctx.Status.Image, + Classpath: ctx.Status.Classpath, + }) + } + return images, nil +} diff --git a/pkg/platform/doc.go b/pkg/platform/doc.go new file mode 100644 index 0000000..74e5c18 --- /dev/null +++ b/pkg/platform/doc.go @@ -0,0 +1,19 @@ +/* +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 platform allows to retrieve information about the current installed platform +package platform diff --git a/pkg/platform/get.go b/pkg/platform/get.go new file mode 100644 index 0000000..0da7163 --- /dev/null +++ b/pkg/platform/get.go @@ -0,0 +1,53 @@ +/* +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 platform + +import ( + "errors" + "github.com/apache/camel-k/pkg/apis/camel/v1alpha1" + "github.com/operator-framework/operator-sdk/pkg/sdk" +) + +// GetCurrentPlatform returns the currently installed platform +func GetCurrentPlatform(namespace string) (*v1alpha1.IntegrationPlatform, error) { + lst, err := ListPlatforms(namespace) + if err != nil { + return nil, err + } + + for _, platform := range lst.Items { + if IsActive(&platform) { + return &platform, nil + } + } + return nil, errors.New("no active integration platforms found in the namespace") +} + +// ListPlatforms returns all platforms installed in a given namespace (only one will be active) +func ListPlatforms(namespace string) (*v1alpha1.IntegrationPlatformList, error) { + lst := v1alpha1.NewIntegrationPlatformList() + if err := sdk.List(namespace, &lst); err != nil { + return nil, err + } + return &lst, nil +} + +// IsActive determines if the given platform is being used +func IsActive(p *v1alpha1.IntegrationPlatform) bool { + return p.Status.Phase != "" && p.Status.Phase != v1alpha1.IntegrationPlatformPhaseDuplicate +} diff --git a/pkg/stub/action/context/action.go b/pkg/stub/action/context/action.go index 23b0f10..97f35c4 100644 --- a/pkg/stub/action/context/action.go +++ b/pkg/stub/action/context/action.go @@ -15,14 +15,14 @@ See the License for the specific language governing permissions and limitations under the License. */ -package action +package context import ( "github.com/apache/camel-k/pkg/apis/camel/v1alpha1" ) -// IntegrationContextAction -- -type IntegrationContextAction interface { +// Action -- +type Action interface { // a user friendly name for the action Name() string diff --git a/pkg/stub/action/context/build.go b/pkg/stub/action/context/build.go index a0ab58f..875114b 100644 --- a/pkg/stub/action/context/build.go +++ b/pkg/stub/action/context/build.go @@ -15,12 +15,11 @@ See the License for the specific language governing permissions and limitations under the License. */ -package action +package context import ( "context" - "github.com/apache/camel-k/pkg/build/assemble" - "github.com/apache/camel-k/pkg/build/publish" + "github.com/apache/camel-k/pkg/platform" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -31,49 +30,52 @@ import ( "github.com/apache/camel-k/pkg/build" ) -// NewIntegrationContextBuildAction creates a new build handling action for the context -func NewIntegrationContextBuildAction(ctx context.Context, namespace string) IntegrationContextAction { - assembler := assemble.NewMavenAssembler(ctx) - publisher := publish.NewS2IIncrementalPublisher(ctx, namespace, newContextLister(namespace)) - manager := build.NewManager(ctx, assembler, publisher) - - return &integrationContextBuildAction{ - buildManager: manager, +// NewBuildAction creates a new build handling action for the context +func NewBuildAction(ctx context.Context) Action { + return &buildAction{ + ctx, } } -type integrationContextBuildAction struct { - buildManager *build.Manager +type buildAction struct { + context.Context } -func (action *integrationContextBuildAction) Name() string { +func (action *buildAction) Name() string { return "build" } -func (action *integrationContextBuildAction) CanHandle(context *v1alpha1.IntegrationContext) bool { +func (action *buildAction) CanHandle(context *v1alpha1.IntegrationContext) bool { return context.Status.Phase == v1alpha1.IntegrationContextPhaseBuilding } -func (action *integrationContextBuildAction) Handle(context *v1alpha1.IntegrationContext) error { +func (action *buildAction) Handle(context *v1alpha1.IntegrationContext) error { + buildManager, err := platform.GetPlatformBuildManager(action.Context, context.Namespace) + if err != nil { + return err + } + buildIdentifier := build.Identifier{ Name: "context-" + context.Name, Qualifier: context.ResourceVersion, } - buildResult := action.buildManager.Get(buildIdentifier) + buildResult := buildManager.Get(buildIdentifier) if buildResult.Status == build.StatusNotRequested { - action.buildManager.Start(build.Request{ + buildManager.Start(build.Request{ Identifier: buildIdentifier, Dependencies: context.Spec.Dependencies, }) logrus.Info("Build started") } else if buildResult.Status == build.StatusError { target := context.DeepCopy() + logrus.Info("Context ", target.Name, " transitioning to state ", v1alpha1.IntegrationContextPhaseError) target.Status.Phase = v1alpha1.IntegrationContextPhaseError return sdk.Update(target) } else if buildResult.Status == build.StatusCompleted { target := context.DeepCopy() target.Status.Image = buildResult.Image + logrus.Info("Context ", target.Name, " transitioning to state ", v1alpha1.IntegrationContextPhaseReady) target.Status.Phase = v1alpha1.IntegrationContextPhaseReady target.Status.Classpath = make([]string, len(buildResult.Classpath)) @@ -93,7 +95,7 @@ func (action *integrationContextBuildAction) Handle(context *v1alpha1.Integratio } // informIntegrations triggers the processing of all integrations waiting for this context to be built -func (action *integrationContextBuildAction) informIntegrations(context *v1alpha1.IntegrationContext) error { +func (action *buildAction) informIntegrations(context *v1alpha1.IntegrationContext) error { list := v1alpha1.NewIntegrationList() err := sdk.List(context.Namespace, &list, sdk.WithListOptions(&metav1.ListOptions{})) if err != nil { @@ -116,37 +118,4 @@ func (action *integrationContextBuildAction) informIntegrations(context *v1alpha return nil } -// ================================================================= - -type contextLister struct { - namespace string -} - -func newContextLister(namespace string) contextLister { - return contextLister{ - namespace: namespace, - } -} - -func (l contextLister) ListPublishedImages() ([]publish.PublishedImage, error) { - list := v1alpha1.NewIntegrationContextList() - err := sdk.List(l.namespace, &list, sdk.WithListOptions(&metav1.ListOptions{})) - if err != nil { - return nil, err - } - images := make([]publish.PublishedImage, 0) - for _, ctx := range list.Items { - if ctx.Status.Phase != v1alpha1.IntegrationContextPhaseReady || ctx.Labels == nil { - continue - } - if ctxType, present := ctx.Labels["camel.apache.org/context.type"]; !present || ctxType != "platform" { - continue - } - images = append(images, publish.PublishedImage{ - Image: ctx.Status.Image, - Classpath: ctx.Status.Classpath, - }) - } - return images, nil -} diff --git a/pkg/stub/action/context/initialize.go b/pkg/stub/action/context/initialize.go index 64d7647..6f7108e 100644 --- a/pkg/stub/action/context/initialize.go +++ b/pkg/stub/action/context/initialize.go @@ -15,34 +15,43 @@ See the License for the specific language governing permissions and limitations under the License. */ -package action +package context import ( "github.com/apache/camel-k/pkg/apis/camel/v1alpha1" + "github.com/apache/camel-k/pkg/platform" "github.com/apache/camel-k/pkg/util/digest" "github.com/operator-framework/operator-sdk/pkg/sdk" + "github.com/sirupsen/logrus" ) -// NewIntegrationContextInitializeAction creates a new initialization handling action for the context -func NewIntegrationContextInitializeAction() IntegrationContextAction { - return &integrationContextInitializeAction{} +// NewInitializeAction creates a new initialization handling action for the context +func NewInitializeAction() Action { + return &initializeAction{} } -type integrationContextInitializeAction struct { +type initializeAction struct { } -func (action *integrationContextInitializeAction) Name() string { +func (action *initializeAction) Name() string { return "initialize" } -func (action *integrationContextInitializeAction) CanHandle(context *v1alpha1.IntegrationContext) bool { +func (action *initializeAction) CanHandle(context *v1alpha1.IntegrationContext) bool { return context.Status.Phase == "" } -func (action *integrationContextInitializeAction) Handle(context *v1alpha1.IntegrationContext) error { +func (action *initializeAction) Handle(context *v1alpha1.IntegrationContext) error { + // The integration platform needs to be initialized before starting to create contexts + if _, err := platform.GetCurrentPlatform(context.Namespace); err != nil { + logrus.Info("Waiting for a integration platform to be initialized") + return nil + } + target := context.DeepCopy() // update the status + logrus.Info("Context ", target.Name, " transitioning to state ", v1alpha1.IntegrationContextPhaseBuilding) target.Status.Phase = v1alpha1.IntegrationContextPhaseBuilding target.Status.Digest = digest.ComputeForIntegrationContext(context) diff --git a/pkg/stub/action/context/monitor.go b/pkg/stub/action/context/monitor.go index e30a1ea..f090ffb 100644 --- a/pkg/stub/action/context/monitor.go +++ b/pkg/stub/action/context/monitor.go @@ -15,7 +15,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package action +package context import ( "github.com/apache/camel-k/pkg/apis/camel/v1alpha1" @@ -24,29 +24,30 @@ import ( "github.com/sirupsen/logrus" ) -// NewIntegrationContextMonitorAction creates a new monitoring handling action for the context -func NewIntegrationContextMonitorAction() IntegrationContextAction { - return &integrationContextMonitorAction{} +// NewMonitorAction creates a new monitoring handling action for the context +func NewMonitorAction() Action { + return &monitorAction{} } -type integrationContextMonitorAction struct { +type monitorAction struct { } -func (action *integrationContextMonitorAction) Name() string { +func (action *monitorAction) Name() string { return "monitor" } -func (action *integrationContextMonitorAction) CanHandle(context *v1alpha1.IntegrationContext) bool { +func (action *monitorAction) CanHandle(context *v1alpha1.IntegrationContext) bool { return context.Status.Phase == v1alpha1.IntegrationContextPhaseReady || context.Status.Phase == v1alpha1.IntegrationContextPhaseError } -func (action *integrationContextMonitorAction) Handle(context *v1alpha1.IntegrationContext) error { +func (action *monitorAction) Handle(context *v1alpha1.IntegrationContext) error { hash := digest.ComputeForIntegrationContext(context) if hash != context.Status.Digest { logrus.Info("IntegrationContext ", context.Name, " needs a rebuild") target := context.DeepCopy() target.Status.Digest = hash + logrus.Info("Context ", target.Name, " transitioning to state ", v1alpha1.IntegrationContextPhaseBuilding) target.Status.Phase = v1alpha1.IntegrationContextPhaseBuilding return sdk.Update(target) } diff --git a/pkg/stub/action/integration/action.go b/pkg/stub/action/integration/action.go index 9e4a69c..729ec5c 100644 --- a/pkg/stub/action/integration/action.go +++ b/pkg/stub/action/integration/action.go @@ -15,14 +15,14 @@ See the License for the specific language governing permissions and limitations under the License. */ -package action +package integration import ( "github.com/apache/camel-k/pkg/apis/camel/v1alpha1" ) -// IntegrationAction -- -type IntegrationAction interface { +// Action -- +type Action interface { // a user friendly name for the action Name() string diff --git a/pkg/stub/action/integration/build.go b/pkg/stub/action/integration/build.go index 20cd506..e107642 100644 --- a/pkg/stub/action/integration/build.go +++ b/pkg/stub/action/integration/build.go @@ -15,10 +15,11 @@ See the License for the specific language governing permissions and limitations under the License. */ -package action +package integration import ( "fmt" + "github.com/sirupsen/logrus" "github.com/apache/camel-k/pkg/util" "github.com/apache/camel-k/pkg/util/digest" @@ -30,7 +31,7 @@ import ( ) // NewBuildAction create an action that handles integration build -func NewBuildAction(namespace string) IntegrationAction { +func NewBuildAction(namespace string) Action { return &buildAction{ namespace: namespace, } @@ -76,6 +77,7 @@ func (action *buildAction) Handle(integration *v1alpha1.Integration) error { target := integration.DeepCopy() target.Status.Image = ctx.Status.Image target.Spec.Context = ctx.Name + logrus.Info("Integration ", target.Name, " transitioning to state ", v1alpha1.IntegrationPhaseDeploying) target.Status.Phase = v1alpha1.IntegrationPhaseDeploying target.Status.Digest = digest.ComputeForIntegration(target) return sdk.Update(target) diff --git a/pkg/stub/action/integration/deploy.go b/pkg/stub/action/integration/deploy.go index a679bbd..8067b3c 100644 --- a/pkg/stub/action/integration/deploy.go +++ b/pkg/stub/action/integration/deploy.go @@ -15,10 +15,11 @@ See the License for the specific language governing permissions and limitations under the License. */ -package action +package integration import ( "fmt" + "github.com/sirupsen/logrus" "strings" "github.com/apache/camel-k/pkg/apis/camel/v1alpha1" @@ -31,7 +32,7 @@ import ( ) // NewDeployAction create an action that handles integration deploy -func NewDeployAction() IntegrationAction { +func NewDeployAction() Action { return &deployAction{} } @@ -60,7 +61,11 @@ func (action *deployAction) Handle(integration *v1alpha1.Integration) error { return err } - return nil + target := integration.DeepCopy() + logrus.Info("Integration ", target.Name, " transitioning to state ", v1alpha1.IntegrationPhaseRunning) + target.Status.Phase = v1alpha1.IntegrationPhaseRunning + + return sdk.Update(target) } // ********************************** @@ -313,8 +318,5 @@ func createOrUpdateDeployment(ctx *v1alpha1.IntegrationContext, integration *v1a return errors.Wrap(err, "could not create or replace deployment for integration "+integration.Name) } - target := integration.DeepCopy() - target.Status.Phase = v1alpha1.IntegrationPhaseRunning - - return sdk.Update(target) + return nil } diff --git a/pkg/stub/action/integration/initialize.go b/pkg/stub/action/integration/initialize.go index 44bac89..d9ab6c0 100644 --- a/pkg/stub/action/integration/initialize.go +++ b/pkg/stub/action/integration/initialize.go @@ -15,9 +15,11 @@ See the License for the specific language governing permissions and limitations under the License. */ -package action +package integration import ( + "github.com/apache/camel-k/pkg/platform" + "github.com/sirupsen/logrus" "sort" "github.com/apache/camel-k/pkg/apis/camel/v1alpha1" @@ -27,7 +29,7 @@ import ( ) // NewInitializeAction creates a new inititialize action -func NewInitializeAction() IntegrationAction { +func NewInitializeAction() Action { return &initializeAction{} } @@ -46,6 +48,12 @@ func (action *initializeAction) CanHandle(integration *v1alpha1.Integration) boo // Handle handles the integratios func (action *initializeAction) Handle(integration *v1alpha1.Integration) error { + // The integration platform needs to be ready before starting to create integrations + if pl, err := platform.GetCurrentPlatform(integration.Namespace); err != nil || pl.Status.Phase != v1alpha1.IntegrationPlatformPhaseReady { + logrus.Info("Waiting for a integration platform to be ready") + return nil + } + target := integration.DeepCopy() // set default values if target.Spec.Replicas == nil { @@ -67,6 +75,7 @@ func (action *initializeAction) Handle(integration *v1alpha1.Integration) error // sort the dependencies to get always the same list if they don't change sort.Strings(target.Spec.Dependencies) // update the status + logrus.Info("Integration ", target.Name, " transitioning to state ", v1alpha1.IntegrationPhaseBuilding) target.Status.Phase = v1alpha1.IntegrationPhaseBuilding target.Status.Digest = digest.ComputeForIntegration(integration) return sdk.Update(target) diff --git a/pkg/stub/action/integration/monitor.go b/pkg/stub/action/integration/monitor.go index 483212e..ebdb420 100644 --- a/pkg/stub/action/integration/monitor.go +++ b/pkg/stub/action/integration/monitor.go @@ -15,7 +15,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package action +package integration import ( "github.com/apache/camel-k/pkg/apis/camel/v1alpha1" @@ -25,7 +25,7 @@ import ( ) // NewMonitorAction creates a new monitoring action for an integration -func NewMonitorAction() IntegrationAction { +func NewMonitorAction() Action { return &monitorAction{} } @@ -49,6 +49,7 @@ func (action *monitorAction) Handle(integration *v1alpha1.Integration) error { target := integration.DeepCopy() target.Status.Digest = hash + logrus.Info("Integration ", target.Name, " transitioning to state ", v1alpha1.IntegrationPhaseBuilding) target.Status.Phase = v1alpha1.IntegrationPhaseBuilding return sdk.Update(target) } diff --git a/pkg/stub/action/integration/util.go b/pkg/stub/action/integration/util.go index 33c3787..ab9cf79 100644 --- a/pkg/stub/action/integration/util.go +++ b/pkg/stub/action/integration/util.go @@ -1,4 +1,21 @@ -package action +/* +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 integration import ( "fmt" diff --git a/pkg/stub/action/platform/action.go b/pkg/stub/action/platform/action.go new file mode 100644 index 0000000..cb9ba4c --- /dev/null +++ b/pkg/stub/action/platform/action.go @@ -0,0 +1,34 @@ +/* +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 platform + +import ( + "github.com/apache/camel-k/pkg/apis/camel/v1alpha1" +) + +// Action -- +type Action interface { + // a user friendly name for the action + Name() string + + // returns true if the action can handle the integration context + CanHandle(platform *v1alpha1.IntegrationPlatform) bool + + // executes the handling function + Handle(platform *v1alpha1.IntegrationPlatform) error +} diff --git a/pkg/stub/action/platform/create.go b/pkg/stub/action/platform/create.go new file mode 100644 index 0000000..c313ccf --- /dev/null +++ b/pkg/stub/action/platform/create.go @@ -0,0 +1,54 @@ +/* +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 platform + +import ( + "github.com/apache/camel-k/pkg/apis/camel/v1alpha1" + "github.com/apache/camel-k/pkg/install" + "github.com/operator-framework/operator-sdk/pkg/sdk" + "github.com/sirupsen/logrus" +) + +// NewCreateAction returns a action that creates resources needed by the platform +func NewCreateAction() Action { + return &createAction{} +} + +type createAction struct { +} + +func (action *createAction) Name() string { + return "create" +} + +func (action *createAction) CanHandle(platform *v1alpha1.IntegrationPlatform) bool { + return platform.Status.Phase == v1alpha1.IntegrationPlatformPhaseCreating +} + +func (action *createAction) Handle(platform *v1alpha1.IntegrationPlatform) error { + err := install.Resources(platform.Namespace, "platform-integration-context-core.yaml", "platform-integration-context-groovy.yaml") + if err != nil { + return err + } + + target := platform.DeepCopy() + logrus.Info("Platform ", target.Name, " transitioning to state ", v1alpha1.IntegrationPlatformPhaseStarting) + target.Status.Phase = v1alpha1.IntegrationPlatformPhaseStarting + + return sdk.Update(target) +} diff --git a/pkg/stub/action/platform/initialize.go b/pkg/stub/action/platform/initialize.go new file mode 100644 index 0000000..4215daa --- /dev/null +++ b/pkg/stub/action/platform/initialize.go @@ -0,0 +1,112 @@ +/* +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 platform + +import ( + "github.com/apache/camel-k/pkg/apis/camel/v1alpha1" + platformutils "github.com/apache/camel-k/pkg/platform" + "github.com/operator-framework/operator-sdk/pkg/k8sclient" + "github.com/operator-framework/operator-sdk/pkg/sdk" + "github.com/sirupsen/logrus" + "k8s.io/apimachinery/pkg/api/errors" +) + +// NewInitializeAction returns a action that initializes the platform configuration when not provided by the user +func NewInitializeAction() Action { + return &initializeAction{} +} + +type initializeAction struct { +} + +func (action *initializeAction) Name() string { + return "initialize" +} + +func (action *initializeAction) CanHandle(platform *v1alpha1.IntegrationPlatform) bool { + return platform.Status.Phase == "" || platform.Status.Phase == v1alpha1.IntegrationPlatformPhaseDuplicate +} + +func (action *initializeAction) Handle(platform *v1alpha1.IntegrationPlatform) error { + target := platform.DeepCopy() + + duplicate, err := action.isDuplicate(platform) + if err != nil { + return err + } + if duplicate { + // another platform already present in the namespace + if platform.Status.Phase != v1alpha1.IntegrationPlatformPhaseDuplicate { + target := platform.DeepCopy() + logrus.Info("Platform ", target.Name, " transitioning to state ", v1alpha1.IntegrationPlatformPhaseDuplicate) + target.Status.Phase = v1alpha1.IntegrationPlatformPhaseDuplicate + return sdk.Update(target) + } + return nil + } + + // update missing fields in the resource + if target.Spec.Cluster == "" { + // determine the kind of cluster the platform in installed into + if openshift, err := action.isOpenshift(); err != nil { + return err + } else if openshift { + target.Spec.Cluster = v1alpha1.IntegrationPlatformClusterOpenShift + } else { + target.Spec.Cluster = v1alpha1.IntegrationPlatformClusterKubernetes + } + } + + if target.Spec.Build.PublishStrategy == "" { + if target.Spec.Cluster == v1alpha1.IntegrationPlatformClusterOpenShift { + target.Spec.Build.PublishStrategy = v1alpha1.IntegrationPlatformBuildPublishStrategyS2I + } else { + target.Spec.Build.PublishStrategy = v1alpha1.IntegrationPlatformBuildPublishStrategyKaniko + // TODO discover registry location + } + } + + // next status + logrus.Info("Platform ", target.Name, " transitioning to state ", v1alpha1.IntegrationPlatformPhaseCreating) + target.Status.Phase = v1alpha1.IntegrationPlatformPhaseCreating + return sdk.Update(target) +} + +func (action *initializeAction) isOpenshift() (bool, error) { + _, err := k8sclient.GetKubeClient().Discovery().ServerResourcesForGroupVersion("image.openshift.io/v1") + if err != nil && errors.IsNotFound(err) { + return false, nil + } else if err != nil { + return false, err + } + return true, nil +} + +func (action *initializeAction) isDuplicate(thisPlatform *v1alpha1.IntegrationPlatform) (bool, error) { + platforms, err := platformutils.ListPlatforms(thisPlatform.Namespace) + if err != nil { + return false, err + } + for _, platform := range platforms.Items { + if platform.Name != thisPlatform.Name && platformutils.IsActive(&platform) { + return true, nil + } + } + + return false, nil +} diff --git a/pkg/stub/action/platform/start.go b/pkg/stub/action/platform/start.go new file mode 100644 index 0000000..df205db --- /dev/null +++ b/pkg/stub/action/platform/start.go @@ -0,0 +1,81 @@ +/* +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 platform + +import ( + "github.com/apache/camel-k/pkg/apis/camel/v1alpha1" + "github.com/operator-framework/operator-sdk/pkg/sdk" + "github.com/sirupsen/logrus" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// NewStartAction returns a action that waits for all required platform resources to start +func NewStartAction() Action { + return &startAction{} +} + +type startAction struct { +} + +func (action *startAction) Name() string { + return "start" +} + +func (action *startAction) CanHandle(platform *v1alpha1.IntegrationPlatform) bool { + return platform.Status.Phase == v1alpha1.IntegrationPlatformPhaseStarting || platform.Status.Phase == v1alpha1.IntegrationPlatformPhaseError +} + +func (action *startAction) Handle(platform *v1alpha1.IntegrationPlatform) error { + aggregatePhase, err := action.aggregatePlatformPhaseFromContexts(platform.Namespace) + if err != nil { + return err + } + if platform.Status.Phase != aggregatePhase { + target := platform.DeepCopy() + logrus.Info("Platform ", target.Name, " transitioning to state ", aggregatePhase) + target.Status.Phase = aggregatePhase + return sdk.Update(target) + } + // wait + return nil +} + +func (action *startAction) aggregatePlatformPhaseFromContexts(namespace string) (v1alpha1.IntegrationPlatformPhase, error) { + ctxs := v1alpha1.NewIntegrationContextList() + options := metav1.ListOptions{ + LabelSelector: "camel.apache.org/context.type=platform", + } + if err := sdk.List(namespace, &ctxs, sdk.WithListOptions(&options)); err != nil { + return "", err + } + + countReady := 0 + for _, ctx := range ctxs.Items { + if ctx.Status.Phase == v1alpha1.IntegrationContextPhaseError { + return v1alpha1.IntegrationPlatformPhaseError, nil + } else if ctx.Status.Phase == v1alpha1.IntegrationContextPhaseReady { + countReady++ + } + } + + if countReady < len(ctxs.Items) { + return v1alpha1.IntegrationPlatformPhaseStarting, nil + } + + return v1alpha1.IntegrationPlatformPhaseReady, nil +} diff --git a/pkg/stub/handler.go b/pkg/stub/handler.go index cb78d7b..18ae691 100644 --- a/pkg/stub/handler.go +++ b/pkg/stub/handler.go @@ -18,44 +18,50 @@ limitations under the License. package stub import ( - "context" - + ctx "context" "github.com/apache/camel-k/pkg/apis/camel/v1alpha1" + "github.com/apache/camel-k/pkg/stub/action/platform" - caction "github.com/apache/camel-k/pkg/stub/action/context" - iaction "github.com/apache/camel-k/pkg/stub/action/integration" + "github.com/apache/camel-k/pkg/stub/action/context" + "github.com/apache/camel-k/pkg/stub/action/integration" "github.com/operator-framework/operator-sdk/pkg/sdk" "github.com/sirupsen/logrus" ) // NewHandler -- -func NewHandler(ctx context.Context, namespace string) sdk.Handler { +func NewHandler(ctx ctx.Context, namespace string) sdk.Handler { return &handler{ - integrationActionPool: []iaction.IntegrationAction{ - iaction.NewInitializeAction(), - iaction.NewBuildAction(namespace), - iaction.NewDeployAction(), - iaction.NewMonitorAction(), + integrationActionPool: []integration.Action{ + integration.NewInitializeAction(), + integration.NewBuildAction(namespace), + integration.NewDeployAction(), + integration.NewMonitorAction(), + }, + integrationContextActionPool: []context.Action{ + context.NewInitializeAction(), + context.NewBuildAction(ctx), + context.NewMonitorAction(), }, - integrationContextActionPool: []caction.IntegrationContextAction{ - caction.NewIntegrationContextInitializeAction(), - caction.NewIntegrationContextBuildAction(ctx, namespace), - caction.NewIntegrationContextMonitorAction(), + integrationPlatformActionPool: []platform.Action{ + platform.NewInitializeAction(), + platform.NewCreateAction(), + platform.NewStartAction(), }, } } type handler struct { - integrationActionPool []iaction.IntegrationAction - integrationContextActionPool []caction.IntegrationContextAction + integrationActionPool []integration.Action + integrationContextActionPool []context.Action + integrationPlatformActionPool []platform.Action } -func (h *handler) Handle(ctx context.Context, event sdk.Event) error { +func (h *handler) Handle(ctx ctx.Context, event sdk.Event) error { switch o := event.Object.(type) { case *v1alpha1.Integration: for _, a := range h.integrationActionPool { if a.CanHandle(o) { - logrus.Info("Invoking action ", a.Name(), " on integration ", o.Name) + logrus.Debug("Invoking action ", a.Name(), " on integration ", o.Name) if err := a.Handle(o); err != nil { return err } @@ -64,7 +70,16 @@ func (h *handler) Handle(ctx context.Context, event sdk.Event) error { case *v1alpha1.IntegrationContext: for _, a := range h.integrationContextActionPool { if a.CanHandle(o) { - logrus.Info("Invoking action ", a.Name(), " on context ", o.Name) + logrus.Debug("Invoking action ", a.Name(), " on context ", o.Name) + if err := a.Handle(o); err != nil { + return err + } + } + } + case *v1alpha1.IntegrationPlatform: + for _, a := range h.integrationPlatformActionPool { + if a.CanHandle(o) { + logrus.Debug("Invoking action ", a.Name(), " on platform ", o.Name) if err := a.Handle(o); err != nil { return err } diff --git a/pkg/util/openshift/register.go b/pkg/util/openshift/register.go index 83b08aa..373e42e 100644 --- a/pkg/util/openshift/register.go +++ b/pkg/util/openshift/register.go @@ -29,7 +29,7 @@ import ( "k8s.io/apimachinery/pkg/runtime" ) -// Register all Openshift types that we want to manage. +// Register all OpenShift types that we want to manage. func init() { k8sutil.AddToSDKScheme(addKnownTypes) } diff --git a/runtime/examples/routes-rest.js b/runtime/examples/routes-rest.js index 47b9c24..e888019 100644 --- a/runtime/examples/routes-rest.js +++ b/runtime/examples/routes-rest.js @@ -1,7 +1,7 @@ // // To run this integrations use: // -// kamel run --name=withrest --dependency=camel:undertow runtime/examples/routes-rest.js +// kamel run --name=withrest --dependency=camel-undertow runtime/examples/routes-rest.js // // **************** ---------------------------------------------------------------- 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: us...@infra.apache.org With regards, Apache Git Services