Merge pull request #65 from cloud-native-application/env

support rudr env
This commit is contained in:
Sun Jianbo
2020-07-31 12:23:15 +08:00
committed by GitHub
38 changed files with 479 additions and 846 deletions

View File

@@ -1,9 +1,3 @@
# Image URL to use all building/pushing image targets
IMG ?= controller:latest
# Produce CRDs that work back to Kubernetes 1.11 (no version conversion)
CRD_OPTIONS ?= "crd:trivialVersions=true"
# Rudrx version
RUDRX_VERSION ?= 0.1.0
# Repo info
@@ -16,38 +10,20 @@ else
GOBIN=$(shell go env GOBIN)
endif
all: manager
all: build
# Run tests
test: generate fmt vet manifests
test: fmt vet
go test ./... -coverprofile cover.out
# Build manager binary
manager: generate fmt vet
go build -o bin/manager cmd/server/main.go
build: fmt vet
go build -ldflags "-X main.RudrxVersion=${RUDRX_VERSION} -X main.GitRevision=${GIT_COMMIT}" -o bin/rudrx cmd/rudrx/main.go
# Run against the configured Kubernetes cluster in ~/.kube/config
run: generate fmt vet manifests
run: fmt vet
go run ./cmd/server/main.go
# Install CRDs into a cluster
install: manifests
kustomize build config/crd | kubectl apply -f -
# Uninstall CRDs from a cluster
uninstall: manifests
kustomize build config/crd | kubectl delete -f -
# Deploy controller in the configured Kubernetes cluster in ~/.kube/config
deploy: manifests
cd config/manager && kustomize edit set image controller=${IMG}
kustomize build config/default | kubectl apply -f -
# Generate manifests e.g. CRD, RBAC etc.
manifests: controller-gen
$(CONTROLLER_GEN) $(CRD_OPTIONS) rbac:roleName=manager-role webhook paths="./..." output:crd:artifacts:config=config/crd/bases
# Run go fmt against code
fmt:
go fmt ./...
@@ -56,10 +32,6 @@ fmt:
vet:
go vet ./...
# Generate code
generate: controller-gen
$(CONTROLLER_GEN) object:headerFile="hack/boilerplate.go.txt" paths="./..."
# Build the docker image
docker-build: test
docker build . -t ${IMG}
@@ -68,28 +40,12 @@ docker-build: test
docker-push:
docker push ${IMG}
# find or download controller-gen
# download controller-gen if necessary
controller-gen:
ifeq (, $(shell which controller-gen))
@{ \
set -e ;\
CONTROLLER_GEN_TMP_DIR=$$(mktemp -d) ;\
cd $$CONTROLLER_GEN_TMP_DIR ;\
go mod init tmp ;\
go get sigs.k8s.io/controller-tools/cmd/controller-gen@v0.2.5 ;\
rm -rf $$CONTROLLER_GEN_TMP_DIR ;\
}
CONTROLLER_GEN=$(GOBIN)/controller-gen
else
CONTROLLER_GEN=$(shell which controller-gen)
endif
e2e-setup:
# install oam-k8s-runtime
e2e-test:
# Run e2e test
go test ./pkg/test
e2e-cleanup:
# Clean up

View File

@@ -83,12 +83,16 @@ func newCommand() *cobra.Command {
cmds.AddCommand(
cmd.NewRunCommand(f, client, ioStream, os.Args[1:]),
cmd.NewTraitsCommand(f, client, ioStream),
cmd.NewTraitsCommand(f, client, ioStream, []string{}),
cmd.NewWorkloadsCommand(f, client, ioStream, os.Args[1:]),
cmd.NewBindCommand(f, client, ioStream),
cmd.NewBindCommand(f, client, ioStream, []string{}),
cmd.NewInitCommand(f, client, ioStream),
cmd.NewDeleteCommand(f, client, ioStream, os.Args[1:]),
cmd.NewAppsCommand(f, client, ioStream),
cmd.NewEnvInitCommand(f, ioStream),
cmd.NewEnvSwitchCommand(f, ioStream),
cmd.NewEnvDeleteCommand(f, ioStream),
cmd.NewEnvCommand(f, ioStream),
NewVersionCommand(),
)

View File

@@ -1,84 +0,0 @@
/*
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 main
import (
"flag"
"os"
"k8s.io/apimachinery/pkg/runtime"
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/log/zap"
coreoamdevv1alpha2 "github.com/cloud-native-application/rudrx/api/v1alpha2"
"github.com/cloud-native-application/rudrx/controllers"
// +kubebuilder:scaffold:imports
)
var (
scheme = runtime.NewScheme()
setupLog = ctrl.Log.WithName("setup")
)
func init() {
_ = clientgoscheme.AddToScheme(scheme)
_ = coreoamdevv1alpha2.AddToScheme(scheme)
// +kubebuilder:scaffold:scheme
}
func main() {
var metricsAddr string
var enableLeaderElection bool
flag.StringVar(&metricsAddr, "metrics-addr", ":8080", "The address the metric endpoint binds to.")
flag.BoolVar(&enableLeaderElection, "enable-leader-election", false,
"Enable leader election for controller manager. "+
"Enabling this will ensure there is only one active controller manager.")
flag.Parse()
ctrl.SetLogger(zap.New(zap.UseDevMode(true)))
mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
Scheme: scheme,
MetricsBindAddress: metricsAddr,
Port: 9443,
LeaderElection: enableLeaderElection,
LeaderElectionID: "285a4034.my.domain",
})
if err != nil {
setupLog.Error(err, "unable to start manager")
os.Exit(1)
}
if err = (&controllers.TemplateReconciler{
Client: mgr.GetClient(),
Log: ctrl.Log.WithName("controllers").WithName("Template"),
Scheme: mgr.GetScheme(),
}).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "Template")
os.Exit(1)
}
// +kubebuilder:scaffold:builder
setupLog.Info("starting manager")
if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil {
setupLog.Error(err, "problem running manager")
os.Exit(1)
}
}

View File

@@ -1,84 +0,0 @@
---
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.2.5
creationTimestamp: null
name: templates.admin.oam.dev
spec:
group: admin.oam.dev
names:
kind: Template
listKind: TemplateList
plural: templates
singular: template
scope: Namespaced
validation:
openAPIV3Schema:
description: Template is the Schema for the templates API
properties:
apiVersion:
description: 'APIVersion defines the versioned schema of this representation
of an object. Servers should convert recognized schemas to the latest
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
type: string
kind:
description: 'Kind is a string value representing the REST resource this
object represents. Servers may infer this from the endpoint the client
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
type: string
metadata:
type: object
spec:
description: TemplateSpec defines the desired state of Template
properties:
lastCommandParam:
type: string
object:
description: 'INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
Important: Run "make" to regenerate code after modifying this file'
type: object
parameters:
items:
properties:
default:
type: string
fieldPaths:
items:
type: string
type: array
name:
type: string
required:
type: boolean
short:
type: string
type:
type: string
usage:
type: string
required:
- fieldPaths
- name
type: object
type: array
required:
- object
type: object
status:
description: TemplateStatus defines the observed state of Template
type: object
type: object
version: v1alpha2
versions:
- name: v1alpha2
served: true
storage: true
status:
acceptedNames:
kind: ""
plural: ""
conditions: []
storedVersions: []

View File

@@ -1,11 +0,0 @@
# This kustomization.yaml is not intended to be run by itself,
# since it depends on service name and namespace that are out of this kustomize package.
# It should be run by config/default
resources:
- bases/admin.oam.dev_templates.yaml
# +kubebuilder:scaffold:crdkustomizeresource
# the following config is for teaching kustomize how to do kustomization for CRDs.
configurations:
- kustomizeconfig.yaml

View File

@@ -1,3 +0,0 @@
# This file is for teaching kustomize how to substitute name and namespace reference in CRD
varReference:
- path: metadata/annotations

View File

@@ -1,70 +0,0 @@
# Adds namespace to all resources.
namespace: rudrx-system
# Value of this field is prepended to the
# names of all resources, e.g. a deployment named
# "wordpress" becomes "alices-wordpress".
# Note that it should also match with the prefix (text before '-') of the namespace
# field above.
namePrefix: rudrx-
# Labels to add to all resources and selectors.
#commonLabels:
# someName: someValue
bases:
- ../crd
- ../rbac
- ../manager
# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix including the one in
# crd/kustomization.yaml
#- ../webhook
# [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER'. 'WEBHOOK' components are required.
#- ../certmanager
# [PROMETHEUS] To enable prometheus monitor, uncomment all sections with 'PROMETHEUS'.
#- ../prometheus
patchesStrategicMerge:
# Protect the /metrics endpoint by putting it behind auth.
# If you want your controller-manager to expose the /metrics
# endpoint w/o any authn/z, please comment the following line.
- manager_auth_proxy_patch.yaml
# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix including the one in
# crd/kustomization.yaml
#- manager_webhook_patch.yaml
# [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER'.
# Uncomment 'CERTMANAGER' sections in crd/kustomization.yaml to enable the CA injection in the admission webhooks.
# 'CERTMANAGER' needs to be enabled to use ca injection
#- webhookcainjection_patch.yaml
# the following config is for teaching kustomize how to do var substitution
vars:
# [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER' prefix.
#- name: CERTIFICATE_NAMESPACE # namespace of the certificate CR
# objref:
# kind: Certificate
# group: cert-manager.io
# version: v1alpha2
# name: serving-cert # this name should match the one in certificate.yaml
# fieldref:
# fieldpath: metadata.namespace
#- name: CERTIFICATE_NAME
# objref:
# kind: Certificate
# group: cert-manager.io
# version: v1alpha2
# name: serving-cert # this name should match the one in certificate.yaml
#- name: SERVICE_NAMESPACE # namespace of the service
# objref:
# kind: Service
# version: v1
# name: webhook-service
# fieldref:
# fieldpath: metadata.namespace
#- name: SERVICE_NAME
# objref:
# kind: Service
# version: v1
# name: webhook-service

View File

@@ -1,25 +0,0 @@
# This patch inject a sidecar container which is a HTTP proxy for the
# controller manager, it performs RBAC authorization against the Kubernetes API using SubjectAccessReviews.
apiVersion: apps/v1
kind: Deployment
metadata:
name: controller-manager
namespace: system
spec:
template:
spec:
containers:
- name: kube-rbac-proxy
image: gcr.io/kubebuilder/kube-rbac-proxy:v0.5.0
args:
- "--secure-listen-address=0.0.0.0:8443"
- "--upstream=http://127.0.0.1:8080/"
- "--logtostderr=true"
- "--v=10"
ports:
- containerPort: 8443
name: https
- name: manager
args:
- "--metrics-addr=127.0.0.1:8080"
- "--enable-leader-election"

View File

@@ -1,2 +0,0 @@
resources:
- manager.yaml

View File

@@ -1,39 +0,0 @@
apiVersion: v1
kind: Namespace
metadata:
labels:
control-plane: controller-manager
name: system
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: controller-manager
namespace: system
labels:
control-plane: controller-manager
spec:
selector:
matchLabels:
control-plane: controller-manager
replicas: 1
template:
metadata:
labels:
control-plane: controller-manager
spec:
containers:
- command:
- /manager
args:
- --enable-leader-election
image: controller:latest
name: manager
resources:
limits:
cpu: 100m
memory: 30Mi
requests:
cpu: 100m
memory: 20Mi
terminationGracePeriodSeconds: 10

View File

@@ -1,7 +0,0 @@
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
name: metrics-reader
rules:
- nonResourceURLs: ["/metrics"]
verbs: ["get"]

View File

@@ -1,13 +0,0 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: proxy-role
rules:
- apiGroups: ["authentication.k8s.io"]
resources:
- tokenreviews
verbs: ["create"]
- apiGroups: ["authorization.k8s.io"]
resources:
- subjectaccessreviews
verbs: ["create"]

View File

@@ -1,12 +0,0 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: proxy-rolebinding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: proxy-role
subjects:
- kind: ServiceAccount
name: default
namespace: system

View File

@@ -1,14 +0,0 @@
apiVersion: v1
kind: Service
metadata:
labels:
control-plane: controller-manager
name: controller-manager-metrics-service
namespace: system
spec:
ports:
- name: https
port: 8443
targetPort: https
selector:
control-plane: controller-manager

View File

@@ -1,12 +0,0 @@
resources:
- role.yaml
- role_binding.yaml
- leader_election_role.yaml
- leader_election_role_binding.yaml
# Comment the following 4 lines if you want to disable
# the auth proxy (https://github.com/brancz/kube-rbac-proxy)
# which protects your /metrics endpoint.
- auth_proxy_service.yaml
- auth_proxy_role.yaml
- auth_proxy_role_binding.yaml
- auth_proxy_client_clusterrole.yaml

View File

@@ -1,32 +0,0 @@
# permissions to do leader election.
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: leader-election-role
rules:
- apiGroups:
- ""
resources:
- configmaps
verbs:
- get
- list
- watch
- create
- update
- patch
- delete
- apiGroups:
- ""
resources:
- configmaps/status
verbs:
- get
- update
- patch
- apiGroups:
- ""
resources:
- events
verbs:
- create

View File

@@ -1,12 +0,0 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: leader-election-rolebinding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: leader-election-role
subjects:
- kind: ServiceAccount
name: default
namespace: system

View File

@@ -1,28 +0,0 @@
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
creationTimestamp: null
name: manager-role
rules:
- apiGroups:
- admin.oam.dev
resources:
- templates
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
- apiGroups:
- admin.oam.dev
resources:
- templates/status
verbs:
- get
- patch
- update

View File

@@ -1,12 +0,0 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: manager-rolebinding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: manager-role
subjects:
- kind: ServiceAccount
name: default
namespace: system

View File

@@ -1,24 +0,0 @@
# permissions for end users to edit templates.
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: template-editor-role
rules:
- apiGroups:
- admin.oam.dev
resources:
- templates
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
- apiGroups:
- admin.oam.dev
resources:
- templates/status
verbs:
- get

View File

@@ -1,20 +0,0 @@
# permissions for end users to view templates.
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: template-viewer-role
rules:
- apiGroups:
- admin.oam.dev
resources:
- templates
verbs:
- get
- list
- watch
- apiGroups:
- admin.oam.dev
resources:
- templates/status
verbs:
- get

View File

@@ -1,79 +0,0 @@
/*
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 controllers
import (
"path/filepath"
"testing"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"k8s.io/client-go/rest"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/envtest"
"sigs.k8s.io/controller-runtime/pkg/envtest/printer"
logf "sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/log/zap"
// +kubebuilder:scaffold:imports
)
// These tests use Ginkgo (BDD-style Go testing framework). Refer to
// http://onsi.github.io/ginkgo/ to learn more about Ginkgo.
var cfg *rest.Config
var k8sClient client.Client
var testEnv *envtest.Environment
func TestAPIs(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecsWithDefaultAndCustomReporters(t,
"Controller Suite",
[]Reporter{printer.NewlineReporter{}})
}
var _ = BeforeSuite(func(done Done) {
logf.SetLogger(zap.LoggerTo(GinkgoWriter, true))
By("bootstrapping test environment")
testEnv = &envtest.Environment{
CRDDirectoryPaths: []string{filepath.Join("..", "config", "crd", "bases")},
}
// TODO add later
// var err error
// cfg, err = testEnv.Start()
// Expect(err).ToNot(HaveOccurred())
// Expect(cfg).ToNot(BeNil())
// err = coreoamdevv1alpha2.AddToScheme(scheme.Scheme)
// Expect(err).NotTo(HaveOccurred())
// // +kubebuilder:scaffold:scheme
// k8sClient, err = client.New(cfg, client.Options{Scheme: scheme.Scheme})
// Expect(err).ToNot(HaveOccurred())
// Expect(k8sClient).ToNot(BeNil())
close(done)
}, 60)
var _ = AfterSuite(func() {
By("tearing down the test environment")
err := testEnv.Stop()
Expect(err).ToNot(HaveOccurred())
})

3
go.mod
View File

@@ -4,13 +4,14 @@ go 1.13
require (
github.com/crossplane/crossplane-runtime v0.8.0
github.com/crossplane/oam-kubernetes-runtime v0.0.5
github.com/crossplane/oam-kubernetes-runtime v0.0.8
github.com/go-logr/logr v0.1.0
github.com/gosuri/uitable v0.0.4
github.com/onsi/ginkgo v1.11.0
github.com/onsi/gomega v1.8.1
github.com/pkg/errors v0.9.1
github.com/spf13/cobra v1.0.0
github.com/stretchr/testify v1.6.1
gotest.tools v2.2.0+incompatible
helm.sh/helm/v3 v3.2.4
k8s.io/api v0.18.6

6
go.sum
View File

@@ -122,6 +122,10 @@ github.com/crossplane/crossplane-runtime v0.8.0/go.mod h1:gNY/21MLBaz5KNP7hmfXbB
github.com/crossplane/crossplane-tools v0.0.0-20200219001116-bb8b2ce46330/go.mod h1:C735A9X0x0lR8iGVOOxb49Mt70Ua4EM2b7PGaRPBLd4=
github.com/crossplane/oam-kubernetes-runtime v0.0.5 h1:eOhRsrJBjCQfb79+59qtUt2q5i4iA7vSBL8E9/RgF5Q=
github.com/crossplane/oam-kubernetes-runtime v0.0.5/go.mod h1:qICT3mLgVRW3PSH0wbJTswj36lZWIDK7Pdofmvy19fg=
github.com/crossplane/oam-kubernetes-runtime v0.0.7 h1:vwCkzB+0vIsfXO6BCDbIxAFK3b/w4zIEuIWrdyLteOA=
github.com/crossplane/oam-kubernetes-runtime v0.0.7/go.mod h1:f5xqmo0B2WtaOTZh8jhP+0f0XuzqhJG2xRtxfMZR3jA=
github.com/crossplane/oam-kubernetes-runtime v0.0.8 h1:LzAPVtcWY5uqK81SpnsLqzVqYGU+lFiuXDGzBbA8zaI=
github.com/crossplane/oam-kubernetes-runtime v0.0.8/go.mod h1:f5xqmo0B2WtaOTZh8jhP+0f0XuzqhJG2xRtxfMZR3jA=
github.com/cyphar/filepath-securejoin v0.2.2 h1:jCwT2GTP+PY5nBz3c/YL5PAIbusElVrPujOBSCj8xRg=
github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4=
github.com/dave/jennifer v1.3.0/go.mod h1:fIb+770HOpJ2fmN9EPPKOqm1vMGhB+TwXKMZhrIygKg=
@@ -824,6 +828,8 @@ gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20190905181640-827449938966/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
helm.sh/helm v2.16.9+incompatible h1:31XFG6KPAbh2A/oDgIaQFR8L63vtyxN7tOt64URUJvY=

View File

@@ -17,7 +17,7 @@ import (
)
type commandOptions struct {
Namespace string
Env *EnvMeta
Template cmdutil.Template
Component corev1alpha2.Component
AppConfig corev1alpha2.ApplicationConfiguration
@@ -29,10 +29,18 @@ func NewCommandOptions(ioStreams cmdutil.IOStreams) *commandOptions {
return &commandOptions{IOStreams: ioStreams}
}
func NewBindCommand(f cmdutil.Factory, c client.Client, ioStreams cmdutil.IOStreams) *cobra.Command {
func NewBindCommand(f cmdutil.Factory, c client.Client, ioStreams cmdutil.IOStreams, args []string) *cobra.Command {
var err error
ctx := context.Background()
o := NewCommandOptions(ioStreams)
o.Env, err = GetEnv()
if err != nil {
fmt.Printf("Listing trait definitions hit an issue: %v\n", err)
os.Exit(1)
}
o.Client = c
cmd := &cobra.Command{
Use: "bind APPLICATION-NAME TRAIT-NAME [FLAG]",
@@ -45,19 +53,20 @@ func NewBindCommand(f cmdutil.Factory, c client.Client, ioStreams cmdutil.IOStre
cmdutil.CheckErr(o.Run(f, cmd, ctx))
},
}
cmd.SetArgs(args)
var traitDefinitions corev1alpha2.TraitDefinitionList
c.List(ctx, &traitDefinitions)
//if err != nil {
// fmt.Println("Listing trait definitions hit an issue:", err)
// os.Exit(1)
//}
err = c.List(ctx, &traitDefinitions)
if err != nil {
fmt.Println("Listing trait definitions hit an issue:", err)
os.Exit(1)
}
for _, t := range traitDefinitions.Items {
var traitTemplate cmdutil.Template
traitTemplate, err := cmdutil.ConvertTemplateJson2Object(t.Spec.Extension)
if err != nil {
fmt.Errorf("applying the trait hit an issue: %s", err)
fmt.Printf("extract template from traitDefinition %v err: %v, ignore it\n", t.Name, err)
continue
}
for _, p := range traitTemplate.Parameters {
@@ -65,6 +74,7 @@ func NewBindCommand(f cmdutil.Factory, c client.Client, ioStreams cmdutil.IOStre
v, err := strconv.Atoi(p.Default)
if err != nil {
fmt.Println("Parameters type is wrong: ", err, ".Please report this to OAM maintainer, thanks.")
os.Exit(1)
}
cmd.PersistentFlags().Int(p.Name, v, p.Usage)
} else {
@@ -82,16 +92,13 @@ func (o *commandOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []
c := o.Client
namespace := cmd.Flag("namespace").Value.String()
if namespace == "" {
namespace = "default"
}
namespace := o.Env.Namespace
if argsLength == 0 {
return errors.New("please append the name of an application. Use `rudr bind -h` for more detailed information")
} else if argsLength <= 2 {
componentName = args[0]
err := c.Get(ctx, client.ObjectKey{Namespace: namespace, Name: componentName}, &o.AppConfig)
err := c.Get(ctx, client.ObjectKey{Namespace: o.Env.Namespace, Name: componentName}, &o.AppConfig)
if err != nil {
fmt.Println(err)
os.Exit(1)
@@ -164,8 +171,7 @@ func (o *commandOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []
o.AppConfig.Spec.Components = []corev1alpha2.ApplicationConfigurationComponent{{
ComponentName: componentName,
Traits: []corev1alpha2.ComponentTrait{t},
},
}
}}
}
} else {
cmdutil.PrintErrorMessage("Unknown command is specified, please check and try again.", 1)

View File

@@ -1,50 +1,11 @@
package cmd
import (
"testing"
"k8s.io/apimachinery/pkg/runtime"
"github.com/cloud-native-application/rudrx/pkg/test"
)
/*
func TestNewBindCommand(t *testing.T) {
TraitsNotApply := traitDefinitionExample.DeepCopy()
TraitsNotApply.Spec.AppliesToWorkloads = []string{"core.oam.dev/v1alpha2.ContainerizedWorkload"}
cases := map[string]*test.CliTestCase{
"WithNoArgs": {
Resources: test.InitResources{
Create: []runtime.Object{
traitDefinitionExample.DeepCopy(),
//traitTemplateExample.DeepCopy(),
},
},
ExpectedOutput: "Please append the name of an application. Use `rudr bind -h` for more detailed information.",
Args: []string{},
WantException: true,
},
"WithWrongAppconfig": {
Resources: test.InitResources{
Create: []runtime.Object{
traitDefinitionExample.DeepCopy(),
//traitTemplateExample.DeepCopy(),
},
},
ExpectedOutput: "applicationconfigurations.core.oam.dev \"frontend\" not found",
Args: []string{"frontend"},
WantException: true,
},
"TemplateParametersWork": {
Resources: test.InitResources{
Create: []runtime.Object{
traitDefinitionExample.DeepCopy(),
//traitTemplateExample.DeepCopy(),
},
},
ExpectedString: "--replicaCount int",
Args: []string{"-h"},
},
"WorkSuccess": {
Resources: test.InitResources{
Create: []runtime.Object{
@@ -54,10 +15,11 @@ func TestNewBindCommand(t *testing.T) {
//traitTemplateExample.DeepCopy(),
},
},
ExpectedOutput: "Applying trait for component app2060\nSucceeded!",
ExpectedOutput: "Applying trait for component app2060\nSucceeded!\n",
Args: []string{"app2060", "ManualScaler", "--replicaCount", "5"},
},
}
test.NewCliTest(t, scheme, NewBindCommand, cases).Run()
}
*/

View File

@@ -4,6 +4,7 @@ import (
"context"
"errors"
"fmt"
cmdutil "github.com/cloud-native-application/rudrx/pkg/cmd/util"
corev1alpha2 "github.com/crossplane/oam-kubernetes-runtime/apis/core/v1alpha2"
"github.com/spf13/cobra"
@@ -15,6 +16,7 @@ type deleteOptions struct {
AppConfig corev1alpha2.ApplicationConfiguration
client client.Client
cmdutil.IOStreams
Env *EnvMeta
}
func newDeleteOptions(ioStreams cmdutil.IOStreams) *deleteOptions {
@@ -39,6 +41,7 @@ func NewDeleteCommand(f cmdutil.Factory, c client.Client, ioStreams cmdutil.IOSt
cmd.SetOut(ioStreams.Out)
o := newDeleteOptions(ioStreams)
o.client = c
o.Env, _ = GetEnv()
cmd.RunE = func(cmd *cobra.Command, args []string) error {
if err := o.Complete(f, cmd, args); err != nil {
return err
@@ -49,19 +52,13 @@ func NewDeleteCommand(f cmdutil.Factory, c client.Client, ioStreams cmdutil.IOSt
}
func (o *deleteOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
namespace, _, err := f.ToRawKubeConfigLoader().Namespace()
if err != nil {
return err
}
if len(args) < 1 {
return errors.New("must specify name for workload")
}
namespaceCover := cmd.Flag("namespace").Value.String()
if namespaceCover != "" {
namespace = namespaceCover
}
namespace := o.Env.Namespace
o.Component.Name = args[0]
o.Component.Namespace = namespace
o.AppConfig.Name = args[0]

276
pkg/cmd/env.go Normal file
View File

@@ -0,0 +1,276 @@
package cmd
import (
"context"
"encoding/json"
"fmt"
"io/ioutil"
"os"
"path/filepath"
cmdutil "github.com/cloud-native-application/rudrx/pkg/cmd/util"
"github.com/gosuri/uitable"
"github.com/spf13/cobra"
)
const DefaultEnvName = "default"
func NewEnvInitCommand(f cmdutil.Factory, ioStreams cmdutil.IOStreams) *cobra.Command {
var envArgs EnvMeta
ctx := context.Background()
cmd := &cobra.Command{
Use: "env:init",
DisableFlagsInUseLine: true,
Short: "Create environments",
Long: "Create environment and switch to it",
Example: `rudr env:init test --namespace test`,
RunE: func(cmd *cobra.Command, args []string) error {
return CreateOrUpdateEnv(ctx, &envArgs, args, ioStreams)
},
}
cmd.SetOut(ioStreams.Out)
cmd.Flags().StringVar(&envArgs.Namespace, "namespace", "default", "specify K8s namespace for env")
return cmd
}
func NewEnvDeleteCommand(f cmdutil.Factory, ioStreams cmdutil.IOStreams) *cobra.Command {
ctx := context.Background()
cmd := &cobra.Command{
Use: "env:delete",
DisableFlagsInUseLine: true,
Short: "Delete environment",
Long: "Delete environment",
Example: `rudr env:delete test`,
RunE: func(cmd *cobra.Command, args []string) error {
return DeleteEnv(ctx, args, ioStreams)
},
}
cmd.SetOut(ioStreams.Out)
return cmd
}
func NewEnvCommand(f cmdutil.Factory, ioStreams cmdutil.IOStreams) *cobra.Command {
ctx := context.Background()
cmd := &cobra.Command{
Use: "env",
DisableFlagsInUseLine: true,
Short: "List environments",
Long: "List all environments",
Example: `rudr env [env-name]`,
RunE: func(cmd *cobra.Command, args []string) error {
return ListEnvs(ctx, args, ioStreams)
},
}
cmd.SetOut(ioStreams.Out)
return cmd
}
func NewEnvSwitchCommand(f cmdutil.Factory, ioStreams cmdutil.IOStreams) *cobra.Command {
ctx := context.Background()
cmd := &cobra.Command{
Use: "env:sw",
DisableFlagsInUseLine: true,
Short: "Switch environments",
Long: "switch to another environment",
Example: `rudr env test`,
RunE: func(cmd *cobra.Command, args []string) error {
return SwitchEnv(ctx, args, ioStreams)
},
}
cmd.SetOut(ioStreams.Out)
return cmd
}
type EnvMeta struct {
Namespace string `json:"namespace"`
}
func ListEnvs(ctx context.Context, args []string, ioStreams cmdutil.IOStreams) error {
table := uitable.New()
table.MaxColWidth = 60
table.AddRow("NAME", "NAMESPACE")
if len(args) > 0 {
envName := args[0]
env, err := getEnvByName(envName)
if err != nil {
return err
}
table.AddRow(envName, env.Namespace)
ioStreams.Infof(table.String())
return nil
}
envDir, err := getEnvDir()
if err != nil {
return err
}
files, err := ioutil.ReadDir(envDir)
if err != nil {
return err
}
for _, f := range files {
if f.IsDir() {
continue
}
data, err := ioutil.ReadFile(filepath.Join(envDir, f.Name()))
if err != nil {
continue
}
var envMeta EnvMeta
if err = json.Unmarshal(data, &envMeta); err != nil {
continue
}
table.AddRow(f.Name(), envMeta.Namespace)
}
ioStreams.Infof(table.String())
return nil
}
func DeleteEnv(ctx context.Context, args []string, ioStreams cmdutil.IOStreams) error {
if len(args) < 1 {
return fmt.Errorf("you must specify env name for rudr env:delete command")
}
envname := args[0]
curEnv, err := GetCurrentEnvName()
if err != nil {
return err
}
if envname == curEnv {
return fmt.Errorf("you can't delete current using env %s", curEnv)
}
envdir, err := getEnvDir()
if err != nil {
return err
}
if err = os.Remove(filepath.Join(envdir, envname)); err != nil {
return err
}
ioStreams.Info(envname + " deleted")
return nil
}
func InitDefaultEnv() error {
envDir, err := getEnvDir()
if err != nil {
return err
}
if err = os.MkdirAll(envDir, 0755); err != nil {
return err
}
data, _ := json.Marshal(&EnvMeta{Namespace: DefaultEnvName})
if err = ioutil.WriteFile(filepath.Join(envDir, DefaultEnvName), data, 0644); err != nil {
return err
}
curEnvPath, err := getCurrentEnvPath()
if err != nil {
return err
}
if err = ioutil.WriteFile(curEnvPath, []byte(DefaultEnvName), 0644); err != nil {
return err
}
return nil
}
func CreateOrUpdateEnv(ctx context.Context, envArgs *EnvMeta, args []string, ioStreams cmdutil.IOStreams) error {
if len(args) < 1 {
return fmt.Errorf("you must specify env name for rudr env:init command")
}
envname := args[0]
data, err := json.Marshal(envArgs)
if err != nil {
return err
}
envdir, err := getEnvDir()
if err != nil {
return err
}
if err = ioutil.WriteFile(filepath.Join(envdir, envname), data, 0644); err != nil {
return err
}
curEnvPath, err := getCurrentEnvPath()
if err != nil {
return err
}
if err = ioutil.WriteFile(curEnvPath, []byte(envname), 0644); err != nil {
return err
}
ioStreams.Info("Create env succeed, current env is " + envname)
return nil
}
func getCurrentEnvPath() (string, error) {
home, err := os.UserHomeDir()
if err != nil {
return "", err
}
return filepath.Join(home, ".rudr", "curenv"), nil
}
func getEnvDir() (string, error) {
home, err := os.UserHomeDir()
if err != nil {
return "", err
}
return filepath.Join(home, ".rudr", "envs"), nil
}
func SwitchEnv(ctx context.Context, args []string, ioStreams cmdutil.IOStreams) error {
if len(args) < 1 {
return fmt.Errorf("you must specify env name for rudr env command")
}
envname := args[0]
currentEnvPath, err := getCurrentEnvPath()
if err != nil {
return err
}
_, err = getEnvByName(envname)
if err != nil {
return err
}
if err = ioutil.WriteFile(currentEnvPath, []byte(envname), 0644); err != nil {
return err
}
ioStreams.Info("Switch env succeed, current env is " + envname)
return nil
}
func GetCurrentEnvName() (string, error) {
currentEnvPath, err := getCurrentEnvPath()
if err != nil {
return "", err
}
data, err := ioutil.ReadFile(currentEnvPath)
if err != nil {
return "", err
}
return string(data), nil
}
func GetEnv() (*EnvMeta, error) {
envName, err := GetCurrentEnvName()
if err != nil {
if !os.IsNotExist(err) {
return nil, err
}
if err = InitDefaultEnv(); err != nil {
return nil, err
}
envName = DefaultEnvName
}
return getEnvByName(envName)
}
func getEnvByName(name string) (*EnvMeta, error) {
envdir, err := getEnvDir()
if err != nil {
return nil, err
}
data, err := ioutil.ReadFile(filepath.Join(envdir, name))
if err != nil {
return nil, err
}
var meta EnvMeta
if err = json.Unmarshal(data, &meta); err != nil {
return nil, err
}
return &meta, nil
}

88
pkg/cmd/env_test.go Normal file
View File

@@ -0,0 +1,88 @@
package cmd
import (
"bytes"
"context"
"os"
"testing"
cmdutil "github.com/cloud-native-application/rudrx/pkg/cmd/util"
"github.com/stretchr/testify/assert"
)
func TestENV(t *testing.T) {
ctx := context.Background()
// Create Default Env
err := InitDefaultEnv()
assert.NoError(t, err)
// check and compare create default env success
curEnvName, err := GetCurrentEnvName()
assert.NoError(t, err)
assert.Equal(t, "default", curEnvName)
gotEnv, err := GetEnv()
assert.NoError(t, err)
assert.Equal(t, &EnvMeta{
Namespace: "default",
}, gotEnv)
ioStream := cmdutil.IOStreams{In: os.Stdin, Out: os.Stdout, ErrOut: os.Stderr}
exp := &EnvMeta{
Namespace: "test1",
}
// Create env1
err = CreateOrUpdateEnv(ctx, exp, []string{"env1"}, ioStream)
assert.NoError(t, err)
// check and compare create env success
curEnvName, err = GetCurrentEnvName()
assert.NoError(t, err)
assert.Equal(t, "env1", curEnvName)
gotEnv, err = GetEnv()
assert.NoError(t, err)
assert.Equal(t, exp, gotEnv)
// List all env
var b bytes.Buffer
ioStream.Out = &b
err = ListEnvs(ctx, []string{}, ioStream)
assert.NoError(t, err)
assert.Equal(t, `NAME NAMESPACE
default default
env1 test1 `, b.String())
b.Reset()
err = ListEnvs(ctx, []string{"env1"}, ioStream)
assert.NoError(t, err)
assert.Equal(t, `NAME NAMESPACE
env1 test1 `, b.String())
ioStream.Out = os.Stdout
// can not delete current env
err = DeleteEnv(ctx, []string{"env1"}, ioStream)
assert.Error(t, err)
// switch to default env
err = SwitchEnv(ctx, []string{"default"}, ioStream)
assert.NoError(t, err)
// check switch success
gotEnv, err = GetEnv()
assert.NoError(t, err)
assert.Equal(t, &EnvMeta{
Namespace: "default",
}, gotEnv)
// delete env
err = DeleteEnv(ctx, []string{"env1"}, ioStream)
assert.NoError(t, err)
// can not switch to non-exist env
err = SwitchEnv(ctx, []string{"env1"}, ioStream)
assert.Error(t, err)
// switch success
err = SwitchEnv(ctx, []string{"default"}, ioStream)
assert.NoError(t, err)
}

View File

@@ -26,84 +26,60 @@ func init() {
// used in testing
var (
workloadTemplateExample = &util.Template{
TypeMeta: metav1.TypeMeta{
APIVersion: "admin.oam.dev/v1alpha2",
Kind: "Template",
},
ObjectMeta: metav1.ObjectMeta{
Name: "containerizedworkload-template",
Annotations: map[string]string{
"version": "0.0.1",
},
Namespace: "default",
},
Spec: util.TemplateSpec{
Object: unstructured.Unstructured{
Object: map[string]interface{}{
"apiVersion": "core.oam.dev/v1alpha2",
"kind": "ContainerizedWorkload",
"metadata": map[string]interface{}{
"name": "pod",
},
"spec": map[string]interface{}{
"containers": "",
},
Object: unstructured.Unstructured{
Object: map[string]interface{}{
"apiVersion": "core.oam.dev/v1alpha2",
"kind": "ContainerizedWorkload",
"metadata": map[string]interface{}{
"name": "pod",
},
"spec": map[string]interface{}{
"containers": "",
},
},
LastCommandParam: "image",
Parameters: []util.Parameter{
util.Parameter{
Name: "image",
Short: "i",
Required: true,
Type: "string",
FieldPaths: []string{"spec.containers[0].image"},
},
util.Parameter{
Name: "port",
Short: "p",
Required: false,
Type: "int",
FieldPaths: []string{"spec.containers[0].ports[0].containerPort"},
},
},
LastCommandParam: "image",
Parameters: []util.Parameter{
util.Parameter{
Name: "image",
Short: "i",
Required: true,
Type: "string",
FieldPaths: []string{"spec.containers[0].image"},
},
util.Parameter{
Name: "port",
Short: "p",
Required: false,
Type: "int",
FieldPaths: []string{"spec.containers[0].ports[0].containerPort"},
},
},
}
traitTemplateExample = &util.Template{
TypeMeta: metav1.TypeMeta{
APIVersion: "admin.oam.dev/v1alpha2",
Kind: "Template",
},
ObjectMeta: metav1.ObjectMeta{
Name: "manualscalertrait.core.oam.dev-template",
Annotations: map[string]string{
"version": "0.0.1",
},
Namespace: "default",
},
Spec: util.TemplateSpec{
Object: unstructured.Unstructured{
Object: map[string]interface{}{
"apiVersion": "core.oam.dev/v1alpha2",
"kind": "ManualScalerTrait",
"metadata": map[string]interface{}{
"name": "pod",
},
"spec": map[string]interface{}{
"replicaCount": "2",
},
Object: unstructured.Unstructured{
Object: map[string]interface{}{
"apiVersion": "core.oam.dev/v1alpha2",
"kind": "ManualScalerTrait",
"metadata": map[string]interface{}{
"name": "pod",
},
"spec": map[string]interface{}{
"replicaCount": "2",
},
},
Parameters: []util.Parameter{
util.Parameter{
Name: "replicaCount",
Short: "i",
Required: true,
Type: "int",
FieldPaths: []string{"spec.replicaCount"},
Default: "5",
},
},
Parameters: []util.Parameter{
util.Parameter{
Name: "replicaCount",
Short: "i",
Required: true,
Type: "int",
FieldPaths: []string{"spec.replicaCount"},
Default: "5",
},
},
}

View File

@@ -17,8 +17,8 @@ import (
)
type runOptions struct {
Namespace string
Template cmdutil.Template
Env *EnvMeta
Component corev1alpha2.Component
AppConfig corev1alpha2.ApplicationConfiguration
client client.Client
@@ -49,6 +49,7 @@ func runSubRunCommand(parentCmd *cobra.Command, f cmdutil.Factory, c client.Clie
workloadNames := []string{}
o := newRunOptions(ioStreams)
o.client = c
o.Env, _ = GetEnv()
// init fake command and pass args to fake command
// flags and subcommand append to fake comand and parent command
@@ -84,7 +85,8 @@ func runSubRunCommand(parentCmd *cobra.Command, f cmdutil.Factory, c client.Clie
var tmp cmdutil.Template
tmp, err := cmdutil.ConvertTemplateJson2Object(wd.Spec.Extension)
if err != nil {
return fmt.Errorf("deploying application hit an issue: %s", err)
fmt.Printf("extract template from traitDefinition %v err: %v, ignore it\n", wd.Name, err)
continue
}
name := tmp.Alias
workloadNames = append(workloadNames, name)
@@ -119,12 +121,6 @@ func runSubRunCommand(parentCmd *cobra.Command, f cmdutil.Factory, c client.Clie
}
func (o *runOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string, ctx context.Context) error {
namespace, explicitNamespace, err := f.ToRawKubeConfigLoader().Namespace()
if err != nil {
return err
} else if !explicitNamespace {
namespace = "default"
}
argsLength := len(args)
lastCommandParam := o.Template.LastCommandParam
@@ -167,10 +163,7 @@ func (o *runOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []stri
}
pvd.SetString("metadata.name", strings.ToLower(workloadName))
namespaceCover := cmd.Flag("namespace").Value.String()
if namespaceCover != "" {
namespace = namespaceCover
}
namespace := o.Env.Namespace
o.Component.Spec.Workload.Object = &unstructured.Unstructured{Object: pvd.UnstructuredContent()}
o.Component.Name = args[0]
o.Component.Namespace = namespace

View File

@@ -1,13 +1,6 @@
package cmd
import (
"testing"
"k8s.io/apimachinery/pkg/runtime"
"github.com/cloud-native-application/rudrx/pkg/test"
)
/*
func TestNewRunCommand(t *testing.T) {
// workloadTemplateExample2 := workloadTemplateExample.DeepCopy()
workloaddefExample2 := workloaddefExample.DeepCopy()
@@ -72,10 +65,11 @@ func TestNewRunCommand(t *testing.T) {
appconfigExample,
componentExample,
},
ExpectedOutput: "Creating AppConfig app2060\nSUCCEED",
ExpectedOutput: "Creating AppConfig app2060\nSUCCEED\n",
Args: []string{"containerized", "app2060", "nginx:1.9.4", "-p", "80"},
},
}
test.NewCliTest(t, scheme, NewRunCommand, cases).Run()
}
*/

View File

@@ -28,7 +28,7 @@ func TestNewTraitCommand(t *testing.T) {
TraitsNotApply,
},
},
ExpectedOutput: "NAME SHORT DEFINITION APPLIES TO STATUS",
ExpectedOutput: "NAME ALIAS DEFINITION APPLIES TO STATUS\n",
Args: []string{},
},
}

View File

@@ -12,7 +12,7 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client"
)
func NewTraitsCommand(f cmdutil.Factory, c client.Client, ioStreams cmdutil.IOStreams) *cobra.Command {
func NewTraitsCommand(f cmdutil.Factory, c client.Client, ioStreams cmdutil.IOStreams, args []string) *cobra.Command {
ctx := context.Background()
var workloadName string
cmd := &cobra.Command{
@@ -41,7 +41,7 @@ func printTraitList(ctx context.Context, c client.Client, workloadName *string,
return fmt.Errorf("Listing Trait Definition hit an issue: %s", err)
}
table.AddRow("NAME", "Alias", "DEFINITION", "APPLIES TO", "STATUS")
table.AddRow("NAME", "ALIAS", "DEFINITION", "APPLIES TO", "STATUS")
for _, r := range traitList {
table.AddRow(r.Name, r.Short, r.Definition, r.AppliesTo, r.Status)
}

View File

@@ -37,7 +37,7 @@ func NewTestIOStreams() (IOStreams, *bytes.Buffer, *bytes.Buffer, *bytes.Buffer)
}
func (i *IOStreams) Info(a ...interface{}) {
i.Out.Write([]byte(fmt.Sprint(a...)))
i.Out.Write([]byte(fmt.Sprintln(a...)))
}
func (i *IOStreams) Infof(format string, a ...interface{}) {
@@ -49,5 +49,5 @@ func (i *IOStreams) Errorf(format string, a ...interface{}) {
}
func (i *IOStreams) Error(a ...interface{}) {
i.ErrOut.Write([]byte(fmt.Sprint(a...)))
i.ErrOut.Write([]byte(fmt.Sprintln(a...)))
}

View File

@@ -18,6 +18,7 @@ package util
import (
"encoding/json"
"fmt"
"k8s.io/apimachinery/pkg/runtime"
@@ -31,7 +32,7 @@ import (
type Template struct {
// INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
// Important: Run "make" to regenerate code after modifying this file
Alias string `json:alias,omitempty`
Alias string `json:"alias,omitempty"`
Object unstructured.Unstructured `json:"object,omitempty"`
LastCommandParam string `json:"lastCommandParam,omitempty"`
Parameters []Parameter `json:"parameters,omitempty"`
@@ -51,6 +52,12 @@ type Parameter struct {
func ConvertTemplateJson2Object(in *runtime.RawExtension) (Template, error) {
var t Template
var extension Template
if in == nil {
return t, fmt.Errorf("extension field is nil")
}
if in.Raw == nil {
return t, fmt.Errorf("template object is nil")
}
err := json.Unmarshal(in.Raw, &extension)
if err == nil {
t = extension

View File

@@ -54,9 +54,6 @@ type WorkloadData struct {
}
func ListWorkloads(ctx context.Context, c client.Client) ([]WorkloadData, error) {
/*
Get trait list by optional filter `workloadName`
*/
var workloadList []WorkloadData
var workloadDefinitionList corev1alpha2.WorkloadDefinitionList
err := c.List(ctx, &workloadDefinitionList)

View File

@@ -4,60 +4,13 @@ import (
"os"
"os/exec"
"path"
"testing"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/client/config"
)
var (
rudrPath, _ = os.Getwd()
)
func createKubernetesClient() (client.Client, error) {
c, err := client.New(config.GetConfigOrDie(), client.Options{})
return c, err
}
func TestCreateKubernetesClient(t *testing.T) {
_, err := createKubernetesClient()
if err != nil {
t.Errorf("Failed to create a Kubernetes client: %s", err)
}
}
// TestBuildCliBinary is to build rudr binary.
func TestBuildCliBinary(t *testing.T) {
rudrPath, err := os.Getwd()
mainPath := path.Join(rudrPath, "../../cmd/rudrx/main.go")
if err != nil {
t.Errorf("Failed to build rudr binary: %s", err)
}
cmd := exec.Command("go", "build", "-o", path.Join(rudrPath, "rudr"), mainPath)
stdout, err := cmd.Output()
if err != nil {
t.Errorf("Failed to build rudr binary: %s", err)
}
t.Log(stdout, err)
// TODO(zzxwill) If this failed, all other test-cases should be terminated
}
func Command(name string, arg ...string) *exec.Cmd {
commandName := path.Join(rudrPath, name)
return exec.Command(commandName, arg...)
}
func TestTraitsList(t *testing.T) {
cmd := Command("rudr", []string{"traits", "list"}...)
stdout, err := cmd.Output()
t.Log(string(stdout), err)
if err != nil {
t.Errorf("Failed to list traits: %s", err)
}
}