Skip to content

Commit

Permalink
Specify globalCIDR while joining cluster
Browse files Browse the repository at this point in the history
Enhance 'subctl join' to be able specify globalCIDR
for each cluster while joining. The logic implemented is

if globalcidr specified by user
  if globalcidr is preconfigured
    take pre-configured value
  else
    error if it overlaps with other clusters
    take specified value

if not specified by user
  if globalcidr is preconfigured
    take pre-configured value
  else automatically assign value

It also checks
* if the specified CIDR is valid
and that both globalcidr and globalnet cluster
size are not specified.
* if globalnet-cidr or globalnet-cluster-size
is specified even if globalnet is not enabled
and ignores its value.

Closes: submariner-io#298
Signed-off-by: Janki Chhatbar
  • Loading branch information
Jaanki authored and mangelajo committed Apr 28, 2020
1 parent 9f39a35 commit 864856c
Showing 1 changed file with 86 additions and 21 deletions.
107 changes: 86 additions & 21 deletions pkg/subctl/cmd/join.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"errors"
"fmt"
"io"
"net"
"os"
"regexp"
"strings"
Expand Down Expand Up @@ -52,7 +53,7 @@ var (
clusterID string
serviceCIDR string
clusterCIDR string
globalCIDR string
globalnetCIDR string
repository string
imageVersion string
nattPort int
Expand Down Expand Up @@ -95,6 +96,8 @@ func addJoinFlags(cmd *cobra.Command) {
"disable OpenShift's cluster version operator if necessary, without prompting")
cmd.Flags().UintVar(&globalnetClusterSize, "globalnet-cluster-size", 0,
"Cluster size for GlobalCIDR allocated to this cluster (amount of global IPs)")
cmd.Flags().StringVar(&globalnetCIDR, "globalnet-cidr", "",
"GlobalCIDR to be allocated to the cluster")
}

const (
Expand Down Expand Up @@ -126,6 +129,8 @@ func checkArgumentPassed(args []string) error {
return nil
}

var status = cli.NewStatus()

func joinSubmarinerCluster(config *rest.Config, subctlData *datafile.SubctlData) {

// Missing information
Expand Down Expand Up @@ -191,20 +196,14 @@ func joinSubmarinerCluster(config *rest.Config, subctlData *datafile.SubctlData)
colorCodes = answers.ColorCodes
}
}
if subctlData.GlobalnetCidrRange != "" && globalnetClusterSize != 0 && globalnetClusterSize != subctlData.GlobalnetClusterSize {
clusterSize, err := globalnet.GetValidClusterSize(subctlData.GlobalnetCidrRange, globalnetClusterSize)
if err != nil || clusterSize == 0 {
exitOnError("Invalid globalnet-cluster-size", err)
}
subctlData.GlobalnetClusterSize = clusterSize
}

validateGlobalnetConfiguration(subctlData)

if !noLabel {
err := handleNodeLabels(config)
exitOnError("Unable to set the gateway node up", err)
}

status := cli.NewStatus()
status.Start("Deploying the Submariner operator")
err := submarinerop.Ensure(status, config, OperatorNamespace, operatorImage)
status.End(err == nil)
Expand Down Expand Up @@ -237,16 +236,31 @@ func joinSubmarinerCluster(config *rest.Config, subctlData *datafile.SubctlData)
err = checkOverlappingClusterCidr(globalNetworks)
status.End(err == nil)
exitOnError("Error validating overlapping ClusterCIDRs", err)
} else if globalNetworks[clusterID] == nil || globalNetworks[clusterID].GlobalCIDRs == nil || len(globalNetworks[clusterID].GlobalCIDRs) <= 0 {
// Globalnet enabled, no globalCidr configured on this cluster
globalCIDR, err = globalnet.AllocateGlobalCIDR(globalNetworks, subctlData)
status.End(err == nil)
status.QueueSuccessMessage(fmt.Sprintf("Allocated GlobalCIDR: %s", globalCIDR))
exitOnError("Globalnet failed", err)
} else if globalnetCIDR == "" {
// Globalnet enabled, GlobalCIDR not specified by the user
if cidrIsPreConfigured(clusterID, globalNetworks) {
// globalCidr already configured on this cluster
globalnetCIDR = globalNetworks[clusterID].GlobalCIDRs[0]
status.QueueSuccessMessage(fmt.Sprintf("Cluster already has GlobalCIDR allocated: %s", globalNetworks[clusterID].GlobalCIDRs[0]))
} else {
// no globalCidr configured on this cluster
globalnetCIDR, err = globalnet.AllocateGlobalCIDR(globalNetworks, subctlData)
status.End(err == nil)
status.QueueSuccessMessage(fmt.Sprintf("Allocated GlobalCIDR: %s", globalnetCIDR))
exitOnError("Globalnet failed", err)
}
} else {
// Globalnet enabled, globalCidr already configured on this cluster
globalCIDR = globalNetworks[clusterID].GlobalCIDRs[0]
status.QueueSuccessMessage(fmt.Sprintf("Cluster already has GlobalCIDR allocated: %s", globalNetworks[clusterID].GlobalCIDRs[0]))
// Globalnet enabled, globalnetCIDR specified by user
if cidrIsPreConfigured(clusterID, globalNetworks) {
// globalCidr pre-configured on this cluster
globalnetCIDR = globalNetworks[clusterID].GlobalCIDRs[0]
status.QueueSuccessMessage(fmt.Sprintf("Pre-configured GlobalCIDR %s detected. Not changing it.", globalnetCIDR))
} else {
// globalCidr as specified by the user
err = checkOverlappingGlobalCidr(globalNetworks)
exitOnError(fmt.Sprintf("Error validating overlapping GlobalCIDRs %s", globalnetCIDR), err)
status.QueueSuccessMessage(fmt.Sprintf("GlobalCIDR is: %s", globalnetCIDR))
}
}

status.Start("Creating SA for cluster")
Expand Down Expand Up @@ -288,6 +302,19 @@ func checkOverlappingClusterCidr(networks map[string]*globalnet.GlobalNetwork) e
return nil
}

func checkOverlappingGlobalCidr(networks map[string]*globalnet.GlobalNetwork) error {
for k, v := range networks {
overlap, err := globalnet.IsOverlappingCIDR(v.GlobalCIDRs, globalnetCIDR)
if err != nil {
return fmt.Errorf("unable to validate overlapping GlobalCIDR: %s", err)
}
if overlap && k != clusterID {
return fmt.Errorf("invalid globalnet CIDR: %s overlaps with cluster %s", globalnetCIDR, k)
}
}
return nil
}

func getGlobalNetworks(subctlData *datafile.SubctlData) map[string]*globalnet.GlobalNetwork {

brokerConfig := subctlData.GetBrokerAdministratorConfig()
Expand Down Expand Up @@ -388,6 +415,45 @@ func isOpenShiftCVOEnabled(config *rest.Config) (bool, error) {
return scale.Spec.Replicas > 0, nil
}

func cidrIsPreConfigured(clusterID string, globalNetworks map[string]*globalnet.GlobalNetwork) bool {
// GlobalCIDR is not pre-configured
if globalNetworks[clusterID] == nil || globalNetworks[clusterID].GlobalCIDRs == nil || len(globalNetworks[clusterID].GlobalCIDRs) <= 0 {
return false
}
// GlobalCIDR is pre-configured
return true
}

func validateGlobalnetConfiguration(subctlData *datafile.SubctlData) {
if subctlData.GlobalnetCidrRange != "" && globalnetClusterSize != 0 && globalnetClusterSize != subctlData.GlobalnetClusterSize {
clusterSize, err := globalnet.GetValidClusterSize(subctlData.GlobalnetCidrRange, globalnetClusterSize)
if err != nil || clusterSize == 0 {
exitOnError("Invalid globalnet-cluster-size", err)
}
subctlData.GlobalnetClusterSize = clusterSize
}

if globalnetCIDR != "" && globalnetClusterSize != 0 {
err := errors.New("Both globalnet-cluster-size and globalnet-cidr can't be specified. Specify either one.\n")
exitOnError("Invalid configuration", err)
}

if globalnetCIDR != "" {
_, _, err := net.ParseCIDR(globalnetCIDR)
exitOnError("Specified globalnet-cidr is invalid", err)
}

if subctlData.GlobalnetCidrRange == "" {
if globalnetCIDR != "" {
status.QueueSuccessMessage("globalnet is not enabled on Broker. Ignoring specified globalnet-cidr\n")
globalnetCIDR = ""
} else if globalnetClusterSize != 0 {
status.QueueSuccessMessage("globalnet is not enabled on Broker. Ignoring specified globalnet-cluster-size\n")
globalnetClusterSize = 0
}
}
}

func populateSubmarinerSpec(subctlData *datafile.SubctlData) submariner.SubmarinerSpec {
brokerURL := subctlData.BrokerURL
if idx := strings.Index(brokerURL, "://"); idx >= 0 {
Expand Down Expand Up @@ -429,9 +495,8 @@ func populateSubmarinerSpec(subctlData *datafile.SubctlData) submariner.Submarin
CableDriver: cableDriver,
ServiceDiscoveryEnabled: subctlData.ServiceDiscovery,
}

if globalCIDR != "" {
submarinerSpec.GlobalCIDR = globalCIDR
if globalnetCIDR != "" {
submarinerSpec.GlobalCIDR = globalnetCIDR
}
return submarinerSpec
}

0 comments on commit 864856c

Please sign in to comment.