| /* |
| Licensed to the Apache Software Foundation (ASF) under one or more |
| contributor license agreements. See the NOTICE file distributed with |
| this work for additional information regarding copyright ownership. |
| The ASF licenses this file to You under the Apache License, Version 2.0 |
| (the "License"); you may not use this file except in compliance with |
| the License. You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| */ |
| |
| package cmd |
| |
| import ( |
| "errors" |
| "fmt" |
| "strings" |
| |
| "github.com/spf13/cobra" |
| |
| k8serrors "k8s.io/apimachinery/pkg/api/errors" |
| k8sclient "sigs.k8s.io/controller-runtime/pkg/client" |
| |
| v1 "github.com/apache/camel-k/pkg/apis/camel/v1" |
| "github.com/apache/camel-k/pkg/trait" |
| "github.com/apache/camel-k/pkg/util" |
| "github.com/apache/camel-k/pkg/util/kubernetes" |
| ) |
| |
| func newKitCreateCmd(rootCmdOptions *RootCmdOptions) (*cobra.Command, *kitCreateCommandOptions) { |
| options := kitCreateCommandOptions{ |
| RootCmdOptions: rootCmdOptions, |
| } |
| |
| cmd := cobra.Command{ |
| Use: "create <name>", |
| Short: "Create an Integration Kit", |
| Long: `Create an Integration Kit.`, |
| Args: options.validateArgs, |
| PreRunE: decode(&options), |
| RunE: options.run, |
| } |
| |
| cmd.Flags().String("image", "", "Image used to create the kit") |
| cmd.Flags().StringArrayP("dependency", "d", nil, "Add a dependency") |
| cmd.Flags().StringArrayP("property", "p", nil, "Add a camel property") |
| cmd.Flags().StringArray("configmap", nil, "Add a ConfigMap") |
| cmd.Flags().StringArray("secret", nil, "Add a Secret") |
| cmd.Flags().StringArray("repository", nil, "Add a maven repository") |
| cmd.Flags().StringArrayP("trait", "t", nil, "Configure a trait. E.g. \"-t service.enabled=false\"") |
| |
| // completion support |
| configureKnownCompletions(&cmd) |
| |
| return &cmd, &options |
| } |
| |
| type kitCreateCommandOptions struct { |
| *RootCmdOptions |
| |
| Image string `mapstructure:"image"` |
| Dependencies []string `mapstructure:"dependencies"` |
| Properties []string `mapstructure:"properties"` |
| Configmaps []string `mapstructure:"configmaps"` |
| Secrets []string `mapstructure:"secrets"` |
| Repositories []string `mapstructure:"repositories"` |
| Traits []string `mapstructure:"traits"` |
| } |
| |
| func (command *kitCreateCommandOptions) validateArgs(_ *cobra.Command, args []string) error { |
| if len(args) != 1 { |
| return errors.New("create expects a single name argument") |
| } |
| |
| return nil |
| } |
| |
| func (command *kitCreateCommandOptions) run(_ *cobra.Command, args []string) error { |
| c, err := command.GetCmdClient() |
| if err != nil { |
| return err |
| } |
| |
| catalog := trait.NewCatalog(command.Context, c) |
| tp := catalog.ComputeTraitsProperties() |
| for _, t := range command.Traits { |
| kv := strings.SplitN(t, "=", 2) |
| |
| if !util.StringSliceExists(tp, kv[0]) { |
| fmt.Printf("Error: %s is not a valid trait property\n", t) |
| return nil |
| } |
| } |
| |
| kit := v1.NewIntegrationKit(command.Namespace, args[0]) |
| key := k8sclient.ObjectKey{ |
| Namespace: command.Namespace, |
| Name: args[0], |
| } |
| if err := c.Get(command.Context, key, &kit); err == nil { |
| // the integration kit already exists, let's check that it is |
| // not a platform one which is supposed to be "read only" |
| |
| if kit.Labels["camel.apache.org/kit.type"] == v1.IntegrationKitTypePlatform { |
| fmt.Printf("integration kit \"%s\" is not editable\n", kit.Name) |
| return nil |
| } |
| } |
| |
| kit = v1.NewIntegrationKit(command.Namespace, kubernetes.SanitizeName(args[0])) |
| kit.Labels = map[string]string{ |
| "camel.apache.org/kit.type": v1.IntegrationKitTypeUser, |
| } |
| kit.Spec = v1.IntegrationKitSpec{ |
| Dependencies: make([]string, 0, len(command.Dependencies)), |
| Configuration: make([]v1.ConfigurationSpec, 0), |
| Repositories: command.Repositories, |
| } |
| |
| if command.Image != "" { |
| // if the Image is set, the kit do not require any build but |
| // is be marked as external as the information about the classpath |
| // is missing so it cannot be used as base for other Kits |
| kit.Labels["camel.apache.org/kit.type"] = v1.IntegrationKitTypeExternal |
| |
| // Set the Image to be used by the kit |
| kit.Spec.Image = command.Image |
| } |
| for _, item := range command.Dependencies { |
| switch { |
| case strings.HasPrefix(item, "mvn:"): |
| kit.Spec.Dependencies = append(kit.Spec.Dependencies, item) |
| case strings.HasPrefix(item, "file:"): |
| kit.Spec.Dependencies = append(kit.Spec.Dependencies, item) |
| case strings.HasPrefix(item, "camel-quarkus-"): |
| kit.Spec.Dependencies = append(kit.Spec.Dependencies, "camel-quarkus:"+strings.TrimPrefix(item, "camel-quarkus-")) |
| case strings.HasPrefix(item, "camel-"): |
| kit.Spec.Dependencies = append(kit.Spec.Dependencies, "camel:"+strings.TrimPrefix(item, "camel-")) |
| } |
| } |
| |
| for _, item := range command.Properties { |
| kit.Spec.Configuration = append(kit.Spec.Configuration, v1.ConfigurationSpec{ |
| Type: "property", |
| Value: item, |
| }) |
| } |
| for _, item := range command.Configmaps { |
| kit.Spec.Configuration = append(kit.Spec.Configuration, v1.ConfigurationSpec{ |
| Type: "configmap", |
| Value: item, |
| }) |
| } |
| for _, item := range command.Secrets { |
| kit.Spec.Configuration = append(kit.Spec.Configuration, v1.ConfigurationSpec{ |
| Type: "secret", |
| Value: item, |
| }) |
| } |
| if err := command.configureTraits(&kit, command.Traits, catalog); err != nil { |
| return nil |
| } |
| |
| existed := false |
| err = c.Create(command.Context, &kit) |
| if err != nil && k8serrors.IsAlreadyExists(err) { |
| existed = true |
| clone := kit.DeepCopy() |
| err = c.Get(command.Context, key, clone) |
| if err != nil { |
| fmt.Print(err.Error()) |
| return nil |
| } |
| kit.ResourceVersion = clone.ResourceVersion |
| err = c.Update(command.Context, &kit) |
| } |
| |
| if err != nil { |
| fmt.Print(err.Error()) |
| return nil |
| } |
| |
| if !existed { |
| fmt.Printf("integration kit \"%s\" created\n", kit.Name) |
| } else { |
| fmt.Printf("integration kit \"%s\" updated\n", kit.Name) |
| } |
| |
| return nil |
| } |
| |
| func (*kitCreateCommandOptions) configureTraits(kit *v1.IntegrationKit, options []string, catalog *trait.Catalog) error { |
| traits, err := configureTraits(options, catalog) |
| if err != nil { |
| return err |
| } |
| |
| kit.Spec.Traits = traits |
| |
| return nil |
| } |