github.com/oam-dev/kubevela@v1.9.11/references/appfile/api/appfile.go (about)

     1  /*
     2  Copyright 2021 The KubeVela Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package api
    18  
    19  import (
    20  	"encoding/json"
    21  	"errors"
    22  	"os"
    23  	"path/filepath"
    24  	"strings"
    25  	"time"
    26  
    27  	"sigs.k8s.io/yaml"
    28  
    29  	"github.com/oam-dev/kubevela/apis/core.oam.dev/common"
    30  	"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
    31  	"github.com/oam-dev/kubevela/pkg/builtin"
    32  	cmdutil "github.com/oam-dev/kubevela/pkg/utils/util"
    33  	"github.com/oam-dev/kubevela/references/appfile/template"
    34  )
    35  
    36  // error msg used in Appfile
    37  var (
    38  	ErrImageNotDefined = errors.New("image not defined")
    39  )
    40  
    41  // DefaultAppfilePath defines the default file path that used by `vela up` command
    42  const (
    43  	DefaultJSONAppfilePath         = "./vela.json"
    44  	DefaultAppfilePath             = "./vela.yaml"
    45  	DefaultUnknowFormatAppfilePath = "./Appfile"
    46  )
    47  
    48  // AppFile defines the spec of KubeVela Appfile
    49  type AppFile struct {
    50  	Name       string             `json:"name"`
    51  	CreateTime time.Time          `json:"createTime,omitempty"`
    52  	UpdateTime time.Time          `json:"updateTime,omitempty"`
    53  	Services   map[string]Service `json:"services"`
    54  	Secrets    map[string]string  `json:"secrets,omitempty"`
    55  
    56  	initialized bool
    57  }
    58  
    59  // NewAppFile init an empty AppFile struct
    60  func NewAppFile() *AppFile {
    61  	return &AppFile{
    62  		Services: make(map[string]Service),
    63  		Secrets:  make(map[string]string),
    64  	}
    65  }
    66  
    67  // Load will load appfile from default path
    68  func Load() (*AppFile, error) {
    69  	if _, err := os.Stat(DefaultAppfilePath); err == nil {
    70  		return LoadFromFile(DefaultAppfilePath)
    71  	}
    72  	if _, err := os.Stat(DefaultJSONAppfilePath); err == nil {
    73  		return LoadFromFile(DefaultJSONAppfilePath)
    74  	}
    75  	return LoadFromFile(DefaultUnknowFormatAppfilePath)
    76  }
    77  
    78  // JSONToYaml will convert JSON format appfile to yaml and load the AppFile struct
    79  func JSONToYaml(data []byte, appFile *AppFile) (*AppFile, error) {
    80  	j, e := yaml.JSONToYAML(data)
    81  	if e != nil {
    82  		return nil, e
    83  	}
    84  	err := yaml.Unmarshal(j, appFile)
    85  	if err != nil {
    86  		return nil, err
    87  	}
    88  	return appFile, nil
    89  }
    90  
    91  // LoadFromFile will read the file and load the AppFile struct
    92  func LoadFromFile(filename string) (*AppFile, error) {
    93  	b, err := os.ReadFile(filepath.Clean(filename))
    94  	if err != nil {
    95  		return nil, err
    96  	}
    97  	return LoadFromBytes(b)
    98  }
    99  
   100  // LoadFromBytes will load AppFile from bytes
   101  func LoadFromBytes(b []byte) (*AppFile, error) {
   102  	af := NewAppFile()
   103  	var err error
   104  	if json.Valid(b) {
   105  		af, err = JSONToYaml(b, af)
   106  	} else {
   107  		err = yaml.Unmarshal(b, af)
   108  	}
   109  	if err != nil {
   110  		return nil, err
   111  	}
   112  	return af, nil
   113  }
   114  
   115  // ExecuteAppfileTasks will execute built-in tasks(such as image builder, etc.) and generate locally executed application
   116  func (app *AppFile) ExecuteAppfileTasks(io cmdutil.IOStreams) error {
   117  	if app.initialized {
   118  		return nil
   119  	}
   120  	for name, svc := range app.Services {
   121  		newSvc, err := builtin.RunBuildInTasks(svc, io)
   122  		if err != nil {
   123  			return err
   124  		}
   125  		app.Services[name] = newSvc
   126  	}
   127  	app.initialized = true
   128  	return nil
   129  }
   130  
   131  // ConvertToApplication renders Appfile into Application, Scopes and other K8s Resources.
   132  func (app *AppFile) ConvertToApplication(namespace string, io cmdutil.IOStreams, tm template.Manager, silence bool) (*v1beta1.Application, error) {
   133  	if err := app.ExecuteAppfileTasks(io); err != nil {
   134  		if strings.Contains(err.Error(), "'image' : not found") {
   135  			return nil, ErrImageNotDefined
   136  		}
   137  		return nil, err
   138  	}
   139  	// auxiliaryObjects currently include OAM Scope Custom Resources and ConfigMaps
   140  	servApp := new(v1beta1.Application)
   141  	servApp.SetNamespace(namespace)
   142  	servApp.SetName(app.Name)
   143  	servApp.Spec.Components = []common.ApplicationComponent{}
   144  	if !silence {
   145  		io.Infof("parsing application components")
   146  	}
   147  	for serviceName, svc := range app.GetServices() {
   148  		comp, err := svc.RenderServiceToApplicationComponent(tm, serviceName)
   149  		if err != nil {
   150  			return nil, err
   151  		}
   152  		servApp.Spec.Components = append(servApp.Spec.Components, comp)
   153  	}
   154  	servApp.SetGroupVersionKind(v1beta1.SchemeGroupVersion.WithKind("Application"))
   155  	return servApp, nil
   156  }