Files
kubevela/pkg/application/app.go
Jianbo Sun 89863b30e8 fix ci and refactor code (#887)
* adjust CI scripts

* fix go ci order

* try fix

* use appfile to update trait

* fix vela status

* use assert.ObjectAreEqual to check diff for map case

* remove application controller own AC and Components

* tune place

* fix lint

* update

* remove error check of vela init test

Co-authored-by: Ryan Zhang <yangzhangrice@hotmail.com>
2021-01-15 19:04:12 +08:00

168 lines
5.0 KiB
Go

package application
import (
"context"
"fmt"
"reflect"
"sort"
"sigs.k8s.io/controller-runtime/pkg/client"
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1alpha2"
"github.com/oam-dev/kubevela/apis/types"
"github.com/oam-dev/kubevela/pkg/appfile/storage"
"github.com/oam-dev/kubevela/pkg/appfile/storage/driver"
"github.com/oam-dev/kubevela/pkg/appfile/template"
)
// NewEmptyApplication new empty application, only set tm
func NewEmptyApplication() (*driver.Application, error) {
tm, err := template.Load()
if err != nil {
return nil, err
}
return driver.NewApplication(nil, tm), nil
}
// IsNotFound is application not found error
func IsNotFound(appName string, err error) bool {
return err != nil && err.Error() == fmt.Sprintf(`application "%s" not found`, appName)
}
// Load will load application with env and name from default vela home dir.
func Load(envName, appName string) (*driver.Application, error) {
app, err := storage.Store.Get(envName, appName)
if err != nil {
return nil, err
}
err = app.Validate()
return app, err
}
// Delete will delete an app along with it's appfile.
func Delete(envName, appName string) error {
return storage.Store.Delete(envName, appName)
}
// List will list all apps
func List(envName string) ([]*driver.Application, error) {
respApps, err := storage.Store.List(envName)
if err != nil {
return nil, err
}
var apps []*driver.Application
for _, resp := range respApps {
app := driver.NewApplication(resp.AppFile, resp.Tm)
err := app.Validate()
if err != nil {
return nil, err
}
apps = append(apps, app)
}
return apps, nil
}
// MatchAppByComp will get application with componentName without AppName.
func MatchAppByComp(envName, compName string) (*driver.Application, error) {
apps, err := List(envName)
if err != nil {
return nil, err
}
for _, subapp := range apps {
for _, v := range GetComponents(subapp) {
if v == compName {
return subapp, nil
}
}
}
return nil, fmt.Errorf("no app found contains %s in env %s", compName, envName)
}
// Save will save appfile into default dir.
func Save(app *driver.Application, envName string) error {
return storage.Store.Save(app, envName)
}
// GetComponents will get oam components from Appfile.
func GetComponents(app *driver.Application) []string {
var components []string
for name := range app.Services {
components = append(components, name)
}
sort.Strings(components)
return components
}
// GetServiceConfig will get service type and it's configuration
func GetServiceConfig(app *driver.Application, componentName string) (string, map[string]interface{}) {
svc, ok := app.Services[componentName]
if !ok {
return "", make(map[string]interface{})
}
return svc.GetType(), svc.GetApplicationConfig()
}
// GetWorkload will get workload type and it's configuration
func GetWorkload(app *driver.Application, componentName string) (string, map[string]interface{}) {
svcType, config := GetServiceConfig(app, componentName)
if svcType == "" {
return "", make(map[string]interface{})
}
workloadData := make(map[string]interface{})
for k, v := range config {
if app.Tm.IsTrait(k) {
continue
}
workloadData[k] = v
}
return svcType, workloadData
}
// GetTraits will list all traits and it's configurations attached to the specified component.
func GetTraits(app *driver.Application, componentName string) (map[string]map[string]interface{}, error) {
_, config := GetServiceConfig(app, componentName)
traitsData := make(map[string]map[string]interface{})
for k, v := range config {
if !app.Tm.IsTrait(k) {
continue
}
newV, ok := v.(map[string]interface{})
if !ok {
return nil, fmt.Errorf("%s is trait, but with invalid format %s, should be map[string]interface{}", k, reflect.TypeOf(v))
}
traitsData[k] = newV
}
return traitsData, nil
}
// GetTraitsByType will get trait configuration with specified component and trait type, we assume one type of trait can only attach to a component once.
func GetTraitsByType(app *driver.Application, componentName, traitType string) (map[string]interface{}, error) {
service, ok := app.Services[componentName]
if !ok {
return nil, fmt.Errorf("service name (%s) doesn't exist", componentName)
}
t, ok := service[traitType]
if !ok {
return make(map[string]interface{}), nil
}
return t.(map[string]interface{}), nil
}
// GetAppConfig will get AppConfig from K8s cluster.
func GetAppConfig(ctx context.Context, c client.Client, app *driver.Application, env *types.EnvMeta) (*v1alpha2.ApplicationConfiguration, error) {
appConfig := &v1alpha2.ApplicationConfiguration{}
if err := c.Get(ctx, client.ObjectKey{Namespace: env.Namespace, Name: app.Name}, appConfig); err != nil {
return nil, err
}
return appConfig, nil
}
// GetApplication will get Application from K8s cluster.
func GetApplication(ctx context.Context, c client.Client, app *driver.Application, env *types.EnvMeta) (*v1alpha2.Application, error) {
appl := &v1alpha2.Application{}
if err := c.Get(ctx, client.ObjectKey{Namespace: env.Namespace, Name: app.Name}, appl); err != nil {
return nil, err
}
return appl, nil
}