forked from TencentBlueKing/bk-bcs
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feature: bcs-client support multiple operation, issue TencentBlueKing…
- Loading branch information
1 parent
ad6eb71
commit 3d8bfab
Showing
9 changed files
with
528 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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()) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.