blob: ceeb4baa863f556301cd1ace89cd2bbe0e33fdbf [file] [log] [blame]
/*
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"
"regexp"
v1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1"
platformutil "github.com/apache/camel-k/v2/pkg/platform"
"github.com/spf13/cobra"
k8serrors "k8s.io/apimachinery/pkg/api/errors"
"sigs.k8s.io/controller-runtime/pkg/client"
)
// kameletRepositoryURIRegexp is the regular expression used to validate the URI of a Kamelet repository.
var kameletRepositoryURIRegexp = regexp.MustCompile(`^github:[^/]+/[^/]+((/[^/]+)*)?$`)
func newKameletAddRepoCmd(rootCmdOptions *RootCmdOptions) (*cobra.Command, *kameletAddRepoCommandOptions) {
options := kameletAddRepoCommandOptions{
kameletUpdateRepoCommandOptions: &kameletUpdateRepoCommandOptions{
RootCmdOptions: rootCmdOptions,
},
}
cmd := cobra.Command{
Use: "add-repo github:owner/repo[/path_to_kamelets_folder][@version] ...",
Short: "Add a Kamelet repository",
Long: `Add a Kamelet repository.`,
PreRunE: decode(&options, options.Flags),
RunE: func(cmd *cobra.Command, args []string) error {
if err := options.validate(args); err != nil {
return err
}
return options.run(cmd, args)
},
}
cmd.Flags().StringP("operator-id", "x", "", "Id of the Operator to update. If not set, the default active Integration Platform is updated.")
return &cmd, &options
}
type kameletUpdateRepoCommandOptions struct {
*RootCmdOptions
OperatorID string `mapstructure:"operator-id" yaml:",omitempty"`
}
type kameletAddRepoCommandOptions struct {
*kameletUpdateRepoCommandOptions
}
func (o *kameletAddRepoCommandOptions) validate(args []string) error {
if len(args) == 0 {
return errors.New("at least one Kamelet repository is expected")
}
return nil
}
func (o *kameletAddRepoCommandOptions) run(cmd *cobra.Command, args []string) error {
c, err := o.GetCmdClient()
if err != nil {
return err
}
var platform *v1.IntegrationPlatform
if o.OperatorID == "" {
o.OperatorID = platformutil.DefaultPlatformName
}
platform, err = o.getIntegrationPlatform(cmd, c)
if err != nil {
return err
} else if platform == nil {
return nil
}
for _, uri := range args {
if err := checkURI(uri, platform.Spec.Kamelet.Repositories); err != nil {
return err
}
platform.Spec.Kamelet.Repositories = append(platform.Spec.Kamelet.Repositories, v1.KameletRepositorySpec{
URI: uri,
})
}
return c.Update(o.Context, platform)
}
// getIntegrationPlatform gives the integration platform matching with the operator id in the provided namespace.
func (o *kameletUpdateRepoCommandOptions) getIntegrationPlatform(cmd *cobra.Command, c client.Client) (*v1.IntegrationPlatform, error) {
key := client.ObjectKey{
Namespace: o.Namespace,
Name: o.OperatorID,
}
platform := v1.IntegrationPlatform{}
if err := c.Get(o.Context, key, &platform); err != nil {
if k8serrors.IsNotFound(err) {
// IntegrationPlatform may be in the operator namespace, but we currently don't have a way to determine it: we just warn
fmt.Fprintf(cmd.ErrOrStderr(), "Warning: IntegrationPlatform %q not found in namespace %q\n", key.Name, key.Namespace)
return nil, nil
}
return nil, err
}
return &platform, nil
}
// findIntegrationPlatform gives the integration platform that could be found in the provided namespace.
func (o *kameletUpdateRepoCommandOptions) findIntegrationPlatform(cmd *cobra.Command, c client.Client) (*v1.IntegrationPlatform, error) {
platforms, err := platformutil.ListPlatforms(o.Context, c, o.Namespace)
if err != nil {
return nil, err
}
for _, p := range platforms.Items {
p := p // pin
if platformutil.IsActive(&p) {
return &p, nil
}
}
fmt.Fprintf(cmd.ErrOrStderr(), "Warning: No active IntegrationPlatform could be found in namespace %q\n", o.Namespace)
return nil, nil
}
func checkURI(uri string, repositories []v1.KameletRepositorySpec) error {
if !kameletRepositoryURIRegexp.MatchString(uri) {
return fmt.Errorf("malformed Kamelet repository uri %s, the expected format is github:owner/repo[/path_to_kamelets_folder][@version]", uri)
}
for _, repo := range repositories {
if repo.URI == uri {
return fmt.Errorf("duplicate Kamelet repository uri %s", uri)
}
}
return nil
}