Skip to content

Commit

Permalink
multi master config
Browse files Browse the repository at this point in the history
  • Loading branch information
fabriziopandini committed Dec 4, 2018
1 parent 4ea2ec7 commit 10e6e43
Show file tree
Hide file tree
Showing 22 changed files with 1,254 additions and 456 deletions.
10 changes: 9 additions & 1 deletion cmd/kind/create/cluster/createcluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,18 @@ func runE(flags *flagpole, cmd *cobra.Command, args []string) error {
return fmt.Errorf("aborting due to invalid configuration")
}

// TODO(fabrizio pandini): this check is temporary / WIP
// kind v1alpha config fully supports multi nodes, but the cluster creation logic implemented in
// pkg/cluster/contex.go does not (yet).
// As soon a multi node support is implemented in pkg/cluster/contex.go, this should go away
if len(cfg.Nodes()) > 1 {
return fmt.Errorf("multi node support is still a work in progress, currently only single node cluster are supported")
}

// create a cluster context and create the cluster
ctx := cluster.NewContext(flags.Name)
if flags.ImageName != "" {
cfg.Image = flags.ImageName
cfg.BootStrapControlPlane().Image = flags.ImageName
err := cfg.Validate()
if err != nil {
log.Errorf("Invalid flags, configuration failed validation: %v", err)
Expand Down
1 change: 0 additions & 1 deletion hack/update-generated.sh
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ deepcopy-gen -i ./pkg/cluster/config/ -O zz_generated.deepcopy --go-header-file

deepcopy-gen -i ./pkg/cluster/config/v1alpha1 -O zz_generated.deepcopy --go-header-file hack/boilerplate.go.txt
defaulter-gen -i ./pkg/cluster/config/v1alpha1 -O zz_generated.default --go-header-file hack/boilerplate.go.txt
conversion-gen -i ./pkg/cluster/config/v1alpha1 -O zz_generated.conversion --go-header-file hack/boilerplate.go.txt

deepcopy-gen -i ./pkg/cluster/config/v1alpha2 -O zz_generated.deepcopy --go-header-file hack/boilerplate.go.txt
defaulter-gen -i ./pkg/cluster/config/v1alpha2 -O zz_generated.default --go-header-file hack/boilerplate.go.txt
Expand Down
220 changes: 220 additions & 0 deletions pkg/cluster/config/config_types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,220 @@
/*
Copyright 2018 The Kubernetes 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 config

import (
"fmt"
"sort"
)

// +k8s:deepcopy-gen=false

// Config groups all nodes in the `kind` Config.
// This is the current internal config type used by `kind` and it is not
// exposed as a object of the public API.
type Config struct {
// nodes constains the list of nodes defined in the `kind` Config
// Such list is not meant to be set by hand, but the Add method
// should be used insted
nodes NodeList

// derivedConfigData is struct populated starting from the node list
// that provides a set of convenience func for accessing nodes
// with different role in the kind cluster.
derivedConfigData
}

// +k8s:deepcopy-gen=false

// NodeList defines a list of Node in the `kind` Config
type NodeList []*Node

// +k8s:deepcopy-gen=false

// derivedConfigData is a struct populated starting from the node list
// that provides a set of convenience func for accessing nodes
// with different role in the kind cluster.
type derivedConfigData struct {
// controlPlanes contains the subset of nodes with control-plane role
controlPlanes NodeList
// workers contains the subset of nodes with worker role, if any
workers NodeList
// externalEtcd contains the node with external-etcd role, if defined
// TODO(fabriziopandini): eventually in future we would like to support
// external etcd clusters with more than one member
externalEtcd *Node
// externalLoadBalancer contains the node with external-load-balancer role, if defined
externalLoadBalancer *Node
}

// Len of the NodeList.
// It is required for making NodeList sortable.
func (t NodeList) Len() int {
return len(t)
}

// Less return the lower between two elements of the NodeList, where the
// lower element should be provisioned before the other.
// It is required for making NodeList sortable.
func (t NodeList) Less(i, j int) bool {
return t[i].ProvisioningOrder() < t[j].ProvisioningOrder() ||
// In case of same provisioning order, the name is used to get predictable/repeatable results
(t[i].ProvisioningOrder() == t[j].ProvisioningOrder() && t[i].Name < t[j].Name)
}

// Swap two elements of the NodeList.
// It is required for making NodeList sortable.
func (t NodeList) Swap(i, j int) {
t[i], t[j] = t[j], t[i]
}

// Add a Node to the `kind` cluster and assignes a unique node name.
// If the node should have replicas, more instances of the node are created as well
func (c *Config) Add(node *Node) error {
// defines the list of expected replica of the node that by default are one (the node itself)
replicas := NodeList{node}

// in case the node should have replicas
if node.Replicas != nil {
// generate expected replicas
replicas = NodeList{}
for i := 1; i <= int(*node.Replicas); i++ {
replicas = append(replicas, node.DeepCopy())
}
}

// adds replica of the node to the config
for _, replica := range replicas {

// adds the replica to the list of nodes
c.nodes = append(c.nodes, replica)

// updates derivedConfigData

// list of nodes with control plane role
if replica.IsControlPlane() {
// assign selected name for control plane node
replica.Name = "controlplane"
// stores the node in derivedConfigData
c.controlPlanes = append(c.controlPlanes, replica)
}

// list of nodes with worker role
if replica.IsWorker() {
// assign selected name for worker node
replica.Name = "worker"
// stores the node in derivedConfigData
c.workers = append(c.workers, replica)
}

// node with external etcd role
if replica.IsExternalEtcd() {
if c.externalEtcd != nil {
return fmt.Errorf("invalid config. there are two nodes with role %q", ExternalEtcdRole)
}
// assign selected name for etcd node
replica.Name = "etcd"
// stores the node in derivedConfigData
c.externalEtcd = replica
}

// node with external load balancer role
if replica.IsExternalLoadBalancer() {
if c.externalLoadBalancer != nil {
return fmt.Errorf("invalid config. there are two nodes with role %q", ExternalLoadBalancerRole)
}
// assign selected name for load balancer node
replica.Name = "lb"
// stores the node in derivedConfigData
c.externalLoadBalancer = replica
}

}

// if only one node exists in the cluster, and it is a control plane, assign empty name
// to keep generated container name short in the simplest cluster scenario
if len(c.nodes) == 1 && len(c.controlPlanes) == 1 {
c.nodes[0].Name = ""
}

if len(c.nodes) > 1 && len(c.controlPlanes) == 1 {
c.controlPlanes[0].Name = "controlplane"
}

// if more than one control plane node exists, fixes names to get a progressive index
if len(c.controlPlanes) > 1 {
for i, n := range c.controlPlanes {
n.Name = fmt.Sprintf("%s%d", "controlplane", i+1)
}
}

// if more than one worker node exists, fixes names to get a progressive index
if len(c.workers) > 1 {
for i, n := range c.workers {
n.Name = fmt.Sprintf("%s%d", "worker", i+1)
}
}

// ensure the list of nodes is ordered
sort.Sort(c.nodes)

return nil
}

// Nodes returns all the nodes defined in the `kind` Config.
// Always use the Add method to add nodes.
func (c *Config) Nodes() NodeList {
return c.nodes
}

// ControlPlanes returns all the nodes with control-plane role
func (c *Config) ControlPlanes() NodeList {
return c.controlPlanes
}

// BootStrapControlPlane returns the first node with control-plane role
// This is the node where kubeadm init will be executed.
func (c *Config) BootStrapControlPlane() *Node {
if len(c.controlPlanes) == 0 {
return nil
}
return c.controlPlanes[0]
}

// SecondaryControlPlanes returns all the nodes with control-plane role
// except the BootStrapControlPlane node, if any,
func (c *Config) SecondaryControlPlanes() NodeList {
if len(c.controlPlanes) <= 1 {
return nil
}
return c.controlPlanes[1:]
}

// Workers returns all the nodes with Worker role, if any
func (c *Config) Workers() NodeList {
return c.workers
}

// ExternalEtcd returns the node with external-etcd role, if defined
func (c *Config) ExternalEtcd() *Node {
return c.externalEtcd
}

// ExternalLoadBalancer returns the node with external-load-balancer role, if defined
func (c *Config) ExternalLoadBalancer() *Node {
return c.externalLoadBalancer
}
Loading

0 comments on commit 10e6e43

Please sign in to comment.