Skip to content

Commit

Permalink
liqoctl install: accept provided parameters for Kind and Kubeadm prov…
Browse files Browse the repository at this point in the history
…iders
  • Loading branch information
lucafrancescato authored and adamjensenbot committed Jan 18, 2022
1 parent 6c45ffb commit d233cf6
Show file tree
Hide file tree
Showing 13 changed files with 301 additions and 39 deletions.
2 changes: 1 addition & 1 deletion cmd/liqo-controller-manager/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ func main() {
"https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#ownerreferencespermissionenforcement")

// Resource sharing parameters
flag.Var(&clusterLabels, "cluster-labels",
flag.Var(&clusterLabels, consts.ClusterLabelsParameter,
"The set of labels which characterizes the local cluster when exposed remotely as a virtual node")
resourceSharingPercentage := argsutils.Percentage{Val: 50}
flag.Var(&resourceSharingPercentage, "resource-sharing-percentage",
Expand Down
12 changes: 6 additions & 6 deletions cmd/liqoctl/cmd/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,17 +40,17 @@ func newInstallCommand(ctx context.Context) *cobra.Command {
installCmd.PersistentFlags().BoolP("only-output-values", "", false, "Generate a values file for further customization")
installCmd.PersistentFlags().StringP("dump-values-path", "", "./values.yaml", "Path for the output value file")
installCmd.PersistentFlags().BoolP("dry-run", "", false, "Simulate an install")
installCmd.PersistentFlags().BoolP("enable-lan-discovery", "", false, "Enable LAN discovery")
installCmd.PersistentFlags().StringP("cluster-labels", "", "",
installCmd.PersistentFlags().BoolP(liqoconst.EnableLanDiscoveryParameter, "", false, "Enable LAN discovery")
installCmd.PersistentFlags().StringP(liqoconst.ClusterLabelsParameter, "", "",
"Cluster Labels to append to Liqo Cluster, supports '='.(e.g. --cluster-labels key1=value1,key2=value2)")
installCmd.PersistentFlags().BoolP("disable-endpoint-check", "", false,
"Disable the check that the current kubeconfig context contains the same endpoint retrieved from the cloud provider (AKS, EKS, GKE)")
installCmd.PersistentFlags().String("chart-path", installutils.LiqoChartFullName,
"Specify a path to get the Liqo chart, instead of installing the chart from the official repository")
installCmd.PersistentFlags().StringP("cluster-name", "n", "", "Name to assign to the Liqo cluster")
installCmd.PersistentFlags().Bool("generate-name", false, "Generate a random Docker-like name for the cluster")
installCmd.PersistentFlags().String("reserved-subnets", "", "In order to prevent IP conflicting between locally used private subnets in your "+
"infrastructure and private subnets belonging to remote clusters "+
installCmd.PersistentFlags().StringP(liqoconst.ClusterNameParameter, "n", "", "Name to assign to the Liqo cluster")
installCmd.PersistentFlags().Bool(liqoconst.GenerateNameParameter, false, "Generate a random Docker-like name for the cluster")
installCmd.PersistentFlags().String(liqoconst.ReservedSubnetsParameter, "", "In order to prevent IP conflicting between "+
"locally used private subnets in your infrastructure and private subnets belonging to remote clusters "+
"you need tell liqo the subnets used in your cluster. E.g if your cluster nodes belong to the 192.168.2.0/24 subnet then "+
"you should add that subnet to the reservedSubnets. PodCIDR and serviceCIDR used in the local cluster are automatically "+
"added to the reserved list. (e.g. --reserved-subnets 192.168.2.0/24,192.168.4.0/24)")
Expand Down
8 changes: 8 additions & 0 deletions pkg/consts/parameters.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,14 @@ package consts
const (
// ClusterNameParameter is the name of the parameter specifying the cluster name.
ClusterNameParameter = "cluster-name"
// ClusterLabelsParameter is the name of the parameter specifying the cluster labels.
ClusterLabelsParameter = "cluster-labels"
// ReservedSubnetsParameter is the name of the parameter specifying the cluster's reserved subnets.
ReservedSubnetsParameter = "reserved-subnets"
// EnableLanDiscoveryParameter is the name of the parameter specifying whether the lan discovery is enabled.
EnableLanDiscoveryParameter = "enable-lan-discovery"
// GenerateNameParameter is the name of the parameter specifying whether to generate a random name for the cluster.
GenerateNameParameter = "generate-name"

// AuthServiceAddressOverrideParameter is the name of the parameter overriding
// the automatically detected authentication service address.
Expand Down
219 changes: 219 additions & 0 deletions pkg/liqoctl/install/install_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
// Copyright 2019-2022 The Liqo Authors
//
// 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.

package install

import (
"fmt"
"testing"

. "github.com/onsi/ginkgo"
. "github.com/onsi/ginkgo/extensions/table"
. "github.com/onsi/gomega"
"github.com/spf13/cobra"

installutils "github.com/liqotech/liqo/pkg/liqoctl/install/utils"
argsutils "github.com/liqotech/liqo/pkg/utils/args"
)

// This recursive function takes a map and a list of keys and visits a tree of nested maps
// using the keys in the order provided. At each iteration, if the number of non-visited keys
// is 1, the function returns the value associated to the last key, else if it is greater
// than 1, the function expects the value to be a map and a new recursive iteration happens.
// In case the key is not found, an empty string is returned.
// In case no keys are provided, an error is returned.
// Example:
// m := map[string]interface{}{
// "first": map[string]interface{}{
// "second": map[string]interface{}{
// "third": "value",
// },
// },
// }
// ValueFor(m, "first", "second", "third") // returns "value", nil
// ValueFor(m, "first", "second") // returns map[string]interface{}{ "third": "value" }, nil
// ValueFor(m, "first", "third") // returns "", nil
// ValueFor(m) // returns nil, "At least one key is required"
func ValueFor(m map[string]interface{}, keys ...string) (val interface{}, err error) {
var ok bool
if len(keys) == 0 {
return nil, fmt.Errorf("At least one key is required")
} else if val, ok = m[keys[0]]; !ok {
return "", nil
} else if len(keys) == 1 {
return val, nil
} else if m, ok = val.(map[string]interface{}); !ok {
return nil, fmt.Errorf("The value for key %s is not map (expected to be a map)", keys[0])
} else {
return ValueFor(m, keys[1:]...)
}
}

func TestInstallCommand(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "Test Install Command")
}

var _ = Describe("Test the install command works as expected", func() {
type testCase struct {
provider string
parameters []string
providerValue string
regionValue string
customLabelValue string
clusterNameValue string
enableAdvertisementValue bool
enableDiscoveryValue bool
reservedSubnetsValue []interface{}
}

DescribeTable("An install command is issued",
func(tc testCase) {
cmd := &cobra.Command{}
cmd.PersistentFlags().Bool("enable-lan-discovery", false, "")
cmd.PersistentFlags().String("cluster-labels", "", "")
cmd.PersistentFlags().String("cluster-name", "default-cluster-name", "")
cmd.PersistentFlags().String("reserved-subnets", "", "")
cmd.PersistentFlags().Bool("generate-name", false, "")
cmd.SetArgs(tc.parameters)
Expect(cmd.Execute()).To(Succeed())

providerInstance := getProviderInstance(tc.provider)
Expect(providerInstance).NotTo(BeNil())
err := providerInstance.PreValidateGenericCommandArguments(cmd.Flags())
Expect(err).ToNot(HaveOccurred())
err = providerInstance.ValidateCommandArguments(cmd.Flags())
Expect(err).ToNot(HaveOccurred())
err = providerInstance.PostValidateGenericCommandArguments("")
Expect(err).ToNot(HaveOccurred())

// Chart values
chartValues := map[string]interface{}{
"discovery": map[string]interface{}{
"config": map[string]interface{}{
"clusterLabels": map[string]interface{}{},
"clusterName": "",
"enableAdvertisement": false,
"enableDiscovery": false,
},
},
"networkManager": map[string]interface{}{
"config": map[string]interface{}{
"reservedSubnets": []interface{}{},
},
},
}

// Common values
enableLanDiscovery, err := cmd.Flags().GetBool("enable-lan-discovery")
Expect(err).ToNot(HaveOccurred())
clusterLabels, err := cmd.Flags().GetString("cluster-labels")
Expect(err).ToNot(HaveOccurred())
clusterLabelsVar := argsutils.StringMap{}
err = clusterLabelsVar.Set(clusterLabels)
Expect(err).ToNot(HaveOccurred())
clusterLabelsMap := installutils.GetInterfaceMap(clusterLabelsVar.StringMap)
commonValues := map[string]interface{}{
"discovery": map[string]interface{}{
"config": map[string]interface{}{
"clusterLabels": clusterLabelsMap,
"enableAdvertisement": enableLanDiscovery,
"enableDiscovery": enableLanDiscovery,
},
},
}

// Provider values
providerValues := make(map[string]interface{})
providerInstance.UpdateChartValues(providerValues)

// Merged values
values, err := generateValues(chartValues, commonValues, providerValues)
Expect(err).ToNot(HaveOccurred())

// Test values over expected ones
Expect(ValueFor(values, "discovery", "config", "clusterLabels", "liqo.io/provider")).To(Equal(tc.providerValue))
Expect(ValueFor(values, "discovery", "config", "clusterName")).To(Equal(tc.clusterNameValue))
Expect(ValueFor(values, "discovery", "config", "clusterLabels", "topology.liqo.io/region")).To(Equal(tc.regionValue))
Expect(ValueFor(values, "discovery", "config", "clusterLabels", "liqo.io/my-label")).To(Equal(tc.customLabelValue))
Expect(ValueFor(values, "discovery", "config", "enableAdvertisement")).To(Equal(tc.enableAdvertisementValue))
Expect(ValueFor(values, "discovery", "config", "enableDiscovery")).To(Equal(tc.enableDiscoveryValue))
Expect(ValueFor(values, "networkManager", "config", "reservedSubnets")).To(Equal(tc.reservedSubnetsValue))
},
Entry("Install Kind cluster with default parameters", testCase{
"kind",
[]string{},
"kind",
"",
"",
"default-cluster-name",
true,
true,
[]interface{}{},
}),
Entry("Install Kind cluster with one cluster labels' key-value pair", testCase{
"kind",
[]string{"--cluster-labels=topology.liqo.io/region=eu-east"},
"kind",
"eu-east",
"",
"default-cluster-name",
true,
true,
[]interface{}{},
}),
Entry("Install Kind cluster with cluster labels, auto-discovery disabled, cluster name and reserved subnets", testCase{
"kind",
[]string{
"--cluster-labels=topology.liqo.io/region=eu-east,liqo.io/my-label=custom,liqo.io/provider=provider-1",
"--enable-lan-discovery=false",
"--cluster-name=cluster-1",
"--reserved-subnets=10.20.30.0/24,10.20.31.0/24",
},
"provider-1",
"eu-east",
"custom",
"cluster-1",
false,
false,
[]interface{}{"10.20.30.0/24", "10.20.31.0/24"},
}),
Entry("Install Kubeadm cluster with default parameters", testCase{
"kubeadm",
[]string{},
"kubeadm",
"",
"",
"default-cluster-name",
false,
false,
[]interface{}{},
}),
Entry("Install Kubeadm cluster with cluster labels, cluster name and reserved subnets", testCase{
"kubeadm",
[]string{
"--cluster-labels=topology.liqo.io/region=eu-east,liqo.io/my-label=custom,liqo.io/provider=provider-1",
"--cluster-name=cluster-1",
"--reserved-subnets=10.20.30.0/24,10.20.31.0/24",
},
"provider-1",
"eu-east",
"custom",
"cluster-1",
false,
false,
[]interface{}{"10.20.30.0/24", "10.20.31.0/24"},
}),
)
})
8 changes: 6 additions & 2 deletions pkg/liqoctl/install/kind/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,16 @@ func (k *Kind) UpdateChartValues(values map[string]interface{}) {
"reservedSubnets": installutils.GetInterfaceSlice(k.ReservedSubnets),
},
}
if k.LanDiscovery == nil {
lanDiscovery := true
k.LanDiscovery = &lanDiscovery
}
values["discovery"] = map[string]interface{}{
"config": map[string]interface{}{
"clusterLabels": installutils.GetInterfaceMap(k.ClusterLabels),
"clusterName": k.ClusterName,
"enableAdvertisement": true,
"enableDiscovery": true,
"enableAdvertisement": *k.LanDiscovery,
"enableDiscovery": *k.LanDiscovery,
},
}
}
16 changes: 4 additions & 12 deletions pkg/liqoctl/install/provider/args.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (

flag "github.com/spf13/pflag"

"github.com/liqotech/liqo/pkg/consts"
installutils "github.com/liqotech/liqo/pkg/liqoctl/install/utils"
argsutils "github.com/liqotech/liqo/pkg/utils/args"
)
Expand Down Expand Up @@ -83,11 +84,7 @@ func ValidateCommonArguments(providerName string, flags *flag.FlagSet) (*CommonA
if err != nil {
return nil, err
}
clusterLabels, err := flags.GetString("cluster-labels")
if err != nil {
return nil, err
}
lanDiscovery, err := flags.GetBool("enable-lan-discovery")
lanDiscovery, err := flags.GetBool(consts.EnableLanDiscoveryParameter)
if err != nil {
return nil, err
}
Expand All @@ -111,7 +108,7 @@ func ValidateCommonArguments(providerName string, flags *flag.FlagSet) (*CommonA
if err != nil {
return nil, err
}
commonValues, err := parseCommonValues(providerName, clusterLabels, chartPath, version, resourceSharingPercentage,
commonValues, err := parseCommonValues(providerName, chartPath, version, resourceSharingPercentage,
lanDiscovery, enableHa, float64(ifaceMTU), float64(listeningPort))
if err != nil {
return nil, err
Expand All @@ -130,12 +127,8 @@ func ValidateCommonArguments(providerName string, flags *flag.FlagSet) (*CommonA
}, nil
}

func parseCommonValues(providerName, clusterLabels, chartPath, version, resourceSharingPercentage string,
func parseCommonValues(providerName, chartPath, version, resourceSharingPercentage string,
lanDiscovery, enableHa bool, mtu, port float64) (map[string]interface{}, error) {
clusterLabelsVar := argsutils.StringMap{}
if err := clusterLabelsVar.Set(clusterLabels); err != nil {
return map[string]interface{}{}, err
}

// If the chartPath is different from the official repo, we force the tag parameter in order to set the correct
// prefix for the images.
Expand Down Expand Up @@ -164,7 +157,6 @@ func parseCommonValues(providerName, clusterLabels, chartPath, version, resource
"tag": tag,
"discovery": map[string]interface{}{
"config": map[string]interface{}{
"clusterLabels": installutils.GetInterfaceMap(clusterLabelsVar.StringMap),
"enableDiscovery": lanDiscovery,
"enableAdvertisement": lanDiscovery,
},
Expand Down
6 changes: 3 additions & 3 deletions pkg/liqoctl/install/provider/args_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ var _ = Describe("Args", func() {
When("mtu is set to zero, falling back to default value for each provider", func() {
It("should return the right mtu in the configuration map", func() {
for _, provider := range Providers {
config, err := parseCommonValues(provider, "", "", "", "", false, false, 0, 0)
config, err := parseCommonValues(provider, "", "", "", false, false, 0, 0)
Expect(err).NotTo(HaveOccurred())
netConfig := config["networkConfig"].(map[string]interface{})
Expect(netConfig["mtu"]).To(BeNumerically("==", providersDefaultMTU[provider]))
Expand All @@ -55,7 +55,7 @@ var _ = Describe("Args", func() {

When("the provider does not exist", func() {
It("should return an error", func() {
_, err := parseCommonValues("notExisting", "", "", "", "", false, false, 0, 0)
_, err := parseCommonValues("notExisting", "", "", "", false, false, 0, 0)
Expect(err).To(HaveOccurred())
Expect(err).To(MatchError(fmt.Errorf("mtu for provider notExisting not found")))
})
Expand All @@ -64,7 +64,7 @@ var _ = Describe("Args", func() {
When("the mtu is set by the user", func() {
It("should set the mtu", func() {
var mtu float64 = 1340
config, err := parseCommonValues("eks", "", "", "", "", false, false, mtu, 0)
config, err := parseCommonValues("eks", "", "", "", false, false, mtu, 0)
Expect(err).NotTo(HaveOccurred())
netConfig := config["networkConfig"].(map[string]interface{})
Expect(netConfig["mtu"]).To(BeNumerically("==", mtu))
Expand Down
Loading

0 comments on commit d233cf6

Please sign in to comment.