Files
sealos/pkg/apply/processor/interface.go
T

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
}