Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/support ipv6 dual #1537

Closed
wants to merge 20 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
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
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ build: clean ## build binaries by default
linux: clean ## build binaries for linux
@echo "build sealer and seautil bin for linux"
GOOS=linux GOARCH=amd64 hack/build.sh $(GitTag)
GOOS=linux GOARCH=arm64 hack/build.sh $(GitTag)

test-sealer:
@echo "run e2e test for sealer bin"
Expand Down
79 changes: 48 additions & 31 deletions apply/apply.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,21 @@ package apply

import (
"fmt"
"net"
"os"
"path/filepath"

k8snet "k8s.io/utils/net"

"github.com/sealerio/sealer/apply/applydriver"
"github.com/sealerio/sealer/common"
"github.com/sealerio/sealer/pkg/clusterfile"
"github.com/sealerio/sealer/pkg/env"
"github.com/sealerio/sealer/pkg/filesystem"
"github.com/sealerio/sealer/pkg/image"
"github.com/sealerio/sealer/pkg/image/store"
v2 "github.com/sealerio/sealer/types/api/v2"
"github.com/sealerio/sealer/utils"
)

type Args struct {
Expand All @@ -37,6 +42,9 @@ type Args struct {
Masters string
Nodes string

MasterSlice []string
NodeSlice []string

User string
Password string
Port uint16
Expand All @@ -49,7 +57,7 @@ type Args struct {
CMDArgs []string
}

func NewApplierFromFile(path string) (applydriver.Interface, error) {
func NewApplierFromFile(path, action string) (applydriver.Interface, error) {
if !filepath.IsAbs(path) {
pa, err := os.Getwd()
if err != nil {
Expand All @@ -61,44 +69,19 @@ func NewApplierFromFile(path string) (applydriver.Interface, error) {
if err != nil {
return nil, err
}
imgSvc, err := image.NewImageService()
if err != nil {
return nil, err
}

mounter, err := filesystem.NewClusterImageMounter()
if err != nil {
return nil, err
}

is, err := store.NewDefaultImageStore()
if err != nil {
return nil, err
}
cluster := Clusterfile.GetCluster()
if cluster.Name == "" {
return nil, fmt.Errorf("cluster name cannot be empty, make sure %s file is correct", path)
}
if cluster.GetAnnotationsByKey(common.ClusterfileName) == "" {
cluster.SetAnnotations(common.ClusterfileName, path)
}
return &applydriver.Applier{
ClusterDesired: &cluster,
ClusterFile: Clusterfile,
ImageManager: imgSvc,
ClusterImageMounter: mounter,
ImageStore: is,
}, nil
}

// NewApplier news an applier.
// In NewApplier, we guarantee that no raw data could be passed in.
// And all data has to be validated and processed in the pre-process layer.
func NewApplier(cluster *v2.Cluster) (applydriver.Interface, error) {
return NewDefaultApplier(cluster)
return NewDefaultApplier(&cluster, action, Clusterfile)
}

func NewDefaultApplier(cluster *v2.Cluster) (applydriver.Interface, error) {
// NewDefaultApplier news an applier.
// In NewDefaultApplier, we guarantee that no raw data could be passed in.
// And all data has to be validated and processed in the pre-process layer.
func NewDefaultApplier(cluster *v2.Cluster, action string, file clusterfile.Interface) (applydriver.Interface, error) {
if cluster.Name == "" {
return nil, fmt.Errorf("cluster name cannot be empty")
}
Expand All @@ -117,10 +100,44 @@ func NewDefaultApplier(cluster *v2.Cluster) (applydriver.Interface, error) {
return nil, err
}

hostList := utils.GetIPListFromHosts(cluster.Spec.Hosts)

if err := checkAllHostsSameFamily(hostList); err != nil {
return nil, err
}

if len(hostList) > 0 && k8snet.IsIPv6String(hostList[0]) &&
env.ConvertEnv(cluster.Spec.Env)[v2.EnvHostIPFamily] == nil {
cluster.Spec.Env = append(cluster.Spec.Env, fmt.Sprintf("%s=%s", v2.EnvHostIPFamily, k8snet.IPv6))
}

return &applydriver.Applier{
ClusterDesired: cluster,
ClusterFile: file,
ImageManager: imgSvc,
ClusterImageMounter: mounter,
ImageStore: is,
}, nil
}

func checkAllHostsSameFamily(nodeList []string) error {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the validate function, you could add them into validate.go . Actually It seems to have nothing to do with the main apply procedure. @VinceCui

hasIPv4 := false
hasIPv6 := false
for _, ip := range nodeList {
parsed := net.ParseIP(ip)
if parsed == nil {
return fmt.Errorf("failed to parse %s as a valid ip", ip)
}
if k8snet.IsIPv4(parsed) {
hasIPv4 = true
} else if k8snet.IsIPv6(parsed) {
hasIPv6 = true
}
}

if hasBoth := hasIPv4 && hasIPv6; hasBoth {
return fmt.Errorf("all hosts must be in same ip family, but the node list given are mixed with ipv4 and ipv6: %v", nodeList)
VinceCui marked this conversation as resolved.
Show resolved Hide resolved
}

return nil
}
27 changes: 26 additions & 1 deletion apply/applydriver/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,32 @@
package applydriver

type Interface interface {
Apply() error
Apply(args *Args) error
Delete() error
Upgrade(imageName string) error
}

type Action string

const (
ActionJoin = "Join"
ActionDelete = "Delete"
ActionRun = "Run"
ActionApply = "Apply"
)

type Args struct {
Action Action
JoiningArgs *JoiningArgs
DeletingArgs *DeletingArgs
}

type DeletingArgs struct {
MastersToDelete []string
WorkersToDelete []string
}

type JoiningArgs struct {
MastersToJoin []string
WorkersToJoin []string
}
28 changes: 25 additions & 3 deletions apply/applydriver/local.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,10 @@ func (c *Applier) Delete() (err error) {
}

// Apply different actions between ClusterDesired and ClusterCurrent.
func (c *Applier) Apply() (err error) {
func (c *Applier) Apply(args *Args) (err error) {
if args == nil {
return fmt.Errorf("args can't be empty")
}
// first time to init cluster
if c.ClusterFile == nil {
c.ClusterFile, err = clusterfile.NewClusterFile(c.ClusterDesired.GetAnnotationsByKey(common.ClusterfileName))
Expand All @@ -71,7 +74,10 @@ func (c *Applier) Apply() (err error) {
return err
}
} else {
if err = c.reconcileCluster(); err != nil {
if args.Action == ActionRun {
return fmt.Errorf("sealer run can only be use for init a new cluster, but we find a cluster is already existing")
}
if err = c.reconcileCluster(args); err != nil {
return err
}
}
Expand Down Expand Up @@ -117,7 +123,8 @@ func (c *Applier) unMountClusterImage() error {
return c.ClusterImageMounter.UnMountImage(c.ClusterDesired)
}

func (c *Applier) reconcileCluster() error {
// only ActionJoin/ActionDelete/ActionApply will into this func
func (c *Applier) reconcileCluster(args *Args) error {
client, err := k8s.Newk8sClient()
if err != nil {
return err
Expand Down Expand Up @@ -153,9 +160,24 @@ func (c *Applier) reconcileCluster() error {

mj, md := strings.Diff(c.ClusterCurrent.GetMasterIPList(), c.ClusterDesired.GetMasterIPList())
nj, nd := strings.Diff(c.ClusterCurrent.GetNodeIPList(), c.ClusterDesired.GetNodeIPList())

switch args.Action {
case ActionJoin:
if len(md) > 0 || len(nd) > 0 {
logrus.Warnf(`we found these master(%v) or node(%v) are in cluster but not in you Kubefile, we will do nothing for them.`, md, nd)
}
return c.scaleCluster(args.JoiningArgs.MastersToJoin, nil, args.JoiningArgs.WorkersToJoin, nil)
case ActionDelete:
if len(mj) > 0 || len(nj) > 0 {
logrus.Warnf(`we found these master(%v) or node(%v) are not in cluster but in you Kubefile, we will do nothing for them.`, mj, nj)
}
return c.scaleCluster(nil, args.DeletingArgs.MastersToDelete, nil, args.DeletingArgs.WorkersToDelete)
}

if len(mj) == 0 && len(md) == 0 && len(nj) == 0 && len(nd) == 0 {
return c.upgrade()
}

return c.scaleCluster(mj, md, nj, nd)
}

Expand Down
3 changes: 3 additions & 0 deletions apply/processor/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,9 @@ func (c *CreateProcessor) RunConfig(cluster *v2.Cluster) error {
}

func (c *CreateProcessor) MountRootfs(cluster *v2.Cluster) error {
if cluster.Annotations["skip-mount"] == "true" {
return nil
}
hosts := append(cluster.GetMasterIPList(), cluster.GetNodeIPList()...)
regConfig := runtime.GetRegistryConfig(platform.DefaultMountClusterImageDir(cluster.Name), cluster.GetMaster0IP())
if net.NotInIPList(regConfig.IP, hosts) {
Expand Down
3 changes: 3 additions & 0 deletions apply/processor/scale.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,9 @@ func (s *ScaleProcessor) RunConfig(cluster *v2.Cluster) error {
}

func (s *ScaleProcessor) MountRootfs(cluster *v2.Cluster) error {
if cluster.Annotations["skip-mount"] == "true" {
return nil
}
return s.fileSystem.MountRootfs(cluster, append(s.MastersToJoin, s.NodesToJoin...), true)
}

Expand Down
28 changes: 21 additions & 7 deletions apply/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,14 +55,18 @@ func ConstructClusterFromArg(imageName string, runArgs *Args) (*v2.Cluster, erro
}

func NewApplierFromArgs(imageName string, runArgs *Args) (applydriver.Interface, error) {
if len(runArgs.Masters) == 0 {
return nil, fmt.Errorf("master ip list cannot be empty")
}
if err := validateArgs(runArgs); err != nil {
return nil, fmt.Errorf("failed to validate input run args: %v", err)
}

cluster, err := ConstructClusterFromArg(imageName, runArgs)
if err != nil {
return nil, fmt.Errorf("failed to initialize cluster instance with command args: %v", err)
}
return NewDefaultApplier(cluster)
return NewDefaultApplier(cluster, common.ApplySubCmd, nil)
}

// validateArgs validates all the input args from sealer run command.
Expand All @@ -71,8 +75,10 @@ func validateArgs(runArgs *Args) error {
var errMsg []string

// validate input masters IP info
if err := validateIPStr(runArgs.Masters); err != nil {
errMsg = append(errMsg, err.Error())
if len(runArgs.Masters) != 0 {
if err := validateIPStr(runArgs.Masters); err != nil {
errMsg = append(errMsg, err.Error())
}
}

// validate input nodes IP info
Expand All @@ -86,6 +92,7 @@ func validateArgs(runArgs *Args) error {
if len(errMsg) == 0 {
return nil
}

return fmt.Errorf(strings.Join(errMsg, ","))
}

Expand All @@ -109,8 +116,12 @@ func getHosts(inMasters, inNodes string) ([]v2.Host, error) {
}

masters := strings.Split(inMasters, ",")
masterHosts := make([]v2.Host, len(masters))
var masterHosts []v2.Host
for index, master := range masters {
if master == "" {
continue
}

if index == 0 {
// only master0 should add two roles: master and master0
masterHosts = append(masterHosts, v2.Host{
Expand All @@ -128,16 +139,19 @@ func getHosts(inMasters, inNodes string) ([]v2.Host, error) {
}

nodes := strings.Split(inNodes, ",")
nodeHosts := make([]v2.Host, len(nodes))
var nodeHosts []v2.Host
for _, node := range nodes {
if node == "" {
continue
}

nodeHosts = append(nodeHosts, v2.Host{
IPS: []string{node},
Roles: []string{common.NODE},
})
}

result := make([]v2.Host, len(masters)+len(nodes))
result = append(result, masterHosts...)
result := masterHosts
result = append(result, nodeHosts...)

return result, nil
Expand Down
Loading