mirror of
https://github.com/labring/sealos.git
synced 2026-09-24 15:46:19 +08:00
add some imgeCrdBuilder change
add CheckLoginStatus() to check wheather push image should appen ReadOrBuildAppConfig() add logic when user didn't write any image config add Image base info read such as image size image arch ... delete action content read now sealos push args is allow to be one or two ,when one ,this arg is both dst and src.when args has two , the secend is dest.
This commit is contained in:
@@ -1,304 +0,0 @@
|
||||
// Copyright © 2022 sealos.
|
||||
//
|
||||
// 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 buildah
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/openconfig/gnmi/errlist"
|
||||
|
||||
"github.com/containers/buildah"
|
||||
v1 "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer/yaml"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
|
||||
imagev1 "github.com/labring/sealos/controllers/imagehub/api/v1"
|
||||
"github.com/labring/sealos/pkg/client-go/kubernetes"
|
||||
"github.com/labring/sealos/pkg/utils/file"
|
||||
"github.com/labring/sealos/pkg/utils/logger"
|
||||
)
|
||||
|
||||
const (
|
||||
AppPath = "app"
|
||||
READMEpath = "README.md"
|
||||
ConfigFileName = "config.yaml"
|
||||
TemplateFileName = "template.yaml"
|
||||
CMDFileName = "CMD"
|
||||
ImagehubGroup = "imagehub.sealos.io"
|
||||
ImagehubVersion = "v1"
|
||||
ImagehubResource = "images"
|
||||
)
|
||||
|
||||
type ImageCRDBuilder struct {
|
||||
imagename string
|
||||
clustername string
|
||||
AppConfig *imagev1.Image
|
||||
}
|
||||
|
||||
func NewAndRunImageCRDBuilder(args []string, iopts *pushOptions) {
|
||||
//run without error returns
|
||||
icb := &ImageCRDBuilder{args[0], "", &imagev1.Image{}}
|
||||
if iopts.imagecrd {
|
||||
icb.Run()
|
||||
}
|
||||
}
|
||||
|
||||
func (icb *ImageCRDBuilder) Run() {
|
||||
MountPoint, err := icb.CreateContainer()
|
||||
if err != nil {
|
||||
// get err when create container ,abort all
|
||||
return
|
||||
}
|
||||
defer func() {
|
||||
err = icb.DeleteContainer()
|
||||
if err != nil {
|
||||
logger.Warn(err)
|
||||
}
|
||||
}()
|
||||
err = icb.GetAppContent(MountPoint)
|
||||
if err != nil {
|
||||
logger.Warn(err)
|
||||
}
|
||||
err = icb.AppContentApply()
|
||||
if err != nil {
|
||||
logger.Warn(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (icb *ImageCRDBuilder) CreateContainer() (string, error) {
|
||||
rnd := rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
clusterName := icb.imagename + strconv.Itoa(rnd.Int())
|
||||
|
||||
realImpl, err := New("")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
builderInfo, err := realImpl.Create(clusterName, icb.imagename)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if iseist := file.IsExist(builderInfo.MountPoint); !iseist {
|
||||
return "", fmt.Errorf("mountPoint not Exist")
|
||||
}
|
||||
icb.clustername = clusterName
|
||||
return builderInfo.MountPoint, nil
|
||||
}
|
||||
|
||||
/*
|
||||
Action path example:
|
||||
app/
|
||||
├── config.yaml
|
||||
├── action1
|
||||
│ ├── cmd
|
||||
│ └── template.yaml
|
||||
├── action2
|
||||
│ ├── cmd
|
||||
│ └── template.yaml
|
||||
x
|
||||
The template and cmd of the action are stored in the folder named after the action,config is used to configure the basic information of the image CRD.
|
||||
*/
|
||||
|
||||
// GetAppContent do content read in filereadPipeline, if one content get failed ,it won't abort.
|
||||
func (icb *ImageCRDBuilder) GetAppContent(MountPoint string) error {
|
||||
//app config is the based file ,it should read first
|
||||
if err := icb.ReadAppConfig(MountPoint); err != nil {
|
||||
return fmt.Errorf("base config cant find")
|
||||
}
|
||||
var errl errlist.List
|
||||
//Using a pipe helps with future file reading needs
|
||||
fileReadPipeLine := []func(MountPoint string) error{
|
||||
icb.ReadImageContent,
|
||||
icb.ReadReadme,
|
||||
icb.ReadActions,
|
||||
}
|
||||
for _, f := range fileReadPipeLine {
|
||||
if err := f(MountPoint); err != nil {
|
||||
errl.Add(err)
|
||||
}
|
||||
}
|
||||
return errl.Err()
|
||||
}
|
||||
|
||||
func (icb *ImageCRDBuilder) AppContentApply() error {
|
||||
client, err := kubernetes.NewKubernetesClient("", "")
|
||||
if err != nil {
|
||||
return fmt.Errorf("new KubernetesClient err: %v", err)
|
||||
}
|
||||
dyclient := client.KubernetesDynamic().Resource(schema.GroupVersionResource{
|
||||
Group: ImagehubGroup,
|
||||
Version: ImagehubVersion,
|
||||
Resource: ImagehubResource,
|
||||
})
|
||||
utd := unstructured.Unstructured{}
|
||||
obj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(icb.AppConfig)
|
||||
if err != nil {
|
||||
return fmt.Errorf("appconfig ToUnstructured err : %v", err)
|
||||
}
|
||||
utd.Object = obj
|
||||
if _, err = dyclient.Create(context.TODO(), &utd, metav1.CreateOptions{}); err != nil {
|
||||
if !apierrors.IsAlreadyExists(err) {
|
||||
return fmt.Errorf("image create err : %v", err)
|
||||
}
|
||||
if utd.GetResourceVersion() == "" {
|
||||
var objGET *unstructured.Unstructured
|
||||
objGET, err = dyclient.Get(context.TODO(), utd.GetName(), metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to get obj: %v", err)
|
||||
}
|
||||
utd.SetResourceVersion(objGET.GetResourceVersion())
|
||||
}
|
||||
if _, err = dyclient.Update(context.TODO(), &utd, metav1.UpdateOptions{}); err != nil {
|
||||
return fmt.Errorf("image update err : %v", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (icb *ImageCRDBuilder) DeleteContainer() error {
|
||||
realImpl, err := New("")
|
||||
if err != nil {
|
||||
return fmt.Errorf("deleteContainer err : %v", err)
|
||||
}
|
||||
return realImpl.Delete(icb.imagename)
|
||||
}
|
||||
|
||||
func (icb *ImageCRDBuilder) ReadAppConfig(MountPoint string) error {
|
||||
if file.IsExist(filepath.Join(MountPoint, AppPath, ConfigFileName)) {
|
||||
c, err := file.ReadAll(filepath.Join(MountPoint, AppPath, ConfigFileName))
|
||||
if err != nil {
|
||||
return fmt.Errorf("read config.yaml err: %v", err)
|
||||
}
|
||||
if err = icb.ConfigParse(c); err != nil {
|
||||
return fmt.Errorf("readAppConfig : %v", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (icb *ImageCRDBuilder) ConfigParse(c []byte) error {
|
||||
config := imagev1.Image{}
|
||||
_, _, err := yaml.NewDecodingSerializer(unstructured.UnstructuredJSONScheme).Decode(c, nil, &config)
|
||||
if err != nil {
|
||||
return fmt.Errorf("configParse err : %v", err)
|
||||
}
|
||||
config.Spec.DetailInfo.Actions = make(map[string]imagev1.Action)
|
||||
icb.AppConfig = &config
|
||||
return nil
|
||||
}
|
||||
|
||||
func (icb *ImageCRDBuilder) ReadReadme(MountPoint string) error {
|
||||
if file.IsExist(filepath.Join(MountPoint, READMEpath)) {
|
||||
c, err := file.ReadAll(filepath.Join(MountPoint, READMEpath))
|
||||
if err != nil {
|
||||
return fmt.Errorf("read README.md err: %v", err)
|
||||
}
|
||||
icb.AppConfig.Spec.DetailInfo.Description = string(c)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (icb *ImageCRDBuilder) ReadImageContent(MountPoint string) error {
|
||||
realImpl, err := New("")
|
||||
if err != nil {
|
||||
return fmt.Errorf("deleteContainer err : %v", err)
|
||||
}
|
||||
containerInfo, err := realImpl.InspectContainer(icb.imagename)
|
||||
if err != nil {
|
||||
return fmt.Errorf("readImageContent InspectImage err : %v", err)
|
||||
}
|
||||
var config v1.Image
|
||||
if err = json.Unmarshal([]byte(containerInfo.Config), &config); err != nil {
|
||||
return fmt.Errorf("get image config err : %v", err)
|
||||
}
|
||||
var manifest v1.Manifest
|
||||
if err = json.Unmarshal([]byte(containerInfo.Manifest), &manifest); err != nil {
|
||||
return fmt.Errorf("get image config err : %v", err)
|
||||
}
|
||||
icb.BindImageContent(containerInfo, config, manifest)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (icb *ImageCRDBuilder) BindImageContent(containerInfo buildah.BuilderInfo, config v1.Image, manifest v1.Manifest) {
|
||||
icb.AppConfig.Spec.DetailInfo.ID = containerInfo.FromImageID
|
||||
icb.AppConfig.Spec.DetailInfo.Arch = config.Architecture
|
||||
var size int64
|
||||
size = manifest.Config.Size * 1000
|
||||
for _, layer := range manifest.Layers {
|
||||
size += layer.Size
|
||||
}
|
||||
icb.AppConfig.Spec.DetailInfo.Size = size
|
||||
}
|
||||
|
||||
// ReadActions read all action in /app dir
|
||||
func (icb *ImageCRDBuilder) ReadActions(MountPoint string) error {
|
||||
if file.IsExist(filepath.Join(MountPoint, AppPath)) {
|
||||
fileEntrys, err := os.ReadDir(filepath.Join(MountPoint, AppPath))
|
||||
if err != nil {
|
||||
return fmt.Errorf("read actions in app dir err: %v ", err)
|
||||
}
|
||||
for _, f := range fileEntrys {
|
||||
if !f.IsDir() {
|
||||
continue
|
||||
}
|
||||
if _, isExist := icb.AppConfig.Spec.DetailInfo.Actions[f.Name()]; isExist {
|
||||
logger.Warn("action name repeat")
|
||||
}
|
||||
icb.AppConfig.Spec.DetailInfo.Actions[f.Name()], err = icb.ReadTemplateAndCmd(MountPoint, f.Name())
|
||||
if err != nil {
|
||||
return fmt.Errorf("read action : %v err: %v ", filepath.Join(MountPoint, AppPath, f.Name()), err)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ReadTemplateAndCmd read template and cmd yaml file in target action dir
|
||||
func (icb *ImageCRDBuilder) ReadTemplateAndCmd(MountPoint string, actionName string) (imagev1.Action, error) {
|
||||
actioncontent := imagev1.Action{
|
||||
Name: actionName,
|
||||
Template: "",
|
||||
CMD: "",
|
||||
}
|
||||
fileEntrys, err := os.ReadDir(filepath.Join(MountPoint, AppPath, actionName))
|
||||
if err != nil {
|
||||
return imagev1.Action{}, fmt.Errorf("read path: %v err: %v", filepath.Join(MountPoint, AppPath), err)
|
||||
}
|
||||
var byt []byte
|
||||
for _, f := range fileEntrys {
|
||||
if f.Name() == TemplateFileName {
|
||||
byt, _ = file.ReadAll(filepath.Join(MountPoint, AppPath, actionName, f.Name()))
|
||||
actioncontent.Template = string(byt)
|
||||
}
|
||||
if f.Name() == CMDFileName {
|
||||
byt, _ = file.ReadAll(filepath.Join(MountPoint, AppPath, actionName, f.Name()))
|
||||
actioncontent.CMD = string(byt)
|
||||
}
|
||||
}
|
||||
return actioncontent, nil
|
||||
}
|
||||
@@ -62,7 +62,6 @@ type pushOptions struct {
|
||||
encryptionKeys []string
|
||||
encryptLayers []int
|
||||
insecure bool
|
||||
imagecrd bool
|
||||
}
|
||||
|
||||
func newDefaultPushOptions() *pushOptions {
|
||||
@@ -95,7 +94,6 @@ func (opts *pushOptions) RegisterFlags(fs *pflag.FlagSet) error {
|
||||
fs.StringSliceVar(&opts.encryptionKeys, "encryption-key", opts.encryptionKeys, "key with the encryption protocol to use needed to encrypt the image (e.g. jwe:/path/to/key.pem)")
|
||||
fs.IntSliceVar(&opts.encryptLayers, "encrypt-layer", opts.encryptLayers, "layers to encrypt, 0-indexed layer indices with support for negative indexing (e.g. 0 is the first layer, -1 is the last layer). If not defined, will encrypt all layers if encryption-key flag is specified")
|
||||
fs.BoolVar(&opts.tlsVerify, "tls-verify", opts.tlsVerify, "require HTTPS and verify certificates when accessing the registry. TLS verification cannot be used when talking to an insecure registry.")
|
||||
fs.BoolVar(&opts.imagecrd, "imagecrd", opts.imagecrd, "")
|
||||
return markFlagsHidden(fs, []string{"signature-policy", "blob-cache", "tls-verify"}...)
|
||||
}
|
||||
|
||||
@@ -122,9 +120,6 @@ func newPushCommand() *cobra.Command {
|
||||
PostRun: func(cmd *cobra.Command, args []string) {
|
||||
NewAndRunImageCRBuilder(args)
|
||||
},
|
||||
PostRun: func(cmd *cobra.Command, args []string) {
|
||||
NewAndRunImageCRDBuilder(args, opts)
|
||||
},
|
||||
Example: fmt.Sprintf(`%[1]s push imageID docker://registry.example.com/repository:tag
|
||||
%[1]s push imageID docker-daemon:image:tagi
|
||||
%[1]s push imageID oci:/path/to/layout:image:tag`, rootCmd.CommandPath()),
|
||||
|
||||
Reference in New Issue
Block a user