update docs & fix vela cap uninstall. (#1319)

This commit is contained in:
yangsoon
2021-03-27 10:59:23 +08:00
committed by GitHub
parent aa21bfcb60
commit 6469d538be
10 changed files with 218 additions and 58 deletions
+45 -45
View File
@@ -1,6 +1,6 @@
# Managing Capabilities
In KubeVela, developers can install more capabilities (i.e. new workload types and traits) from any GitHub repo that contains OAM definition files. We call these GitHub repos as _Capability Centers_.
In KubeVela, developers can install more capabilities (i.e. new component types and traits) from any GitHub repo that contains OAM definition files. We call these GitHub repos as _Capability Centers_.
KubeVela is able to discover OAM definition files in this repo automatically and sync them to your own KubeVela platform.
@@ -44,88 +44,88 @@ Or, list all available capabilities in certain center.
```bash
$ vela cap ls my-center
NAME CENTER TYPE DEFINITION STATUS APPLIES-TO
kubewatch my-center trait kubewatches.labs.bitnami.com uninstalled []
NAME CENTER TYPE DEFINITION STATUS APPLIES-TO
clonesetservice my-center componentDefinition clonesets.apps.kruise.io uninstalled []
```
## Install a capability from capability center
Now let's try to install the new trait named `kubewatch` from `my-center` to your own KubeVela platform.
Now let's try to install the new component named `clonesetservice` from `my-center` to your own KubeVela platform.
> [KubeWatch](https://github.com/bitnami-labs/kubewatch) is a Kubernetes plugin that watches events and publishes notifications to Slack channel etc. We can use it as a trait to watch important changes of your app and notify the platform administrators via Slack.
You need to install OpenKruise first.
Install `kubewatch` trait from `my-center`.
```shell
helm install kruise https://github.com/openkruise/kruise/releases/download/v0.7.0/kruise-chart.tgz
```
Install `clonesetservice` component from `my-center`.
```bash
$ vela cap install my-center/kubewatch
Installing trait capability kubewatch
"my-repo" has been added to your repositories
2020/11/06 16:19:30 [debug] creating 1 resource(s)
2020/11/06 16:19:30 [debug] CRD kubewatches.labs.bitnami.com is already present. Skipping.
2020/11/06 16:19:37 [debug] creating 3 resource(s)
Successfully installed chart (kubewatch) with release name (kubewatch)
Successfully installed capability kubewatch from my-center
$ vela cap install my-center/clonesetservice
Installing component capability clonesetservice
Successfully installed capability clonesetservice from my-center
```
## Use the newly installed capability
Let's check the `kubewatch` trait appears in your platform firstly:
Let's check the `clonesetservice` appears in your platform firstly:
```bash
$ vela traits
Synchronizing capabilities from cluster⌛ ...
Sync capabilities successfully ✅ (no changes)
TYPE CATEGORY DESCRIPTION
kubewatch trait Add a watch for resource
...
$ vela components
NAME NAMESPACE WORKLOAD DESCRIPTION
clonesetservice vela-system clonesets.apps.kruise.io Describes long-running, scalable, containerized services
that have a stable network endpoint to receive external
network traffic from customers. If workload type is skipped
for any service defined in Appfile, it will be defaulted to
`webservice` type.
```
Great! Now let's deploy an app via Appfile.
```bash
$ cat << EOF > vela.yaml
name: testapp
services:
testsvc:
type: webservice
type: clonesetservice
image: crccheck/hello-world
port: 8000
route:
domain: testsvc.example.com
EOF
```
```bash
$ vela up
Parsing vela appfile ...
Load Template ...
Rendering configs for service (testsvc)...
Writing deploy config to (.vela/deploy.yaml)
Applying application ...
Checking if app has been deployed...
App has not been deployed, creating a new deployment...
Updating: core.oam.dev/v1alpha2, Kind=HealthScope in default
✅ App has been deployed 🚀🚀🚀
Port forward: vela port-forward testapp
SSH: vela exec testapp
Logging: vela logs testapp
App status: vela status testapp
Service status: vela status testapp --svc testsvc
```
Then let's add `kubewatch` as a trait in this Appfile.
then you can Get a cloneset in your environment.
```bash
$ cat << EOF >> vela.yaml
kubewatch:
webhook: https://hooks.slack.com/<your-token>
EOF
```shell
$ kubectl get clonesets.apps.kruise.io
NAME DESIRED UPDATED UPDATED_READY READY TOTAL AGE
testsvc 1 1 1 1 1 46s
```
> The `https://hooks.slack.com/<your-token>` is the Slack channel that your platform administrators are keeping an eye on.
Update the deployment:
```
$ vela up
```
Now, your platform administrators should receive notifications whenever important changes happen to your app. For example, a fresh new deployment.
![Image of Kubewatch](../../resources/kubewatch-notif.jpg)
## Uninstall a capability
> NOTE: make sure no apps are using the capability before uninstalling.
```bash
$ vela cap uninstall my-center/kubewatch
Successfully removed chart (kubewatch) with release name (kubewatch)
$ vela cap uninstall my-center/clonesetservice
Successfully uninstalled capability clonesetservice
```
+1 -1
View File
@@ -50,7 +50,7 @@ In a word, just like the fields shown in the sample, the helm schematic module d
Here is an example `Application`.
```yaml
apiVersion: core.oam.dev/v1alpha2
apiVersion: core.oam.dev/v1beta1
kind: Application
metadata:
name: myapp
+2 -2
View File
@@ -5,7 +5,7 @@ and [virtualgroup](https://github.com/oam-dev/kubevela/blob/master/docs/examples
to a Helm based component.
```yaml
apiVersion: core.oam.dev/v1alpha2
apiVersion: core.oam.dev/v1beta1
kind: Application
metadata:
name: myapp
@@ -65,7 +65,7 @@ workload.
Let's make several changes on the configuration of the sample application.
```yaml
apiVersion: core.oam.dev/v1alpha2
apiVersion: core.oam.dev/v1beta1
kind: Application
metadata:
name: myapp
+4 -2
View File
@@ -314,7 +314,7 @@ func uninstallCap(client client.Client, cap types.Capability, ioStreams cmdutil.
case types.TypeScope:
return fmt.Errorf("uninstall scope capability was not supported yet")
case types.TypeComponentDefinition:
// TODO(yangsoon): support uninstall componentDefinition here
obj = &v1beta1.ComponentDefinition{ObjectMeta: v1.ObjectMeta{Name: cap.Name, Namespace: types.DefaultKubeVelaNS}}
}
if err := client.Delete(ctx, obj); err != nil {
return err
@@ -344,7 +344,9 @@ func uninstallCap(client client.Client, cap types.Capability, ioStreams cmdutil.
case types.TypeScope:
// TODO(wonderflow): add scope remove here.
case types.TypeComponentDefinition:
// TODO(yangsoon): add componenetDefinition remove here
if err := os.Remove(filepath.Join(capdir, "", cap.Name)); err != nil {
return err
}
}
ioStreams.Infof("Successfully uninstalled capability %s", cap.Name)
return nil
+40 -1
View File
@@ -43,7 +43,7 @@ const DescriptionUndefined = "description not defined"
// GetCapabilitiesFromCluster will get capability from K8s cluster
func GetCapabilitiesFromCluster(ctx context.Context, namespace string, c common.Args, selector labels.Selector) ([]types.Capability, error) {
workloads, _, err := GetWorkloadsFromCluster(ctx, namespace, c, selector)
workloads, _, err := GetComponentsFromCluster(ctx, namespace, c, selector)
if err != nil {
return nil, err
}
@@ -89,6 +89,45 @@ func GetWorkloadsFromCluster(ctx context.Context, namespace string, c common.Arg
return templates, templateErrors, nil
}
// GetComponentsFromCluster will get capability from K8s cluster
func GetComponentsFromCluster(ctx context.Context, namespace string, c common.Args, selector labels.Selector) ([]types.Capability, []error, error) {
newClient, err := c.GetClient()
if err != nil {
return nil, nil, err
}
dm, err := discoverymapper.New(c.Config)
if err != nil {
return nil, nil, err
}
var templates []types.Capability
var componentsDefs v1beta1.ComponentDefinitionList
err = newClient.List(ctx, &componentsDefs, &client.ListOptions{Namespace: namespace, LabelSelector: selector})
if err != nil {
return nil, nil, fmt.Errorf("list ComponentDefinition err: %w", err)
}
var templateErrors []error
for _, cd := range componentsDefs.Items {
ref, err := util.ConvertWorkloadGVK2Definition(dm, cd.Spec.Workload.Definition)
if err != nil {
templateErrors = append(templateErrors, errors.Wrapf(err, "convert workload definition `%s` failed", cd.Name))
continue
}
tmp, err := HandleDefinition(cd.Name, ref.Name, cd.Annotations, cd.Spec.Extension, types.TypeComponentDefinition, nil, cd.Spec.Schematic)
if err != nil {
templateErrors = append(templateErrors, errors.Wrapf(err, "handle workload template `%s` failed", cd.Name))
continue
}
tmp.Namespace = namespace
if tmp, err = validateCapabilities(tmp, dm, cd.Name, ref); err != nil {
return nil, nil, err
}
templates = append(templates, tmp)
}
return templates, templateErrors, nil
}
// GetTraitsFromCluster will get capability from K8s cluster
func GetTraitsFromCluster(ctx context.Context, namespace string, c common.Args, selector labels.Selector) ([]types.Capability, []error, error) {
newClient, err := c.GetClient()
+5 -5
View File
@@ -45,7 +45,7 @@ var _ = Describe("DefinitionFiles", func() {
deployment := types.Capability{
Namespace: "testdef",
Name: DeployName,
Type: types.TypeWorkload,
Type: types.TypeComponentDefinition,
CrdName: "deployments.apps",
Description: "description not defined",
Parameters: []types.Parameter{
@@ -78,7 +78,7 @@ var _ = Describe("DefinitionFiles", func() {
websvc := types.Capability{
Namespace: "testdef",
Name: WebserviceName,
Type: types.TypeWorkload,
Type: types.TypeComponentDefinition,
Description: "description not defined",
Parameters: []types.Parameter{{
Name: "env", Type: cue.ListKind,
@@ -108,10 +108,10 @@ var _ = Describe("DefinitionFiles", func() {
// Notice!! DefinitionPath Object is Cluster Scope object
// which means objects created in other DefinitionNamespace will also affect here.
It("getworkload", func() {
workloadDefs, _, err := GetWorkloadsFromCluster(context.Background(), DefinitionNamespace, common.Args{Config: cfg, Schema: scheme}, selector)
It("getcomponents", func() {
workloadDefs, _, err := GetComponentsFromCluster(context.Background(), DefinitionNamespace, common.Args{Config: cfg, Schema: scheme}, selector)
Expect(err).Should(BeNil())
logf.Log.Info(fmt.Sprintf("Getting workload definitions %v", workloadDefs))
logf.Log.Info(fmt.Sprintf("Getting component definitions %v", workloadDefs))
for i := range workloadDefs {
// CueTemplate should always be fulfilled, even those whose CueTemplateURI is assigend,
By("check CueTemplate is fulfilled")
+10 -2
View File
@@ -87,9 +87,17 @@ func LoadInstalledCapabilityWithType(userNamespace string, c common.Args, capT t
return caps, nil
case types.TypeScope:
case types.TypeComponentDefinition:
// TODO(yangsoon): support ComponentDefinition here
caps, _, err := GetComponentsFromCluster(context.TODO(), userNamespace, c, nil)
if err != nil {
return nil, err
}
systemCaps, _, err := GetComponentsFromCluster(context.TODO(), types.DefaultKubeVelaNS, c, nil)
if err != nil {
return nil, err
}
caps = append(caps, systemCaps...)
return caps, nil
}
return nil, nil
}
+18
View File
@@ -55,6 +55,7 @@ var testEnv *envtest.Environment
var definitionDir string
var td corev1beta1.TraitDefinition
var wd, websvcWD corev1beta1.WorkloadDefinition
var cd, websvcCD corev1beta1.ComponentDefinition
func TestAPIs(t *testing.T) {
RegisterFailHandler(Fail)
@@ -101,6 +102,15 @@ var _ = BeforeSuite(func(done Done) {
logf.Log.Info("Creating workload definition", "data", wd)
Expect(k8sClient.Create(ctx, &wd)).Should(SatisfyAny(BeNil(), &util.AlreadyExistMatcher{}))
componentdata, err := ioutil.ReadFile("testdata/componentDef.yaml")
Expect(err).Should(BeNil())
Expect(yaml.Unmarshal(componentdata, &cd)).Should(BeNil())
cd.Namespace = DefinitionNamespace
logf.Log.Info("Creating component definition", "data", cd)
Expect(k8sClient.Create(ctx, &cd)).Should(SatisfyAny(BeNil(), &util.AlreadyExistMatcher{}))
websvcWorkloadData, err := ioutil.ReadFile("testdata/websvcWorkloadDef.yaml")
Expect(err).Should(BeNil())
@@ -109,6 +119,14 @@ var _ = BeforeSuite(func(done Done) {
logf.Log.Info("Creating workload definition whose CUE template from remote", "data", &websvcWD)
Expect(k8sClient.Create(ctx, &websvcWD)).Should(SatisfyAny(BeNil(), &util.AlreadyExistMatcher{}))
websvcComponentDefData, err := ioutil.ReadFile("testdata/websvcComponentDef.yaml")
Expect(err).Should(BeNil())
Expect(yaml.Unmarshal(websvcComponentDefData, &websvcCD)).Should(BeNil())
websvcCD.Namespace = DefinitionNamespace
logf.Log.Info("Creating component definition whose CUE template from remote", "data", &websvcCD)
Expect(k8sClient.Create(ctx, &websvcCD)).Should(SatisfyAny(BeNil(), &util.AlreadyExistMatcher{}))
close(done)
}, 60)
+42
View File
@@ -0,0 +1,42 @@
apiVersion: core.oam.dev/v1beta1
kind: ComponentDefinition
metadata:
name: deployments.testapps
labels:
usecase: forplugintest
spec:
workload:
definition:
apiVersion: apps/v1
kind: Deployment
extension:
template: |
output: {
apiVersion: "apps/v1"
kind: "Deployment"
metadata: name: context.name
spec: {
containers: [{
image: parameter.image
name: context.name
env: parameter.env
ports: [{
containerPort: parameter.port
protocol: "TCP"
name: "default"
}]
}]
}
}
parameter: {
// +usage=Which image would you like to use for your service
// +short=i
image: string
// +usage=Which port do you want customer traffic sent to
// +short=p
port: *8080 | int
env: [...{
name: string
value: string
}]
}
+51
View File
@@ -0,0 +1,51 @@
apiVersion: core.oam.dev/v1beta1
kind: ComponentDefinition
metadata:
name: webservice.testapps
labels:
usecase: forplugintest
spec:
workload:
definition:
apiVersion: apps/v1
kind: Deployment
extension:
template: |
output: {
apiVersion: "apps/v1"
kind: "Deployment"
metadata: name: context.name
spec: {
replicas: 1
podSpec: {
containers: [{
name: context.name
image: parameter.image
env: parameter.env
ports: [{
containerPort: parameter.port
}]
}]
}
}
}
parameter: {
// +usage=Which image would you like to use for your service
// +short=i
image: string
// +usage=Which port do you want customer traffic sent to
// +short=p
port: *6379 | int
env: [...{
name: string
value?: string
valueFrom?: {
secretKeyRef: {
name: string
key: string
}
}
}]
}