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:
cdjianghan
2023-01-04 16:51:33 +08:00
parent fd336f9e2c
commit e257b1d7e0
2 changed files with 0 additions and 309 deletions
-304
View File
@@ -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
}
-5
View File
@@ -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()),