Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ require (
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.1.1 // indirect
github.com/coreos/go-semver v0.3.0 // indirect
github.com/coreos/go-systemd/v22 v22.3.2 // indirect
github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/evanphx/json-patch v4.9.0+incompatible // indirect
github.com/fsnotify/fsnotify v1.4.9 // indirect
Expand Down Expand Up @@ -79,7 +79,11 @@ require (
sigs.k8s.io/yaml v1.2.0 // indirect
)

require cloud.google.com/go/compute v1.8.0
require (
cloud.google.com/go/compute v1.8.0
github.com/rs/zerolog v1.27.0
github.com/spf13/cobra v0.0.5
)

require (
github.com/aws/aws-sdk-go-v2/credentials v1.12.14 // indirect
Expand All @@ -92,4 +96,7 @@ require (
github.com/aws/aws-sdk-go-v2/service/sts v1.16.13 // indirect
github.com/aws/smithy-go v1.12.1 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.1.0 // indirect
github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/mattn/go-colorable v0.1.12 // indirect
github.com/mattn/go-isatty v0.0.14 // indirect
)
39 changes: 12 additions & 27 deletions go.sum

Large diffs are not rendered by default.

43 changes: 42 additions & 1 deletion pkg/cluster/kubernetes.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright © 2021 Cisco
// Copyright © 2021, 2022 Cisco
//
// SPDX-License-Identifier: Apache-2.0
//
Expand Down Expand Up @@ -133,6 +133,8 @@ func GetEtcdCredentialsSecret(ctx context.Context) (string, string, error) {
return string(secret.Data["username"]), string(secret.Data["password"]), nil
}

// DEPRECATED
// TODO: remove me
func GetOperatorSettingsConfigMap(ctx context.Context) ([]byte, error) {
cli, err := getK8sClientSet()
if err != nil {
Expand Down Expand Up @@ -160,3 +162,42 @@ func GetOperatorSettingsConfigMap(ctx context.Context) ([]byte, error) {

return data, err
}

func GetFilesFromConfigMap(ctx context.Context, nsName, name string) ([][]byte, error) {
cli, err := getK8sClientSet()
if err != nil {
return nil, err
}

cfgm, err := cli.CoreV1().ConfigMaps(nsName).Get(ctx, name, metav1.GetOptions{})
if err != nil {
return nil, err
}

data := [][]byte{}
for _, d := range cfgm.Data {
data = append(data, []byte(d))
}

return data, err
}

func GetFilesFromSecret(ctx context.Context, nsName, name string) ([][]byte, error) {
cli, err := getK8sClientSet()
if err != nil {
return nil, err
}

secret, err := cli.CoreV1().Secrets(nsName).Get(ctx, name, metav1.GetOptions{})
if err != nil {
return nil, err
}

data := [][]byte{}
for _, d := range secret.Data {
data = append(data, d)
break
}

return data, nil
}
37 changes: 37 additions & 0 deletions pkg/command/root.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// Copyright © 2022 Cisco
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// All rights reserved.
//
// SPDX-License-Identifier: Apache-2.0

package command

import (
"github.com/CloudNativeSDWAN/cnwan-operator/pkg/command/run"
"github.com/spf13/cobra"
)

func GetRootCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "cnwan-operator [COMMAND] [OPTIONS]",
Short: "Watch and synchronize your Kubernetes services on a service registry.",
Example: "cnwan-operator run service-directory --default-region us-east1",
}

// Commands
cmd.AddCommand(run.GetRunCommand())

return cmd
}
209 changes: 209 additions & 0 deletions pkg/command/run/cloud_map.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
// Copyright © 2022 Cisco
//
// SPDX-License-Identifier: Apache-2.0
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// All rights reserved.

package run

import (
"context"
"fmt"
"io/ioutil"
"os"
"path"
"time"

"github.com/CloudNativeSDWAN/cnwan-operator/pkg/servregistry/aws/cloudmap"
"github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/service/servicediscovery"
"github.com/spf13/cobra"
"gopkg.in/yaml.v3"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/log/zap"
)

const (
defaultCloudMapConfigMapName = "cloud-map-options"
defaultCloudMapCredentialsSecretName = "cloud-map-credentials"
)

type CloudMapOptions struct {
DefaultRegion string `yaml:"defaultRegion"`

credentialsBytes []byte
}

func getRunCloudMapCommand(operatorOpts *Options) *cobra.Command {
// -----------------------------
// Inits and defaults
// -----------------------------

opts := &CloudMapOptions{}
cmFileOpts := &fileOrK8sResource{}
credsOpts := &fileOrK8sResource{}

// -----------------------------
// The command
// -----------------------------

cmd := &cobra.Command{
Use: "cloudmap [OPTIONS]",
Aliases: []string{"cm", "aws-cloud-map", "with-cloud-map"},
Short: "Run the program with AWS Cloud Map",
PreRunE: func(cmd *cobra.Command, args []string) error {
// -- Parse the options
if err := parseCloudMapCommand(cmFileOpts, opts, operatorOpts, cmd); err != nil {
return fmt.Errorf("error while parsing cloud map command: %w", err)
}

// -- Get the credentials file
if credsOpts.path == "" && credsOpts.k8s == "" {
homeDir, err := os.UserHomeDir()
if err != nil {
return fmt.Errorf("cannot detect user home directory: %w", err)
}

credsOpts.path = path.Join(homeDir, ".aws", "credentials")
}

var k8sres *k8sResource
if credsOpts.k8s != "" {
k8sres = &k8sResource{
Type: "secret",
Namespace: operatorOpts.Namespace,
Name: credsOpts.k8s,
}
}
credentialsBytes, err := getFileFromPathOrK8sResource(credsOpts.path, k8sres)
if err != nil {
return fmt.Errorf("cannot get credentials for cloud metadata: %w", err)
}

opts.credentialsBytes = credentialsBytes

return nil
},
RunE: func(_ *cobra.Command, _ []string) error {
return runWithCloudMap(operatorOpts, opts)
},
Example: "cloudmap --default-region us-east-1",
}

// -----------------------------
// Flags
// -----------------------------

cmd.Flags().StringVar(&opts.DefaultRegion, "default-region", "",
"region/location where to register resources.")
cmd.Flags().StringVar(&cmFileOpts.path, "cloud-map.options-path", "",
"path to the file containing cloud map options.")
cmd.Flags().StringVar(&cmFileOpts.k8s, "cloud-map.options-configmap", func() string {
if operatorOpts.RunningInK8s {
return defaultCloudMapConfigMapName
}

return ""
}(),
"name of the Kubernetes config map containing settings.")
cmd.Flags().StringVar(&credsOpts.path, "cloud-map.credentials-path", "",
"path to the credentials file.")
cmd.Flags().StringVar(&credsOpts.k8s, "cloud-map.credentials-secret", func() string {
if operatorOpts.RunningInK8s {
return defaultCloudMapCredentialsSecretName
}

return ""
}(),
"name of the Kubernetes secret containing the credentials.")

return cmd
}

func parseCloudMapCommand(flagOpts *fileOrK8sResource, cmOpts *CloudMapOptions, operatorOpts *Options, cmd *cobra.Command) error {
// --------------------------------
// Get options from path or configmap
// --------------------------------

if flagOpts.path != "" || flagOpts.k8s != "" {
var (
fileOptions []byte
decodedFileOptions *CloudMapOptions
)

var k8sres *k8sResource
if flagOpts.k8s != "" {
k8sres = &k8sResource{
Type: "configmap",
Namespace: operatorOpts.Namespace,
Name: flagOpts.k8s,
}
}

fileOptions, err := getFileFromPathOrK8sResource(flagOpts.path, k8sres)
if err != nil {
return fmt.Errorf("could not load options: %w", err)
}

// Unmarshal the file and put the values found inside into our main
// options struct...
if err := yaml.Unmarshal(fileOptions, &decodedFileOptions); err != nil {
return fmt.Errorf("cannot decode options %s: %w", flagOpts.path, err)
}

// ... unless cmd flags are provided. In which case they (the flags)
// take precedence.
if !cmd.Flag("default-region").Changed {
cmOpts.DefaultRegion = decodedFileOptions.DefaultRegion
}
}

// -- Are the settings provided at least?
if cmOpts.DefaultRegion == "" {
return fmt.Errorf("no region provided")
}

return nil
}

func runWithCloudMap(operatorOpts *Options, cmOpts *CloudMapOptions) error {
// TODO: when #81 is solved an merged this will be replaced
// with zerolog
l := ctrl.Log.WithName("CloudMap")
ctrl.SetLogger(zap.New(zap.UseDevMode(true)))
l.Info("starting...")

ctx, canc := context.WithTimeout(context.Background(), 15*time.Second)
defer canc()
const tempPath = "/tmp/cnwan-operator-aws-credentials"

opts := []func(*config.LoadOptions) error{config.WithRegion(cmOpts.DefaultRegion)}
if err := ioutil.WriteFile(tempPath, cmOpts.credentialsBytes, 0644); err != nil {
return fmt.Errorf("error while trying to write credentials to temporary path: %w", err)
}

opts = append(opts, config.WithSharedCredentialsFiles([]string{tempPath}))
defer os.Remove(tempPath)

cfg, err := config.LoadDefaultConfig(ctx, opts...)
if err != nil {
return fmt.Errorf("error while trying to load AWS configuration: %w", err)
}

// TODO: the context should be given by the run function, or explicitly
// provide a context for each call. This will be fixed with the new API
servreg := cloudmap.NewHandler(context.Background(), servicediscovery.NewFromConfig(cfg), l)
return run(servreg, operatorOpts)
}
Loading