Implement component related API

Update app list/show, implmented
component show
This commit is contained in:
zzxwill
2020-09-24 16:30:12 +08:00
parent 50ba36eb1e
commit 28c3c683a0
12 changed files with 374 additions and 97 deletions

View File

@@ -150,7 +150,7 @@ $ vela route mycomp --app myapp
It will create route trait for this component.
```shell script
$ kubeclt get routes.standard.oam.dev -n myenv
$ kubectl get routes.standard.oam.dev -n myenv
NAME AGE
mycomp-trait-5b576c4fc 18s
```

View File

@@ -12,34 +12,20 @@ import (
"github.com/oam-dev/kubevela/cmd/vela/fake"
"github.com/oam-dev/kubevela/pkg/commands"
cmdutil "github.com/oam-dev/kubevela/pkg/commands/util"
"github.com/oam-dev/kubevela/pkg/oam"
"github.com/oam-dev/kubevela/pkg/utils/system"
"github.com/oam-dev/kubevela/version"
"github.com/crossplane/oam-kubernetes-runtime/apis/core"
"github.com/gosuri/uitable"
certmanager "github.com/jetstack/cert-manager/pkg/apis/certmanager/v1alpha2"
"github.com/spf13/cobra"
k8sruntime "k8s.io/apimachinery/pkg/runtime"
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
"k8s.io/klog"
"sigs.k8s.io/controller-runtime/pkg/client/config"
)
var (
scheme = k8sruntime.NewScheme()
)
// chartTGZSource is a base64-encoded, gzipped tarball of the default Helm chart.
// Its value is initialized at build time.
var chartTGZSource string
func init() {
_ = clientgoscheme.AddToScheme(scheme)
_ = certmanager.AddToScheme(scheme)
_ = core.AddToScheme(scheme)
// +kubebuilder:scaffold:scheme
}
func main() {
rand.Seed(time.Now().UnixNano())
@@ -83,7 +69,7 @@ func newCommand() *cobra.Command {
commandArgs := types.Args{
Config: restConf,
Schema: scheme,
Schema: oam.Scheme,
}
if err := system.InitDirs(); err != nil {

View File

@@ -171,44 +171,93 @@ sample response
sample response
```json
{
"code": 200,
"data": {
"Status": "UNKNOWN",
"Workload": {
"workload": {
"apiVersion": "core.oam.dev/v1alpha2",
"kind": "ContainerizedWorkload",
"metadata": {
"name": "poc5"
},
"spec": {
"containers": [{
"image": "nginx:1.9.4",
"name": "poc5",
"ports": [{
"containerPort": 80,
"name": "default",
"protocol": "TCP"
}]
}]
}
}
},
"Traits": [{
"trait": {
"apiVersion": "core.oam.dev/v1alpha2",
"kind": "ManualScalerTrait",
"metadata": {
"annotations": {
"vela.oam.dev/traitDef": "scale"
}
},
"spec": {
"replicaCount": 2
}
}
}]
}
"code": 200,
"data": {
"Status": "True",
"Components": [
{
"name": "web-comp",
"Status": "True",
"workload": {
"apiVersion": "standard.oam.dev/v1alpha1",
"kind": "Containerized",
"metadata": {
"name": "web-comp"
},
"spec": {
"podSpec": {
"containers": [
{
"image": "nginx:1.9.4",
"name": "web-comp",
"ports": [
{
"containerPort": 80,
"name": "default",
"protocol": "TCP"
}
]
}
]
},
"replicas": 1
}
},
"Traits": [
{
"trait": {
"apiVersion": "standard.oam.dev/v1alpha1",
"kind": "Route",
"metadata": {
"annotations": {
"trait.oam.dev/name": "route"
}
},
"spec": {
"backend": {
"port": 0
},
"host": "web-comp.poc.oam.dev",
"path": "",
"tls": {
"issuerName": "oam-env-default"
}
}
}
}
]
},
{
"name": "comp1",
"Status": "True",
"workload": {
"apiVersion": "standard.oam.dev/v1alpha1",
"kind": "Containerized",
"metadata": {
"name": "comp1"
},
"spec": {
"podSpec": {
"containers": [
{
"image": "nginx:1.9.4",
"name": "comp1",
"ports": [
{
"containerPort": 6379,
"name": "default",
"protocol": "TCP"
}
]
}
]
},
"replicas": 1
}
}
}
]
}
}
```
### DELETE /api/envs/:envName/apps/:appName (app delete)
@@ -221,8 +270,74 @@ sample response
}
```
## Components
### GET /api/envs/:envName/apps/:appName/components/:compName (component details)
- example
sample response
```json
{
"code": 200,
"data": {
"name": "web-comp",
"Status": "True",
"workload": {
"apiVersion": "standard.oam.dev/v1alpha1",
"kind": "Containerized",
"metadata": {
"name": "web-comp"
},
"spec": {
"podSpec": {
"containers": [
{
"image": "nginx:1.9.4",
"name": "web-comp",
"ports": [
{
"containerPort": 80,
"name": "default",
"protocol": "TCP"
}
]
}
]
},
"replicas": 1
}
},
"Traits": [
{
"trait": {
"apiVersion": "standard.oam.dev/v1alpha1",
"kind": "Route",
"metadata": {
"annotations": {
"trait.oam.dev/name": "route"
}
},
"spec": {
"backend": {
"port": 0
},
"host": "web-comp.poc.oam.dev",
"path": "",
"tls": {
"issuerName": "oam-env-default"
}
}
}
}
]
}
}
```
### GET /api/envs/:envName/apps/:appName/components/ (component list)
Same as `GET /api/envs/:envName/apps/:appName (app description)`.
## Workloads
### POST /api/workloads/ (workload create)
### POST /api/workloads/ (workload create, component create)
- parameters
```go
type WorkloadRunBody struct {

View File

@@ -5,11 +5,10 @@ import (
"os"
"strings"
"github.com/gosuri/uitable"
"github.com/oam-dev/kubevela/api/types"
"github.com/oam-dev/kubevela/pkg/application"
cmdutil "github.com/oam-dev/kubevela/pkg/commands/util"
"github.com/gosuri/uitable"
"github.com/spf13/cobra"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

View File

@@ -17,10 +17,10 @@ import (
)
type ComponentMeta struct {
Name string `json:"name"`
App string `json:"app"`
Workload string `json:"workload,omitempty"`
Traits []string `json:"traits,omitempty"`
// Name string `json:"name"`
App string `json:"app"`
// Workload string `json:"workload,omitempty"`
// Traits []string `json:"traits,omitempty"`
Status string `json:"status,omitempty"`
CreatedTime string `json:"created,omitempty"`
AppConfig corev1alpha2.ApplicationConfiguration `json:"-"`
@@ -79,17 +79,17 @@ func ListComponents(ctx context.Context, c client.Client, opt Option) ([]Compone
if err != nil {
return componentMetaList, err
}
traitAlias := GetTraitAliasByComponentTraitList(com.Traits)
var workload string
if component.Annotations != nil {
workload = component.Annotations[types.AnnWorkloadDef]
}
//traitAlias := GetTraitAliasByComponentTraitList(com.Traits)
//var workload string
//if component.Annotations != nil {
// workload = component.Annotations[types.AnnWorkloadDef]
//}
componentMetaList = append(componentMetaList, ComponentMeta{
Name: com.ComponentName,
App: a.Name,
Workload: workload,
Status: types.StatusDeployed,
Traits: traitAlias,
// Name: com.ComponentName,
App: a.Name,
//Workload: workload,
Status: types.StatusDeployed,
//Traits: traitAlias,
CreatedTime: a.ObjectMeta.CreationTimestamp.String(),
Component: component,
AppConfig: a,
@@ -100,32 +100,36 @@ func ListComponents(ctx context.Context, c client.Client, opt Option) ([]Compone
return componentMetaList, nil
}
func RetrieveApplicationStatusByName(ctx context.Context, c client.Client, applicationName string, namespace string) (apis.ApplicationStatusMeta, error) {
var applicationStatusMeta apis.ApplicationStatusMeta
func RetrieveApplicationStatusByName(ctx context.Context, c client.Client, applicationName string, namespace string) (apis.ApplicationMeta, error) {
var applicationMeta apis.ApplicationMeta
var appConfig corev1alpha2.ApplicationConfiguration
if err := c.Get(ctx, client.ObjectKey{Name: applicationName, Namespace: namespace}, &appConfig); err != nil {
return applicationStatusMeta, err
return applicationMeta, err
}
var status = "Unknown"
if len(appConfig.Status.Conditions) != 0 {
status = string(appConfig.Status.Conditions[0].Status)
}
applicationMeta.Status = status
for _, com := range appConfig.Spec.Components {
// Just get the one component from appConfig
if com.ComponentName != applicationName {
continue
}
component, err := cmdutil.GetComponent(ctx, c, com.ComponentName, namespace)
componentName := com.ComponentName
component, err := cmdutil.GetComponent(ctx, c, componentName, namespace)
if err != nil {
return applicationStatusMeta, err
return applicationMeta, err
}
var status = "UNKNOWN"
if len(appConfig.Status.Conditions) != 0 {
status = string(appConfig.Status.Conditions[0].Status)
}
applicationStatusMeta = apis.ApplicationStatusMeta{
applicationMeta.Components = append(applicationMeta.Components, apis.ComponentMeta{
Name: componentName,
Status: status,
Workload: component.Spec,
Workload: component.Spec.Workload,
Traits: com.Traits,
}
})
applicationMeta.Status = status
}
return applicationStatusMeta, nil
return applicationMeta, nil
}
func (o *DeleteOptions) DeleteApp() (string, error) {

42
pkg/oam/common.go Normal file
View File

@@ -0,0 +1,42 @@
package oam
import (
"fmt"
"os"
"github.com/crossplane/oam-kubernetes-runtime/apis/core"
certmanager "github.com/jetstack/cert-manager/pkg/apis/certmanager/v1alpha2"
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
"sigs.k8s.io/controller-runtime/pkg/client"
"github.com/oam-dev/kubevela/api/types"
k8sruntime "k8s.io/apimachinery/pkg/runtime"
"sigs.k8s.io/controller-runtime/pkg/client/config"
)
var (
Scheme = k8sruntime.NewScheme()
)
func init() {
_ = clientgoscheme.AddToScheme(Scheme)
_ = certmanager.AddToScheme(Scheme)
_ = core.AddToScheme(Scheme)
// +kubebuilder:scaffold:scheme
}
func InitKubeClient() (client.Client, error) {
restConf, err := config.GetConfig()
if err != nil {
fmt.Println("get kubeConfig err", err)
os.Exit(1)
}
commandArgs := types.Args{
Config: restConf,
Schema: Scheme,
}
return client.New(commandArgs.Config, client.Options{Scheme: commandArgs.Schema})
}

24
pkg/oam/component.go Normal file
View File

@@ -0,0 +1,24 @@
package oam
import (
"context"
"github.com/oam-dev/kubevela/pkg/server/apis"
"sigs.k8s.io/controller-runtime/pkg/client"
)
func RetrieveComponent(ctx context.Context, c client.Client, applicationName, componentName, namespace string) (apis.ComponentMeta, error) {
var componentMeta apis.ComponentMeta
applicationMeta, err := RetrieveApplicationStatusByName(ctx, c, applicationName, namespace)
if err != nil {
return componentMeta, err
}
for _, com := range applicationMeta.Components {
if com.Name != componentName {
continue
}
return com, nil
}
return componentMeta, nil
}

View File

@@ -68,10 +68,16 @@ type TraitBody struct {
Staging string `json:"staging,omitempty"`
}
type ApplicationStatusMeta struct {
Status string `json:"status,omitempty"`
Workload corev1alpha2.ComponentSpec `json:"workload,omitempty"`
Traits []corev1alpha2.ComponentTrait `json:"traits,omitempty"`
type ComponentMeta struct {
Name string `json:"name"`
Status string `json:"Status,omitempty"`
Workload runtime.RawExtension `json:"workload,omitempty"`
Traits []corev1alpha2.ComponentTrait `json:"Traits,omitempty"`
}
type ApplicationMeta struct {
Status string `json:"Status,omitempty"`
Components []ComponentMeta `json:"Components,omitempty"`
}
type CapabilityMeta struct {

View File

@@ -0,0 +1,28 @@
package handler
import (
"github.com/gin-gonic/gin"
"github.com/oam-dev/kubevela/pkg/oam"
"github.com/oam-dev/kubevela/pkg/server/util"
"sigs.k8s.io/controller-runtime/pkg/client"
)
func GetComponent(c *gin.Context) {
kubeClient := c.MustGet("KubeClient")
envName := c.Param("envName")
envMeta, err := oam.GetEnvByName(envName)
if err != nil {
util.HandleError(c, util.StatusInternalServerError, err)
return
}
namespace := envMeta.Namespace
applicationName := c.Param("appName")
componentName := c.Param("compName")
ctx := util.GetContext(c)
componentMeta, err := oam.RetrieveComponent(ctx, kubeClient.(client.Client), applicationName, componentName, namespace)
if err != nil {
util.HandleError(c, util.StatusInternalServerError, err)
return
}
util.AssembleResponse(c, componentMeta, nil)
}

View File

@@ -0,0 +1,50 @@
package main
import (
"context"
"io"
"os"
"os/signal"
"syscall"
"time"
"github.com/oam-dev/kubevela/pkg/oam"
"github.com/oam-dev/kubevela/pkg/server"
"github.com/oam-dev/kubevela/pkg/server/util"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/log/zap"
)
// main will only start up API server
func main() {
var development = true
// setup logging
var w io.Writer
w = os.Stdout
ctrl.SetLogger(zap.New(func(o *zap.Options) {
o.Development = development
o.DestWritter = w
}))
server := server.APIServer{}
kubeClient, err := oam.InitKubeClient()
if err != nil {
ctrl.Log.Error(err, "failed to init an Kubernetes client")
os.Exit(1)
}
errCh := make(chan error, 1)
server.Launch(kubeClient, util.DefaultAPIServerPort, "", errCh)
select {
case err = <-errCh:
ctrl.Log.Error(err, "failed to launch API server")
}
// handle signal: SIGTERM(15)
sc := make(chan os.Signal, 1)
signal.Notify(sc, syscall.SIGTERM)
select {
case <-sc:
ctx, _ := context.WithTimeout(context.Background(), time.Minute)
go server.Shutdown(ctx)
}
}

View File

@@ -16,9 +16,10 @@ import (
// setup the gin http server handler
func setupRoute(kubeClient client.Client, staticPath string) http.Handler {
gin.SetMode(gin.ReleaseMode)
// if deploying static Dashboard, set the mode to `release`, or to `debug`
if staticPath != "" {
gin.SetMode(gin.ReleaseMode)
}
// create the router
router := gin.New()
loggerConfig := gin.LoggerConfig{
@@ -35,7 +36,10 @@ func setupRoute(kubeClient client.Client, staticPath string) http.Handler {
)
},
}
router.Use(static.Serve("/", static.LocalFile(staticPath, false)))
if staticPath != "" {
router.Use(static.Serve("/", static.LocalFile(staticPath, false)))
}
router.Use(gin.LoggerWithConfig(loggerConfig))
router.Use(util.SetRequestID())
@@ -69,7 +73,24 @@ func setupRoute(kubeClient client.Client, staticPath string) http.Handler {
traitWorkload.POST("/", handler.AttachTrait)
traitWorkload.DELETE("/:traitName", handler.DetachTrait)
}
// component related operation
components := apps.Group("/:appName/components")
{
components.GET("/:compName", handler.GetComponent)
components.PUT("/:compName", handler.GetComponent)
components.GET("/", handler.GetApp)
components.DELETE("/:compName", handler.GetComponent)
traitWorkload := components.Group("/:compName/" + util.TraitDefinitionPath)
{
traitWorkload.POST("/", handler.AttachTrait)
traitWorkload.DELETE("/:traitName", handler.DetachTrait)
}
}
}
}
// workload related api
workload := api.Group(util.WorkloadDefinitionPath)

View File

@@ -11,6 +11,8 @@ import (
var DefaultDashboardPort = ":38081"
const DefaultAPIServerPort = ":8081"
func AssembleResponse(c *gin.Context, data interface{}, err error) {
var code = http.StatusOK
if err != nil {