mirror of
https://github.com/labring/sealos.git
synced 2026-08-30 17:58:09 +08:00
226 lines
6.6 KiB
Go
226 lines
6.6 KiB
Go
// Copyright © 2021 Alibaba Group Holding Ltd.
|
|
//
|
|
// 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 processor
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"path"
|
|
|
|
"github.com/containers/storage"
|
|
"k8s.io/apimachinery/pkg/util/sets"
|
|
|
|
"github.com/labring/sealos/pkg/buildah"
|
|
"github.com/labring/sealos/pkg/constants"
|
|
"github.com/labring/sealos/pkg/filesystem/registry"
|
|
"github.com/labring/sealos/pkg/ssh"
|
|
v2 "github.com/labring/sealos/pkg/types/v1beta1"
|
|
"github.com/labring/sealos/pkg/utils/confirm"
|
|
"github.com/labring/sealos/pkg/utils/file"
|
|
"github.com/labring/sealos/pkg/utils/logger"
|
|
"github.com/labring/sealos/pkg/utils/maps"
|
|
"github.com/labring/sealos/pkg/utils/rand"
|
|
"github.com/labring/sealos/pkg/utils/strings"
|
|
)
|
|
|
|
type Interface interface {
|
|
// Execute :according to the different of desired cluster to do cluster apply.
|
|
Execute(cluster *v2.Cluster) error
|
|
}
|
|
|
|
func SyncNewVersionConfig(clusterName string) {
|
|
d := constants.NewData(clusterName)
|
|
if !file.IsExist(d.PkiPath()) {
|
|
src, target := path.Join(d.Homedir(), constants.PkiDirName), d.PkiPath()
|
|
logger.Info("sync new version copy pki config: %s %s", src, target)
|
|
_ = file.RecursionCopy(src, target)
|
|
}
|
|
if !file.IsExist(d.EtcPath()) {
|
|
src, target := path.Join(d.Homedir(), constants.EtcDirName), d.EtcPath()
|
|
logger.Info("sync new version copy etc config: %s %s", src, target)
|
|
_ = file.RecursionCopy(src, target)
|
|
}
|
|
}
|
|
|
|
func SyncClusterStatus(cluster *v2.Cluster, bdah buildah.Interface, reset bool) error {
|
|
if cluster.Status.Mounts == nil {
|
|
containers, err := bdah.ListContainers()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
cluster.Status.Mounts = make([]v2.MountImage, 0)
|
|
for _, ctr := range containers {
|
|
bderInfo, err := bdah.InspectContainer(ctr.ContainerName)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
mount := &v2.MountImage{
|
|
MountPoint: bderInfo.MountPoint,
|
|
ImageName: ctr.ImageName,
|
|
Name: ctr.ContainerName,
|
|
}
|
|
if err = OCIToImageMount(mount, bdah); err != nil {
|
|
return err
|
|
}
|
|
|
|
if reset || strings.InList(ctr.ImageName, cluster.Spec.Image) {
|
|
cluster.Status.Mounts = append(cluster.Status.Mounts, *mount)
|
|
}
|
|
}
|
|
}
|
|
logger.Debug("sync cluster status is: %s", cluster.String())
|
|
return nil
|
|
}
|
|
|
|
type imageInspector interface {
|
|
InspectImage(imgName string, opts ...string) (*buildah.InspectOutput, error)
|
|
}
|
|
|
|
func OCIToImageMount(mount *v2.MountImage, inspector imageInspector) error {
|
|
oci, err := inspector.InspectImage(mount.ImageName)
|
|
if err != nil {
|
|
if errors.Is(err, storage.ErrImageUnknown) || errors.Is(err, storage.ErrNotAnImage) {
|
|
logger.Debug("cannot find image in local storage, trying to inspect from remote")
|
|
oci, err = inspector.InspectImage(mount.ImageName, "docker")
|
|
}
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
mount.Env = maps.ListToMap(oci.OCIv1.Config.Env)
|
|
delete(mount.Env, "PATH")
|
|
// mount.Entrypoint
|
|
var entrypoint []string
|
|
for _, cmd := range oci.OCIv1.Config.Entrypoint {
|
|
if cmd == "/bin/sh" || cmd == "-c" {
|
|
continue
|
|
}
|
|
entrypoint = append(entrypoint, cmd)
|
|
}
|
|
mount.Entrypoint = entrypoint
|
|
|
|
//mount.Cmd
|
|
cmds := oci.OCIv1.Config.Cmd
|
|
var newCMDs []string
|
|
for _, cmd := range cmds {
|
|
if cmd == "/bin/sh" || cmd == "-c" {
|
|
continue
|
|
}
|
|
newCMDs = append(newCMDs, cmd)
|
|
}
|
|
mount.Cmd = newCMDs
|
|
mount.Labels = oci.OCIv1.Config.Labels
|
|
imageType := v2.AppImage
|
|
if mount.Labels[v2.ImageTypeKey] != "" {
|
|
imageType = v2.ImageType(mount.Labels[v2.ImageTypeKey])
|
|
}
|
|
mount.Type = imageType
|
|
return nil
|
|
}
|
|
|
|
func ConfirmDeleteNodes() error {
|
|
if !ForceDelete {
|
|
prompt := "are you sure to delete these nodes?"
|
|
cancel := "you have canceled to delete these nodes !"
|
|
if pass, err := confirm.Confirm(prompt, cancel); err != nil {
|
|
return err
|
|
} else if !pass {
|
|
return ErrCancelled
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func MirrorRegistry(cluster *v2.Cluster, mounts []v2.MountImage) error {
|
|
registries := cluster.GetRegistryIPAndPortList()
|
|
logger.Debug("registry nodes is: %+v", registries)
|
|
sshClient := ssh.NewSSHClient(&cluster.Spec.SSH, true)
|
|
mirror := registry.New(constants.NewData(cluster.GetName()).RootFSPath(), sshClient, mounts)
|
|
return mirror.MirrorTo(context.Background(), registries...)
|
|
}
|
|
|
|
func CheckImageType(cluster *v2.Cluster, bd buildah.Interface) error {
|
|
imageTypes := sets.NewString()
|
|
for _, image := range cluster.Spec.Image {
|
|
oci, err := bd.InspectImage(image)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if oci.OCIv1.Config.Labels != nil {
|
|
imageTypes.Insert(oci.OCIv1.Config.Labels[v2.ImageTypeKey])
|
|
} else {
|
|
imageTypes.Insert(string(v2.AppImage))
|
|
}
|
|
}
|
|
if !imageTypes.Has(string(v2.RootfsImage)) {
|
|
return errors.New("can't apply application type images only since RootFS type image is not applied yet")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func getIndexOfContainerInMounts(mounts []v2.MountImage, imageName string) int {
|
|
for idx, m := range mounts {
|
|
if m.ImageName == imageName {
|
|
return idx
|
|
}
|
|
}
|
|
return -1
|
|
}
|
|
|
|
func MountClusterImages(cluster *v2.Cluster, bd buildah.Interface) error {
|
|
err := bd.Pull(cluster.Spec.Image, buildah.WithPlatformOption(buildah.DefaultPlatform()),
|
|
buildah.WithPullPolicyOption(buildah.PullIfMissing.String()))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if err := CheckImageType(cluster, bd); err != nil {
|
|
return err
|
|
}
|
|
if cluster.Status.Mounts == nil {
|
|
cluster.Status.Mounts = make([]v2.MountImage, 0)
|
|
}
|
|
for _, img := range cluster.Spec.Image {
|
|
idx := getIndexOfContainerInMounts(cluster.Status.Mounts, img)
|
|
var ctrName string
|
|
// reuse container name
|
|
if idx >= 0 {
|
|
ctrName = cluster.Status.Mounts[idx].Name
|
|
} else {
|
|
ctrName = rand.Generator(8)
|
|
}
|
|
// recreate container anyway, this function call will remount the mount point of the image
|
|
// since after the host reboot, the `merged` dir will become an empty dir when we using `overlayfs` as driver
|
|
bderInfo, err := bd.Create(ctrName, img)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
mount := &v2.MountImage{
|
|
Name: bderInfo.Container,
|
|
ImageName: img,
|
|
MountPoint: bderInfo.MountPoint,
|
|
}
|
|
if err = OCIToImageMount(mount, bd); err != nil {
|
|
return err
|
|
}
|
|
if idx >= 0 {
|
|
cluster.Status.Mounts[idx] = *mount
|
|
} else {
|
|
cluster.Status.Mounts = append(cluster.Status.Mounts, *mount)
|
|
}
|
|
}
|
|
return nil
|
|
}
|