Skip to content

Commit

Permalink
feature: bcs-client support multiple operation, issue TencentBlueKing…
Browse files Browse the repository at this point in the history
  • Loading branch information
DeveloperJim committed Feb 21, 2020
1 parent ad6eb71 commit 3d8bfab
Show file tree
Hide file tree
Showing 9 changed files with 528 additions and 2 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ scheduler:pre
logbeat-sidecar:pre
mkdir -p ${PACKAGEPATH}/bcs-services
cp -R ./install/conf/bcs-services/bcs-logbeat-sidecar ${PACKAGEPATH}/bcs-services
go build ${LDFLAG} -o ${PACKAGEPATH}/bcs-logbeat-sidecar/bcs-logbeat-sidecar ./bcs-services/bcs-logbeat-sidecar/main.go
go build ${LDFLAG} -o ${PACKAGEPATH}/bcs-services/bcs-logbeat-sidecar/bcs-logbeat-sidecar ./bcs-services/bcs-logbeat-sidecar/main.go

hpacontroller:pre
mkdir -p ${PACKAGEPATH}/bcs-mesos-master
Expand Down
1 change: 1 addition & 0 deletions bcs-common/common/types/meta.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ const (
BcsDataType_CRR BcsDataType = "crr"
BcsDataType_WebConsole BcsDataType = "webconsole"
BcsDataType_Admissionwebhook BcsDataType = "admissionwebhook"
BcsDataType_CRD BcsDataType = "customresourcedefinition"
)

//TypeMeta for bcs data type
Expand Down
199 changes: 199 additions & 0 deletions bcs-services/bcs-client/cmd/batch/apply.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
/*
* Tencent is pleased to support the open source community by making Blueking Container Service available.
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
* Licensed under the MIT License (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
* http://opensource.org/licenses/MIT
* 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 batch

import (
"bytes"
"fmt"
"io/ioutil"
"net/url"
"os"
"strings"

mesostype "bk-bcs/bcs-common/common/types"
"bk-bcs/bcs-services/bcs-client/cmd/utils"
"bk-bcs/bcs-services/bcs-client/pkg/metastream"
"bk-bcs/bcs-services/bcs-client/pkg/scheduler/v4"
"bk-bcs/bcs-services/bcs-client/pkg/storage/v1"

"github.com/urfave/cli"
)

//NewApplyCommand sub command apply registration
func NewApplyCommand() cli.Command {
return cli.Command{
Name: "apply",
Usage: "create multiple Mesos resources, like application/deployment/service/configmap/secret",
UsageText: `
example:
> helm template myname sometemplate -n bcs-system | grep -v "^#" | bcs-client apply
or reading resource from file
> bcs-client apply -f myresource.json
`,
Flags: []cli.Flag{
cli.StringFlag{
Name: "from-file, f",
Usage: "reading with configuration `FILE`",
},
cli.StringFlag{
Name: "clusterid",
Usage: "Cluster ID",
},
},
Action: func(c *cli.Context) error {
return apply(utils.NewClientContext(c))
},
}
}

type createFunc func(string, string, []byte) error
type updateFunc func(string, string, []byte, url.Values) error

type metaInfo struct {
clusterID string
apiVersion string
kind string
namespace string
name string
rawJson []byte
}

//apply multiple mesos json resources to bcs-scheduler
func apply(cxt *utils.ClientContext) error {
//step: check parameter from command line
if err := cxt.MustSpecified(utils.OptionClusterID); err != nil {
return err
}
var data []byte
var err error
if !cxt.IsSet(utils.OptionFile) {
//reading all data from stdin
data, err = ioutil.ReadAll(os.Stdin)
} else {
data, err = cxt.FileData()
}
if err != nil {
return err
}
if len(data) == 0 {
return fmt.Errorf("failed to apply: no available resource datas")
}
//step: reading json object from input(file or stdin)
metaList := metastream.NewMetaStream(bytes.NewReader(data))
//step: initialize storage client & scheduler client
storage := v1.NewBcsStorage(utils.GetClientOption())
scheduler := v4.NewBcsScheduler(utils.GetClientOption())

//step: create/update all resource according json list
for metaList.HasNext() {
info := metaInfo{}
//step: check json object from parsing
info.apiVersion, info.kind, err = metaList.GetResourceKind()
if err != nil {
fmt.Printf("apply partial failed, %s, continue...", err.Error())
continue
}
info.namespace, info.name, err = metaList.GetResourceKey()
if err != nil {
fmt.Printf("apply partial failed, %s, continue...", err.Error())
continue
}
info.rawJson = metaList.GetRawJSON()
info.clusterID = cxt.ClusterID()
//step: inspect resource object from storage
// if resource exist, update resource to bcs-scheduler, print object status from response
// otherwise, create resources to bcs-scheduler and print object status from response
var inspectStatus error
var create createFunc
var update updateFunc
switch mesostype.BcsDataType(strings.ToLower(info.kind)) {
case mesostype.BcsDataType_APP:
_, inspectStatus = storage.InspectApplication(cxt.ClusterID(), info.namespace, info.name)
create = scheduler.CreateApplication
update = scheduler.UpdateApplication
case mesostype.BcsDataType_PROCESS:
_, inspectStatus = storage.InspectProcess(cxt.ClusterID(), info.namespace, info.name)
create = scheduler.CreateProcess
update = scheduler.UpdateProcess
case mesostype.BcsDataType_SECRET:
_, inspectStatus = storage.InspectSecret(cxt.ClusterID(), info.namespace, info.name)
create = scheduler.CreateSecret
update = scheduler.UpdateSecret
case mesostype.BcsDataType_CONFIGMAP:
_, inspectStatus = storage.InspectConfigMap(cxt.ClusterID(), info.namespace, info.name)
create = scheduler.CreateConfigMap
update = scheduler.UpdateConfigMap
case mesostype.BcsDataType_SERVICE:
_, inspectStatus = storage.InspectService(cxt.ClusterID(), info.namespace, info.name)
create = scheduler.CreateService
update = scheduler.UpdateService
case mesostype.BcsDataType_DEPLOYMENT:
_, inspectStatus = storage.InspectDeployment(cxt.ClusterID(), info.namespace, info.name)
create = scheduler.CreateDeployment
update = scheduler.UpdateDeployment
case mesostype.BcsDataType_CRD:
_, inspectStatus = scheduler.GetCustomResourceDefinition(cxt.ClusterID(), info.name)
create = func(cluster string, ns string, data []byte) error {
return scheduler.CreateCustomResourceDefinition(cluster, data)
}
update = func(cluster, ns string, data []byte, urlv url.Values) error {
return scheduler.UpdateCustomResourceDefinition(cluster, info.name, data)
}
default:
//unkown type, try custom resource
crdapiVersion, plural, crdErr := utils.GetCustomResourceTypeByKind(scheduler, cxt.ClusterID(), info.kind)
if err != nil {
fmt.Printf("resource %s/%s %s apply failed, %s.", info.apiVersion, info.kind, info.name, crdErr.Error())
continue
}
_, inspectStatus = scheduler.GetCustomResource(cxt.ClusterID(), crdapiVersion, plural, info.namespace, info.name)
create = func(cluster string, ns string, data []byte) error {
return scheduler.CreateCustomResource(cluster, crdapiVersion, plural, ns, data)
}
update = func(cluster, ns string, data []byte, urlv url.Values) error {
return scheduler.UpdateCustomResource(cluster, crdapiVersion, plural, ns, info.name, data)
}
}
applySpecifiedResource(inspectStatus, create, update, &info)
}
return nil
}

func isObjectNotExist(err error) bool {
str := err.Error()
return strings.Contains(str, "resource does not exist") || strings.Contains(str, "not found")
}

func applySpecifiedResource(inspectStatus error, create createFunc, update updateFunc, info *metaInfo) {
if inspectStatus == nil {
//update object
if err := update(info.clusterID, info.namespace, info.rawJson, nil); err != nil {
fmt.Printf("resource %s/%s %s update successfully.", info.apiVersion, info.kind, info.name)
} else {
fmt.Printf("resource %s/%s %s update failed, %s.", info.apiVersion, info.kind, info.name, err.Error())
}
return
}

if !isObjectNotExist(inspectStatus) {
fmt.Printf("resource %s/%s %s apply failed, %s.", info.apiVersion, info.kind, info.name, inspectStatus.Error())
return
}
//create
if err := create(info.clusterID, info.namespace, info.rawJson); err != nil {
fmt.Printf("resource %s/%s %s create failed, %s.", info.apiVersion, info.kind, info.name, err.Error())
} else {
fmt.Printf("resource %s/%s %s create successfully", info.apiVersion, info.kind, info.name)
}
}
163 changes: 163 additions & 0 deletions bcs-services/bcs-client/cmd/batch/clean.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
/*
* Tencent is pleased to support the open source community by making Blueking Container Service available.
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
* Licensed under the MIT License (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
* http://opensource.org/licenses/MIT
* 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 batch

import (
mesostype "bk-bcs/bcs-common/common/types"
"bk-bcs/bcs-services/bcs-client/cmd/utils"
"bk-bcs/bcs-services/bcs-client/pkg/metastream"
"bk-bcs/bcs-services/bcs-client/pkg/scheduler/v4"
"bk-bcs/bcs-services/bcs-client/pkg/storage/v1"
"bytes"
"fmt"
"io/ioutil"
"os"
"strings"

"github.com/urfave/cli"
)

//NewCleanCommand sub command clean all registration
func NewCleanCommand() cli.Command {
return cli.Command{
Name: "clean",
Usage: "delete multiple Mesos resources, like application/deployment/service/configmap/secret/customresourcedefinition",
UsageText: `
example:
> helm template myname sometemplate -n bcs-system | grep -v "^#" | bcs-client clean
or reading resource from file
> bcs-client clean -f myresource.json
`,
Flags: []cli.Flag{
cli.StringFlag{
Name: "from-file, f",
Usage: "reading all resources reference from `FILE`",
},
cli.StringFlag{
Name: "clusterid",
Usage: "Cluster ID",
},
},
Action: func(c *cli.Context) error {
return clean(utils.NewClientContext(c))
},
}
}

type deleteFunc func(clusterID, namespace, name string, enforce bool) error

//clean multiple mesos json resources to bcs-scheduler
func clean(cxt *utils.ClientContext) error {
//step: check parameter from command line
if err := cxt.MustSpecified(utils.OptionClusterID); err != nil {
return err
}
var data []byte
var err error
if !cxt.IsSet(utils.OptionFile) {
//reading all data from stdin
data, err = ioutil.ReadAll(os.Stdin)
} else {
data, err = cxt.FileData()
}
if err != nil {
return err
}
if len(data) == 0 {
return fmt.Errorf("failed to clean: no available resource datas")
}
//step: reading json object from input(file or stdin)
metaList := metastream.NewMetaStream(bytes.NewReader(data))
//step: initialize storage client & scheduler client
storage := v1.NewBcsStorage(utils.GetClientOption())
scheduler := v4.NewBcsScheduler(utils.GetClientOption())

//step: delete all resource according json list
for metaList.HasNext() {
info := metaInfo{}
//step: check json object from parsing
info.apiVersion, info.kind, err = metaList.GetResourceKind()
if err != nil {
fmt.Printf("apply partial failed, %s, continue...", err.Error())
continue
}
info.namespace, info.name, err = metaList.GetResourceKey()
if err != nil {
fmt.Printf("apply partial failed, %s, continue...", err.Error())
continue
}
//info.rawJson = metaList.GetRawJSON()
info.clusterID = cxt.ClusterID()
//step: inspect resource object from storage
// if resource exist, delete resource in bcs-scheduler, print object status from response
// otherwise, do nothing~
var inspectStatus error
var delFunc deleteFunc
switch mesostype.BcsDataType(strings.ToLower(info.kind)) {
case mesostype.BcsDataType_APP:
_, inspectStatus = storage.InspectApplication(cxt.ClusterID(), info.namespace, info.name)
delFunc = scheduler.DeleteApplication
case mesostype.BcsDataType_PROCESS:
_, inspectStatus = storage.InspectProcess(cxt.ClusterID(), info.namespace, info.name)
delFunc = scheduler.DeleteProcess
case mesostype.BcsDataType_SECRET:
_, inspectStatus = storage.InspectSecret(cxt.ClusterID(), info.namespace, info.name)
delFunc = scheduler.DeleteSecret
case mesostype.BcsDataType_CONFIGMAP:
_, inspectStatus = storage.InspectConfigMap(cxt.ClusterID(), info.namespace, info.name)
delFunc = scheduler.DeleteConfigMap
case mesostype.BcsDataType_SERVICE:
_, inspectStatus = storage.InspectService(cxt.ClusterID(), info.namespace, info.name)
delFunc = scheduler.DeleteService
case mesostype.BcsDataType_DEPLOYMENT:
_, inspectStatus = storage.InspectDeployment(cxt.ClusterID(), info.namespace, info.name)
delFunc = scheduler.DeleteDeployment
case mesostype.BcsDataType_CRD:
_, inspectStatus = scheduler.GetCustomResourceDefinition(cxt.ClusterID(), info.name)
delFunc = func(cluster, namespace, name string, enforce bool) error {
return scheduler.DeleteCustomResourceDefinition(cluster, name)
}
default:
//unkown type, try custom resource
crdapiVersion, plural, crdErr := utils.GetCustomResourceTypeByKind(scheduler, cxt.ClusterID(), info.kind)
if err != nil {
fmt.Printf("resource %s/%s %s clean failed, %s.", info.apiVersion, info.kind, info.name, crdErr.Error())
continue
}
_, inspectStatus = scheduler.GetCustomResource(cxt.ClusterID(), crdapiVersion, plural, info.namespace, info.name)
delFunc = func(cluster, namespace, name string, enforce bool) error {
return scheduler.DeleteCustomResource(cluster, crdapiVersion, plural, namespace, name)
}
}
cleanSpecifiedResource(inspectStatus, delFunc, &info)
}
return nil
}

func cleanSpecifiedResource(inspectStatus error, delfunc deleteFunc, info *metaInfo) {
if inspectStatus == nil {
//no error when inspect, it means data exist
if err := delfunc(info.clusterID, info.namespace, info.name, false); err != nil {
fmt.Printf("resource %s/%s %s clean failed, %s.", info.apiVersion, info.kind, info.name, err.Error())
} else {
fmt.Printf("resource %s/%s %s clean successfully", info.apiVersion, info.kind, info.name)
}
return
}
if isObjectNotExist(inspectStatus) {
fmt.Printf("resource %s/%s %s clean nothing", info.apiVersion, info.kind, info.name)
} else {
fmt.Printf("resource %s/%s %s clean failed, %s", info.apiVersion, info.kind, info.name, inspectStatus.Error())
}
}
2 changes: 1 addition & 1 deletion bcs-services/bcs-client/cmd/delete/delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ func NewDeleteCommand() cli.Command {
},
cli.StringFlag{
Name: "name, n",
Usage: "Application name",
Usage: "resource name",
},
cli.StringFlag{
Name: "namespace, ns",
Expand Down
Loading

0 comments on commit 3d8bfab

Please sign in to comment.