This is an automated email from the ASF dual-hosted git repository. lburgazzoli pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/camel-k.git
commit 21caae8ff53055dff840f3d6f19ff562fbfff148 Author: nferraro <ni.ferr...@gmail.com> AuthorDate: Tue Sep 25 12:30:22 2018 +0200 Add IntegrationPlatform CRD --- cmd/camel-k-operator/camel_k_operator.go | 1 + deploy/crd-integration-platform.yaml | 17 ++++ deploy/platform-cr.yaml | 6 ++ deploy/resources.go | 31 ++++++ pkg/apis/camel/v1alpha1/register.go | 2 + pkg/apis/camel/v1alpha1/types.go | 76 ++++++++++++++ pkg/apis/camel/v1alpha1/types_support.go | 10 ++ pkg/apis/camel/v1alpha1/zz_generated.deepcopy.go | 110 ++++++++++++++++++++ pkg/client/cmd/install.go | 4 +- pkg/install/cluster.go | 5 + pkg/install/{operator.go => common.go} | 39 ++----- pkg/install/operator.go | 56 +---------- pkg/platform/build.go | 91 +++++++++++++++++ .../integration/action.go => platform/doc.go} | 20 +--- pkg/platform/get.go | 53 ++++++++++ pkg/stub/action/context/action.go | 6 +- pkg/stub/action/context/build.go | 73 ++++---------- pkg/stub/action/context/initialize.go | 25 +++-- pkg/stub/action/context/monitor.go | 17 ++-- pkg/stub/action/integration/action.go | 6 +- pkg/stub/action/integration/build.go | 6 +- pkg/stub/action/integration/deploy.go | 16 +-- pkg/stub/action/integration/initialize.go | 13 ++- pkg/stub/action/integration/monitor.go | 5 +- pkg/stub/action/integration/util.go | 19 +++- pkg/stub/action/{context => platform}/action.go | 11 +- pkg/stub/action/platform/create.go | 54 ++++++++++ pkg/stub/action/platform/initialize.go | 112 +++++++++++++++++++++ pkg/stub/action/platform/start.go | 79 +++++++++++++++ pkg/stub/handler.go | 53 ++++++---- pkg/util/openshift/register.go | 2 +- 31 files changed, 803 insertions(+), 215 deletions(-) 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 @@ -2123,6 +2123,27 @@ spec: 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"] = ` apiVersion: apiextensions.k8s.io/v1beta1 @@ -2436,6 +2457,16 @@ 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"] = ` apiVersion: camel.apache.org/v1alpha1 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 @@ -211,6 +211,116 @@ func (in *IntegrationList) DeepCopyObject() runtime.Object { } // 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 if in.Replicas != nil { 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/operator.go b/pkg/install/common.go similarity index 66% copy from pkg/install/operator.go copy to pkg/install/common.go index 58aed65..bef7f6f 100644 --- a/pkg/install/operator.go +++ b/pkg/install/common.go @@ -26,42 +26,18 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) -// Operator -- -func Operator(namespace string) error { - return installResources(namespace, - "operator-service-account.yaml", - "operator-role-openshift.yaml", // TODO distinguish between Openshift and Kubernetes - "operator-role-binding.yaml", - "operator-deployment.yaml", - "operator-service.yaml", - ) -} - -// PlatformContexts -- -func PlatformContexts(namespace string) error { - return installResources(namespace, - "platform-integration-context-core.yaml", - "platform-integration-context-groovy.yaml", - ) -} - -// Example -- -func Example(namespace string) error { - return installResources(namespace, - "cr-example.yaml", - ) -} - -func installResources(namespace string, names ...string) error { +// Resources installs named resources from the project resource directory +func Resources(namespace string, names ...string) error { for _, name := range names { - if err := installResource(namespace, name); err != nil { + if err := Resource(namespace, name); err != nil { return err } } return nil } -func installResource(namespace string, name string) error { +// 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 @@ -77,10 +53,13 @@ func installResource(namespace string, name string) error { if obj.GetObjectKind().GroupVersionKind().Kind == "Service" { return nil } - // Don't recreate integration contexts + // 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/stub/action/integration/action.go b/pkg/platform/doc.go similarity index 65% copy from pkg/stub/action/integration/action.go copy to pkg/platform/doc.go index 9e4a69c..74e5c18 100644 --- a/pkg/stub/action/integration/action.go +++ b/pkg/platform/doc.go @@ -15,21 +15,5 @@ See the License for the specific language governing permissions and limitations under the License. */ -package action - -import ( - "github.com/apache/camel-k/pkg/apis/camel/v1alpha1" -) - -// IntegrationAction -- -type IntegrationAction interface { - - // a user friendly name for the action - Name() string - - // returns true if the action can handle the integration - CanHandle(integration *v1alpha1.Integration) bool - - // executes the handling function - Handle(integration *v1alpha1.Integration) error -} +// 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/context/action.go b/pkg/stub/action/platform/action.go similarity index 82% copy from pkg/stub/action/context/action.go copy to pkg/stub/action/platform/action.go index 23b0f10..cb9ba4c 100644 --- a/pkg/stub/action/context/action.go +++ b/pkg/stub/action/platform/action.go @@ -15,21 +15,20 @@ See the License for the specific language governing permissions and limitations under the License. */ -package action +package platform 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 // returns true if the action can handle the integration context - CanHandle(integration *v1alpha1.IntegrationContext) bool + CanHandle(platform *v1alpha1.IntegrationPlatform) bool // executes the handling function - Handle(integration *v1alpha1.IntegrationContext) error + 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..e56ba09 --- /dev/null +++ b/pkg/stub/action/platform/start.go @@ -0,0 +1,79 @@ +/* +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" +) + +// 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 { + + coreStatus, err := action.getContextReady(platform.Namespace, "core") + if err != nil { + return err + } + + groovyStatus, err := action.getContextReady(platform.Namespace, "groovy") + if err != nil { + return err + } + + if coreStatus == v1alpha1.IntegrationContextPhaseError || groovyStatus == v1alpha1.IntegrationContextPhaseError { + if platform.Status.Phase != v1alpha1.IntegrationPlatformPhaseError { + target := platform.DeepCopy() + logrus.Info("Platform ", target.Name, " transitioning to state ", v1alpha1.IntegrationPlatformPhaseError) + target.Status.Phase = v1alpha1.IntegrationPlatformPhaseError + return sdk.Update(target) + } + return nil + } else if coreStatus == v1alpha1.IntegrationContextPhaseReady && groovyStatus == v1alpha1.IntegrationContextPhaseReady { + target := platform.DeepCopy() + logrus.Info("Platform ", target.Name, " transitioning to state ", v1alpha1.IntegrationPlatformPhaseReady) + target.Status.Phase = v1alpha1.IntegrationPlatformPhaseReady + return sdk.Update(target) + } + + // wait + return nil +} + +func (action *startAction) getContextReady(namespace string, name string) (v1alpha1.IntegrationContextPhase, error) { + ctx := v1alpha1.NewIntegrationContext(namespace, name) + if err := sdk.Get(&ctx); err != nil { + return "", err + } + return ctx.Status.Phase, 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) }