From 660f2c1caa0879581fa2bb3d77de46dcc49b42cd Mon Sep 17 00:00:00 2001 From: Zexi Li Date: Fri, 27 Jul 2018 15:56:10 +0800 Subject: [PATCH] Add climc CLI tool. --- .gitignore | 41 +- LICENSE | 2 +- Makefile | 98 +++ README.md | 1 + build/build.sh | 124 ++++ build/climc/vars | 1 + cmd/climc/README.md | 3 + cmd/climc/climc.go | 188 ++++++ cmd/climc/promputils/completor.go | 121 ++++ cmd/climc/promputils/executor.go | 93 +++ cmd/climc/promputils/filter.go | 15 + cmd/climc/promputils/option_arguments.go | 74 +++ cmd/climc/shell/actions.go | 87 +++ cmd/climc/shell/alarmevents.go | 85 +++ cmd/climc/shell/alarmlogs.go | 77 +++ cmd/climc/shell/alarms.go | 144 +++++ cmd/climc/shell/alarmtemplates.go | 345 ++++++++++ cmd/climc/shell/baremetalnetworks.go | 47 ++ cmd/climc/shell/baremetalstorages.go | 42 ++ cmd/climc/shell/cachedimages.go | 51 ++ cmd/climc/shell/cloudproviders.go | 147 +++++ cmd/climc/shell/cloudregions.go | 102 +++ cmd/climc/shell/contactgroups.go | 28 + cmd/climc/shell/contacts.go | 169 +++++ cmd/climc/shell/current.go | 14 + cmd/climc/shell/disks.go | 175 +++++ cmd/climc/shell/dnsrecords.go | 178 +++++ cmd/climc/shell/domains.go | 274 ++++++++ cmd/climc/shell/email_config.go | 97 +++ cmd/climc/shell/endpoints.go | 138 ++++ cmd/climc/shell/events.go | 87 +++ cmd/climc/shell/groups.go | 138 ++++ cmd/climc/shell/hostcachedimages.go | 52 ++ cmd/climc/shell/hosts.go | 414 ++++++++++++ cmd/climc/shell/hoststorages.go | 77 +++ cmd/climc/shell/hostwires.go | 90 +++ cmd/climc/shell/images.go | 398 ++++++++++++ cmd/climc/shell/instances.go | 21 + cmd/climc/shell/isolatedevices.go | 55 ++ cmd/climc/shell/keypairs.go | 152 +++++ cmd/climc/shell/keystoneutils.go | 75 +++ cmd/climc/shell/labels.go | 96 +++ cmd/climc/shell/metric_types.go | 27 + cmd/climc/shell/metrics.go | 81 +++ cmd/climc/shell/monitor_metrics.go | 53 ++ cmd/climc/shell/monitor_types.go | 28 + cmd/climc/shell/monitorinputs.go | 47 ++ cmd/climc/shell/monitortemplates.go | 185 ++++++ cmd/climc/shell/networks.go | 221 +++++++ cmd/climc/shell/nodes.go | 165 +++++ cmd/climc/shell/notification.go | 86 +++ cmd/climc/shell/operations.go | 119 ++++ cmd/climc/shell/performances.go | 24 + cmd/climc/shell/processes.go | 33 + cmd/climc/shell/processlogs.go | 21 + cmd/climc/shell/project_admin.go | 28 + cmd/climc/shell/project_admin_candidates.go | 28 + cmd/climc/shell/projects.go | 353 ++++++++++ cmd/climc/shell/quotas.go | 110 ++++ cmd/climc/shell/rates.go | 152 +++++ cmd/climc/shell/recipient.go | 95 +++ cmd/climc/shell/regions.go | 109 ++++ cmd/climc/shell/reservedips.go | 59 ++ cmd/climc/shell/resource_details.go | 35 + cmd/climc/shell/resource_fees.go | 50 ++ cmd/climc/shell/role_assignments.go | 70 ++ cmd/climc/shell/roles.go | 158 +++++ cmd/climc/shell/schedtaghosts.go | 53 ++ cmd/climc/shell/schedtags.go | 99 +++ cmd/climc/shell/schedulers.go | 219 +++++++ cmd/climc/shell/secgrouprules.go | 147 +++++ cmd/climc/shell/secgroups.go | 157 +++++ cmd/climc/shell/serverdisks.go | 136 ++++ cmd/climc/shell/serverisolatedevices.go | 43 ++ cmd/climc/shell/servernetworks.go | 135 ++++ cmd/climc/shell/servers.go | 681 ++++++++++++++++++++ cmd/climc/shell/service_hosts.go | 93 +++ cmd/climc/shell/service_name_suggestions.go | 28 + cmd/climc/shell/services.go | 148 +++++ cmd/climc/shell/servicetrees.go | 109 ++++ cmd/climc/shell/shell.go | 110 ++++ cmd/climc/shell/sms_configs.go | 109 ++++ cmd/climc/shell/specs.go | 111 ++++ cmd/climc/shell/storagecachedimages.go | 66 ++ cmd/climc/shell/storagecaches.go | 34 + cmd/climc/shell/storages.go | 196 ++++++ cmd/climc/shell/tasks.go | 43 ++ cmd/climc/shell/tenants.go | 19 + cmd/climc/shell/treenodes.go | 177 +++++ cmd/climc/shell/usages.go | 83 +++ cmd/climc/shell/users.go | 320 +++++++++ cmd/climc/shell/utils.go | 19 + cmd/climc/shell/vcenters.go | 118 ++++ cmd/climc/shell/verification.go | 32 + cmd/climc/shell/version.go | 21 + cmd/climc/shell/vncproxy.go | 26 + cmd/climc/shell/vpcs.go | 119 ++++ cmd/climc/shell/wires.go | 94 +++ cmd/climc/shell/zones.go | 102 +++ 99 files changed, 10790 insertions(+), 10 deletions(-) create mode 100644 Makefile create mode 100644 README.md create mode 100755 build/build.sh create mode 100644 build/climc/vars create mode 100644 cmd/climc/README.md create mode 100644 cmd/climc/climc.go create mode 100644 cmd/climc/promputils/completor.go create mode 100644 cmd/climc/promputils/executor.go create mode 100644 cmd/climc/promputils/filter.go create mode 100644 cmd/climc/promputils/option_arguments.go create mode 100644 cmd/climc/shell/actions.go create mode 100644 cmd/climc/shell/alarmevents.go create mode 100644 cmd/climc/shell/alarmlogs.go create mode 100644 cmd/climc/shell/alarms.go create mode 100644 cmd/climc/shell/alarmtemplates.go create mode 100644 cmd/climc/shell/baremetalnetworks.go create mode 100644 cmd/climc/shell/baremetalstorages.go create mode 100644 cmd/climc/shell/cachedimages.go create mode 100644 cmd/climc/shell/cloudproviders.go create mode 100644 cmd/climc/shell/cloudregions.go create mode 100644 cmd/climc/shell/contactgroups.go create mode 100644 cmd/climc/shell/contacts.go create mode 100644 cmd/climc/shell/current.go create mode 100644 cmd/climc/shell/disks.go create mode 100644 cmd/climc/shell/dnsrecords.go create mode 100644 cmd/climc/shell/domains.go create mode 100644 cmd/climc/shell/email_config.go create mode 100644 cmd/climc/shell/endpoints.go create mode 100644 cmd/climc/shell/events.go create mode 100644 cmd/climc/shell/groups.go create mode 100644 cmd/climc/shell/hostcachedimages.go create mode 100644 cmd/climc/shell/hosts.go create mode 100644 cmd/climc/shell/hoststorages.go create mode 100644 cmd/climc/shell/hostwires.go create mode 100644 cmd/climc/shell/images.go create mode 100644 cmd/climc/shell/instances.go create mode 100644 cmd/climc/shell/isolatedevices.go create mode 100644 cmd/climc/shell/keypairs.go create mode 100644 cmd/climc/shell/keystoneutils.go create mode 100644 cmd/climc/shell/labels.go create mode 100644 cmd/climc/shell/metric_types.go create mode 100644 cmd/climc/shell/metrics.go create mode 100644 cmd/climc/shell/monitor_metrics.go create mode 100644 cmd/climc/shell/monitor_types.go create mode 100644 cmd/climc/shell/monitorinputs.go create mode 100644 cmd/climc/shell/monitortemplates.go create mode 100644 cmd/climc/shell/networks.go create mode 100644 cmd/climc/shell/nodes.go create mode 100644 cmd/climc/shell/notification.go create mode 100644 cmd/climc/shell/operations.go create mode 100644 cmd/climc/shell/performances.go create mode 100644 cmd/climc/shell/processes.go create mode 100644 cmd/climc/shell/processlogs.go create mode 100644 cmd/climc/shell/project_admin.go create mode 100644 cmd/climc/shell/project_admin_candidates.go create mode 100644 cmd/climc/shell/projects.go create mode 100644 cmd/climc/shell/quotas.go create mode 100644 cmd/climc/shell/rates.go create mode 100644 cmd/climc/shell/recipient.go create mode 100644 cmd/climc/shell/regions.go create mode 100644 cmd/climc/shell/reservedips.go create mode 100644 cmd/climc/shell/resource_details.go create mode 100644 cmd/climc/shell/resource_fees.go create mode 100644 cmd/climc/shell/role_assignments.go create mode 100644 cmd/climc/shell/roles.go create mode 100644 cmd/climc/shell/schedtaghosts.go create mode 100644 cmd/climc/shell/schedtags.go create mode 100644 cmd/climc/shell/schedulers.go create mode 100644 cmd/climc/shell/secgrouprules.go create mode 100644 cmd/climc/shell/secgroups.go create mode 100644 cmd/climc/shell/serverdisks.go create mode 100644 cmd/climc/shell/serverisolatedevices.go create mode 100644 cmd/climc/shell/servernetworks.go create mode 100644 cmd/climc/shell/servers.go create mode 100644 cmd/climc/shell/service_hosts.go create mode 100644 cmd/climc/shell/service_name_suggestions.go create mode 100644 cmd/climc/shell/services.go create mode 100644 cmd/climc/shell/servicetrees.go create mode 100644 cmd/climc/shell/shell.go create mode 100644 cmd/climc/shell/sms_configs.go create mode 100644 cmd/climc/shell/specs.go create mode 100644 cmd/climc/shell/storagecachedimages.go create mode 100644 cmd/climc/shell/storagecaches.go create mode 100644 cmd/climc/shell/storages.go create mode 100644 cmd/climc/shell/tasks.go create mode 100644 cmd/climc/shell/tenants.go create mode 100644 cmd/climc/shell/treenodes.go create mode 100644 cmd/climc/shell/usages.go create mode 100644 cmd/climc/shell/users.go create mode 100644 cmd/climc/shell/utils.go create mode 100644 cmd/climc/shell/vcenters.go create mode 100644 cmd/climc/shell/verification.go create mode 100644 cmd/climc/shell/version.go create mode 100644 cmd/climc/shell/vncproxy.go create mode 100644 cmd/climc/shell/vpcs.go create mode 100644 cmd/climc/shell/wires.go create mode 100644 cmd/climc/shell/zones.go diff --git a/.gitignore b/.gitignore index f1c181ec9c..4a0d0899c7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,12 +1,35 @@ -# Binaries for programs and plugins -*.exe -*.exe~ -*.dll +# ---> Go +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a *.so -*.dylib +*.swp -# Test binary, build with `go test -c` +# Folders +_obj +_test + +.VERSION +.DS_Store +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe *.test - -# Output of the go coverage tool, specifically when used with LiteIDE -*.out +*.prof +_output +/relay +/structargtest +.idea +GPATH +GRTAGS +GTAGS diff --git a/LICENSE b/LICENSE index 261eeb9e9f..adcdafcd4e 100644 --- a/LICENSE +++ b/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright [yyyy] [name of copyright owner] + Copyright [2018] [Yunion Technology] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000000..0d39ba1762 --- /dev/null +++ b/Makefile @@ -0,0 +1,98 @@ +##################################################### + +VERSION_PKG := github.com/yunionio/pkg/util/version +REPO_PREFIX := github.com/yunionio/onecloud +ROOT_DIR := $(shell pwd) +BUILD_DIR := $(ROOT_DIR)/_output +BIN_DIR := $(BUILD_DIR)/bin +BUILD_SCRIPT := $(ROOT_DIR)/build/build.sh + +GIT_COMMIT := $(shell git rev-parse --short HEAD) +GIT_BRANCH := $(shell git rev-parse --abbrev-ref HEAD) +GIT_VERSION := $(shell git describe --tags --abbrev=14 $(GIT_COMMIT)^{commit}) +GIT_TREE_STATE := $(shell s=`git status --porcelain 2>/dev/null`; if [ -z "$$s" ]; then echo "clean"; else echo "dirty"; fi) +BUILD_DATE := $(shell date -u +'%Y-%m-%dT%H:%M:%SZ') + +LDFLAGS := "-w \ + -X $(VERSION_PKG).gitVersion=$(GIT_VERSION) \ + -X $(VERSION_PKG).gitCommit=$(GIT_COMMIT) \ + -X $(VERSION_PKG).gitBranch=$(GIT_BRANCH) \ + -X $(VERSION_PKG).buildDate=$(BUILD_DATE) \ + -X $(VERSION_PKG).gitTreeState=$(GIT_TREE_STATE) \ + -X $(VERSION_PKG).gitMajor=0 \ + -X $(VERSION_PKG).gitMinor=0" + + +##################################################### + +GO_BUILD := go build -ldflags $(LDFLAGS) +GO_INSTALL := go install -ldflags $(LDFLAGS) +GO_TEST := go test + +PKGS := go list ./... +CMDS := $(shell find ./cmd -mindepth 1 -maxdepth 1 -type d) + + +all: build + + +install: prepare_dir + @for PKG in $$( $(PKGS) | grep -w "$(filter-out $@,$(MAKECMDGOALS))" ); do \ + echo $$PKG; \ + $(GO_INSTALL) $$PKG; \ + done + + +build: prepare_dir + @for PKG in $(CMDS); do \ + echo build $$PKG; \ + $(GO_BUILD) -o $(BIN_DIR)/`basename $${PKG}` $$PKG; \ + done + + +test: prepare_dir + @for PKG in $$( $(PKGS) | grep "$(filter-out $@,$(MAKECMDGOALS))" ); do \ + echo $$PKG; \ + $(GO_TEST) $$PKG; \ + done + + +cmd/%: prepare_dir + $(GO_BUILD) -o $(BIN_DIR)/$(shell basename $@) $(REPO_PREFIX)/$@ + + +pkg/%: prepare_dir + $(GO_INSTALL) $(REPO_PREFIX)/$@ + + +rpm: + make cmd/$(filter-out $@,$(MAKECMDGOALS)) + $(BUILD_SCRIPT) $(filter-out $@,$(MAKECMDGOALS)) + +rpmclean: + rm -fr $(BUILD_DIR)/rpms + +prepare_dir: bin_dir + + +bin_dir: output_dir + @mkdir -p $(BUILD_DIR)/bin + + +output_dir: + @mkdir -p $(BUILD_DIR) + + +.PHONY: all build prepare_dir clean fmt rpm + + +clean: + @rm -fr $(BUILD_DIR) + + +fmt: + find . -type f -name "*.go" -not -path "./_output/*" \ + -not -path "./vendor/*" | xargs gofmt -s -w + +%: + @: diff --git a/README.md b/README.md new file mode 100644 index 0000000000..5b0563ee70 --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +# Yunion onecloud diff --git a/build/build.sh b/build/build.sh new file mode 100755 index 0000000000..9444566268 --- /dev/null +++ b/build/build.sh @@ -0,0 +1,124 @@ +#!/bin/sh + +set -e + +pushd $(dirname $(readlink -f "$BASH_SOURCE")) > /dev/null +ROOT_DIR=$(cd .. && pwd) +popd > /dev/null + +SRC_BIN=$ROOT_DIR/_output/bin +SRC_BUILD=$ROOT_DIR/build +OUTPUT_DIR=$ROOT_DIR/_output/rpms + +PKG=$1 + +if [ -z "$PKG" ]; then + echo "Usage: $0 " + exit 1 +fi + +BIN="$SRC_BIN/$PKG" +ROOT="$SRC_BUILD/$PKG" + +if [ ! -x "$BIN" ]; then + echo "$BIN not exists" + exit 1 +fi + +if [ ! -x "$ROOT" ]; then + echo "$ROOT not exists" + exit 1 +fi + +. $ROOT/vars + +BUILDROOT=$(mktemp -d 2>/dev/null || mktemp -d -t 'yunion') + +echo "Build root ${BUILDROOT}" + +# BRANCH=$(git rev-parse --abbrev-ref HEAD) +# TAG=$(git describe --exact-match --tags) +TAG=$(git describe --abbrev=0 --tags) +VERSION=${TAG/\//-} +VERSION=${VERSION/v/} +RELEASE=`date +"%y%m%d%H"` + +SPEC_DIR=$BUILDROOT/SPECS +SPEC_FILE=$SPEC_DIR/${PKG}.spec +RPM_DIR=$BUILDROOT/RPMS + +if [ -z "$SERVICE" ]; then + SERVICE="0" +fi + +mkdir -p $SPEC_DIR + +echo "# Yunion RPM spec + +%global owner yunion +%global pkgname yunion-$PKG +%global homedir /var/run/%{owner} +%global use_systemd $SERVICE + +Name: %{pkgname} +Version: $VERSION +Release: $RELEASE +Summary: %{pkgname} + +Group: Unspecified +License: GPL +URL: https://www.yunion.io/doc +%if %{use_systemd} +Requires: systemd +BuildRequires: systemd +%endif + +%description +$DESCRIPTION + +%prep + +%build + +%install +install -D -m 0755 $BIN \$RPM_BUILD_ROOT/opt/yunion/bin/$PKG +if [ -d $ROOT/root ]; then + rsync -a $ROOT/root/ \$RPM_BUILD_ROOT +fi + +%pre +%if %{use_systemd} +getent group %{owner} >/dev/null || /usr/sbin/groupadd -r %{owner} +getent passwd %{owner} >/dev/null || /usr/sbin/useradd -r -s /sbin/nologin -d %{homedir} -M -g %{owner} %{owner} +%endif + +%post +%if %{use_systemd} + mkdir -p /var/run/%{owner} + chown -R %{owner}:%{owner} /var/run/%{owner} + /usr/bin/systemctl preset %{pkgname}.service >/dev/null 2>&1 ||: +%endif + +%preun +%if %{use_systemd} + /usr/bin/systemctl --no-reload disable %{pkgname}.service >/dev/null 2>&1 || : + /usr/bin/systemctl stop %{pkgname}.service >/dev/null 2>&1 ||: +%endif + +%postun +%if %{use_systemd} + /usr/bin/systemctl daemon-reload >/dev/null 2>&1 ||: +%endif + +%files +%doc +/opt/yunion/bin/$PKG" > $SPEC_FILE + +find $ROOT/root/ -type f | sed -e "s:$ROOT/root::g" >> $SPEC_FILE + +rpmbuild --define "_topdir $BUILDROOT" -bb $SPEC_FILE + +mkdir -p $OUTPUT_DIR +cp -fr $RPM_DIR/* $OUTPUT_DIR/ + +rm -fr $BUILDROOT diff --git a/build/climc/vars b/build/climc/vars new file mode 100644 index 0000000000..e9c31d3014 --- /dev/null +++ b/build/climc/vars @@ -0,0 +1 @@ +DESCRIPTION="Yunion Command Line Utility" diff --git a/cmd/climc/README.md b/cmd/climc/README.md new file mode 100644 index 0000000000..033300914d --- /dev/null +++ b/cmd/climc/README.md @@ -0,0 +1,3 @@ +Yunion Cloud API go client +================================= + diff --git a/cmd/climc/climc.go b/cmd/climc/climc.go new file mode 100644 index 0000000000..c67c4832c5 --- /dev/null +++ b/cmd/climc/climc.go @@ -0,0 +1,188 @@ +package main + +import ( + "fmt" + "os" + "strings" + + "github.com/c-bata/go-prompt" + "github.com/yunionio/log" + "github.com/yunionio/mcclient" + "github.com/yunionio/pkg/util/version" + "github.com/yunionio/structarg" + + "github.com/yunionio/onecloud/cmd/climc/promputils" + "github.com/yunionio/onecloud/cmd/climc/shell" +) + +type BaseOptions struct { + Help bool `help:"Show help" short-token:"h"` + Debug bool `help:"Show debug information"` + Version bool `help:"Show version"` + Timeout int `default:"600" help:"Number of seconds to wait for a response"` + Secure bool `default:"False" help:"do server cert verification if URL is https"` + OsUsername string `default:"$OS_USERNAME" help:"Username, defaults to env[OS_USERNAME]"` + OsPassword string `default:"$OS_PASSWORD" help:"Password, defaults to env[OS_PASSWORD]"` + // OsProjectId string `default:"$OS_PROJECT_ID" help:"Proejct ID, defaults to env[OS_PROJECT_ID]"` + OsProjectName string `default:"$OS_PROJECT_NAME" help:"Project name, defaults to env[OS_PROJECT_NAME]"` + OsDomainName string `default:"$OS_DOMAIN_NAME" help:"Domain name, defaults to env[OS_DOMAIN_NAME]"` + OsAuthURL string `default:"$OS_AUTH_URL" help:"Defaults to env[OS_AUTH_URL]"` + OsRegionName string `default:"$OS_REGION_NAME" help:"Defaults to env[OS_REGION_NAME]"` + OsZoneName string `default:"$OS_ZONE_NAME" help:"Defaults to env[OS_ZONE_NAME]"` + OsEndpointType string `default:"$OS_ENDPOINT_TYPE|internalURL" help:"Defaults to env[OS_ENDPOINT_TYPE] or internalURL" choices:"publicURL|internalURL|adminURL"` + ApiVersion string `default:"$API_VERSION|v1" help:"apiVersion, default to v1"` + SUBCOMMAND string `help:"climc subcommand" subcommand:"true"` +} + +func getSubcommandsParser() (*structarg.ArgumentParser, error) { + parse, e := structarg.NewArgumentParser(&BaseOptions{}, + "climc", + `Command-line interface to the API server.`, + `See "climc help COMMAND" for help on a specific command.`) + if e != nil { + return nil, e + } + subcmd := parse.GetSubcommand() + if subcmd == nil { + return nil, fmt.Errorf("No subcommand argument") + } + type HelpOptions struct { + SUBCOMMAND string `help:"Sub-command name"` + } + shell.R(&HelpOptions{}, "help", "Show help information of any subcommand", func(suboptions *HelpOptions) error { + helpstr, e := subcmd.SubHelpString(suboptions.SUBCOMMAND) + if e != nil { + return e + } else { + fmt.Print(helpstr) + return nil + } + }) + for _, v := range shell.CommandTable { + _par, e := subcmd.AddSubParser(v.Options, v.Command, v.Desc, v.Callback) + + if e != nil { + return nil, e + } + promputils.AppendCommand(v.Command, v.Desc) + cmd := v.Command + + for _, v := range _par.GetOptArgs() { + _name := strings.Replace(v.String(), "]", "", -1) + _name = strings.Replace(_name, "[", "", -1) + promputils.AppendOpt(cmd, _name, v.HelpString("")) + + } + for _, v := range _par.GetPosArgs() { + _name := strings.Replace(v.String(), "<", "", -1) + _name = strings.Replace(_name, ">", "", -1) + promputils.AppendPos(cmd, _name, v.HelpString("")) + } + } + return parse, nil +} + +func showErrorAndExit(e error) { + fmt.Printf("Error: %s\n", e) + os.Exit(1) +} + +func newClientSession(options *BaseOptions) (*mcclient.ClientSession, error) { + if len(options.OsAuthURL) == 0 { + return nil, fmt.Errorf("Missing OS_AUTH_URL") + } + if len(options.OsUsername) == 0 { + return nil, fmt.Errorf("Missing OS_USERNAME") + } + if len(options.OsPassword) == 0 { + return nil, fmt.Errorf("Missing OS_PASSWORD") + } + if len(options.OsRegionName) == 0 { + return nil, fmt.Errorf("Missing OS_REGION_NAME") + } + // if len(options.OsProjectId) == 0 && len(options.OsProjectName) == 0 { + // showErrorAndExit(fmt.Errorf("Missing OS_PROEJCT_ID or OS_PROJECT_NAME")) + if len(options.OsProjectName) == 0 { + return nil, fmt.Errorf("Missing OS_PROJECT_NAME") + } + + logLevel := "info" + if options.Debug { + logLevel = "debug" + } + log.SetLogLevelByString(log.Logger(), logLevel) + + client := mcclient.NewClient(options.OsAuthURL, + options.Timeout, + options.Debug, + options.Secure) + token, err := client.Authenticate(options.OsUsername, + options.OsPassword, + options.OsDomainName, + options.OsProjectName) + if err != nil { + return nil, err + } + + session := client.NewSession(options.OsRegionName, + options.OsZoneName, + options.OsEndpointType, + token, + options.ApiVersion) + return session, nil +} + +func main() { + parser, e := getSubcommandsParser() + if e != nil { + showErrorAndExit(e) + } + e = parser.ParseArgs(os.Args[1:], false) + options := parser.Options().(*BaseOptions) + + if options.Help { + fmt.Print(parser.HelpString()) + } else if options.Version { + fmt.Printf("Yunion API client version:\n %s\n", version.GetJsonString()) + } else if len(os.Args) <= 1 { + session, e := newClientSession(options) + if e != nil { + showErrorAndExit(e) + } + promputils.InitEnv(parser, session) + defer fmt.Println("Bye!") + p := prompt.New( + promputils.Executor, + promputils.Completer, + prompt.OptionPrefix("climc> "), + prompt.OptionTitle("Climc, a Command Line Interface to Manage Clouds"), + prompt.OptionMaxSuggestion(16), + ) + p.Run() + } else { + subcmd := parser.GetSubcommand() + subparser := subcmd.GetSubParser() + if e != nil { + if subparser != nil { + fmt.Print(subparser.Usage()) + } else { + fmt.Print(parser.Usage()) + } + showErrorAndExit(e) + } else { + session, e := newClientSession(options) + if e != nil { + showErrorAndExit(e) + } + suboptions := subparser.Options() + if options.SUBCOMMAND == "help" { + e = subcmd.Invoke(suboptions) + } else { + e = subcmd.Invoke(session, suboptions) + } + if e != nil { + showErrorAndExit(e) + } + } + } +} diff --git a/cmd/climc/promputils/completor.go b/cmd/climc/promputils/completor.go new file mode 100644 index 0000000000..57914edcc1 --- /dev/null +++ b/cmd/climc/promputils/completor.go @@ -0,0 +1,121 @@ +package promputils + +import ( + "regexp" + "strings" + + "github.com/c-bata/go-prompt" +) + +type Cmd struct { + desc string + optArgs []prompt.Suggest + posArgs []prompt.Suggest +} + +var cmds = make(map[string]*Cmd) + +var optionHelp = []prompt.Suggest{ + {Text: "-h"}, + {Text: "--help"}, +} + +func optionCompleter(args []string, long bool) []prompt.Suggest { + l := len(args) + if l == 0 { + return []prompt.Suggest{} + } + if l <= 1 { + if long { + return prompt.FilterHasPrefix(optionHelp, "--", false) + } + return optionHelp + } + + if cmds[args[0]] == nil { + return []prompt.Suggest{} + } + + _cmd := cmds[args[0]].optArgs + return prompt.FilterContains(_cmd, strings.TrimLeft(args[l-1], "-"), true) +} + +func Completer(d prompt.Document) []prompt.Suggest { + if d.TextBeforeCursor() == "" { + return []prompt.Suggest{} + } + var re = regexp.MustCompile(`(?m)^(?:-d|--debug)\s+`) + s := re.ReplaceAllString(d.TextBeforeCursor(), "") + s = strings.TrimSpace(s) + args := strings.Split(s, " ") + w := d.GetWordBeforeCursor() + + // If PIPE is in text before the cursor, returns empty suggestions. + for i := range args { + if args[i] == "|" { + return []prompt.Suggest{} + } + } + + // If word before the cursor starts with "-", returns CLI flag options. + if strings.HasPrefix(w, "-") { + return optionCompleter(args, strings.HasPrefix(w, "--")) + } + + // Return suggestions for option + if suggests, found := completeOptionArguments(d); found { + return suggests + } + + return argumentsCompleter(excludeOptions(args)) +} + +var commands = []prompt.Suggest{ + + // Custom command. + {Text: "exit", Description: "Exit this program"}, + {Text: "quit", Description: "Exit this program"}, +} + +func argumentsCompleter(args []string) []prompt.Suggest { + if len(args) == 0 { + return []prompt.Suggest{} + } + + if len(args) == 1 { + return prompt.FilterHasPrefix(commands, args[0], true) + } + _cmd, ok := cmds[args[0]] + if !ok { + return []prompt.Suggest{} + } + + if len(args)-1 > len(_cmd.posArgs) { + return []prompt.Suggest{} + } + + prm := _cmd.posArgs[len(args)-2] + subcommands := []prompt.Suggest{ + prm, + } + + return prompt.FilterHasPrefix(subcommands, args[len(args)-1], true) +} + +func AppendCommand(text, desc string) { + commands = append(commands, prompt.Suggest{Text: text, Description: desc}) + cmds[text] = &Cmd{} + cmds[text].desc = desc + cmds[text].posArgs = []prompt.Suggest{} + cmds[text].optArgs = []prompt.Suggest{} +} + +func AppendPos(text, cmd, desc string) { + var v = []prompt.Suggest{{Text: cmd, Description: desc}} + cmds[text].posArgs = append(cmds[text].posArgs, v...) +} + +func AppendOpt(text, cmd, desc string) { + var v = []prompt.Suggest{{Text: cmd, Description: desc}} + cmds[text].optArgs = append(cmds[text].optArgs, v...) +} diff --git a/cmd/climc/promputils/executor.go b/cmd/climc/promputils/executor.go new file mode 100644 index 0000000000..b5bd4706be --- /dev/null +++ b/cmd/climc/promputils/executor.go @@ -0,0 +1,93 @@ +package promputils + +import ( + "bytes" + "errors" + "fmt" + "os" + "os/exec" + "regexp" + "strings" + + "github.com/yunionio/mcclient" + "github.com/yunionio/structarg" +) + +var ( + parser *structarg.ArgumentParser + session *mcclient.ClientSession +) + +func InitEnv(_parser *structarg.ArgumentParser, _session *mcclient.ClientSession) { + parser = _parser + session = _session +} + +func escaper(str string) string { + var re = regexp.MustCompile(`(?i)--filter\s+[a-z0-9]+[^\s]+( |$)`) + for _, match := range re.FindAllString(str, -1) { + rep := strings.Replace(match, "--filter", "", -1) + rep = strings.TrimSpace(rep) + rep = strings.Replace(rep, `\'`, "efWpvXpY6lH5", -1) + rep = strings.Replace(rep, "'", "", -1) + rep = strings.Replace(rep, `\"`, "GsVHUhkj68Be", -1) + rep = strings.Replace(rep, `"`, "", -1) + rep = strings.Replace(rep, `GsVHUhkj68Be`, `\"`, -1) + rep = strings.Replace(rep, `efWpvXpY6lH5`, `\'`, -1) + rep = `--filter ` + rep + str = strings.Replace(str, match, rep, -1) + } + return str +} + +func Executor(s string) { + s = strings.TrimSpace(s) + if s == "" { + return + } else if s == "quit" || s == "exit" || s == "x" || s == "q" { + fmt.Println("Bye!") + os.Exit(0) + return + } + s = escaper(s) + args := strings.Split(s, " ") + e := parser.ParseArgs(strings.Split(s, " "), false) + subcmd := parser.GetSubcommand() + subparser := subcmd.GetSubParser() + if e != nil { + if subparser != nil { + fmt.Print(subparser.Usage()) + } else { + fmt.Print(parser.Usage()) + } + fmt.Println(e) + } else { + suboptions := subparser.Options() + if args[0] == "help" { + e = subcmd.Invoke(suboptions) + } else { + e = subcmd.Invoke(session, suboptions) + } + if e != nil { + fmt.Println(e) + } + } + return +} + +func ExecuteAndGetResult(s string) (string, error) { + s = strings.TrimSpace(s) + if s == "" { + return "", errors.New("you need to pass the something arguments") + } + + out := &bytes.Buffer{} + cmd := exec.Command("/bin/sh", "-c", "source ~/.RC_ADMIN &&/home/yunion/git/yunioncloud/_output/bin/climc "+s) + cmd.Stdin = os.Stdin + cmd.Stdout = out + if err := cmd.Run(); err != nil { + return "", err + } + r := string(out.Bytes()) + return r, nil +} diff --git a/cmd/climc/promputils/filter.go b/cmd/climc/promputils/filter.go new file mode 100644 index 0000000000..fd66fce37b --- /dev/null +++ b/cmd/climc/promputils/filter.go @@ -0,0 +1,15 @@ +package promputils + +import ( + "strings" +) + +func excludeOptions(args []string) []string { + ret := make([]string, 0, len(args)) + for i := range args { + if !strings.HasPrefix(args[i], "-") { + ret = append(ret, args[i]) + } + } + return ret +} diff --git a/cmd/climc/promputils/option_arguments.go b/cmd/climc/promputils/option_arguments.go new file mode 100644 index 0000000000..1d9e14072c --- /dev/null +++ b/cmd/climc/promputils/option_arguments.go @@ -0,0 +1,74 @@ +package promputils + +import ( + "io/ioutil" + "log" + "path/filepath" + "strings" + + "github.com/c-bata/go-prompt" +) + +func init() { + fileListCache = map[string][]prompt.Suggest{} +} + +func getPreviousOption(d prompt.Document) (cmd, option string, found bool) { + args := strings.Split(d.TextBeforeCursor(), " ") + l := len(args) + if l >= 2 { + option = args[l-2] + } + if strings.HasPrefix(option, "-") { + return args[0], option, true + } + return "", "", false +} + +func completeOptionArguments(d prompt.Document) ([]prompt.Suggest, bool) { + cmd, option, found := getPreviousOption(d) + if !found { + return []prompt.Suggest{}, false + } + switch cmd { + case "server-attach-disk", "describe", "create", "delete", "replace", "patch", + "edit", "apply", "expose", "rolling-update", "rollout", + "label", "annotate", "scale", "convert", "autoscale": + switch option { + case "-f", "--filename": + return fileCompleter(d), true + } + } + return []prompt.Suggest{}, false +} + +/* file list */ + +var fileListCache map[string][]prompt.Suggest + +func fileCompleter(d prompt.Document) []prompt.Suggest { + path := d.GetWordBeforeCursor() + if strings.HasPrefix(path, "./") { + path = path[2:] + } + dir := filepath.Dir(path) + if cached, ok := fileListCache[dir]; ok { + return cached + } + + files, err := ioutil.ReadDir(dir) + if err != nil { + log.Print("[ERROR] catch error " + err.Error()) + return []prompt.Suggest{} + } + suggests := make([]prompt.Suggest, 0, len(files)) + for _, f := range files { + if !f.IsDir() && + !strings.HasSuffix(f.Name(), ".yml") && + !strings.HasSuffix(f.Name(), ".yaml") { + continue + } + suggests = append(suggests, prompt.Suggest{Text: filepath.Join(dir, f.Name())}) + } + return prompt.FilterHasPrefix(suggests, path, false) +} diff --git a/cmd/climc/shell/actions.go b/cmd/climc/shell/actions.go new file mode 100644 index 0000000000..f4f07131de --- /dev/null +++ b/cmd/climc/shell/actions.go @@ -0,0 +1,87 @@ +package shell + +import ( + "github.com/yunionio/jsonutils" + "github.com/yunionio/mcclient" + "github.com/yunionio/mcclient/modules" +) + +type BaseActionListOptions struct { + Since string `help:"Show logs since specific date" metavar:"DATETIME"` + Until string `help:"Show logs until specific date" metavar:"DATETIME"` + Limit int64 `help:"Limit number of logs" default:"20"` + Offset int64 `help:"Offset"` + Ascending bool `help:"Ascending order"` + Descending bool `help:"Descending order"` + Action []string `help:"Log action"` + Search string `help:"Filter action logs by obj_name, using 'like' syntax."` +} + +type ActionListOptions struct { + BaseActionListOptions + Id string `help:"" metavar:"OBJ_ID"` + Type []string `help:"Type of relevant object" metavar:"OBJ_TYPE"` +} + +type TypeActionListOptions struct { + BaseActionListOptions + ID string `help:"" metavar:"OBJ_ID"` +} + +func doActionList(s *mcclient.ClientSession, args *ActionListOptions) error { + params := jsonutils.NewDict() + if len(args.Type) > 0 { + params.Add(jsonutils.NewStringArray(args.Type), "obj_type") + } + if len(args.Id) > 0 { + params.Add(jsonutils.NewString(args.Id), "obj_id") + } + if len(args.Search) > 0 { + params.Add(jsonutils.NewString(args.Search), "search") + } + if len(args.Since) > 0 { + params.Add(jsonutils.NewString(args.Since), "since") + } + if len(args.Until) > 0 { + params.Add(jsonutils.NewString(args.Until), "until") + } + if args.Limit > 0 { + params.Add(jsonutils.NewInt(args.Limit), "limit") + } + if args.Offset > 0 { + params.Add(jsonutils.NewInt(args.Offset), "offset") + } + if args.Ascending && !args.Descending { + params.Add(jsonutils.NewString("asc"), "order") + } else if !args.Ascending && args.Descending { + params.Add(jsonutils.NewString("desc"), "order") + } + if len(args.Action) > 0 { + params.Add(jsonutils.NewStringArray(args.Action), "action") + } + logs, err := modules.Actions.List(s, params) + if err != nil { + return err + } + printList(logs, modules.Actions.GetColumns(s)) + return nil +} + +func init() { + R(&ActionListOptions{}, "action-show", "Show operation action logs", doActionList) + + R(&TypeActionListOptions{}, "server-action", "Show operation action logs of server", func(s *mcclient.ClientSession, args *TypeActionListOptions) error { + nargs := ActionListOptions{BaseActionListOptions: args.BaseActionListOptions, Id: args.ID, Type: []string{"server"}} + return doActionList(s, &nargs) + }) + + R(&TypeActionListOptions{}, "host-action", "Show operation action logs of host", func(s *mcclient.ClientSession, args *TypeActionListOptions) error { + nargs := ActionListOptions{BaseActionListOptions: args.BaseActionListOptions, Id: args.ID, Type: []string{"host"}} + return doActionList(s, &nargs) + }) + + R(&TypeActionListOptions{}, "vcenter-action", "Show operation action logs of vcenter", func(s *mcclient.ClientSession, args *TypeActionListOptions) error { + nargs := ActionListOptions{BaseActionListOptions: args.BaseActionListOptions, Id: args.ID, Type: []string{"vcenter"}} + return doActionList(s, &nargs) + }) +} diff --git a/cmd/climc/shell/alarmevents.go b/cmd/climc/shell/alarmevents.go new file mode 100644 index 0000000000..595343fce3 --- /dev/null +++ b/cmd/climc/shell/alarmevents.go @@ -0,0 +1,85 @@ +package shell + +import ( + "github.com/yunionio/jsonutils" + "github.com/yunionio/mcclient" + "github.com/yunionio/mcclient/modules" +) + +func init() { + /** + * 列出报警事件 + */ + type AlarmEventListOptions struct { + BaseListOptions + NodeLabels string `help:"Service tree node labels"` + MetricName string `help:"Metric name"` + HostName string `help:"Host name"` + HostIp string `help:"Host IP address"` + AlarmLevel string `help:"Alarm level"` + AlarmCondition string `help:"Concrete alarm rule"` + Template string `help:"Template number of the alarm condition"` + AckStatus string `help:"Alarm event ack status"` + } + R(&AlarmEventListOptions{}, "alarmevent-list", "List all alarm's event", func(s *mcclient.ClientSession, args *AlarmEventListOptions) error { + params := FetchPagingParams(args.BaseListOptions) + + if len(args.NodeLabels) > 0 { + params.Add(jsonutils.NewString(args.NodeLabels), "node_labels") + } + if len(args.MetricName) > 0 { + params.Add(jsonutils.NewString(args.MetricName), "metric_name") + } + if len(args.HostName) > 0 { + params.Add(jsonutils.NewString(args.HostName), "host_name") + } + if len(args.HostIp) > 0 { + params.Add(jsonutils.NewString(args.HostIp), "host_ip") + } + if len(args.AlarmLevel) > 0 { + params.Add(jsonutils.NewString(args.AlarmLevel), "alarm_level") + } + if len(args.AlarmCondition) > 0 { + params.Add(jsonutils.NewString(args.AlarmCondition), "alarm_condition") + } + if len(args.Template) > 0 { + params.Add(jsonutils.NewString(args.Template), "template") + } + if len(args.AckStatus) > 0 { + params.Add(jsonutils.NewString(args.AckStatus), "ack_status") + } + + result, err := modules.AlarmEvents.List(s, params) + if err != nil { + return err + } + printList(result, modules.AlarmEvents.GetColumns(s)) + return nil + }) + + /* + * 修改报警事件ACK确认状态 + */ + type AlarmEventUpdateOptions struct { + ID string `help:"ID of the alarm event"` + STATUS int64 `help:"Alarm event ack status" choices:"0|1"` + } + R(&AlarmEventUpdateOptions{}, "alarmevent-ack-update", "Update ack status of alarm event", func(s *mcclient.ClientSession, args *AlarmEventUpdateOptions) error { + arr := jsonutils.NewArray() + tmpObj := jsonutils.NewDict() + tmpObj.Add(jsonutils.NewString(args.ID), "id") + tmpObj.Add(jsonutils.NewInt(args.STATUS), "ack_status") + arr.Add(tmpObj) + + params := jsonutils.NewDict() + params.Add(arr, "alarm_events") + + alarmevent, err := modules.AlarmEvents.DoBatchUpdate(s, params) + if err != nil { + return err + } + printObject(alarmevent) + return nil + }) + +} diff --git a/cmd/climc/shell/alarmlogs.go b/cmd/climc/shell/alarmlogs.go new file mode 100644 index 0000000000..23dedae443 --- /dev/null +++ b/cmd/climc/shell/alarmlogs.go @@ -0,0 +1,77 @@ +package shell + +import ( + "fmt" + "strings" + + "github.com/yunionio/jsonutils" + "github.com/yunionio/mcclient" + "github.com/yunionio/mcclient/modules" +) + +func init() { + + /** + * 列出报警日志 + */ + type AlarmLogListOptions struct { + BaseListOptions + Host string `help:"Name of the host"` + Id int64 `help:"ID of tree node"` + Label []string `help:"Labels to this tree node"` + Metric string `help:"Metric name"` + StartTimeSince string `help:"Start time since the alarm event"` + StartTimeUntil string `help:"Start time until the alarm event"` + ThisTimeSince string `help:"This time since the alarm event"` + ThisTimeUntil string `help:"This time until the alarm event"` + } + R(&AlarmLogListOptions{}, "alarmlog-list", "List all alarm's event", func(s *mcclient.ClientSession, args *AlarmLogListOptions) error { + params := FetchPagingParams(args.BaseListOptions) + if len(args.Host) > 0 { + params.Add(jsonutils.NewString(args.Host), "host") + } + if len(args.Label) > 0 { + names := []string{"corp", "owt", "pdl", "srv", "env"} + segs := make([]string, len(args.Label)) + + for i := 0; i < len(args.Label); i += 1 { + sublabel := args.Label[:i+1] + pid, _ := modules.TreeNodes.GetNodeIDByLabels(s, sublabel) + + if pid < 0 { + fmt.Errorf("Invalid node data") + return nil + } + + segs[i] = fmt.Sprintf("%s=%d", names[i], pid) + } + + node_labels := strings.Join(segs, ",") + + params.Add(jsonutils.NewString(node_labels), "node_labels") + } + if len(args.Metric) > 0 { + params.Add(jsonutils.NewString(args.Metric), "metric") + } + if len(args.StartTimeSince) > 0 { + params.Add(jsonutils.NewString(args.StartTimeSince), "start_time_since") + } + if len(args.StartTimeUntil) > 0 { + params.Add(jsonutils.NewString(args.StartTimeUntil), "start_time_until") + } + if len(args.ThisTimeSince) > 0 { + params.Add(jsonutils.NewString(args.ThisTimeSince), "this_time_since") + } + if len(args.ThisTimeUntil) > 0 { + params.Add(jsonutils.NewString(args.ThisTimeUntil), "this_time_until") + } + + result, err := modules.AlarmLogs.List(s, params) + if err != nil { + return err + } + printList(result, modules.AlarmLogs.GetColumns(s)) + return nil + }) + +} diff --git a/cmd/climc/shell/alarms.go b/cmd/climc/shell/alarms.go new file mode 100644 index 0000000000..3b946bfc15 --- /dev/null +++ b/cmd/climc/shell/alarms.go @@ -0,0 +1,144 @@ +package shell + +import ( + "github.com/yunionio/jsonutils" + "github.com/yunionio/mcclient" + "github.com/yunionio/mcclient/modules" +) + +func init() { + + /** + * 创建报警规则 + */ + type AlarmDetailOptions struct { + METRICNAME string `help:"Metric name of the alarm"` + ALARMCONDITION string `help:"Alarm condition template of the alarm"` + TEMPLATE string `help:"Alarm condition template of the alarm"` + ALARMLEVEL string `help:"Alarm level of the alarm"` + CONTACT_TYPE string `help:"Alarm contact type"` + EXPIRESECONDS int64 `help:"Expire seconds of the alarm"` + ESCALATESECONDS int64 `help:"Escalate seconds of the alarm"` + ALARMTEMPLATE_ID string `help:"ID of the alarm template"` + Remark string `help:"Remark or description of the new alarm"` + } + R(&AlarmDetailOptions{}, "alarm-create", "Create a alarm", func(s *mcclient.ClientSession, args *AlarmDetailOptions) error { + params := jsonutils.NewDict() + params.Add(jsonutils.NewString(args.METRICNAME), "metric_name") + params.Add(jsonutils.NewString(args.ALARMCONDITION), "alarm_condition") + params.Add(jsonutils.NewString(args.TEMPLATE), "template") + params.Add(jsonutils.NewString(args.ALARMLEVEL), "alarm_level") + params.Add(jsonutils.NewString(args.CONTACT_TYPE), "contact_type") + params.Add(jsonutils.NewInt(args.EXPIRESECONDS), "expire_seconds") + params.Add(jsonutils.NewInt(args.ESCALATESECONDS), "escalate_seconds") + params.Add(jsonutils.NewString(args.ALARMTEMPLATE_ID), "alarm_template_id") + if len(args.Remark) > 0 { + params.Add(jsonutils.NewString(args.Remark), "remark") + } + alarm, err := modules.Alarms.Create(s, params) + if err != nil { + return err + } + printObject(alarm) + return nil + }) + + /** + * 删除指定ID的报警规则 + */ + type AlarmDeleteOptions struct { + ID string `help:"ID of alarm"` + } + R(&AlarmDeleteOptions{}, "alarm-delete", "Delete a alarm", func(s *mcclient.ClientSession, args *AlarmDeleteOptions) error { + alarm, e := modules.Alarms.Delete(s, args.ID, nil) + if e != nil { + return e + } + printObject(alarm) + return nil + }) + + /** + * 修改指定ID的报警规则 + */ + type AlarmUpdateOptions struct { + ID string `help:"ID of the alarm"` + Name string `help:"Name of the new alarm"` + MetricName string `help:"Metric name of the alarm"` + AlarmCondition string `help:"Alarm condition template of the alarm"` + Template string `help:"Alarm condition template of the alarm"` + AlarmLevel string `help:"Alarm level of the alarm"` + ContactType string `help:"Alarm contact type"` + ExpireSeconds int64 `help:"Expire seconds of the alarm"` + EscalateSeconds int64 `help:"Escalate seconds of the alarm"` + Remark string `help:"Remark or description of the new alarm"` + } + R(&AlarmUpdateOptions{}, "alarm-update", "Update a alarm", func(s *mcclient.ClientSession, args *AlarmUpdateOptions) error { + params := jsonutils.NewDict() + if len(args.Name) > 0 { + params.Add(jsonutils.NewString(args.Name), "name") + } + if len(args.MetricName) > 0 { + params.Add(jsonutils.NewString(args.MetricName), "metric_name") + } + if len(args.AlarmCondition) > 0 { + params.Add(jsonutils.NewString(args.AlarmCondition), "alarm_condition") + } + if len(args.Template) > 0 { + params.Add(jsonutils.NewString(args.Template), "template") + } + if len(args.AlarmLevel) > 0 { + params.Add(jsonutils.NewString(args.AlarmLevel), "alarm_level") + } + if len(args.ContactType) > 0 { + params.Add(jsonutils.NewString(args.ContactType), "contact_type") + } + if args.ExpireSeconds > 0 { + params.Add(jsonutils.NewInt(args.ExpireSeconds), "expire_seconds") + } + if args.EscalateSeconds > 0 { + params.Add(jsonutils.NewInt(args.EscalateSeconds), "escalate_seconds") + } + if len(args.Remark) > 0 { + params.Add(jsonutils.NewString(args.Remark), "remark") + } + + alarm, err := modules.Labels.Patch(s, args.ID, params) + if err != nil { + return err + } + printObject(alarm) + return nil + }) + + /** + * 列出报警规则 + */ + type AlarmListOptions struct { + BaseListOptions + } + R(&AlarmListOptions{}, "alarm-list", "List all alarms", func(s *mcclient.ClientSession, args *AlarmListOptions) error { + params := FetchPagingParams(args.BaseListOptions) + result, err := modules.Alarms.List(s, params) + if err != nil { + return err + } + printList(result, modules.Alarms.GetColumns(s)) + return nil + }) + + /** + * 根据ID查询报警规则 + */ + type AlarmShowOptions struct { + ID string `help:"ID of the alarm to show"` + } + R(&AlarmShowOptions{}, "alarm-show", "Show alarm details", func(s *mcclient.ClientSession, args *AlarmShowOptions) error { + result, err := modules.Alarms.Get(s, args.ID, nil) + if err != nil { + return err + } + printObject(result) + return nil + }) +} diff --git a/cmd/climc/shell/alarmtemplates.go b/cmd/climc/shell/alarmtemplates.go new file mode 100644 index 0000000000..03511c6db9 --- /dev/null +++ b/cmd/climc/shell/alarmtemplates.go @@ -0,0 +1,345 @@ +package shell + +import ( + "strings" + + "github.com/yunionio/jsonutils" + "github.com/yunionio/mcclient" + "github.com/yunionio/mcclient/modules" +) + +func init() { + + /** + * 创建报警模板 + */ + type AlarmTemplateOptions struct { + NAME string `help:"Name of the new alarm-template"` + BELONGTO string `help:"Detect the service-tree-node' labels which alarm-template belong to"` + Description string `help:"Description of the alarm-template"` + } + R(&AlarmTemplateOptions{}, "alarmtemplate-create", "Create a alarm-template", func(s *mcclient.ClientSession, args *AlarmTemplateOptions) error { + params := jsonutils.NewDict() + params.Add(jsonutils.NewString(args.NAME), "alarm_template_name") + params.Add(jsonutils.NewString(args.BELONGTO), "belongto") + if len(args.Description) > 0 { + params.Add(jsonutils.NewString(args.Description), "alarm_template_desc") + } + alarmTemplate, err := modules.AlarmTemplates.Create(s, params) + if err != nil { + return err + } + printObject(alarmTemplate) + return nil + }) + + /** + * 删除指定ID的报警模板 + */ + type AlarmTemplateDeleteOptions struct { + ID string `help:"ID of alarm-template"` + } + R(&AlarmTemplateDeleteOptions{}, "alarmtemplate-delete", "Delete a alarm-template", func(s *mcclient.ClientSession, args *AlarmTemplateDeleteOptions) error { + alarmTemplate, e := modules.AlarmTemplates.Delete(s, args.ID, nil) + if e != nil { + return e + } + printObject(alarmTemplate) + return nil + }) + + /** + * 修改指定ID的报警模板 + */ + type AlarmTemplateUpdateOptions struct { + ID string `help:"ID of the alarm-template"` + Name string `help:"New name of the new alarm-template"` + Description string `help:"New description of the alarm-template"` + } + R(&AlarmTemplateUpdateOptions{}, "alarmtemplate-update", "Update a alarm-template", func(s *mcclient.ClientSession, args *AlarmTemplateUpdateOptions) error { + params := jsonutils.NewDict() + if len(args.Name) > 0 { + params.Add(jsonutils.NewString(args.Name), "alarm_template_name") + } + if len(args.Description) > 0 { + params.Add(jsonutils.NewString(args.Description), "alarm_template_desc") + } + + alarmTemplate, err := modules.AlarmTemplates.Put(s, args.ID, params) + if err != nil { + return err + } + printObject(alarmTemplate) + return nil + }) + + /** + * 列出报警模板 + */ + type AlarmTemplateListOptions struct { + BaseListOptions + LIST_TYPE string `help:"Type of list: avaliable|applied|created "` + LABELS string `help:"Labels for node(split by comma)"` + } + R(&AlarmTemplateListOptions{}, "alarmtemplate-list", "List all alarm templates ", func(s *mcclient.ClientSession, args *AlarmTemplateListOptions) error { + params := FetchPagingParams(args.BaseListOptions) + params.Add(jsonutils.NewString(args.LIST_TYPE), "type") + params.Add(jsonutils.NewString(args.LABELS), "node_labels") + + result, err := modules.AlarmTemplates.List(s, params) + if err != nil { + return err + } + + printList(result, modules.AlarmTemplates.GetColumns(s)) + return nil + }) + + /** + * 根据ID查询报警模板(查看报警模板详情) + */ + type AlarmTemplateShowOptions struct { + ID string `help:"ID of the alarm-template to show"` + } + R(&AlarmTemplateShowOptions{}, "alarmtemplate-show", "Show alarm template details", func(s *mcclient.ClientSession, args *AlarmTemplateShowOptions) error { + result, err := modules.AlarmTemplates.Get(s, args.ID, nil) + if err != nil { + return err + } + printObject(result) + return nil + }) + + /** + * 查看报警模板下的报警项 + */ + type AlarmTemplateBaseOptions struct { + ID string `help:"ID of the alarm template"` + } + R(&AlarmTemplateBaseOptions{}, "alarmtemplate-alarm-list", "List alarms of alarm template", func(s *mcclient.ClientSession, args *AlarmTemplateBaseOptions) error { + result, err := modules.AlarmTemplateAlarms.ListDescendent(s, args.ID, nil) + if err != nil { + return err + } + printList(result, modules.Alarms.GetColumns(s)) + return nil + }) + + /** + * 向指定的报警模板中添加报警项(添加报警项) + */ + type AlarmTemplateAlarmOptions struct { + ALARMTEMPLATE_ID string `help:"ID of alarm-template"` + ALARM_ID string `help:"ID of alarm"` + } + R(&AlarmTemplateAlarmOptions{}, "add-alarm-to-template", "Add alarm to alarm-template", func(s *mcclient.ClientSession, args *AlarmTemplateAlarmOptions) error { + _, err := modules.AlarmTemplateAlarms.Attach(s, args.ALARMTEMPLATE_ID, args.ALARM_ID, nil) + if err != nil { + return err + } + return nil + }) + + /** + * 从指定的报警模板中删除报警项(删除报警项) + */ + R(&AlarmTemplateAlarmOptions{}, "remove-alarm-from-template", "Remove alarm from alarm-template", func(s *mcclient.ClientSession, args *AlarmTemplateAlarmOptions) error { + _, err := modules.Alarms.DeleteInContext(s, args.ALARM_ID, nil, &modules.AlarmTemplates, args.ALARMTEMPLATE_ID) + if err != nil { + return err + } + return nil + }) + + /** + * 给服务树节点增加报警模板 + */ + type AlarmTemplateNodeAddOptions struct { + ID string `help:"ID of alarm-template"` + Labels []string `help:"Labels for node" nargs:"+"` + Receiver1 string `help:"Primary alarm receiver" nargs:"+"` + Receiver2 string `help:"Secondary alarm receiver"` + } + R(&AlarmTemplateNodeAddOptions{}, "bind-template-to-node", "Bind alarm-template to service-tree node", func(s *mcclient.ClientSession, args *AlarmTemplateNodeAddOptions) error { + labels := jsonutils.NewDict() + for _, f := range args.Labels { + parts := strings.Split(f, "=") + labels.Add(jsonutils.NewString(parts[1]), parts[0]) + } + + params := jsonutils.NewDict() + params.Add(labels, "labels") + params.Add(jsonutils.NewString(args.Receiver1), "tier1_receivers") + params.Add(jsonutils.NewString(args.Receiver2), "tier2_receivers") + + _, err := modules.AlarmTemplates.PerformAction(s, args.ID, "add-labels", params) + if err != nil { + return err + } + return nil + }) + + /** + * 将报警模板从服务数节点移除 + */ + type AlarmTemplateRemoveFromNodeOptions struct { + ID string `help:"ID of the alarm-template"` + Labels []string `help:"Node labels" nargs:"+"` + } + R(&AlarmTemplateRemoveFromNodeOptions{}, "unbind-template-from-node", "Unbind alarm-template from service-tree node", func(s *mcclient.ClientSession, args *AlarmTemplateRemoveFromNodeOptions) error { + labels := jsonutils.NewDict() + for _, f := range args.Labels { + parts := strings.Split(f, "=") + labels.Add(jsonutils.NewString(parts[1]), parts[0]) + } + + params := jsonutils.NewDict() + params.Add(labels, "labels") + + _, err := modules.AlarmTemplates.PerformAction(s, args.ID, "remove-labels", params) + if err != nil { + return err + } + return nil + }) + + /** + * 给服务树编辑模板详情 + */ + type AlarmTemplateNodeUpdateOptions struct { + ID string `help:"ID of alarm-template"` + Labels []string `help:"Labels for node" nargs:"+"` + Receiver1 string `help:"Primary alarm receiver"` + Receiver2 string `help:"Secondary alarm receiver"` + } + R(&AlarmTemplateNodeUpdateOptions{}, "update-template-for-node", "Update alarm-template for service-tree node", func(s *mcclient.ClientSession, args *AlarmTemplateNodeUpdateOptions) error { + labels := jsonutils.NewDict() + for _, f := range args.Labels { + parts := strings.Split(f, "=") + labels.Add(jsonutils.NewString(parts[1]), parts[0]) + } + + params := jsonutils.NewDict() + params.Add(labels, "labels") + params.Add(jsonutils.NewString(args.Receiver1), "tier1_receivers") + params.Add(jsonutils.NewString(args.Receiver2), "tier2_receivers") + + _, err := modules.AlarmTemplates.PerformAction(s, args.ID, "update-labels", params) + if err != nil { + return err + } + return nil + }) + + /** + * 查看此模板有哪些label正在使用 + */ + type AlarmTemplateLabelListOptions struct { + ID string `help:"ID of alarm-template"` + } + R(&AlarmTemplateLabelListOptions{}, "labels-for-alarmtemplate", "List all the labels for the alarm-templates", func(s *mcclient.ClientSession, args *AlarmTemplateLabelListOptions) error { + result, err := modules.AlarmTemplates.GetSpecific(s, args.ID, "labels", nil) + if err != nil { + return err + } + printObject(result) + return nil + }) + + /** + * 为树务树节点添加报警模板 + */ + type AlarmTemplateAddToNodeOptions struct { + ID string `help:"ID of alarm-template"` + LABELS string `help:"Labels for node"` + Status int64 `help:"Enabled or disabled binding status" choices:"1|0"` + } + R(&AlarmTemplateAddToNodeOptions{}, "add-alarmtemplate-to-treenode", "Bind alarm-template to service-tree node", func(s *mcclient.ClientSession, args *AlarmTemplateAddToNodeOptions) error { + params := jsonutils.NewDict() + params.Add(jsonutils.NewString(args.LABELS), "node_labels") + if args.Status > 0 { + params.Add(jsonutils.NewInt(args.Status), "enabled") + } + + _, err := modules.AlarmTemplates.PerformAction(s, args.ID, "add-to-treenode", params) + if err != nil { + return err + } + return nil + }) + + /** + * 从树务树节点删除报警模板 + */ + type AlarmTemplateDeleteFromNodeOptions struct { + ID string `help:"ID of alarm-template"` + LABELS string `help:"Labels for node"` + } + R(&AlarmTemplateDeleteFromNodeOptions{}, "delete-alarmtemplate-from-treenode", "UnBind alarm-template from service-tree node", func(s *mcclient.ClientSession, args *AlarmTemplateDeleteFromNodeOptions) error { + params := jsonutils.NewDict() + params.Add(jsonutils.NewString(args.LABELS), "node_labels") + + _, err := modules.AlarmTemplates.PerformAction(s, args.ID, "delete-from-treenode", params) + if err != nil { + return err + } + return nil + }) + + /** + * 克隆报警模板到服务树节点 + */ + type AlarmTemplateeCloneToNodeOptions struct { + ID string `help:"ID of alarm-template"` + LABELS string `help:"Labels for node"` + } + R(&AlarmTemplateeCloneToNodeOptions{}, "clone-alarmtemplate-to-treenode", "Bind alarm-template to service-tree node", func(s *mcclient.ClientSession, args *AlarmTemplateeCloneToNodeOptions) error { + params := jsonutils.NewDict() + params.Add(jsonutils.NewString(args.LABELS), "node_labels") + + _, err := modules.AlarmTemplates.PerformAction(s, args.ID, "clone-to-treenode", params) + if err != nil { + return err + } + return nil + }) + + /** + * 修改树务树节点绑定的报警模板状态 + */ + type AlarmTemplateDChangeStatusNodeOptions struct { + ID string `help:"ID of alarm-template"` + LABELS string `help:"Labels for node"` + STATUS int64 `help:"Enabled or disabled binding status, choices is 1|0"` + } + R(&AlarmTemplateDChangeStatusNodeOptions{}, "change-status-alarmtemplate-for-treenode", "UnBind alarm-template from service-tree node", func(s *mcclient.ClientSession, args *AlarmTemplateDChangeStatusNodeOptions) error { + params := jsonutils.NewDict() + params.Add(jsonutils.NewString(args.LABELS), "node_labels") + params.Add(jsonutils.NewInt(args.STATUS), "enabled") + + _, err := modules.AlarmTemplates.PerformAction(s, args.ID, "change-bind-status", params) + if err != nil { + return err + } + return nil + }) + + /** + * 修改报警模板下的报警规则的状态 + */ + type AlarmTemplateAlarmEnabledOptions struct { + ALARMTEMPLATE_ID string `help:"ID of alarm-template"` + ALARM_ID string `help:"ID of alarm"` + ENABLED int64 `help:"Enabled or disabled binding status, choices is 1|0"` + } + R(&AlarmTemplateAlarmEnabledOptions{}, "change-alarm-enabled", "UnBind alarm-template from service-tree node", func(s *mcclient.ClientSession, args *AlarmTemplateAlarmEnabledOptions) error { + params := jsonutils.NewDict() + params.Add(jsonutils.NewInt(args.ENABLED), "enabled") + + _, err := modules.AlarmTemplateAlarms.Update(s, args.ALARMTEMPLATE_ID, args.ALARM_ID, params) + if err != nil { + return err + } + return nil + }) +} diff --git a/cmd/climc/shell/baremetalnetworks.go b/cmd/climc/shell/baremetalnetworks.go new file mode 100644 index 0000000000..b38ad610d6 --- /dev/null +++ b/cmd/climc/shell/baremetalnetworks.go @@ -0,0 +1,47 @@ +package shell + +import ( + "github.com/yunionio/jsonutils" + "github.com/yunionio/mcclient" + "github.com/yunionio/mcclient/modules" +) + +func init() { + type HostNetworkListOptions struct { + BaseListOptions + Host string `help:"ID or Name of Host"` + Network string `help:"ID or name of network"` + } + R(&HostNetworkListOptions{}, "host-network-list", "List baremetal network pairs", func(s *mcclient.ClientSession, args *HostNetworkListOptions) error { + params := FetchPagingParams(args.BaseListOptions) + if len(args.Network) > 0 { + params.Add(jsonutils.NewString(args.Network), "network_id") + } + var result *modules.ListResult + var err error + if len(args.Host) > 0 { + result, err = modules.Baremetalnetworks.ListDescendent(s, args.Host, params) + } else { + result, err = modules.Baremetalnetworks.List(s, params) + } + if err != nil { + return err + } + printList(result, modules.Baremetalnetworks.GetColumns(s)) + return nil + }) + + type HostNetworkDetailOptions struct { + HOST string `help:"ID or Name of Host"` + NETWORK string `help:"ID or Name of Wire"` + } + R(&HostNetworkDetailOptions{}, "host-network-show", "Show baremetal network details", func(s *mcclient.ClientSession, args *HostNetworkDetailOptions) error { + result, err := modules.Baremetalnetworks.Get(s, args.HOST, args.NETWORK, nil) + if err != nil { + return err + } + printObject(result) + return nil + }) + +} diff --git a/cmd/climc/shell/baremetalstorages.go b/cmd/climc/shell/baremetalstorages.go new file mode 100644 index 0000000000..afa9d7d093 --- /dev/null +++ b/cmd/climc/shell/baremetalstorages.go @@ -0,0 +1,42 @@ +package shell + +import ( + "github.com/yunionio/mcclient" + "github.com/yunionio/mcclient/modules" + // "github.com/yunionio/jsonutils" +) + +func init() { + type BaremetalStorageListOptions struct { + BaseListOptions + Host string `help:"ID or Name of Host"` + } + R(&BaremetalStorageListOptions{}, "baremetal-storage-list", "List baremetal storage pairs", func(s *mcclient.ClientSession, args *BaremetalStorageListOptions) error { + params := FetchPagingParams(args.BaseListOptions) + var result *modules.ListResult + var err error + if len(args.Host) > 0 { + result, err = modules.Baremetalstorages.ListDescendent(s, args.Host, params) + } else { + result, err = modules.Baremetalstorages.List(s, params) + } + if err != nil { + return err + } + printList(result, modules.Baremetalstorages.GetColumns(s)) + return nil + }) + + type BaremetalStorageDetailOptions struct { + HOST string `help:"ID or Name of Host"` + STORAGE string `help:"ID or Name of Storage"` + } + R(&BaremetalStorageDetailOptions{}, "baremetal-storage-show", "Show baremetal storage details", func(s *mcclient.ClientSession, args *BaremetalStorageDetailOptions) error { + result, err := modules.Baremetalstorages.Get(s, args.HOST, args.STORAGE, nil) + if err != nil { + return err + } + printObject(result) + return nil + }) +} diff --git a/cmd/climc/shell/cachedimages.go b/cmd/climc/shell/cachedimages.go new file mode 100644 index 0000000000..f9f7e9392e --- /dev/null +++ b/cmd/climc/shell/cachedimages.go @@ -0,0 +1,51 @@ +package shell + +import ( + "github.com/yunionio/mcclient" + "github.com/yunionio/mcclient/modules" +) + +func init() { + type CachedImageListOptions struct { + BaseListOptions + } + R(&CachedImageListOptions{}, "cached-image-list", "List cached images", func(s *mcclient.ClientSession, args *CachedImageListOptions) error { + params := FetchPagingParams(args.BaseListOptions) + result, err := modules.Cachedimages.List(s, params) + if err != nil { + return err + } + printList(result, modules.Cachedimages.GetColumns(s)) + return nil + }) + + type CachedImageShowOptions struct { + ID string `help:"ID or Name of the cached image to show"` + } + R(&CachedImageShowOptions{}, "cached-image-show", "Show cached image details", func(s *mcclient.ClientSession, args *CachedImageShowOptions) error { + result, err := modules.Cachedimages.Get(s, args.ID, nil) + if err != nil { + return err + } + printObject(result) + return nil + }) + + R(&CachedImageShowOptions{}, "cached-image-refresh", "Refresh cached image details", func(s *mcclient.ClientSession, args *CachedImageShowOptions) error { + result, err := modules.Cachedimages.PerformAction(s, args.ID, "refresh", nil) + if err != nil { + return err + } + printObject(result) + return nil + }) + + R(&CachedImageShowOptions{}, "cached-image-delete", "Remove cached image information", func(s *mcclient.ClientSession, args *CachedImageShowOptions) error { + result, err := modules.Cachedimages.Delete(s, args.ID, nil) + if err != nil { + return err + } + printObject(result) + return nil + }) +} diff --git a/cmd/climc/shell/cloudproviders.go b/cmd/climc/shell/cloudproviders.go new file mode 100644 index 0000000000..b6a69f0af2 --- /dev/null +++ b/cmd/climc/shell/cloudproviders.go @@ -0,0 +1,147 @@ +package shell + +import ( + "github.com/yunionio/jsonutils" + "github.com/yunionio/mcclient" + "github.com/yunionio/mcclient/modules" +) + +func init() { + + type CloudproviderListOptions struct { + BaseListOptions + } + R(&CloudproviderListOptions{}, "cloud-provider-list", "List cloud providers", func(s *mcclient.ClientSession, args *CloudproviderListOptions) error { + params := FetchPagingParams(args.BaseListOptions) + result, err := modules.Cloudproviders.List(s, params) + if err != nil { + return err + } + printList(result, modules.Cloudproviders.GetColumns(s)) + return nil + }) + + type CloudproviderCreateOptions struct { + NAME string `help:"Name of cloud provider"` + ACCOUNT string `help:"Account to access the cloud provider"` + SECRET string `help:"Secret to access the cloud provider"` + PROVIDER string `help:"Driver for cloud provider" choices:"VMware|Aliyun"` + AccessUrl string `help:"Access url"` + Desc string `help:"Description"` + } + R(&CloudproviderCreateOptions{}, "cloud-provider-create", "Create a cloud provider", func(s *mcclient.ClientSession, args *CloudproviderCreateOptions) error { + params := jsonutils.NewDict() + params.Add(jsonutils.NewString(args.NAME), "name") + params.Add(jsonutils.NewString(args.ACCOUNT), "account") + params.Add(jsonutils.NewString(args.SECRET), "secret") + params.Add(jsonutils.NewString(args.PROVIDER), "provider") + if len(args.AccessUrl) > 0 { + params.Add(jsonutils.NewString(args.AccessUrl), "access_url") + } + if len(args.Desc) > 0 { + params.Add(jsonutils.NewString(args.Desc), "description") + } + result, err := modules.Cloudproviders.Create(s, params) + if err != nil { + return err + } + printObject(result) + return nil + }) + + type CloudproviderUpdateOptions struct { + ID string `help:"ID or Name of cloud provider"` + Name string `help:"New name to update"` + AccessUrl string `help:"New access url"` + Desc string `help:"Description"` + } + R(&CloudproviderUpdateOptions{}, "cloud-provider-update", "Update a cloud provider", func(s *mcclient.ClientSession, args *CloudproviderUpdateOptions) error { + params := jsonutils.NewDict() + if len(args.Name) > 0 { + params.Add(jsonutils.NewString(args.Name), "name") + } + if len(args.AccessUrl) > 0 { + params.Add(jsonutils.NewString(args.AccessUrl), "access_url") + } + if len(args.Desc) > 0 { + params.Add(jsonutils.NewString(args.Desc), "description") + } + if params.Size() == 0 { + return InvalidUpdateError() + } + result, err := modules.Cloudproviders.Update(s, args.ID, params) + if err != nil { + return err + } + printObject(result) + return nil + }) + + type CloudproviderShowOptions struct { + ID string `help:"ID or Name of cloud provider"` + } + R(&CloudproviderShowOptions{}, "cloud-provider-show", "Get details of a cloud provider", func(s *mcclient.ClientSession, args *CloudproviderShowOptions) error { + result, err := modules.Cloudproviders.Get(s, args.ID, nil) + if err != nil { + return err + } + printObject(result) + return nil + }) + + R(&CloudproviderShowOptions{}, "cloud-provider-delete", "Delete a cloud provider", func(s *mcclient.ClientSession, args *CloudproviderShowOptions) error { + result, err := modules.Cloudproviders.Delete(s, args.ID, nil) + if err != nil { + return err + } + printObject(result) + return nil + }) + + type CloudproviderUpdateCredentialOptions struct { + ID string `help:"ID or Name of cloud provider"` + ACCOUNT string `help:"new account"` + SECRET string `help:"new secret"` + } + R(&CloudproviderUpdateCredentialOptions{}, "cloud-provider-update-credential", "Update credential of a cloud provider", func(s *mcclient.ClientSession, args *CloudproviderUpdateCredentialOptions) error { + params := jsonutils.NewDict() + params.Add(jsonutils.NewString(args.ACCOUNT), "account") + params.Add(jsonutils.NewString(args.SECRET), "secret") + + result, err := modules.Cloudproviders.PerformAction(s, args.ID, "update-credential", params) + if err != nil { + return err + } + printObject(result) + return nil + }) + + type CloudproviderSyncOptions struct { + ID string `help:"ID or Name of cloud provider"` + Force bool `help:"Force sync no matter what"` + Region []string `help:"region to sync"` + Zone []string `help:"region to sync"` + Host []string `help:"region to sync"` + } + R(&CloudproviderSyncOptions{}, "cloud-provider-sync", "Sync of a cloud provider account", func(s *mcclient.ClientSession, args *CloudproviderSyncOptions) error { + params := jsonutils.NewDict() + if args.Force { + params.Add(jsonutils.JSONTrue, "force") + } + if len(args.Region) > 0 { + params.Add(jsonutils.NewStringArray(args.Region), "region") + } + if len(args.Zone) > 0 { + params.Add(jsonutils.NewStringArray(args.Zone), "zone") + } + if len(args.Host) > 0 { + params.Add(jsonutils.NewStringArray(args.Host), "host") + } + result, err := modules.Cloudproviders.PerformAction(s, args.ID, "sync", params) + if err != nil { + return err + } + printObject(result) + return nil + }) +} diff --git a/cmd/climc/shell/cloudregions.go b/cmd/climc/shell/cloudregions.go new file mode 100644 index 0000000000..81e74f1e18 --- /dev/null +++ b/cmd/climc/shell/cloudregions.go @@ -0,0 +1,102 @@ +package shell + +import ( + "github.com/yunionio/jsonutils" + "github.com/yunionio/mcclient" + "github.com/yunionio/mcclient/modules" +) + +func init() { + type CloudregionListOptions struct { + BaseListOptions + } + R(&CloudregionListOptions{}, "cloud-region-list", "List cloud regions", func(s *mcclient.ClientSession, args *CloudregionListOptions) error { + params := FetchPagingParams(args.BaseListOptions) + result, err := modules.Cloudregions.List(s, params) + if err != nil { + return err + } + printList(result, modules.Cloudregions.GetColumns(s)) + return nil + }) + + type CloudregionCreateOptions struct { + Id string `help:"ID of the region"` + NAME string `help:"Name of the region"` + Provider string `help:"Cloud provider"` + Desc string `help:"Description"` + } + R(&CloudregionCreateOptions{}, "cloud-region-create", "Create a cloud region", func(s *mcclient.ClientSession, args *CloudregionCreateOptions) error { + params := jsonutils.NewDict() + params.Add(jsonutils.NewString(args.NAME), "name") + if len(args.Id) > 0 { + params.Add(jsonutils.NewString(args.Id), "id") + } + if len(args.Desc) > 0 { + params.Add(jsonutils.NewString(args.Desc), "description") + } + results, err := modules.Cloudregions.Create(s, params) + if err != nil { + return err + } + printObject(results) + return nil + }) + + type CloudregionShowOptions struct { + ID string `help:"ID or name of the region"` + } + R(&CloudregionShowOptions{}, "cloud-region-show", "Show a cloud region", func(s *mcclient.ClientSession, args *CloudregionShowOptions) error { + results, err := modules.Cloudregions.Get(s, args.ID, nil) + if err != nil { + return err + } + printObject(results) + return nil + }) + + R(&CloudregionShowOptions{}, "cloud-region-delete", "Delete a cloud region", func(s *mcclient.ClientSession, args *CloudregionShowOptions) error { + results, err := modules.Cloudregions.Delete(s, args.ID, nil) + if err != nil { + return err + } + printObject(results) + return nil + }) + + type CloudregionUpdateOptions struct { + ID string `help:"ID or name of the region"` + Name string `help:"New name of the region"` + Desc string `help:"Description of the region"` + } + R(&CloudregionUpdateOptions{}, "cloud-region-update", "Update a cloud region", func(s *mcclient.ClientSession, args *CloudregionUpdateOptions) error { + params := jsonutils.NewDict() + if len(args.Name) > 0 { + params.Add(jsonutils.NewString(args.Name), "name") + } + if len(args.Desc) > 0 { + params.Add(jsonutils.NewString(args.Desc), "description") + } + results, err := modules.Cloudregions.Update(s, args.ID, params) + if err != nil { + return err + } + printObject(results) + return nil + }) + + type CloudregionSetDefaultVpcOptions struct { + ID string `help:"ID or name of the region"` + VPC string `help:"ID or name of VPC to make default"` + } + R(&CloudregionSetDefaultVpcOptions{}, "cloud-region-set-default-vpc", "Set default vpc for a region", func(s *mcclient.ClientSession, args *CloudregionSetDefaultVpcOptions) error { + params := jsonutils.NewDict() + params.Add(jsonutils.NewString(args.VPC), "vpc") + result, err := modules.Cloudregions.PerformAction(s, args.ID, "default-vpc", params) + if err != nil { + return err + } + printObject(result) + return nil + }) +} diff --git a/cmd/climc/shell/contactgroups.go b/cmd/climc/shell/contactgroups.go new file mode 100644 index 0000000000..c09eeff847 --- /dev/null +++ b/cmd/climc/shell/contactgroups.go @@ -0,0 +1,28 @@ +package shell + +import ( + "github.com/yunionio/mcclient" + "github.com/yunionio/mcclient/modules" +) + +func init() { + + /** + * 获得一个全部通信地址组 + */ + type ContactGroupsListOptions struct { + BaseListOptions + } + R(&ContactGroupsListOptions{}, "contact-group-list", "List all contact groups for all the domainsconta", func(s *mcclient.ClientSession, args *ContactGroupsListOptions) error { + params := FetchPagingParams(args.BaseListOptions) + + result, err := modules.ContactGroups.List(s, params) + if err != nil { + return err + } + + printList(result, modules.ContactGroups.GetColumns(s)) + return nil + }) + +} diff --git a/cmd/climc/shell/contacts.go b/cmd/climc/shell/contacts.go new file mode 100644 index 0000000000..cfe7c98a54 --- /dev/null +++ b/cmd/climc/shell/contacts.go @@ -0,0 +1,169 @@ +package shell + +import ( + "github.com/yunionio/jsonutils" + "github.com/yunionio/mcclient" + "github.com/yunionio/mcclient/modules" +) + +func init() { + + /** + * 操作用户的通信地址(如果用户的通信地址不存在则进行添加;如果已存在则进行修改;如果设置空则进行删除。) + */ + type ContactsUpdateOptions struct { + UID string `help:"The user you wanna add contact to (Keystone User ID)"` + CONTACTTYPE string `help:"The contact type email|mobile" choices:"email|mobile"` + CONTACT string `help:"The contacts details mobile number or email address, if set it the empty str means delete"` + Status string `help:"Enabled or disabled contact status" choices:"enable|disable"` + } + R(&ContactsUpdateOptions{}, "contact-update", "Create, delete or update contact for user", func(s *mcclient.ClientSession, args *ContactsUpdateOptions) error { + arr := jsonutils.NewArray() + tmpObj := jsonutils.NewDict() + tmpObj.Add(jsonutils.NewString(args.CONTACTTYPE), "contact_type") + tmpObj.Add(jsonutils.NewString(args.CONTACT), "contact") + if len(args.Status) > 0 { + if args.Status == "disable" { + tmpObj.Add(jsonutils.JSONFalse, "enabled") + } else { + tmpObj.Add(jsonutils.JSONTrue, "enabled") + } + } + + arr.Add(tmpObj) + + params := jsonutils.NewDict() + params.Add(arr, "contacts") + + contact, err := modules.Contacts.PerformAction(s, args.UID, "update-contact", params) + + if err != nil { + return err + } + + printObject(contact) + return nil + }) + + type ContactsDeleteOptions struct { + UID string `help:"The user you wanna add contact to (Keystone User ID)"` + CONTACTTYPE string `help:"The contact type email|mobile" choices:"email|mobile"` + } + R(&ContactsDeleteOptions{}, "contact-delete", "Delete contact for user", func(s *mcclient.ClientSession, args *ContactsDeleteOptions) error { + arr := jsonutils.NewArray() + tmpObj := jsonutils.NewDict() + tmpObj.Add(jsonutils.NewString(args.CONTACTTYPE), "contact_type") + tmpObj.Add(jsonutils.NewString(""), "contact") + arr.Add(tmpObj) + params := jsonutils.NewDict() + params.Add(arr, "contacts") + contact, err := modules.Contacts.PerformAction(s, args.UID, "update-contact", params) + if err != nil { + return err + } + printObject(contact) + return nil + }) + + /** + * 获得所有用户的所有通信地址列表 + */ + type ContactsListOptions struct { + BaseListOptions + } + R(&ContactsListOptions{}, "contact-list", "List all contacts for all users", func(s *mcclient.ClientSession, args *ContactsListOptions) error { + params := FetchPagingParams(args.BaseListOptions) + + result, err := modules.Contacts.List(s, params) + if err != nil { + return err + } + + printList(result, modules.Contacts.GetColumns(s)) + return nil + }) + + /** + * 获得一个用户全部通信地址 + */ + type ContactsListForUserOptions struct { + BaseListOptions + UID string `help:"The user you wanna find contact from (Keystone User ID)"` + } + R(&ContactsListForUserOptions{}, "contact-show", "List all contacts for the users", func(s *mcclient.ClientSession, args *ContactsListForUserOptions) error { + params := FetchPagingParams(args.BaseListOptions) + + result, err := modules.Contacts.Get(s, args.UID, params) + if err != nil { + return err + } + + contactsStr, err := result.GetString("details") + if err != nil { + return err + } + + contactsJson, err := jsonutils.ParseString(contactsStr) + if err != nil { + return err + } + + contacts, err := contactsJson.GetArray() + if err != nil { + return err + } + + printList(&modules.ListResult{Data: contacts}, nil) + return nil + }) + + /** + * 触发验证通信地址操作 + */ + type ContactsVerifyOptions struct { + UID string `help:"The user you wanna verify contact for (Keystone User ID)"` + CONTACT_TYPE string `help:"The contact type email|mobile"` + CONTACT string `help:"The contacts details mobile number or email address"` + } + R(&ContactsVerifyOptions{}, "contact-verify-trigger", "Trigger contact verify", func(s *mcclient.ClientSession, args *ContactsVerifyOptions) error { + params := jsonutils.NewDict() + params.Add(jsonutils.NewString(args.CONTACT_TYPE), "contact_type") + params.Add(jsonutils.NewString(args.CONTACT), "contact") + /* + if len(args.Email) > 0 { + params.Add(jsonutils.NewString(args.Email), "email") + } + if len(args.Mobile) > 0 { + params.Add(jsonutils.NewString(args.Mobile), "mobile") + } + */ + + _, err := modules.Contacts.PerformAction(s, args.UID, "verify", params) + if err != nil { + return err + } + return nil + }) + + type ContactsBatchDeleteOptions struct { + UIDS []string `help:"All user'id you wanna to delete contacts (Keystone User ID)"` + } + R(&ContactsBatchDeleteOptions{}, "contact-delete", "Delete all contacts for the user", func(s *mcclient.ClientSession, args *ContactsBatchDeleteOptions) error { + arr := jsonutils.NewArray() + for _, f := range args.UIDS { + arr.Add(jsonutils.NewString(f)) + } + + params := jsonutils.NewDict() + params.Add(arr, "contacts") + + contact, err := modules.Contacts.DoBatchDeleteContacts(s, params) + + if err != nil { + return err + } + + printObject(contact) + return nil + }) +} diff --git a/cmd/climc/shell/current.go b/cmd/climc/shell/current.go new file mode 100644 index 0000000000..32641c1012 --- /dev/null +++ b/cmd/climc/shell/current.go @@ -0,0 +1,14 @@ +package shell + +import ( + "github.com/yunionio/mcclient" +) + +func init() { + type CurrentUserOptions struct { + } + R(&CurrentUserOptions{}, "session-show", "show information of current account", func(s *mcclient.ClientSession, args *CurrentUserOptions) error { + printObject(s.ToJson()) + return nil + }) +} diff --git a/cmd/climc/shell/disks.go b/cmd/climc/shell/disks.go new file mode 100644 index 0000000000..bf25282f9a --- /dev/null +++ b/cmd/climc/shell/disks.go @@ -0,0 +1,175 @@ +package shell + +import ( + "github.com/yunionio/jsonutils" + "github.com/yunionio/mcclient" + "github.com/yunionio/mcclient/modules" +) + +func init() { + type DiskListOptions struct { + BaseListOptions + Unused bool `help:"Show unused disks"` + Share bool `help:"Show Share storage disks"` + Local bool `help:"Show Local storage disks"` + Guest string `help:"Guest ID or name"` + Storage string `help:"Storage ID or name"` + } + R(&DiskListOptions{}, "disk-list", "List virtual disks", func(s *mcclient.ClientSession, suboptions *DiskListOptions) error { + params := FetchPagingParams(suboptions.BaseListOptions) + if suboptions.Unused { + params.Add(jsonutils.JSONTrue, "unused") + } + if suboptions.Share { + params.Add(jsonutils.JSONTrue, "share") + } + if suboptions.Local { + params.Add(jsonutils.JSONTrue, "local") + } + if len(suboptions.Guest) > 0 { + params.Add(jsonutils.NewString(suboptions.Guest), "guest") + } + if len(suboptions.Storage) > 0 { + params.Add(jsonutils.NewString(suboptions.Storage), "storage") + } + result, err := modules.Disks.List(s, params) + if err != nil { + return err + } + printList(result, modules.Disks.GetColumns(s)) + return nil + }) + + type DiskDetailOptions struct { + ID string `help:"ID or Name of disk"` + } + R(&DiskDetailOptions{}, "disk-show", "Show details of disk", func(s *mcclient.ClientSession, args *DiskDetailOptions) error { + disk, e := modules.Disks.Get(s, args.ID, nil) + if e != nil { + return e + } + printObject(disk) + return nil + }) + R(&DiskDetailOptions{}, "disk-cancel-delete", "Cancel pending delete disks", func(s *mcclient.ClientSession, args *DiskDetailOptions) error { + disk, e := modules.Disks.PerformAction(s, args.ID, "cancel-delete", nil) + if e != nil { + return e + } + printObject(disk) + return nil + }) + + R(&DiskDetailOptions{}, "disk-delete", "Delete a disk", func(s *mcclient.ClientSession, args *DiskDetailOptions) error { + disk, e := modules.Disks.Delete(s, args.ID, nil) + if e != nil { + return e + } + printObject(disk) + return nil + }) + + R(&DiskDetailOptions{}, "disk-purge", "Delete a disk record in database, not actually do deletion", func(s *mcclient.ClientSession, args *DiskDetailOptions) error { + disk, e := modules.Disks.PerformAction(s, args.ID, "purge", nil) + if e != nil { + return e + } + printObject(disk) + return nil + }) + + R(&DiskDetailOptions{}, "disk-public", "Make a disk public", func(s *mcclient.ClientSession, args *DiskDetailOptions) error { + disk, e := modules.Disks.PerformAction(s, args.ID, "public", nil) + if e != nil { + return e + } + printObject(disk) + return nil + }) + + R(&DiskDetailOptions{}, "disk-private", "Make a disk private", func(s *mcclient.ClientSession, args *DiskDetailOptions) error { + disk, e := modules.Disks.PerformAction(s, args.ID, "private", nil) + if e != nil { + return e + } + printObject(disk) + return nil + }) + + R(&DiskDetailOptions{}, "disk-metadata", "Get metadata of a disk", func(s *mcclient.ClientSession, args *DiskDetailOptions) error { + meta, e := modules.Disks.GetMetadata(s, args.ID, nil) + if e != nil { + return e + } + printObject(meta) + return nil + }) + + type DiskUpdateOptions struct { + ID string `help:"ID or name of disk"` + Name string `help:"New name of disk"` + Desc string `help:"Description" metavar:"DESCRIPTION"` + AutoDelete string `help:"enable/disable auto delete of disk" choices:"enable|disable"` + } + R(&DiskUpdateOptions{}, "disk-update", "Update property of a virtual disk", func(s *mcclient.ClientSession, args *DiskUpdateOptions) error { + params := jsonutils.NewDict() + if len(args.Name) > 0 { + params.Add(jsonutils.NewString(args.Name), "name") + } + if len(args.Desc) > 0 { + params.Add(jsonutils.NewString(args.Desc), "description") + } + if len(args.AutoDelete) > 0 { + if args.AutoDelete == "enable" { + params.Add(jsonutils.JSONTrue, "auto_delete") + } else { + params.Add(jsonutils.JSONFalse, "auto_delete") + } + } + if params.Size() == 0 { + return InvalidUpdateError() + } + disk, e := modules.Disks.Update(s, args.ID, params) + if e != nil { + return e + } + printObject(disk) + return nil + }) + + type DiskCreateOptions struct { + STORAGE string `help:"ID or name of storage where the disk is created"` + NAME string `help:"Name of the disk"` + DISKDESC string `help:"Image size or size of virtual disk"` + Desc string `help:"Description" metavar:"Description"` + } + R(&DiskCreateOptions{}, "disk-create", "Create a virtual disk", func(s *mcclient.ClientSession, args *DiskCreateOptions) error { + params := jsonutils.NewDict() + params.Add(jsonutils.NewString(args.NAME), "name") + params.Add(jsonutils.NewString(args.DISKDESC), "disk") + if len(args.Desc) > 0 { + params.Add(jsonutils.NewString(args.Desc), "description") + } + disk, err := modules.Disks.CreateInContext(s, params, &modules.Storages, args.STORAGE) + if err != nil { + return err + } + printObject(disk) + return nil + }) + + type DiskResizeOptions struct { + DISK string `help:"ID or name of disk"` + SIZE string `help:"Size of disk"` + } + R(&DiskResizeOptions{}, "disk-resize", "Resize a disk", func(s *mcclient.ClientSession, args *DiskResizeOptions) error { + params := jsonutils.NewDict() + params.Add(jsonutils.NewString(args.SIZE), "size") + disk, err := modules.Disks.PerformAction(s, args.DISK, "resize", params) + if err != nil { + return err + } + printObject(disk) + return nil + }) +} diff --git a/cmd/climc/shell/dnsrecords.go b/cmd/climc/shell/dnsrecords.go new file mode 100644 index 0000000000..0281e127a0 --- /dev/null +++ b/cmd/climc/shell/dnsrecords.go @@ -0,0 +1,178 @@ +package shell + +import ( + "fmt" + + "github.com/yunionio/jsonutils" + "github.com/yunionio/mcclient" + "github.com/yunionio/mcclient/modules" +) + +type DNSRecordOptions struct { + A []string `help:"DNS A record" metavar:"A_RECORD" optional:"true"` + AAAA []string `help:"DNS AAAA record" metavar:"AAAA_RECORD" optional:"true"` + CNAME string `help:"DNS CNAME record" metavar:"CNAME_RECORD" optional:"true"` + SRVHost string `help:"DNS SRV record, server of service" metavar:"SRV_RECORD_HOST" optional:"true"` + SRVPort int64 `help:"DNS SRV record, port of service" metavar:"SRV_RECORD_PORT" optional:"true"` + PTR string `help:"DNS PTR record" metavar:"PTR_RECORD" optional:"true"` +} + +func parseDNSRecords(args *DNSRecordOptions, params *jsonutils.JSONDict) { + if len(args.A) > 0 || len(args.AAAA) > 0 { + for i, a := range args.A { + params.Add(jsonutils.NewString(a), fmt.Sprintf("A.%d", i)) + } + for i, a := range args.AAAA { + params.Add(jsonutils.NewString(a), fmt.Sprintf("AAAA.%d", i)) + } + } else if len(args.CNAME) > 0 { + params.Add(jsonutils.NewString(args.CNAME), "CNAME") + } else if len(args.SRVHost) > 0 && args.SRVPort > 0 { + params.Add(jsonutils.NewString(args.SRVHost), "SRV_host") + params.Add(jsonutils.NewInt(args.SRVPort), "SRV_port") + } else if len(args.PTR) > 0 { + params.Add(jsonutils.NewString(args.PTR), "PTR") + } +} + +func init() { + type DNSListOptions struct { + BaseListOptions + } + R(&DNSListOptions{}, "dns-list", "List dns records", func(s *mcclient.ClientSession, suboptions *DNSListOptions) error { + params := FetchPagingParams(suboptions.BaseListOptions) + result, err := modules.DNSRecords.List(s, params) + if err != nil { + return err + } + printList(result, modules.DNSRecords.GetColumns(s)) + return nil + }) + + type DNSCreateOptions struct { + NAME string `help:"DNS name to create"` + TTL int64 `help:"TTL in seconds" optional:"true"` + Desc string `help:"Description" metavar:"DESCRIPTION"` + DNSRecordOptions + } + R(&DNSCreateOptions{}, "dns-create", "Create dns record", func(s *mcclient.ClientSession, args *DNSCreateOptions) error { + params := jsonutils.NewDict() + parseDNSRecords(&args.DNSRecordOptions, params) + if params.Size() == 0 { + return fmt.Errorf("No records to create") + } + params.Add(jsonutils.NewString(args.NAME), "name") + if args.TTL > 0 { + params.Add(jsonutils.NewInt(args.TTL), "ttl") + } + if len(args.Desc) > 0 { + params.Add(jsonutils.NewString(args.Desc), "description") + } + rec, e := modules.DNSRecords.Create(s, params) + if e != nil { + return e + } + printObject(rec) + return nil + }) + + type DNSShowOptions struct { + ID string `help:"ID of DNS record to show"` + } + R(&DNSShowOptions{}, "dns-show", "Show details of a dns records", func(s *mcclient.ClientSession, args *DNSShowOptions) error { + dns, e := modules.DNSRecords.Get(s, args.ID, nil) + if e != nil { + return e + } + printObject(dns) + return nil + }) + + type DNSUpdateOptions struct { + ID string `help:"ID of DNS record to update"` + Name string `help:"Domain name"` + TTL int64 `help:"TTL in seconds" optional:"true"` + Desc string `help:"Description"` + } + R(&DNSUpdateOptions{}, "dns-update", "Update details of a dns records", func(s *mcclient.ClientSession, args *DNSUpdateOptions) error { + params := jsonutils.NewDict() + if len(args.Name) > 0 { + params.Add(jsonutils.NewString(args.Name), "name") + } + if len(args.Desc) > 0 { + params.Add(jsonutils.NewString(args.Desc), "description") + } + if args.TTL > 0 { + params.Add(jsonutils.NewInt(args.TTL), "ttl") + } + if params.Size() == 0 { + return InvalidUpdateError() + } + dns, e := modules.DNSRecords.Update(s, args.ID, params) + if e != nil { + return e + } + printObject(dns) + return nil + }) + + R(&DNSShowOptions{}, "dns-delete", "Delete a dns record", func(s *mcclient.ClientSession, args *DNSShowOptions) error { + dns, e := modules.DNSRecords.Delete(s, args.ID, nil) + if e != nil { + return e + } + printObject(dns) + return nil + }) + + R(&DNSShowOptions{}, "dns-public", "Make a dns record publicly available", func(s *mcclient.ClientSession, args *DNSShowOptions) error { + dns, e := modules.DNSRecords.PerformAction(s, args.ID, "public", nil) + if e != nil { + return e + } + printObject(dns) + return nil + }) + + R(&DNSShowOptions{}, "dns-private", "Make a dns record private", func(s *mcclient.ClientSession, args *DNSShowOptions) error { + dns, e := modules.DNSRecords.PerformAction(s, args.ID, "private", nil) + if e != nil { + return e + } + printObject(dns) + return nil + }) + + type DNSUpdateRecordsOptions struct { + ID string `help:"ID of dns record to modify"` + DNSRecordOptions + } + R(&DNSUpdateRecordsOptions{}, "dns-add-records", "Add DNS records to a name", func(s *mcclient.ClientSession, args *DNSUpdateRecordsOptions) error { + params := jsonutils.NewDict() + parseDNSRecords(&args.DNSRecordOptions, params) + if params.Size() == 0 { + return fmt.Errorf("Nothing to add") + } + dns, e := modules.DNSRecords.PerformAction(s, args.ID, "add-records", params) + if e != nil { + return e + } + printObject(dns) + return nil + }) + + R(&DNSUpdateRecordsOptions{}, "dns-remove-records", "Remove DNS records from a name", func(s *mcclient.ClientSession, args *DNSUpdateRecordsOptions) error { + params := jsonutils.NewDict() + parseDNSRecords(&args.DNSRecordOptions, params) + if params.Size() == 0 { + return fmt.Errorf("Nothing to remove") + } + dns, e := modules.DNSRecords.PerformAction(s, args.ID, "remove-records", params) + if e != nil { + return e + } + printObject(dns) + return nil + }) + +} diff --git a/cmd/climc/shell/domains.go b/cmd/climc/shell/domains.go new file mode 100644 index 0000000000..4a3321189c --- /dev/null +++ b/cmd/climc/shell/domains.go @@ -0,0 +1,274 @@ +package shell + +import ( + "fmt" + + "github.com/yunionio/jsonutils" + "github.com/yunionio/mcclient" + "github.com/yunionio/mcclient/modules" +) + +func init() { + type DomainListOptions struct { + Search string `help:"search domain name"` + Limit int64 `help:"Items per page" default:"20"` + Offset int64 `help:"Offset"` + } + R(&DomainListOptions{}, "domain-list", "List domains", func(s *mcclient.ClientSession, args *DomainListOptions) error { + params := jsonutils.NewDict() + if len(args.Search) > 0 { + params.Add(jsonutils.NewString(args.Search), "name__icontains") + } + if args.Limit > 0 { + params.Add(jsonutils.NewInt(args.Limit), "limit") + } + if args.Offset > 0 { + params.Add(jsonutils.NewInt(args.Offset), "offset") + } + result, err := modules.Domains.List(s, params) + if err != nil { + return err + } + printList(result, modules.Domains.GetColumns(s)) + return nil + }) + + type DomainDetailOptions struct { + ID string `help:"ID or domain"` + } + R(&DomainDetailOptions{}, "domain-show", "Show detail of domain", func(s *mcclient.ClientSession, args *DomainDetailOptions) error { + result, err := modules.Domains.Get(s, args.ID, nil) + if err != nil { + return err + } + printObject(result) + return nil + }) + R(&DomainDetailOptions{}, "domain-delete", "Delete a domain", func(s *mcclient.ClientSession, args *DomainDetailOptions) error { + objId, err := modules.Domains.GetId(s, args.ID, nil) + if err != nil { + return err + } + result, err := modules.Domains.Delete(s, objId, nil) + if err != nil { + return err + } + printObject(result) + return nil + }) + R(&DomainDetailOptions{}, "domain-config-show", "Show detail of a domain config", func(s *mcclient.ClientSession, args *DomainDetailOptions) error { + objId, err := modules.Domains.GetId(s, args.ID, nil) + if err != nil { + return err + } + config, err := modules.Domains.GetConfig(s, objId) + if err != nil { + return err + } + fmt.Println(config.PrettyString()) + return nil + }) + R(&DomainDetailOptions{}, "domain-config-delete", "Delete a domain config", func(s *mcclient.ClientSession, args *DomainDetailOptions) error { + objId, err := modules.Domains.GetId(s, args.ID, nil) + if err != nil { + return err + } + config, err := modules.Domains.DeleteConfig(s, objId) + if err != nil { + return err + } + printObject(config) + return nil + }) + /* R(&DomainDetailOptions{}, "domain-config-sql", "Config a domain with SQL driver", func(s *mcclient.ClientSession, args *DomainDetailOptions) error { + config := jsonutils.NewDict() + config.Add(jsonutils.NewString("sql"), "config", "identity", "driver") + objId, err := modules.Domains.GetId(s, args.ID, nil) + if err != nil { + return err + } + nconf, err := modules.Domains.UpdateConfig(s, objId, config) + if err != nil { + return err + } + fmt.Println(nconf.PrettyString()) + return nil + }) */ + + type DomainConfigLDAPOptions struct { + ID string `help:"ID of domain to config"` + URL string `help:"LDAP server URL"` + SUFFIX string `help:"Suffix"` + QueryScope string `help:"Query scope, either one or sub" choices:"one|sub" default:"sub"` + PageSize int `help:"Page size, default 20" default:"20"` + User string `help:"User"` + Password string `help:"Password"` + UserTreeDN string `help:"User tree distinguished name"` + UserFilter string `help:"user_filter"` + UserObjectclass string `help:"user_objectclass"` + UserIdAttribute string `help:"user_id_attribute"` + UserNameAttribute string `help:"user_name_attribute"` + UserEnabledAttribute string `help:"user_enabled_attribute"` + UserEnabledMask int64 `help:"user_enabled_mask" default:"-1"` + UserEnabledDefault string `help:"user_enabled_default"` + UserEnabledInvert string `help:"user_enabled_invert" choices:"true|false"` + UserAdditionalAttribute []string `help:"user_additional_attribute_mapping"` + GroupTreeDN string `help:"User tree distinguished name"` + GroupFilter string `help:"group_filter"` + GroupObjectclass string `help:"group_objectclass"` + GroupIdAttribute string `help:"group_id_attribute"` + GroupNameAttribute string `help:"group_name_attribute"` + GroupMemberAttribute string `help:"group_member_attribute"` + GroupMembersAreIds bool `help:"group_members_are_ids"` + } + R(&DomainConfigLDAPOptions{}, "domain-config-ldap", "Config a domain with LDAP driver", func(s *mcclient.ClientSession, args *DomainConfigLDAPOptions) error { + config := jsonutils.NewDict() + config.Add(jsonutils.NewString("ldap"), "config", "identity", "driver") + config.Add(jsonutils.NewString(args.URL), "config", "ldap", "url") + config.Add(jsonutils.NewString(args.SUFFIX), "config", "ldap", "suffix") + if len(args.QueryScope) > 0 { + config.Add(jsonutils.NewString(args.QueryScope), "config", "ldap", "query_scope") + } + if args.PageSize > 0 { + config.Add(jsonutils.NewInt(int64(args.PageSize)), "config", "ldap", "page_size") + } + if len(args.User) > 0 { + config.Add(jsonutils.NewString(args.User), "config", "ldap", "user") + } + if len(args.Password) > 0 { + config.Add(jsonutils.NewString(args.Password), "config", "ldap", "password") + } + if len(args.UserTreeDN) > 0 { + config.Add(jsonutils.NewString(args.UserTreeDN), "config", "ldap", "user_tree_dn") + } + if len(args.UserFilter) > 0 { + config.Add(jsonutils.NewString(args.UserFilter), "config", "ldap", "user_filter") + } + if len(args.UserObjectclass) > 0 { + config.Add(jsonutils.NewString(args.UserObjectclass), "config", "ldap", "user_objectclass") + } + if len(args.UserIdAttribute) > 0 { + config.Add(jsonutils.NewString(args.UserIdAttribute), "config", "ldap", "user_id_attribute") + } + if len(args.UserNameAttribute) > 0 { + config.Add(jsonutils.NewString(args.UserNameAttribute), "config", "ldap", "user_name_attribute") + } + if len(args.UserEnabledAttribute) > 0 { + config.Add(jsonutils.NewString(args.UserEnabledAttribute), "config", "ldap", "user_enabled_attribute") + } + if args.UserEnabledMask >= 0 { + config.Add(jsonutils.NewInt(int64(args.UserEnabledMask)), "config", "ldap", "user_enabled_mask") + } + if len(args.UserEnabledDefault) > 0 { + config.Add(jsonutils.NewString(args.UserEnabledDefault), "config", "ldap", "user_enabled_default") + } + if len(args.UserEnabledInvert) > 0 { + if args.UserEnabledInvert == "true" { + config.Add(jsonutils.JSONTrue, "config", "ldap", "user_enabled_invert") + } else { + config.Add(jsonutils.JSONFalse, "config", "ldap", "user_enabled_invert") + } + } + if len(args.UserAdditionalAttribute) > 0 { + config.Add(jsonutils.NewStringArray(args.UserAdditionalAttribute), "config", "ldap", "user_additional_attribute_mapping") + } + if len(args.GroupTreeDN) > 0 { + config.Add(jsonutils.NewString(args.GroupTreeDN), "config", "ldap", "group_tree_dn") + } + if len(args.GroupFilter) > 0 { + config.Add(jsonutils.NewString(args.GroupFilter), "config", "ldap", "group_filter") + } + if len(args.GroupObjectclass) > 0 { + config.Add(jsonutils.NewString(args.GroupObjectclass), "config", "ldap", "group_objectclass") + } + if len(args.GroupIdAttribute) > 0 { + config.Add(jsonutils.NewString(args.GroupIdAttribute), "config", "ldap", "group_id_attribute") + } + if len(args.GroupNameAttribute) > 0 { + config.Add(jsonutils.NewString(args.GroupNameAttribute), "config", "ldap", "group_name_attribute") + } + if len(args.GroupMemberAttribute) > 0 { + config.Add(jsonutils.NewString(args.GroupMemberAttribute), "config", "ldap", "group_member_attribute") + } + if args.GroupMembersAreIds { + config.Add(jsonutils.JSONTrue, "config", "ldap", "group_members_are_ids") + } + objId, err := modules.Domains.GetId(s, args.ID, nil) + if err != nil { + return err + } + nconf, err := modules.Domains.UpdateConfig(s, objId, config) + if err != nil { + return err + } + fmt.Println(nconf.PrettyString()) + return nil + }) + + type DomainCreateOptions struct { + NAME string `help:"Name of domain"` + Desc string `help:"Description"` + Enabled bool `help:"Set the domain enabled"` + Disabled bool `help:"Set the domain disabled"` + } + R(&DomainCreateOptions{}, "domain-create", "Create a new domain", func(s *mcclient.ClientSession, args *DomainCreateOptions) error { + params := jsonutils.NewDict() + params.Add(jsonutils.NewString(args.NAME), "name") + if len(args.Desc) > 0 { + params.Add(jsonutils.NewString(args.Desc), "description") + } + if args.Enabled && !args.Disabled { + params.Add(jsonutils.JSONTrue, "enabled") + } else if !args.Enabled && args.Disabled { + params.Add(jsonutils.JSONFalse, "enabled") + } + result, err := modules.Domains.Create(s, params) + if err != nil { + return err + } + printObject(result) + return nil + }) + + type DomainUpdateOptions struct { + ID string `help:"ID of domain to update"` + Name string `help:"Name of domain"` + Desc string `help:"Description"` + Enabled bool `help:"Set the domain enabled"` + Disabled bool `help:"Set the domain disabled"` + Driver string `help:"Set the domain Driver"` + } + R(&DomainUpdateOptions{}, "domain-update", "Update a domain", func(s *mcclient.ClientSession, args *DomainUpdateOptions) error { + obj, err := modules.Domains.Get(s, args.ID, nil) + if err != nil { + return err + } + objId, err := obj.GetString("id") + if err != nil { + return err + } + params := jsonutils.NewDict() + if len(args.Name) > 0 { + params.Add(jsonutils.NewString(args.Name), "name") + } + if len(args.Desc) > 0 { + params.Add(jsonutils.NewString(args.Desc), "description") + } + if len(args.Driver) > 0 { + params.Add(jsonutils.NewString(args.Driver), "driver") + } + + if args.Enabled && !args.Disabled { + params.Add(jsonutils.JSONTrue, "enabled") + } else if !args.Enabled && args.Disabled { + params.Add(jsonutils.JSONFalse, "enabled") + } + result, err := modules.Domains.Patch(s, objId, params) + if err != nil { + return err + } + printObject(result) + return nil + }) + +} diff --git a/cmd/climc/shell/email_config.go b/cmd/climc/shell/email_config.go new file mode 100644 index 0000000000..c4761f68b3 --- /dev/null +++ b/cmd/climc/shell/email_config.go @@ -0,0 +1,97 @@ +package shell + +import ( + "github.com/yunionio/jsonutils" + "github.com/yunionio/mcclient" + "github.com/yunionio/mcclient/modules" +) + +func init() { + + /** + * 查询邮件配置信息 + */ + type EmailConfigShowOptions struct { + TYPE string `help:"type "` + } + R(&EmailConfigShowOptions{}, "email-config-show", "Show email-config details", + func(s *mcclient.ClientSession, args *EmailConfigShowOptions) error { + result, err := modules.EmailConfigs.Get(s, args.TYPE, nil) + if err != nil { + return err + } + printObject(result) + return nil + }) + + /** + * 增加邮件配置信息 + */ + type EmailConfigCreateOptions struct { + USERNAME string `help:"Username for email sender"` + PASSWORD string `help:"Password for email sender"` + HOSTNAME string `help:"Email server name"` + SSLGLOBAL string `help:"use ssl_global"` + HOSTPORT int64 `help:"Email server port"` + } + + R(&EmailConfigCreateOptions{}, "email-config-create", "Create a Email Config", + func(s *mcclient.ClientSession, args *EmailConfigCreateOptions) error { + params := jsonutils.NewDict() + params.Add(jsonutils.NewString(args.USERNAME), "username") + params.Add(jsonutils.NewString(args.PASSWORD), "password") + params.Add(jsonutils.NewString(args.HOSTNAME), "hostname") + params.Add(jsonutils.NewString(args.SSLGLOBAL), "ssl_global") + params.Add(jsonutils.NewInt(args.HOSTPORT), "hostport") + + result, err := modules.EmailConfigs.Create(s, params) + if err != nil { + return err + } + printObject(result) + return nil + }) + + /** + * 修改 + */ + type EmailConfigUpdateOptions struct { + TYPE string `help:"type of email "` + USERNAME string `help:"Username for email sender"` + PASSWORD string `help:"Password for email sender"` + HOSTNAME string `help:"Email server name"` + SSLGLOBAL string `help:"use ssl_global"` + HOSTPORT int64 `help:"Email server port"` + } + R(&EmailConfigUpdateOptions{}, "email-config-update", "Update a email-config", func(s *mcclient.ClientSession, args *EmailConfigUpdateOptions) error { + params := jsonutils.NewDict() + params.Add(jsonutils.NewString(args.USERNAME), "username") + params.Add(jsonutils.NewString(args.PASSWORD), "password") + params.Add(jsonutils.NewString(args.HOSTNAME), "hostname") + params.Add(jsonutils.NewString(args.SSLGLOBAL), "ssl_global") + params.Add(jsonutils.NewInt(args.HOSTPORT), "hostport") + + result, err := modules.EmailConfigs.Put(s, args.TYPE, params) + if err != nil { + return err + } + printObject(result) + return nil + }) + + /** + * 删除 + */ + type EmailConfigDeleteOptions struct { + TYPE string `help:"type of email "` + } + R(&EmailConfigDeleteOptions{}, "email-config-delete", "Delete a email config", func(s *mcclient.ClientSession, args *EmailConfigDeleteOptions) error { + result, e := modules.EmailConfigs.Delete(s, args.TYPE, nil) + if e != nil { + return e + } + printObject(result) + return nil + }) + +} diff --git a/cmd/climc/shell/endpoints.go b/cmd/climc/shell/endpoints.go new file mode 100644 index 0000000000..e402f87132 --- /dev/null +++ b/cmd/climc/shell/endpoints.go @@ -0,0 +1,138 @@ +package shell + +import ( + "github.com/yunionio/jsonutils" + "github.com/yunionio/mcclient" + "github.com/yunionio/mcclient/modules" +) + +func init() { + type EndpointListOptions struct { + Limit int64 `help:"Limit, default 0, i.e. no limit" default:"20"` + Offset int64 `help:"Offset, default 0, i.e. no offset"` + Region string `help:"Search by region"` + Interface string `help:"Search by interface"` + } + R(&EndpointListOptions{}, "endpoint-list", "List service endpoints", func(s *mcclient.ClientSession, args *EndpointListOptions) error { + mod, err := modules.GetModule(s, "endpoints") + if err != nil { + return err + } + query := jsonutils.NewDict() + if args.Limit > 0 { + query.Add(jsonutils.NewInt(args.Limit), "limit") + } + if args.Offset > 0 { + query.Add(jsonutils.NewInt(args.Offset), "offset") + } + if len(args.Region) > 0 { + query.Add(jsonutils.NewString(args.Region), "region_id") + } + if len(args.Interface) > 0 { + query.Add(jsonutils.NewString(args.Interface), "interface") + } + result, err := mod.List(s, query) + if err != nil { + return err + } + printList(result, mod.GetColumns(s)) + return nil + }) + + type EndpointDetailOptions struct { + ID string `help:"ID or name of endpoints"` + } + R(&EndpointDetailOptions{}, "endpoint-show", "Show details of an endpoint", func(s *mcclient.ClientSession, args *EndpointDetailOptions) error { + mod, err := modules.GetModule(s, "endpoints") + if err != nil { + return err + } + ep, err := mod.Get(s, args.ID, nil) + if err != nil { + return err + } + printObject(ep) + return nil + }) + + R(&EndpointDetailOptions{}, "endpoint-delete", "Delete an endpoint", func(s *mcclient.ClientSession, args *EndpointDetailOptions) error { + mod, err := modules.GetModule(s, "endpoints") + if err != nil { + return err + } + ep, err := mod.Delete(s, args.ID, nil) + if err != nil { + return err + } + printObject(ep) + return nil + }) + + type EndpointCreateOptions struct { + SERVICE string `help:"Service ID or Name"` + REGION string `help:"Region"` + INTERFACE string `help:"Interface types" choices:"internal|public|admin"` + URL string `help:"URL"` + Zone string `help:"Zone"` + Name string `help:"Name"` + Enabled bool `help:"Enabled"` + Disabled bool `help:"Disabled"` + } + R(&EndpointCreateOptions{}, "endpoint-create", "Create endpoint", func(s *mcclient.ClientSession, args *EndpointCreateOptions) error { + params := jsonutils.NewDict() + srvId, err := modules.ServicesV3.GetId(s, args.SERVICE, nil) + if err != nil { + return err + } + params.Add(jsonutils.NewString(srvId), "service_id") + regionId, err := modules.Regions.GetId(s, mcclient.RegionID(args.REGION, args.Zone), nil) + if err != nil { + return err + } + params.Add(jsonutils.NewString(regionId), "region_id") + params.Add(jsonutils.NewString(args.INTERFACE), "interface") + params.Add(jsonutils.NewString(args.URL), "url") + if len(args.Name) > 0 { + params.Add(jsonutils.NewString(args.Name), "name") + } + if args.Enabled && !args.Disabled { + params.Add(jsonutils.JSONTrue, "enabled") + } else if !args.Enabled && args.Disabled { + params.Add(jsonutils.JSONFalse, "enabled") + } + ep, err := modules.EndpointsV3.Create(s, params) + if err != nil { + return err + } + printObject(ep) + return nil + }) + + type EndpointUpdateOptions struct { + ID string `help:"ID or name of endpoint"` + Url string `help:"URL"` + Name string `help:"Name"` + Enabled bool `help:"Enabled"` + Disabled bool `help:"Disabled"` + } + R(&EndpointUpdateOptions{}, "endpoint-update", "Update a endpoint", func(s *mcclient.ClientSession, args *EndpointUpdateOptions) error { + params := jsonutils.NewDict() + if len(args.Url) > 0 { + params.Add(jsonutils.NewString(args.Url), "url") + } + if len(args.Name) > 0 { + params.Add(jsonutils.NewString(args.Name), "name") + } + if args.Enabled && !args.Disabled { + params.Add(jsonutils.JSONTrue, "enabled") + } else if !args.Enabled && args.Disabled { + params.Add(jsonutils.JSONFalse, "enabled") + } + ep, err := modules.EndpointsV3.Patch(s, args.ID, params) + if err != nil { + return err + } + printObject(ep) + return nil + }) +} diff --git a/cmd/climc/shell/events.go b/cmd/climc/shell/events.go new file mode 100644 index 0000000000..55a27b5b08 --- /dev/null +++ b/cmd/climc/shell/events.go @@ -0,0 +1,87 @@ +package shell + +import ( + "github.com/yunionio/jsonutils" + "github.com/yunionio/mcclient" + "github.com/yunionio/mcclient/modules" +) + +type BaseEventListOptions struct { + Since string `help:"Show logs since specific date" metavar:"DATETIME"` + Until string `help:"Show logs until specific date" metavar:"DATETIME"` + Limit int64 `help:"Limit number of logs" default:"20"` + Offset int64 `help:"Offset"` + Ascending bool `help:"Ascending order"` + Descending bool `help:"Descending order"` + Action []string `help:"Log action"` +} + +type EventListOptions struct { + BaseEventListOptions + Id string `help:"" metavar:"OBJ_ID"` + Type []string `help:"Type of relevant object" metavar:"OBJ_TYPE"` +} + +type TypeEventListOptions struct { + BaseEventListOptions + ID string `help:"" metavar:"OBJ_ID"` +} + +func doComputeEventList(s *mcclient.ClientSession, args *EventListOptions) error { + return doEventList(modules.Logs, s, args) +} + +func doEventList(man modules.ResourceManager, s *mcclient.ClientSession, args *EventListOptions) error { + params := jsonutils.NewDict() + if len(args.Type) > 0 { + params.Add(jsonutils.NewStringArray(args.Type), "obj_type") + } + if len(args.Id) > 0 { + params.Add(jsonutils.NewString(args.Id), "obj_id") + } + if len(args.Since) > 0 { + params.Add(jsonutils.NewString(args.Since), "since") + } + if len(args.Until) > 0 { + params.Add(jsonutils.NewString(args.Until), "until") + } + if args.Limit > 0 { + params.Add(jsonutils.NewInt(args.Limit), "limit") + } + if args.Offset > 0 { + params.Add(jsonutils.NewInt(args.Offset), "offset") + } + if args.Ascending && !args.Descending { + params.Add(jsonutils.NewString("asc"), "order") + } else if !args.Ascending && args.Descending { + params.Add(jsonutils.NewString("desc"), "order") + } + if len(args.Action) > 0 { + params.Add(jsonutils.NewStringArray(args.Action), "action") + } + logs, err := man.List(s, params) + if err != nil { + return err + } + printList(logs, man.GetColumns(s)) + return nil +} + +func init() { + R(&EventListOptions{}, "event-show", "Show operation event logs", doComputeEventList) + + R(&TypeEventListOptions{}, "server-event", "Show operation event logs of server", func(s *mcclient.ClientSession, args *TypeEventListOptions) error { + nargs := EventListOptions{BaseEventListOptions: args.BaseEventListOptions, Id: args.ID, Type: []string{"server"}} + return doComputeEventList(s, &nargs) + }) + + R(&TypeEventListOptions{}, "host-event", "Show operation event logs of host", func(s *mcclient.ClientSession, args *TypeEventListOptions) error { + nargs := EventListOptions{BaseEventListOptions: args.BaseEventListOptions, Id: args.ID, Type: []string{"host"}} + return doComputeEventList(s, &nargs) + }) + + R(&TypeEventListOptions{}, "vcenter-event", "Show operation event logs of vcenter", func(s *mcclient.ClientSession, args *TypeEventListOptions) error { + nargs := EventListOptions{BaseEventListOptions: args.BaseEventListOptions, Id: args.ID, Type: []string{"vcenter"}} + return doComputeEventList(s, &nargs) + }) +} diff --git a/cmd/climc/shell/groups.go b/cmd/climc/shell/groups.go new file mode 100644 index 0000000000..5f0b280add --- /dev/null +++ b/cmd/climc/shell/groups.go @@ -0,0 +1,138 @@ +package shell + +import ( + "github.com/yunionio/jsonutils" + "github.com/yunionio/mcclient" + "github.com/yunionio/mcclient/modules" +) + +func init() { + type GroupListOptions struct { + Name string `help:"Name of the groups to filter"` + Domain string `help:"Domain to filter"` + Limit int64 `help:"Items per page" default:"20"` + Offset int64 `help:"Offset"` + Search string `help:"search text"` + } + R(&GroupListOptions{}, "group-list", "List groups", func(s *mcclient.ClientSession, args *GroupListOptions) error { + params := jsonutils.NewDict() + if len(args.Name) > 0 { + params.Add(jsonutils.NewString(args.Name), "name") + } + if len(args.Domain) > 0 { + domainId, e := modules.Domains.GetId(s, args.Domain, nil) + if e != nil { + return e + } + params.Add(jsonutils.NewString(domainId), "domain_id") + } + if args.Limit > 0 { + params.Add(jsonutils.NewInt(args.Limit), "limit") + } + if args.Offset > 0 { + params.Add(jsonutils.NewInt(args.Offset), "offset") + } + if len(args.Search) > 0 { + params.Add(jsonutils.NewString(args.Search), "name__icontains") + } + result, err := modules.Groups.List(s, params) + if err != nil { + return err + } + printList(result, modules.Groups.GetColumns(s)) + return nil + }) + + type GroupShowOptions struct { + ID string `help:"ID or Name of group"` + Domain string `help:"Id or Name of domain"` + } + R(&GroupShowOptions{}, "group-show", "Show details of a group", func(s *mcclient.ClientSession, args *GroupShowOptions) error { + params := jsonutils.NewDict() + if len(args.Domain) > 0 { + domainId, err := modules.Domains.GetId(s, args.Domain, nil) + if err != nil { + return err + } + params.Add(jsonutils.NewString(domainId), "domain_id") + } + grpId, err := modules.Groups.GetId(s, args.ID, params) + if err != nil { + return err + } + result, err := modules.Groups.GetById(s, grpId, nil) + if err != nil { + return err + } + printObject(result) + return nil + }) + R(&GroupShowOptions{}, "group-user-list", "Show members of a group", func(s *mcclient.ClientSession, args *GroupShowOptions) error { + params := jsonutils.NewDict() + if len(args.Domain) > 0 { + domainId, err := modules.Domains.GetId(s, args.Domain, nil) + if err != nil { + return err + } + params.Add(jsonutils.NewString(domainId), "domain_id") + } + grpId, err := modules.Groups.GetId(s, args.ID, params) + if err != nil { + return err + } + users, err := modules.Groups.GetUsers(s, grpId) + if err != nil { + return err + } + printList(users, modules.UsersV3.GetColumns(s)) + return nil + }) + + type GroupCreateOptions struct { + NAME string `help:"Name of the group"` + Desc string `help:"Description"` + Domain string `help:"Domain ID or Name"` + } + R(&GroupCreateOptions{}, "group-create", "Create a group", func(s *mcclient.ClientSession, args *GroupCreateOptions) error { + params := jsonutils.NewDict() + params.Add(jsonutils.NewString(args.NAME), "name") + if len(args.Desc) > 0 { + params.Add(jsonutils.NewString(args.Desc), "description") + } + if len(args.Domain) > 0 { + domainId, e := modules.Domains.GetId(s, args.Domain, nil) + if e != nil { + return e + } + params.Add(jsonutils.NewString(domainId), "domain_id") + } + result, e := modules.Groups.Create(s, params) + if e != nil { + return e + } + printObject(result) + return nil + }) + + R(&GroupShowOptions{}, "group-delete", "Delete a group", func(s *mcclient.ClientSession, args *GroupShowOptions) error { + params := jsonutils.NewDict() + if len(args.Domain) > 0 { + domainId, err := modules.Domains.GetId(s, args.Domain, nil) + if err != nil { + return err + } + params.Add(jsonutils.NewString(domainId), "domain_id") + } + grpId, err := modules.Groups.GetId(s, args.ID, params) + if err != nil { + return err + } + result, err := modules.Groups.Delete(s, grpId, nil) + if err != nil { + return err + } + printObject(result) + return nil + }) + +} diff --git a/cmd/climc/shell/hostcachedimages.go b/cmd/climc/shell/hostcachedimages.go new file mode 100644 index 0000000000..7742ef04a0 --- /dev/null +++ b/cmd/climc/shell/hostcachedimages.go @@ -0,0 +1,52 @@ +package shell + +import ( + "github.com/yunionio/jsonutils" + "github.com/yunionio/mcclient" + "github.com/yunionio/mcclient/modules" +) + +func init() { + type HostCachedImageListOptions struct { + BaseListOptions + Host string `help:"ID or Name of Host"` + Image string `help:"ID or Name of image"` + } + R(&HostCachedImageListOptions{}, "host-cachedimage-list", "List host cached image pairs", func(s *mcclient.ClientSession, args *HostCachedImageListOptions) error { + params := FetchPagingParams(args.BaseListOptions) + var result *modules.ListResult + var err error + if len(args.Host) > 0 { + result, err = modules.Hostcachedimages.ListDescendent(s, args.Host, params) + } else { + result, err = modules.Hostcachedimages.List(s, params) + } + if err != nil { + return err + } + printList(result, modules.Hostcachedimages.GetColumns(s)) + return nil + }) + + type HostCachedImageUpdateOptions struct { + HOST string `help:"ID or Name of Host"` + IMAGE string `help:"ID or name of image"` + Status string `help:"Status"` + } + R(&HostCachedImageUpdateOptions{}, "host-cachedimage-update", "Update host cached image", func(s *mcclient.ClientSession, args *HostCachedImageUpdateOptions) error { + params := jsonutils.NewDict() + if len(args.Status) > 0 { + params.Add(jsonutils.NewString(args.Status), "status") + } + if params.Size() == 0 { + return InvalidUpdateError() + } + result, err := modules.Hostcachedimages.Update(s, args.HOST, args.IMAGE, params) + if err != nil { + return err + } + printObject(result) + return nil + }) + +} diff --git a/cmd/climc/shell/hosts.go b/cmd/climc/shell/hosts.go new file mode 100644 index 0000000000..539de5091a --- /dev/null +++ b/cmd/climc/shell/hosts.go @@ -0,0 +1,414 @@ +package shell + +import ( + "fmt" + + "github.com/yunionio/jsonutils" + "github.com/yunionio/mcclient" + "github.com/yunionio/mcclient/modules" +) + +func init() { + type HostListOptions struct { + Schedtag string `help:"List hosts in schedtag"` + Zone string `help:"List hosts in zone"` + Wire string `help:"List hosts in wire"` + VCenter string `help:"List hosts in vcenter"` + Image string `help:"List hosts cached images"` + Storage string `help:"List hosts attached to storages"` + Baremetal string `help:"List hosts that is managed by baremetal system" choices:"true|false"` + Empty bool `help:"show empty host"` + Occupied bool `help:"show occupid host"` + Enabled bool `help:"Show enabled host only"` + Disabled bool `help:"Show disabled host only"` + HostType string `help:"Host type filter" choices:"baremetal|hypervisor|esxi|kubelet|hyperv"` + AnyMac string `help:"Mac matches one of the host's interface"` + BaseListOptions + } + R(&HostListOptions{}, "host-list", "List hosts", func(s *mcclient.ClientSession, args *HostListOptions) error { + params := FetchPagingParams(args.BaseListOptions) + if len(args.Schedtag) > 0 { + params.Add(jsonutils.NewString(args.Schedtag), "schedtag") + } + if len(args.Zone) > 0 { + params.Add(jsonutils.NewString(args.Zone), "zone") + } + if len(args.Wire) > 0 { + params.Add(jsonutils.NewString(args.Wire), "wire") + } + if len(args.VCenter) > 0 { + params.Add(jsonutils.NewString(args.VCenter), "vcenter") + } + if len(args.Image) > 0 { + params.Add(jsonutils.NewString(args.Image), "cachedimage") + } + if len(args.Storage) > 0 { + params.Add(jsonutils.NewString(args.Storage), "storage") + } + if len(args.Baremetal) > 0 { + params.Add(jsonutils.NewString(args.Baremetal), "baremetal") + } + if len(args.HostType) > 0 { + params.Add(jsonutils.NewString(args.HostType), "host_type") + } + if args.Empty { + params.Add(jsonutils.JSONTrue, "is_empty") + } else if args.Occupied { + params.Add(jsonutils.JSONFalse, "is_empty") + } + if args.Enabled { + params.Add(jsonutils.NewInt(1), "enabled") + } else if args.Disabled { + params.Add(jsonutils.NewInt(0), "enabled") + } + if len(args.AnyMac) > 0 { + params.Add(jsonutils.NewString(args.AnyMac), "any_mac") + } + result, err := modules.Hosts.List(s, params) + if err != nil { + return err + } + printList(result, modules.Hosts.GetColumns(s)) + return nil + }) + + type HostDetailOptions struct { + ID string `help:"ID or name of host"` + } + R(&HostDetailOptions{}, "host-show", "Show details of a host", func(s *mcclient.ClientSession, args *HostDetailOptions) error { + result, err := modules.Hosts.Get(s, args.ID, nil) + if err != nil { + return err + } + printObject(result) + return nil + }) + + R(&HostDetailOptions{}, "host-ping", "Ping a host", func(s *mcclient.ClientSession, args *HostDetailOptions) error { + result, err := modules.Hosts.PerformAction(s, args.ID, "ping", nil) + if err != nil { + return err + } + printObject(result) + return nil + }) + + R(&HostDetailOptions{}, "host-metadata", "Show metadata of a host", func(s *mcclient.ClientSession, args *HostDetailOptions) error { + result, err := modules.Hosts.GetMetadata(s, args.ID, nil) + if err != nil { + return err + } + printObject(result) + return nil + }) + + R(&HostDetailOptions{}, "host-enable", "Enable a host", func(s *mcclient.ClientSession, args *HostDetailOptions) error { + result, err := modules.Hosts.PerformAction(s, args.ID, "enable", nil) + if err != nil { + return err + } + printObject(result) + return nil + }) + + R(&HostDetailOptions{}, "host-disable", "Disable a host", func(s *mcclient.ClientSession, args *HostDetailOptions) error { + result, err := modules.Hosts.PerformAction(s, args.ID, "disable", nil) + if err != nil { + return err + } + printObject(result) + return nil + }) + + R(&HostDetailOptions{}, "host-syncstatus", "Synchronize status of a host", func(s *mcclient.ClientSession, args *HostDetailOptions) error { + result, err := modules.Hosts.PerformAction(s, args.ID, "syncstatus", nil) + if err != nil { + return err + } + printObject(result) + return nil + }) + + R(&HostDetailOptions{}, "host-prepare", "Prepare a host for installation", func(s *mcclient.ClientSession, args *HostDetailOptions) error { + result, err := modules.Hosts.PerformAction(s, args.ID, "prepare", nil) + if err != nil { + return err + } + printObject(result) + return nil + }) + + R(&HostDetailOptions{}, "host-ipmi", "Get IPMI information of a host", func(s *mcclient.ClientSession, args *HostDetailOptions) error { + result, err := modules.Hosts.GetSpecific(s, args.ID, "ipmi", nil) + if err != nil { + return err + } + printObject(result) + return nil + }) + + R(&HostDetailOptions{}, "host-logininfo", "Get SSH login information of a host", func(s *mcclient.ClientSession, args *HostDetailOptions) error { + srvid, e := modules.Hosts.GetId(s, args.ID, nil) + if e != nil { + return e + } + i, e := modules.Hosts.GetLoginInfo(s, srvid, nil) + if e != nil { + return e + } + printObject(i) + return nil + }) + + R(&HostDetailOptions{}, "host-vnc", "Get VNC information of a host", func(s *mcclient.ClientSession, args *HostDetailOptions) error { + result, err := modules.Hosts.GetSpecific(s, args.ID, "vnc", nil) + if err != nil { + return err + } + printObject(result) + return nil + }) + + type HostUpdateOptions struct { + ID string `help:"ID or Name of Host"` + Name string `help:"New name of the host"` + Desc string `help:"New Description of the host"` + CpuCommitBound float64 `help:"CPU overcommit upper bound at this host"` + MemoryCommitBound float64 `help:"Memory overcommit upper bound at this host"` + MemoryReserved string `help:"Memory reserved"` + CpuReserved int64 `help:"CPU reserved"` + HostType string `help:"Change host type, CAUTION!!!!" choices:"hypervisor|kubelet|esxi|baremetal"` + AccessIp string `help:"Change access ip, CAUTION!!!!"` + } + R(&HostUpdateOptions{}, "host-update", "Update information of a host", func(s *mcclient.ClientSession, args *HostUpdateOptions) error { + params := jsonutils.NewDict() + if len(args.Name) > 0 { + params.Add(jsonutils.NewString(args.Name), "name") + } + if len(args.Desc) > 0 { + params.Add(jsonutils.NewString(args.Desc), "description") + } + if args.CpuCommitBound > 0.0 { + params.Add(jsonutils.NewFloat(args.CpuCommitBound), "cpu_cmtbound") + } + if args.MemoryCommitBound > 0.0 { + params.Add(jsonutils.NewFloat(args.MemoryCommitBound), "mem_cmtbound") + } + if len(args.MemoryReserved) > 0 { + params.Add(jsonutils.NewString(args.MemoryReserved), "mem_reserved") + } + if args.CpuReserved > 0 { + params.Add(jsonutils.NewInt(args.CpuReserved), "cpu_reserved") + } + if len(args.HostType) > 0 { + params.Add(jsonutils.NewString(args.HostType), "host_type") + } + if len(args.AccessIp) > 0 { + params.Add(jsonutils.NewString(args.AccessIp), "access_ip") + } + if params.Size() == 0 { + return fmt.Errorf("Not data to update") + } + result, err := modules.Hosts.Update(s, args.ID, params) + if err != nil { + return err + } + printObject(result) + return nil + }) + + type HostConvertOptions struct { + ID string `help:"Host ID or Name"` + Name string `help:"New name of the converted host"` + HOSTTYPE string `help:"Convert host type" choices:"hypervisor|esxi|kubelet|hyperv"` + Image string `help:"Template image to install"` + Raid string `help:"Raid to deploy" choices:"raid0|raid1|raid10|raid5|none"` + RaidConfig []string `help:"Baremetal raid config"` + Disk []string `help:"Disk descriptions" metavar:"DISK"` + Net []string `help:"Network descriptions" metavar:"NETWORK"` + } + R(&HostConvertOptions{}, "host-convert-hypervisor", "Convert a baremetal into a hypervisor", func(s *mcclient.ClientSession, args *HostConvertOptions) error { + params := jsonutils.NewDict() + params.Add(jsonutils.NewString(args.HOSTTYPE), "host_type") + if len(args.Name) > 0 { + params.Add(jsonutils.NewString(args.Name), "name") + } + if len(args.RaidConfig) > 0 && len(args.Raid) > 0 { + return fmt.Errorf("Cannot specifiy raidconfig and raid simultaneously") + } else if len(args.RaidConfig) > 0 { + for i := 0; i < len(args.RaidConfig); i += 1 { + params.Add(jsonutils.NewString(args.RaidConfig[i]), fmt.Sprintf("baremetal_disk_config.%d", i)) + } + } else if len(args.Raid) > 0 { + params.Add(jsonutils.NewString(args.Raid), "raid") + } + if len(args.Disk) > 0 && len(args.Image) > 0 { + return fmt.Errorf("Cannot specify disk and image simultaneously") + } else if len(args.Disk) > 0 { + for i := 0; i < len(args.Disk); i += 1 { + params.Add(jsonutils.NewString(args.Disk[i]), fmt.Sprintf("disk.%d", i)) + } + } else if len(args.Image) > 0 { + params.Add(jsonutils.NewString(args.Image), "image") + } + if len(args.Net) > 0 { + for i := 0; i < len(args.Net); i += 1 { + params.Add(jsonutils.NewString(args.Net[i]), fmt.Sprintf("net.%d", i)) + } + } + result, err := modules.Hosts.PerformAction(s, args.ID, "convert-hypervisor", params) + if err != nil { + return err + } + printObject(result) + return nil + }) + + R(&HostDetailOptions{}, "host-undo-convert", "Undo converting a host to hypervisor", func(s *mcclient.ClientSession, args *HostDetailOptions) error { + result, err := modules.Hosts.PerformAction(s, args.ID, "undo-convert", nil) + if err != nil { + return err + } + printObject(result) + return nil + }) + + R(&HostDetailOptions{}, "host-maintenance", "Reboot host into PXE offline OS, do maintenance jobs", func(s *mcclient.ClientSession, args *HostDetailOptions) error { + result, err := modules.Hosts.PerformAction(s, args.ID, "maintenance", nil) + if err != nil { + return err + } + printObject(result) + return nil + }) + + R(&HostDetailOptions{}, "host-unmaintenance", "Reboot host back into disk installed OS", func(s *mcclient.ClientSession, args *HostDetailOptions) error { + result, err := modules.Hosts.PerformAction(s, args.ID, "unmaintenance", nil) + if err != nil { + return err + } + printObject(result) + return nil + }) + + R(&HostDetailOptions{}, "host-start", "Power on host", func(s *mcclient.ClientSession, args *HostDetailOptions) error { + result, err := modules.Hosts.PerformAction(s, args.ID, "start", nil) + if err != nil { + return err + } + printObject(result) + return nil + }) + + R(&HostDetailOptions{}, "host-stop", "Power on host", func(s *mcclient.ClientSession, args *HostDetailOptions) error { + result, err := modules.Hosts.PerformAction(s, args.ID, "stop", nil) + if err != nil { + return err + } + printObject(result) + return nil + }) + + R(&HostDetailOptions{}, "host-reset", "Power reset host", func(s *mcclient.ClientSession, args *HostDetailOptions) error { + result, err := modules.Hosts.PerformAction(s, args.ID, "reset", nil) + if err != nil { + return err + } + printObject(result) + return nil + }) + + R(&HostDetailOptions{}, "host-delete", "Delete host record", func(s *mcclient.ClientSession, args *HostDetailOptions) error { + result, err := modules.Hosts.Delete(s, args.ID, nil) + if err != nil { + return err + } + printObject(result) + return nil + }) + + type HostAddNetIfOptions struct { + ID string `help:"ID or Name of host"` + WIRE string `help:"ID or Name of wire to attach"` + MAC string `help:"Mac address of NIC"` + Type string `help:"Nic type" choices:"admin|ipmi"` + IpAddr string `help:"IP address"` + } + R(&HostAddNetIfOptions{}, "host-add-netif", "Host add a NIC", func(s *mcclient.ClientSession, args *HostAddNetIfOptions) error { + params := jsonutils.NewDict() + params.Add(jsonutils.NewString(args.WIRE), "wire") + params.Add(jsonutils.NewString(args.MAC), "mac") + params.Add(jsonutils.JSONTrue, "link_up") + if len(args.Type) > 0 { + params.Add(jsonutils.NewString(args.Type), "nic_type") + } + if len(args.IpAddr) > 0 { + params.Add(jsonutils.NewString(args.IpAddr), "ip_addr") + } + result, err := modules.Hosts.PerformAction(s, args.ID, "add-netif", params) + if err != nil { + return err + } + printObject(result) + return nil + }) + + type HostRemoveNetIfOptions struct { + ID string `help:"ID or Name of host"` + MAC string `help:"MAC of NIC to remove"` + } + R(&HostRemoveNetIfOptions{}, "host-remove-netif", "Remove NIC from host", func(s *mcclient.ClientSession, args *HostRemoveNetIfOptions) error { + params := jsonutils.NewDict() + params.Add(jsonutils.NewString(args.MAC), "mac") + result, err := modules.Hosts.PerformAction(s, args.ID, "remove-netif", params) + if err != nil { + return err + } + printObject(result) + return nil + }) + + R(&HostDetailOptions{}, "host-remove-all-netifs", "Remvoe all netifs expect admin&ipmi netifs", func(s *mcclient.ClientSession, args *HostDetailOptions) error { + result, err := modules.Hosts.PerformAction(s, args.ID, "remove-all-netifs", nil) + if err != nil { + return err + } + printObject(result) + return nil + }) + + type HostCacheImageActionOptions struct { + ID string `help:"ID or name of host"` + IMAGE string `help:"ID or name of image"` + Force bool `help:"Force refresh cache, even if the image exists in cache"` + } + R(&HostCacheImageActionOptions{}, "host-cache-image", "Ask a host to cache a image", func(s *mcclient.ClientSession, args *HostCacheImageActionOptions) error { + params := jsonutils.NewDict() + params.Add(jsonutils.NewString(args.IMAGE), "image") + if args.Force { + params.Add(jsonutils.JSONTrue, "is_force") + } + host, err := modules.Hosts.PerformAction(s, args.ID, "cache-image", params) + if err != nil { + return err + } + printObject(host) + return nil + }) + + type HostUncacheImageActionOptions struct { + ID string `help:"ID or name of host"` + IMAGE string `help:"ID or name of image"` + } + R(&HostUncacheImageActionOptions{}, "host-uncache-image", "Ask a host to remove image from a cache", func(s *mcclient.ClientSession, args *HostUncacheImageActionOptions) error { + params := jsonutils.NewDict() + params.Add(jsonutils.NewString(args.IMAGE), "image") + host, err := modules.Hosts.PerformAction(s, args.ID, "uncache-image", params) + if err != nil { + return err + } + printObject(host) + return nil + }) + +} diff --git a/cmd/climc/shell/hoststorages.go b/cmd/climc/shell/hoststorages.go new file mode 100644 index 0000000000..a466de7e8a --- /dev/null +++ b/cmd/climc/shell/hoststorages.go @@ -0,0 +1,77 @@ +package shell + +import ( + "github.com/yunionio/jsonutils" + "github.com/yunionio/mcclient" + "github.com/yunionio/mcclient/modules" +) + +func init() { + type HostStorageListOptions struct { + BaseListOptions + Host string `help:"ID or Name of Host"` + Storage string `help:"ID or Name of Storage"` + } + R(&HostStorageListOptions{}, "host-storage-list", "List host storage pairs", func(s *mcclient.ClientSession, args *HostStorageListOptions) error { + params := FetchPagingParams(args.BaseListOptions) + var result *modules.ListResult + var err error + if len(args.Storage) > 0 { + params.Add(jsonutils.NewString(args.Storage), "storage") + } + if len(args.Host) > 0 { + result, err = modules.Hoststorages.ListDescendent(s, args.Host, params) + } else if len(args.Storage) > 0 { + result, err = modules.Hoststorages.ListDescendent2(s, args.Storage, params) + } else { + result, err = modules.Hoststorages.List(s, params) + } + if err != nil { + return err + } + printList(result, modules.Hoststorages.GetColumns(s)) + return nil + }) + + type HostStorageDetailOptions struct { + HOST string `help:"ID or Name of Host"` + STORAGE string `help:"ID or Name of Storage"` + } + R(&HostStorageDetailOptions{}, "host-storage-show", "Show host storage details", func(s *mcclient.ClientSession, args *HostStorageDetailOptions) error { + result, err := modules.Hoststorages.Get(s, args.HOST, args.STORAGE, nil) + if err != nil { + return err + } + printObject(result) + return nil + }) + + R(&HostStorageDetailOptions{}, "host-storage-detach", "Detach a storage from a host", func(s *mcclient.ClientSession, args *HostStorageDetailOptions) error { + result, err := modules.Hoststorages.Detach(s, args.HOST, args.STORAGE) + if err != nil { + return err + } + printObject(result) + return nil + }) + + type HostStorageAttachOptions struct { + HOST string `help:"ID or Name of Host"` + STORAGE string `help:"ID or Name of Storage"` + MountPoint string `help:"MountPoint of Storage"` + } + + R(&HostStorageAttachOptions{}, "host-storage-attach", "Attach a storage to a host", func(s *mcclient.ClientSession, args *HostStorageAttachOptions) error { + params := jsonutils.NewDict() + if args.MountPoint != "" { + params.Add(jsonutils.NewString(args.MountPoint), "mount_point") + } + result, err := modules.Hoststorages.Attach(s, args.HOST, args.STORAGE, params) + if err != nil { + return err + } + printObject(result) + return nil + }) + +} diff --git a/cmd/climc/shell/hostwires.go b/cmd/climc/shell/hostwires.go new file mode 100644 index 0000000000..a69ea7011b --- /dev/null +++ b/cmd/climc/shell/hostwires.go @@ -0,0 +1,90 @@ +package shell + +import ( + "github.com/yunionio/jsonutils" + "github.com/yunionio/mcclient" + "github.com/yunionio/mcclient/modules" +) + +func init() { + type HostWireListOptions struct { + BaseListOptions + Host string `help:"ID or Name of Host"` + } + R(&HostWireListOptions{}, "host-wire-list", "List host wire", func(s *mcclient.ClientSession, args *HostWireListOptions) error { + params := FetchPagingParams(args.BaseListOptions) + var result *modules.ListResult + var err error + if len(args.Host) > 0 { + result, err = modules.Hostwires.ListDescendent(s, args.Host, params) + } else { + result, err = modules.Hostwires.List(s, params) + } + if err != nil { + return err + } + printList(result, modules.Hostwires.GetColumns(s)) + return nil + }) + + type HostWireDetailOptions struct { + HOST string `help:"ID or Name of Host"` + WIRE string `help:"ID or Name of Wire"` + } + R(&HostWireDetailOptions{}, "host-wire-show", "Show host wire details", func(s *mcclient.ClientSession, args *HostWireDetailOptions) error { + result, err := modules.Hostwires.Get(s, args.HOST, args.WIRE, nil) + if err != nil { + return err + } + printObject(result) + return nil + }) + + type HostWireUpdateOptions struct { + HOST string `help:"ID or Name of Host"` + WIRE string `help:"ID or Name of Wire"` + Mac string `help:"Mac address"` + Interface string `help:"Interface"` + Bridge string `help:"Bridge"` + IsMaster string `help:"Master interface" choices:"true|false"` + } + R(&HostWireUpdateOptions{}, "host-wire-update", "Update host wire information", func(s *mcclient.ClientSession, args *HostWireUpdateOptions) error { + params := jsonutils.NewDict() + if len(args.Mac) > 0 { + params.Add(jsonutils.NewString(args.Mac), "mac_addr") + } + if len(args.Interface) > 0 { + params.Add(jsonutils.NewString(args.Interface), "interface") + } + if len(args.Bridge) > 0 { + params.Add(jsonutils.NewString(args.Bridge), "bridge") + } + if len(args.IsMaster) > 0 { + if args.IsMaster == "true" { + params.Add(jsonutils.JSONTrue, "is_master") + } else { + params.Add(jsonutils.JSONFalse, "is_master") + } + } + result, err := modules.Hostwires.Update(s, args.HOST, args.WIRE, params) + if err != nil { + return err + } + printObject(result) + return nil + }) + + type HostWireDetachOptions struct { + HOST string `help:"ID or Name of Host"` + WIRE string `help:"ID or Name of Wire"` + } + R(&HostWireDetachOptions{}, "host-wire-detach", "Detach host from wire", func(s *mcclient.ClientSession, args *HostWireDetachOptions) error { + result, err := modules.Hostwires.Detach(s, args.HOST, args.WIRE) + if err != nil { + return err + } + printObject(result) + return nil + }) + +} diff --git a/cmd/climc/shell/images.go b/cmd/climc/shell/images.go new file mode 100644 index 0000000000..37c399d28b --- /dev/null +++ b/cmd/climc/shell/images.go @@ -0,0 +1,398 @@ +package shell + +import ( + "fmt" + "io" + "os" + "strings" + + "github.com/yunionio/jsonutils" + "github.com/yunionio/mcclient" + "github.com/yunionio/mcclient/modules" +) + +type ImageOptionalOptions struct { + Public bool `help:"Make image public"` + Private bool `help:"Make image private"` + Format string `help:"Image format" choices:"raw|qcow2|iso|vmdk|docker|vhd"` + Protected bool `help:"Prevent image from being deleted"` + Unprotected bool `help:"Allow image to be deleted"` + MinDisk int64 `help:"Disk size after expanded, in MB" metavar:"MIN_DISK_SIZE_MB"` + MinRam int64 `help:"Minimal memory size required" metavar:"MIN_RAM_MB"` + VirtualSize int64 `help:"Disk size after expanded, in MB"` + Size int64 `help:"Disk size, in MB"` + Location string `help:"Image location"` + Status string `help:"Image status" choices:"killed|active|queued"` + OwnerProject string `help:"Owner project Id or Name"` + OwnerProjectDomain string `help:"Owner project Domain"` + OsType string `help:"Type of OS" choices:"Windows|Linux|Freebsd|Android|macOS|VMWare"` + OsDist string `help:"Distribution name of OS" metavar:"OS_DISTRIBUTION"` + OsVersion string `help:"Version of OS"` + OsCodename string `help:"Codename of OS"` + OsArch string `help:"Os hardware architecture" choices:"x86|x86_64"` + OsLang string `help:"OS Language" choices:"zh_CN|en_US"` + Preference int64 `help:"Disk preferences"` + Notes string `help:"Notes about the image"` + Hypervisor []string `help:"Prefer hypervisor type" choices:"kvm|esxi|baremetal|container"` + DiskDriver string `help:"Perfer disk driver" choices:"virtio|scsi|pvscsi|ide|sata"` + NetDriver string `help:"Preferred network driver" choices:"virtio|e1000|vmxnet3"` +} + +func addImageOptionalOptions(s *mcclient.ClientSession, params *jsonutils.JSONDict, args ImageOptionalOptions) error { + if args.Public && !args.Private { + params.Add(jsonutils.NewString("true"), "is-public") + } else if !args.Public && args.Private { + params.Add(jsonutils.NewString("false"), "is-public") + } + if len(args.Format) > 0 { + params.Add(jsonutils.NewString("bare"), "container-format") + params.Add(jsonutils.NewString(args.Format), "disk-format") + } + if args.Protected && !args.Unprotected { + params.Add(jsonutils.NewString("true"), "protected") + } else if !args.Protected && args.Unprotected { + params.Add(jsonutils.NewString("false"), "protected") + } + if args.MinDisk > 0 { + params.Add(jsonutils.NewString(fmt.Sprintf("%d", args.MinDisk)), "min_disk") + } + if args.MinRam > 0 { + params.Add(jsonutils.NewString(fmt.Sprintf("%d", args.MinRam)), "min_ram") + } + if args.Size > 0 { + params.Add(jsonutils.NewString(fmt.Sprintf("%d", args.Size*1024*1024)), "size") + } + if args.VirtualSize > 0 { + params.Add(jsonutils.NewString(fmt.Sprintf("%d", args.VirtualSize)), "min_disk") + } + if len(args.Location) > 0 { + params.Add(jsonutils.NewString(args.Location), "location") + } + if len(args.Status) > 0 { + params.Add(jsonutils.NewString(args.Status), "status") + } + if len(args.OwnerProject) > 0 { + projectId, e := modules.Projects.GetId(s, args.OwnerProject, nil) + if e != nil { + return e + } + params.Add(jsonutils.NewString(projectId), "owner") + } + if len(args.OsType) > 0 { + params.Add(jsonutils.NewString(args.OsType), "properties", "os_type") + } + if len(args.OsDist) > 0 { + params.Add(jsonutils.NewString(args.OsDist), "properties", "os_distribution") + } + if len(args.OsVersion) > 0 { + params.Add(jsonutils.NewString(args.OsVersion), "properties", "os_version") + } + if len(args.OsCodename) > 0 { + params.Add(jsonutils.NewString(args.OsCodename), "properties", "os_codename") + } + if len(args.OsArch) > 0 { + params.Add(jsonutils.NewString(args.OsArch), "properties", "os_arch") + } + if len(args.OsLang) > 0 { + params.Add(jsonutils.NewString(args.OsLang), "properties", "os_language") + } + if args.Preference > 0 { + params.Add(jsonutils.NewString(fmt.Sprintf("%d", args.Preference)), "properties", "preference") + } + if len(args.Notes) > 0 { + params.Add(jsonutils.NewString(args.Notes), "properties", "notes") + } + if len(args.DiskDriver) > 0 { + params.Add(jsonutils.NewString(args.DiskDriver), "properties", "disk_driver") + } + if len(args.NetDriver) > 0 { + params.Add(jsonutils.NewString(args.NetDriver), "properties", "net_driver") + } + if len(args.Hypervisor) > 0 { + params.Add(jsonutils.NewString(strings.Join(args.Hypervisor, ",")), "properties", "hypervisor") + } + return nil +} + +func init() { + type ImageListOptions struct { + Tenant string `help:"Tenant id of image owner"` + IsPublic string `help:"filter images public or not(True, False or None)" choices:"true|false|none"` + Admin bool `help:"Show images of all tenants, ADMIN only"` + PendingDelete bool `help:"Show pending deleted images"` + Limit int64 `help:"Max items show, 0 means no limit"` + Offset int64 `help:"Pagination offset, default 0"` + Format []string `help:"Disk formats"` + Search string `help:"Search text"` + Marker string `help:"The last Image ID of the previous page"` + Name string `help:"Name filter"` + Details bool `help:"Show details"` + } + R(&ImageListOptions{}, "image-list", "List images", func(s *mcclient.ClientSession, args *ImageListOptions) error { + params := jsonutils.NewDict() + if len(args.IsPublic) > 0 { + params.Add(jsonutils.NewString(args.IsPublic), "is_public") + } + if args.PendingDelete { + params.Add(jsonutils.JSONTrue, "pending_delete") + } + if !args.Admin && len(args.Tenant) == 0 { + if s.IsSystemAdmin() { + params.Add(jsonutils.NewString(s.GetTenantId()), "owner") + } + } else if !s.IsSystemAdmin() { + return fmt.Errorf("System admin ONLY options") + } else if len(args.Tenant) > 0 { + tid, e := modules.Projects.GetId(s, args.Tenant, nil) + if e != nil { + return e + } + params.Add(jsonutils.NewString(tid), "owner") + } + if len(args.Name) > 0 { + params.Add(jsonutils.NewString(args.Name), "name") + } + if len(args.Marker) > 0 { + params.Add(jsonutils.NewString(args.Marker), "marker") + } + if args.Limit > 0 { + params.Add(jsonutils.NewInt(args.Limit), "limit") + } + if args.Offset > 0 { + params.Add(jsonutils.NewInt(args.Offset), "offset") + } + if len(args.Search) > 0 { + params.Add(jsonutils.NewString(args.Search), "search") + } + if len(args.Format) > 0 { + if len(args.Format) == 1 { + params.Add(jsonutils.NewString(args.Format[0]), "disk_format") + } else { + fs := jsonutils.NewArray() + for _, f := range args.Format { + fs.Add(jsonutils.NewString(f)) + } + params.Add(fs, "disk_formats") + } + } + if args.Details { + params.Add(jsonutils.JSONTrue, "details") + } else { + params.Add(jsonutils.JSONFalse, "details") + } + result, err := modules.Images.List(s, params) + if err != nil { + return err + } + printList(result, modules.Images.GetColumns(s)) + return nil + }) + + type ImageShowOptions struct { + ID []string `help:"Image id or name" metavar:"IMAGE"` + } + R(&ImageShowOptions{}, "image-show", "Show details of a image", func(s *mcclient.ClientSession, args *ImageShowOptions) error { + if len(args.ID) == 0 { + return fmt.Errorf("No image ID provided") + } else if len(args.ID) == 1 { + result, e := modules.Images.Get(s, args.ID[0], nil) + if e != nil { + return e + } + printObject(result) + } else { + sr := modules.Images.BatchGet(s, args.ID, nil) + printBatchResults(sr, modules.Images.GetColumns(s)) + } + return nil + }) + + type ImageUpdateOptions struct { + ID string `help:"ID or Name of Image"` + Name string `help:"New name of the image"` + ImageOptionalOptions + } + + R(&ImageUpdateOptions{}, "image-update", "Update images meta infomation", func(s *mcclient.ClientSession, args *ImageUpdateOptions) error { + img, e := modules.Images.Get(s, args.ID, nil) + if e != nil { + return e + } + idstr, e := img.GetString("id") + if e != nil { + return e + } + params := jsonutils.NewDict() + properties, _ := img.Get("properties") + if properties != nil { + params.Add(properties, "properties") + } + if len(args.Name) > 0 { + params.Add(jsonutils.NewString(args.Name), "name") + } + e = addImageOptionalOptions(s, params, args.ImageOptionalOptions) + if e != nil { + return e + } + img, e = modules.Images.Update(s, idstr, params) + if e != nil { + return e + } + printObject(img) + return nil + }) + + type ImageMembershipOptions struct { + IMAGE string `help:"ID or name of image to share"` + PROJECT string `help:"ID or name of project to share image with"` + } + type ImageMembershipAddOptions struct { + ImageMembershipOptions + CanShare bool `help:"Indicating whether the project can share the image with others"` + } + R(&ImageMembershipAddOptions{}, "image-add-project", "Add a project to private image's membership list", func(s *mcclient.ClientSession, args *ImageMembershipAddOptions) error { + return modules.Images.AddMembership(s, args.IMAGE, args.PROJECT, args.CanShare) + }) + + R(&ImageMembershipOptions{}, "image-remove-project", "Remove a project from private image's membership list", func(s *mcclient.ClientSession, args *ImageMembershipOptions) error { + return modules.Images.RemoveMembership(s, args.IMAGE, args.PROJECT) + }) + + type ImageDetailOptions struct { + ID string `help:"Image ID or name"` + } + + R(&ImageDetailOptions{}, "image-delete", "Delete a image", func(s *mcclient.ClientSession, args *ImageDetailOptions) error { + imgID, err := modules.Images.GetId(s, args.ID, nil) + if err != nil { + return err + } + if result, err := modules.Images.Delete(s, imgID, nil); err != nil { + return err + } else { + printObject(result) + } + return nil + }) + + R(&ImageDetailOptions{}, "image-list-project", "List image members", func(s *mcclient.ClientSession, args *ImageDetailOptions) error { + imgId, e := modules.Images.GetId(s, args.ID, nil) + if e != nil { + return e + } + result, e := modules.Images.ListMemberProjects(s, imgId) + if e != nil { + return e + } + printList(result, modules.Projects.GetColumns(s)) + return nil + }) + + type ImageCancelDeleteOptions struct { + ID string `help:"Image id or name" metavar:"IMAGE"` + } + R(&ImageCancelDeleteOptions{}, "image-cancel-delete", "Cancel pending delete images", func(s *mcclient.ClientSession, args *ImageCancelDeleteOptions) error { + if image, e := modules.Images.PerformAction(s, args.ID, "cancel-delete", nil); e != nil { + return e + } else { + printObject(image) + } + return nil + }) + + type ImageUploadOptions struct { + NAME string `help:"Image Name"` + FILE string `help:"The local image filename to Upload"` + ImageOptionalOptions + } + R(&ImageUploadOptions{}, "image-upload", "Upload a local image", func(s *mcclient.ClientSession, args *ImageUploadOptions) error { + params := jsonutils.NewDict() + params.Add(jsonutils.NewString(args.NAME), "name") + if len(args.Format) == 0 { + return fmt.Errorf("Please specify image format") + } + if len(args.OsType) == 0 { + return fmt.Errorf("Please specify OS type") + } + err := addImageOptionalOptions(s, params, args.ImageOptionalOptions) + if err != nil { + return err + } + f, err := os.Open(args.FILE) + if err != nil { + return err + } + defer f.Close() + finfo, err := f.Stat() + if err != nil { + return err + } + size := finfo.Size() + img, err := modules.Images.Upload(s, params, f, size) + if err != nil { + return err + } + printObject(img) + return nil + }) + + type ImageImportOptions struct { + ImageOptionalOptions + NAME string `help:"Image Name"` + COPYFROM string `help:"Image external location url"` + } + R(&ImageImportOptions{}, "image-import", "Import a external image", func(s *mcclient.ClientSession, args *ImageImportOptions) error { + params := jsonutils.NewDict() + params.Add(jsonutils.NewString(args.NAME), "name") + if len(args.Format) == 0 { + return fmt.Errorf("Please specify image format") + } + err := addImageOptionalOptions(s, params, args.ImageOptionalOptions) + if err != nil { + return err + } + + params.Add(jsonutils.NewString(args.COPYFROM), "copy_from") + img, err := modules.Images.Create(s, params) + if err != nil { + return err + } + printObject(img) + return nil + }) + + type ImageDownloadOptions struct { + ID string `help:"ID or Name of image"` + Output string `help:"Destination file, if omitted, output to stdout"` + } + R(&ImageDownloadOptions{}, "image-download", "Download image data to a file or stdout", func(s *mcclient.ClientSession, args *ImageDownloadOptions) error { + imgId, err := modules.Images.GetId(s, args.ID, nil) + if err != nil { + return err + } + var sink io.Writer + if len(args.Output) > 0 { + f, err := os.Create(args.Output) + if err != nil { + return err + } + defer f.Close() + sink = f + } else { + sink = os.Stdout + } + meta, src, err := modules.Images.Download(s, imgId) + if err != nil { + return err + } + _, e := io.Copy(sink, src) + if e != nil { + return e + } + if len(args.Output) > 0 { + printObject(meta) + } + return nil + }) + +} diff --git a/cmd/climc/shell/instances.go b/cmd/climc/shell/instances.go new file mode 100644 index 0000000000..d630df3220 --- /dev/null +++ b/cmd/climc/shell/instances.go @@ -0,0 +1,21 @@ +package shell + +import ( + "github.com/yunionio/mcclient" + "github.com/yunionio/mcclient/modules" +) + +func init() { + type InstanceListOptions struct { + BaseListOptions + } + R(&InstanceListOptions{}, "instance-list", "List instances", func(s *mcclient.ClientSession, suboptions *InstanceListOptions) error { + params := FetchPagingParams(suboptions.BaseListOptions) + result, err := modules.Instances.List(s, params) + if err != nil { + return err + } + printList(result, modules.Instances.GetColumns(s)) + return nil + }) +} diff --git a/cmd/climc/shell/isolatedevices.go b/cmd/climc/shell/isolatedevices.go new file mode 100644 index 0000000000..ce68a91e31 --- /dev/null +++ b/cmd/climc/shell/isolatedevices.go @@ -0,0 +1,55 @@ +package shell + +import ( + "github.com/yunionio/jsonutils" + "github.com/yunionio/mcclient" + "github.com/yunionio/mcclient/modules" +) + +func init() { + type DeviceListOptions struct { + BaseListOptions + Unused bool `help:"Only show unused devices"` + Gpu bool `help:"Only show gpu devices"` + Host string `help:"Host ID or Name"` + } + R(&DeviceListOptions{}, "isolated-device-list", "List isolated devices like GPU", func(s *mcclient.ClientSession, args *DeviceListOptions) error { + params := FetchPagingParams(args.BaseListOptions) + if len(args.Host) > 0 { + params.Add(jsonutils.NewString(args.Host), "host") + } + if args.Unused { + params.Add(jsonutils.JSONTrue, "unused") + } + if args.Gpu { + params.Add(jsonutils.JSONTrue, "gpu") + } + result, err := modules.IsolatedDevices.List(s, params) + if err != nil { + return err + } + printList(result, modules.IsolatedDevices.GetColumns(s)) + return nil + }) + + type DeviceShowOptions struct { + ID string `help:"ID of the isolated device"` + } + R(&DeviceShowOptions{}, "isolated-device-show", "Show isolated device details", func(s *mcclient.ClientSession, args *DeviceShowOptions) error { + result, err := modules.IsolatedDevices.Get(s, args.ID, nil) + if err != nil { + return err + } + printObject(result) + return nil + }) + + R(&DeviceShowOptions{}, "isolated-device-delete", "Delete a isolated device", func(s *mcclient.ClientSession, args *DeviceShowOptions) error { + result, err := modules.IsolatedDevices.Delete(s, args.ID, nil) + if err != nil { + return err + } + printObject(result) + return nil + }) +} diff --git a/cmd/climc/shell/keypairs.go b/cmd/climc/shell/keypairs.go new file mode 100644 index 0000000000..1fcbe656a6 --- /dev/null +++ b/cmd/climc/shell/keypairs.go @@ -0,0 +1,152 @@ +package shell + +import ( + "fmt" + "io/ioutil" + + "github.com/yunionio/jsonutils" + "github.com/yunionio/mcclient" + "github.com/yunionio/mcclient/modules" +) + +func init() { + type KeypairList struct { + BaseListOptions + } + + R(&KeypairList{}, "keypair-list", "List keypairs.", func(s *mcclient.ClientSession, args *KeypairList) error { + params := FetchPagingParams(args.BaseListOptions) + + result, err := modules.Keypairs.List(s, params) + if err != nil { + return err + } + + printList(result, modules.Keypairs.GetColumns(s)) + return nil + }) + + type KeypairCreate struct { + NAME string `help:"Name of keypair to be created"` + Scheme string `help:"Scheme of keypair, RSA or DSA, default is RSA" choices:"RSA|DSA" default:"RSA"` + Desc string `help:"Short description of keypair"` + } + + R(&KeypairCreate{}, "keypair-create", "Create a new keypair", func(s *mcclient.ClientSession, args *KeypairCreate) error { + params := jsonutils.NewDict() + params.Add(jsonutils.NewString(args.NAME), "name") + if len(args.Scheme) > 0 { + params.Add(jsonutils.NewString(args.Scheme), "scheme") + } + + if len(args.Desc) > 0 { + params.Add(jsonutils.NewString(args.Desc), "description") + } + + result, e := modules.Keypairs.Create(s, params) + if e != nil { + return e + } + printObject(result) + return nil + }) + + type KeypairUpdate struct { + ID string `help:"ID of keypair to be updated"` + Name string `help:"New name of keypair"` + Desc string `help:"Short description of keypair"` + } + + R(&KeypairUpdate{}, "keypair-update", "Update a keypair", func(s *mcclient.ClientSession, args *KeypairUpdate) error { + params := jsonutils.NewDict() + if len(args.Name) > 0 { + params.Add(jsonutils.NewString(args.Name), "name") + } + + if len(args.Desc) > 0 { + params.Add(jsonutils.NewString(args.Desc), "description") + } + + result, e := modules.Keypairs.Update(s, args.ID, params) + if e != nil { + return e + } + printObject(result) + return nil + }) + + type KeypairDelete struct { + ID string `help:"ID of keypair to be deleted"` + } + + R(&KeypairDelete{}, "keypair-delete", "Delete a keypair", func(s *mcclient.ClientSession, args *KeypairDelete) error { + result, e := modules.Keypairs.Delete(s, args.ID, nil) + if e != nil { + return e + } + printObject(result) + return nil + }) + + type KeypairShow struct { + ID string `help:"ID of keypair to be shown"` + } + + R(&KeypairShow{}, "keypair-show", "Show details of a keypair", func(s *mcclient.ClientSession, args *KeypairShow) error { + result, e := modules.Keypairs.Get(s, args.ID, nil) + if e != nil { + return e + } + printObject(result) + return nil + }) + + type KeypairImport struct { + NAME string `help:"Name of keypair to be imported"` + PublicKey string `help:"Filename of public key file, or public key can be supplied via stdin"` + Desc string `help:"Short description of keypair"` + } + + R(&KeypairImport{}, "keypair-import", "Create a new keypair with a existing public key", func(s *mcclient.ClientSession, args *KeypairImport) error { + params := jsonutils.NewDict() + params.Add(jsonutils.NewString(args.NAME), "name") + if len(args.PublicKey) > 0 { + content, e := ioutil.ReadFile(args.PublicKey) + if e != nil { + params.Add(jsonutils.NewString(args.PublicKey), "public_Key") + } else { + params.Add(jsonutils.NewString(string(content)), "public_Key") + } + } else { + return fmt.Errorf("no public key provided") + } + + if len(args.Desc) > 0 { + params.Add(jsonutils.NewString(args.Desc), "description") + } + + result, e := modules.Keypairs.Create(s, params) + if e != nil { + return e + } + printObject(result) + return nil + }) + + type KeypairPrivateKey struct { + ID string `help:"ID of keypair to fetch"` + } + + R(&KeypairPrivateKey{}, "keypair-privatekey", "Fetch the private key of a keypair, this can be done once only", func(s *mcclient.ClientSession, args *KeypairPrivateKey) error { + result, e := modules.Keypairs.GetSpecific(s, args.ID, "privatekey", nil) + if e != nil { + return e + } + key, e := result.GetString("private_key") + if e != nil { + return fmt.Errorf("Private key has been fetched") + } + fmt.Printf("%s", key) + return nil + }) +} diff --git a/cmd/climc/shell/keystoneutils.go b/cmd/climc/shell/keystoneutils.go new file mode 100644 index 0000000000..95fb92aaa4 --- /dev/null +++ b/cmd/climc/shell/keystoneutils.go @@ -0,0 +1,75 @@ +package shell + +import ( + "github.com/yunionio/jsonutils" + "github.com/yunionio/mcclient" + "github.com/yunionio/mcclient/modules" +) + +func getUserId(s *mcclient.ClientSession, user string, domain string) (string, error) { + query := jsonutils.NewDict() + if len(domain) > 0 { + domainId, err := modules.Domains.GetId(s, domain, nil) + if err != nil { + return "", err + } + query.Add(jsonutils.NewString(domainId), "domain_id") + } + return modules.UsersV3.GetId(s, user, query) +} + +func getGroupId(s *mcclient.ClientSession, group string, domain string) (string, error) { + query := jsonutils.NewDict() + if len(domain) > 0 { + domainId, err := modules.Domains.GetId(s, domain, nil) + if err != nil { + return "", err + } + query.Add(jsonutils.NewString(domainId), "domain_id") + } + return modules.Groups.GetId(s, group, query) +} + +func getRoleId(s *mcclient.ClientSession, role string, domain string) (string, error) { + query := jsonutils.NewDict() + if len(domain) > 0 { + domainId, err := modules.Domains.GetId(s, domain, nil) + if err != nil { + return "", err + } + query.Add(jsonutils.NewString(domainId), "domain_id") + } + return modules.RolesV3.GetId(s, role, query) +} + +func getProjectId(s *mcclient.ClientSession, project string, domain string) (string, error) { + query := jsonutils.NewDict() + if len(domain) > 0 { + domainId, err := modules.Domains.GetId(s, domain, nil) + if err != nil { + return "", err + } + query.Add(jsonutils.NewString(domainId), "domain_id") + } + return modules.Projects.GetId(s, project, query) +} + +func getUserGroupId(s *mcclient.ClientSession, user, group, domain string) (string, string, error) { + query := jsonutils.NewDict() + if len(domain) > 0 { + domainId, err := modules.Domains.GetId(s, domain, nil) + if err != nil { + return "", "", err + } + query.Add(jsonutils.NewString(domainId), "domain_id") + } + uid, err := modules.UsersV3.GetId(s, user, query) + if err != nil { + return "", "", err + } + gid, err := modules.Groups.GetId(s, group, query) + if err != nil { + return "", "", err + } + return uid, gid, nil +} diff --git a/cmd/climc/shell/labels.go b/cmd/climc/shell/labels.go new file mode 100644 index 0000000000..f04d8b3644 --- /dev/null +++ b/cmd/climc/shell/labels.go @@ -0,0 +1,96 @@ +package shell + +import ( + "github.com/yunionio/jsonutils" + "github.com/yunionio/mcclient" + "github.com/yunionio/mcclient/modules" +) + +func init() { + + /** + * 新建一个标签 + */ + type LabelCreateOptions struct { + NAME string `help:"Name of the new label"` + VALUETYPE string `help:"Label value's type such as int, float, string, bool, choices"` + Remark string `help:"Remark or description of the new label"` + } + R(&LabelCreateOptions{}, "label-create", "Create a label", func(s *mcclient.ClientSession, args *LabelCreateOptions) error { + mod, err := modules.GetModule(s, "labels") + if err != nil { + return err + } + params := jsonutils.NewDict() + params.Add(jsonutils.NewString(args.NAME), "name") + params.Add(jsonutils.NewString(args.VALUETYPE), "value_type") + if len(args.Remark) > 0 { + params.Add(jsonutils.NewString(args.Remark), "remark") + } + + label, err := mod.Create(s, params) + if err != nil { + return err + } + printObject(label) + return nil + }) + + /** + * 删除指定name的标签(删除指定name的标签) + */ + type LabelDeleteOptions struct { + NAME string `help:"Name of label"` + } + R(&LabelDeleteOptions{}, "label-delete", "Delete a label", func(s *mcclient.ClientSession, args *LabelDeleteOptions) error { + label, e := modules.Labels.Delete(s, args.NAME, nil) + if e != nil { + return e + } + printObject(label) + return nil + }) + + /** + * 修改标签(修改指定name的标签) + */ + type LabelUpdateOptions struct { + NAME string `help:"Name of the label"` + ValueType string `help:"Label value's type such as int, float, string, bool, choices"` + Remark string `help:"Remark or description of the new label"` + } + R(&LabelUpdateOptions{}, "label-update", "Update a label", func(s *mcclient.ClientSession, args *LabelUpdateOptions) error { + params := jsonutils.NewDict() + params.Add(jsonutils.NewString(args.NAME), "name") + if len(args.ValueType) > 0 { + params.Add(jsonutils.NewString(args.ValueType), "value_type") + } + if len(args.Remark) > 0 { + params.Add(jsonutils.NewString(args.Remark), "remark") + } + + label, err := modules.Labels.Patch(s, args.NAME, params) + if err != nil { + return err + } + printObject(label) + return nil + }) + + /** + * 列出所有的标签 + */ + type LabelListOptions struct { + BaseListOptions + } + R(&LabelListOptions{}, "label-list", "List labels", func(s *mcclient.ClientSession, args *LabelListOptions) error { + params := FetchPagingParams(args.BaseListOptions) + result, err := modules.Labels.List(s, params) + if err != nil { + return err + } + printList(result, modules.Labels.GetColumns(s)) + return nil + }) + +} diff --git a/cmd/climc/shell/metric_types.go b/cmd/climc/shell/metric_types.go new file mode 100644 index 0000000000..7b35bca8cf --- /dev/null +++ b/cmd/climc/shell/metric_types.go @@ -0,0 +1,27 @@ +package shell + +import ( + "github.com/yunionio/mcclient" + "github.com/yunionio/mcclient/modules" +) + +func init() { + + /** + * 列出指定监控类型下的全部指标类型 + */ + type MonitorTypesBaseOptions struct { + ID string `help:"ID of the monitor type"` + } + R(&MonitorTypesBaseOptions{}, "monitortype-metrictype-list", "List metric types of the monitor type", func(s *mcclient.ClientSession, args *MonitorTypesBaseOptions) error { + result, err := modules.MetricsTypes.ListInContext(s, nil, &modules.MonitorTypes, args.ID) + + if err != nil { + return err + } + + printList(result, modules.MetricsTypes.GetColumns(s)) + return nil + }) + +} diff --git a/cmd/climc/shell/metrics.go b/cmd/climc/shell/metrics.go new file mode 100644 index 0000000000..8b3a9f1476 --- /dev/null +++ b/cmd/climc/shell/metrics.go @@ -0,0 +1,81 @@ +package shell + +import ( + "github.com/yunionio/mcclient" + "github.com/yunionio/mcclient/modules" +) + +func init() { + + /** + * 列出指定指标类型下的全部指标 + */ + type MetricTypesBaseOptions struct { + ID string `help:"ID of the metric type"` + } + R(&MetricTypesBaseOptions{}, "metrictype-metric-list", "List metric types of the monitor type", func(s *mcclient.ClientSession, args *MetricTypesBaseOptions) error { + result, err := modules.Metrics.ListInContext(s, nil, &modules.MetricsTypes, args.ID) + if err != nil { + return err + } + printList(result, modules.Metrics.GetColumns(s)) + return nil + }) + + /** + * 列出所有监控指标 + */ + type MetricsListOptions struct { + BaseListOptions + } + R(&MetricsListOptions{}, "metric-list", "List all metrics", func(s *mcclient.ClientSession, args *MetricsListOptions) error { + params := FetchPagingParams(args.BaseListOptions) + + result, err := modules.Metrics.List(s, params) + if err != nil { + return err + } + + printList(result, modules.Metrics.GetColumns(s)) + return nil + }) + + /** + * 查看监控指标详情 + */ + type MetricsShowOptions struct { + BaseListOptions + ID string `help:"The ID of the metric"` + } + R(&MetricsShowOptions{}, "metric-show", "Show metric details", func(s *mcclient.ClientSession, args *MetricsShowOptions) error { + params := FetchPagingParams(args.BaseListOptions) + + result, err := modules.Metrics.Get(s, args.ID, params) + if err != nil { + return err + } + + printObject(result) + return nil + }) + + /** + * 根据name查看监控指标详情 + */ + type MetricsShowByNameOptions struct { + BaseListOptions + NAME string `help:"The NAME of the metric"` + } + R(&MetricsShowByNameOptions{}, "metric-details", "Show metric details by name", func(s *mcclient.ClientSession, args *MetricsShowByNameOptions) error { + params := FetchPagingParams(args.BaseListOptions) + + result, err := modules.Metrics.GetSpecific(s, "", args.NAME, params) + if err != nil { + return err + } + + printObject(result) + return nil + }) + +} diff --git a/cmd/climc/shell/monitor_metrics.go b/cmd/climc/shell/monitor_metrics.go new file mode 100644 index 0000000000..99ee190ba8 --- /dev/null +++ b/cmd/climc/shell/monitor_metrics.go @@ -0,0 +1,53 @@ +package shell + +import ( + "fmt" + "strings" + + "github.com/yunionio/jsonutils" + "github.com/yunionio/mcclient" + "github.com/yunionio/mcclient/modules" +) + +func init() { + + /** + * 添加/修改树节点的统计指标(配置服务树某个节点都有什么监控指标) + */ + type MonitorMetricsUpdateOptions struct { + LABEL []string `help:"Labels to this tree node"` + MetricName []string `help:"Metric names to add to" nargs:"+"` + } + R(&MonitorMetricsUpdateOptions{}, "monitor-metrics-set", "Set monitor metric for the tree-node", func(s *mcclient.ClientSession, args *MonitorMetricsUpdateOptions) error { + names := []string{"corp", "owt", "pdl", "srv", "env"} + segs := make([]string, len(args.LABEL)) + + for i := 0; i < len(args.LABEL); i += 1 { + sublabel := args.LABEL[:i+1] + pid, _ := modules.TreeNodes.GetNodeIDByLabels(s, sublabel) + segs[i] = fmt.Sprintf("%s=%d", names[i], pid) + } + + node_labels := strings.Join(segs, ",") + + params := jsonutils.NewDict() + params.Add(jsonutils.NewString(node_labels), "node_labels") + arr := jsonutils.NewArray() + if len(args.MetricName) > 0 { + for _, f := range args.MetricName { + arr.Add(jsonutils.NewString(f)) + } + } + params.Add(arr, "metrics") + + rst, err := modules.MonitorMetrics.Create(s, params) + + if err != nil { + return err + } + + printObject(rst) + return nil + }) + +} diff --git a/cmd/climc/shell/monitor_types.go b/cmd/climc/shell/monitor_types.go new file mode 100644 index 0000000000..c8424428fb --- /dev/null +++ b/cmd/climc/shell/monitor_types.go @@ -0,0 +1,28 @@ +package shell + +import ( + "github.com/yunionio/mcclient" + "github.com/yunionio/mcclient/modules" +) + +func init() { + + /** + * 列出全部的监控类型 + */ + type MonitorTypesOptions struct { + BaseListOptions + } + R(&MonitorTypesOptions{}, "monitortype-list", "List all monitor types", func(s *mcclient.ClientSession, args *MonitorTypesOptions) error { + params := FetchPagingParams(args.BaseListOptions) + + result, err := modules.MonitorTypes.List(s, params) + if err != nil { + return err + } + + printList(result, modules.MonitorTypes.GetColumns(s)) + return nil + }) + +} diff --git a/cmd/climc/shell/monitorinputs.go b/cmd/climc/shell/monitorinputs.go new file mode 100644 index 0000000000..67e3f08175 --- /dev/null +++ b/cmd/climc/shell/monitorinputs.go @@ -0,0 +1,47 @@ +package shell + +import ( + "github.com/yunionio/mcclient" + "github.com/yunionio/mcclient/modules" +) + +func init() { + + /** + * 列出所有监控数据源 + */ + type MonitorInputsListOptions struct { + BaseListOptions + } + R(&MonitorInputsListOptions{}, "monitorinputs-list", "List all monitor-inputs", func(s *mcclient.ClientSession, args *MonitorInputsListOptions) error { + params := FetchPagingParams(args.BaseListOptions) + + result, err := modules.MonitorInputs.List(s, params) + if err != nil { + return err + } + + printList(result, modules.MonitorInputs.GetColumns(s)) + return nil + }) + + /** + * 查看监控数据源下的监控项 + */ + type MonitorInputsShowOptions struct { + BaseListOptions + ID string `help:"The ID of the monitor-input"` + } + R(&MonitorInputsShowOptions{}, "monitorinputs-metrics-list", "List all metrics for the monitor-inputs", func(s *mcclient.ClientSession, args *MonitorInputsShowOptions) error { + params := FetchPagingParams(args.BaseListOptions) + + result, err := modules.MonitorInputs.GetSpecific(s, args.ID, "metrics", params) + if err != nil { + return err + } + + printObject(result) + return nil + }) + +} diff --git a/cmd/climc/shell/monitortemplates.go b/cmd/climc/shell/monitortemplates.go new file mode 100644 index 0000000000..2de270e59f --- /dev/null +++ b/cmd/climc/shell/monitortemplates.go @@ -0,0 +1,185 @@ +package shell + +import ( + "strings" + "github.com/yunionio/jsonutils" + "github.com/yunionio/mcclient" + "github.com/yunionio/mcclient/modules" +) + +func init() { + + /** + * 创建监控模板 + */ + type MonitorTemplateCreateOptions struct { + NAME string `help:"The name of the monitor-template"` + Desc string `help:"Description of the monitor-template"` + MonitorInputs []string `help:"Monitor-inputs add to the monitor-template"` + } + R(&MonitorTemplateCreateOptions{}, "monitortemplate-create", "Create or update contact for user", func(s *mcclient.ClientSession, args *MonitorTemplateCreateOptions) error { + params := jsonutils.NewDict() + params.Add(jsonutils.NewString(args.NAME), "monitor_template_name") + if len(args.Desc) > 0 { + params.Add(jsonutils.NewString(args.Desc), "monitor_template_desc") + } + if len(args.MonitorInputs) > 0 { + monitors := jsonutils.NewDict() + for _, f := range args.MonitorInputs { + parts := strings.Split(f, "=") + monitors.Add(jsonutils.NewString(parts[1]), parts[0]) + } + params.Add(monitors, "monitors") + } + + monitortemplate, err := modules.MonitorTemplates.Create(s, params) + + if err != nil { + return err + } + + printObject(monitortemplate) + return nil + }) + + /** + * 列出监控模板 + */ + type MonitorTemplateListOptions struct { + BaseListOptions + } + R(&MonitorTemplateListOptions{}, "monitortemplate-list", "List all monitor-template", func(s *mcclient.ClientSession, args *MonitorTemplateListOptions) error { + params := FetchPagingParams(args.BaseListOptions) + + result, err := modules.MonitorTemplates.List(s, params) + if err != nil { + return err + } + + printList(result, modules.MonitorTemplates.GetColumns(s)) + return nil + }) + + /** + * 查看监控模板详情 + */ + type MonitorTemplateShowOptions struct { + BaseListOptions + ID string `help:"The ID of the monitor-template"` + } + R(&MonitorTemplateShowOptions{}, "monitortemplate-show", "Show monitor-template", func(s *mcclient.ClientSession, args *MonitorTemplateShowOptions) error { + params := FetchPagingParams(args.BaseListOptions) + + result, err := modules.MonitorTemplates.Get(s, args.ID, params) + if err != nil { + return err + } + + printObject(result) + return nil + }) + + /** + * 查看模板下的监控项 + */ + type MonitorTemplateMonitorInputsListOptions struct { + MONITOR_TEMPLATE_ID string `help:"The ID of the monitor-template"` + } + R(&MonitorTemplateMonitorInputsListOptions{}, "monitortemplate-monitorinput-list", "Get monitor-inputs of a monitor-template", func(s *mcclient.ClientSession, args *MonitorTemplateMonitorInputsListOptions) error { + result, err := modules.MonitorTemplateInputs.ListDescendent(s, args.MONITOR_TEMPLATE_ID, nil) + + if err != nil { + return err + } + + printList(result, modules.MonitorInputs.GetColumns(s)) + return nil + }) + + /** + * 更新监控模板信息 + */ + type MonitorTemplateUpdateOptions struct { + ID string `help:"The ID of the monitor-template"` + NAME string `help:"The name of the monitor-template"` + Desc string `help:"Description of the monitor-template"` + MonitorInputs []string `help:"Monitor-inputs attached to the monitor-template"` + } + R(&MonitorTemplateUpdateOptions{}, "monitortemplate-update", "Update a monitor-template", func(s *mcclient.ClientSession, args *MonitorTemplateUpdateOptions) error { + params := jsonutils.NewDict() + params.Add(jsonutils.NewString(args.NAME), "monitor_template_name") + if len(args.Desc) > 0 { + params.Add(jsonutils.NewString(args.Desc), "monitor_template_desc") + } + if len(args.MonitorInputs) > 0 { + monitors := jsonutils.NewDict() + for _, f := range args.MonitorInputs { + parts := strings.Split(f, "=") + monitors.Add(jsonutils.NewString(parts[1]), parts[0]) + } + params.Add(monitors, "monitors") + } + + monitortemplate, err := modules.MonitorTemplates.Put(s, args.ID, params) + + if err != nil { + return err + } + + printObject(monitortemplate) + return nil + }) + + /** + * 向监控模板中添加监控项 + */ + type MonitorTemplateMonitorInputsOptions struct { + MONITOR_TEMPLATE_ID string `help:"The ID of the monitor-template"` + MONITOR_INPUT_NAME string `help:"The name of the monitor-input"` + MonitorConfig string `help:"The config of the monitor-input"` + } + R(&MonitorTemplateMonitorInputsOptions{}, "monitortemplate-attach-monitorinput", "Add a monitor-input to a monitor-template", func(s *mcclient.ClientSession, args *MonitorTemplateMonitorInputsOptions) error { + params := jsonutils.NewDict() + if len(args.MonitorConfig) > 0 { + + params.Add(jsonutils.NewString(args.MonitorConfig), "monitor_conf_value") + } + + monitor_template_inputs, err := modules.MonitorTemplateInputs.Update(s, args.MONITOR_TEMPLATE_ID, args.MONITOR_INPUT_NAME, params) + + if err != nil { + return err + } + + printObject(monitor_template_inputs) + return nil + }) + + /** + * 从监控模板中删除监控项 + */ + R(&MonitorTemplateMonitorInputsOptions{}, "monitortemplate-detach-monitorinput", "Add a monitor-input to a monitor-template", func(s *mcclient.ClientSession, args *MonitorTemplateMonitorInputsOptions) error { + _, err := modules.MonitorInputs.DeleteInContext(s, args.MONITOR_INPUT_NAME, nil, &modules.MonitorTemplates, args.MONITOR_TEMPLATE_ID) + if err != nil { + return err + } + return nil + }) + + /** + * 删除监控模板 + */ + type MonitorTemplateDeleteOptions struct { + ID string `help:"The ID of the monitor-template"` + } + R(&MonitorTemplateDeleteOptions{}, "monitortemplate-delete", "Delete a monitor-template", func(s *mcclient.ClientSession, args *MonitorTemplateDeleteOptions) error { + monitortemplate, e := modules.MonitorInputs.Delete(s, args.ID, nil) + if e != nil { + return e + } + + printObject(monitortemplate) + return nil + }) + +} diff --git a/cmd/climc/shell/networks.go b/cmd/climc/shell/networks.go new file mode 100644 index 0000000000..bc1a17239e --- /dev/null +++ b/cmd/climc/shell/networks.go @@ -0,0 +1,221 @@ +package shell + +import ( + "github.com/yunionio/jsonutils" + "github.com/yunionio/mcclient" + "github.com/yunionio/mcclient/modules" +) + +func init() { + type NetworkListOptions struct { + BaseListOptions + Ip string `help:"search networks that contain this IP"` + } + R(&NetworkListOptions{}, "network-list", "List networks", func(s *mcclient.ClientSession, args *NetworkListOptions) error { + params := FetchPagingParams(args.BaseListOptions) + if len(args.Ip) > 0 { + params.Add(jsonutils.NewString(args.Ip), "ip") + } + result, err := modules.Networks.List(s, params) + if err != nil { + return err + } + printList(result, modules.Networks.GetColumns(s)) + return nil + }) + + type NetworkUpdateOptions struct { + ID string `help:"ID or Name of zone to update"` + Name string `help:"Name of zone"` + Desc string `metavar:"" help:"Description"` + ServerType string `help:"server type," choices:"baremetal|guest"` + StartIp string `help:"Start ip"` + EndIp string `help:"end ip"` + NetMask int64 `help:"Netmask"` + Gateway string `help:"IP of gateway"` + Dns string `help:"IP of DNS server"` + Domain string `help:"Domain"` + Dhcp string `help:"DHCP server IP"` + VlanId int64 `help:"Vlan ID" default:"1"` + ExternalId string `help:"External ID"` + AllocPolicy string `help:"Address allocation policy" choices:"none|stepdown|stepup|random"` + } + R(&NetworkUpdateOptions{}, "network-update", "Update network", func(s *mcclient.ClientSession, args *NetworkUpdateOptions) error { + params := jsonutils.NewDict() + if len(args.Name) > 0 { + params.Add(jsonutils.NewString(args.Name), "name") + } + if len(args.Desc) > 0 { + params.Add(jsonutils.NewString(args.Desc), "description") + } + if len(args.ServerType) > 0 { + params.Add(jsonutils.NewString(args.ServerType), "server_type") + } + if len(args.StartIp) > 0 { + params.Add(jsonutils.NewString(args.StartIp), "guest_ip_start") + } + if len(args.EndIp) > 0 { + params.Add(jsonutils.NewString(args.EndIp), "guest_ip_end") + } + if args.NetMask > 0 { + params.Add(jsonutils.NewInt(args.NetMask), "guest_ip_mask") + } + if len(args.Gateway) > 0 { + params.Add(jsonutils.NewString(args.Gateway), "guest_gateway") + } + if len(args.Dns) > 0 { + if args.Dns == "none" { + params.Add(jsonutils.NewString(""), "guest_dns") + } else { + params.Add(jsonutils.NewString(args.Dns), "guest_dns") + } + } + if len(args.Domain) > 0 { + if args.Domain == "none" { + params.Add(jsonutils.NewString(""), "guest_domain") + } else { + params.Add(jsonutils.NewString(args.Domain), "guest_domain") + } + } + if len(args.Dhcp) > 0 { + if args.Dhcp == "none" { + params.Add(jsonutils.NewString(""), "guest_dhcp") + } else { + params.Add(jsonutils.NewString(args.Dhcp), "guest_dhcp") + } + } + if args.VlanId > 0 { + params.Add(jsonutils.NewInt(args.VlanId), "vlan_id") + } + if len(args.ExternalId) > 0 { + params.Add(jsonutils.NewString(args.ExternalId), "external_id") + } + if len(args.AllocPolicy) > 0 { + params.Add(jsonutils.NewString(args.AllocPolicy), "alloc_policy") + } + if params.Size() == 0 { + return InvalidUpdateError() + } + result, err := modules.Networks.Update(s, args.ID, params) + if err != nil { + return err + } + printObject(result) + return nil + }) + + type NetworkShowOptions struct { + ID string `help:"ID or Name of the zone to show"` + } + R(&NetworkShowOptions{}, "network-show", "Show network details", func(s *mcclient.ClientSession, args *NetworkShowOptions) error { + result, err := modules.Networks.Get(s, args.ID, nil) + if err != nil { + return err + } + printObject(result) + return nil + }) + + R(&NetworkShowOptions{}, "network-private", "Make a network private", func(s *mcclient.ClientSession, args *NetworkShowOptions) error { + result, err := modules.Networks.PerformAction(s, args.ID, "private", nil) + if err != nil { + return err + } + printObject(result) + return nil + }) + + R(&NetworkShowOptions{}, "network-public", "Make a network public", func(s *mcclient.ClientSession, args *NetworkShowOptions) error { + result, err := modules.Networks.PerformAction(s, args.ID, "public", nil) + if err != nil { + return err + } + printObject(result) + return nil + }) + + R(&NetworkShowOptions{}, "network-delete", "Delete a network", func(s *mcclient.ClientSession, args *NetworkShowOptions) error { + result, err := modules.Networks.Delete(s, args.ID, nil) + if err != nil { + return err + } + printObject(result) + return nil + }) + + type NetworkCreateOptions struct { + WIRE string `help:"ID or Name of wire in wihich the network is created"` + NETWORK string `help:"Name of new network"` + STARTIP string `help:"Start of IPv4 address range"` + ENDIP string `help:"End of IPv4 address rnage"` + NETMASK int64 `help:"Length of network mask"` + Gateway string `help:"Default gateway"` + VlanId int64 `help:"Vlan ID" default:"1"` + AllocPolicy string `help:"Address allocation policy" choices:"none|stepdown|stepup|random"` + ServerType string `help:"Server type" choices:"baremetal|guest"` + Desc string `help:"Description" metavar:"DESCRIPTION"` + } + R(&NetworkCreateOptions{}, "network-create", "Create a virtual network", func(s *mcclient.ClientSession, args *NetworkCreateOptions) error { + params := jsonutils.NewDict() + params.Add(jsonutils.NewString(args.NETWORK), "name") + params.Add(jsonutils.NewString(args.STARTIP), "guest_ip_start") + params.Add(jsonutils.NewString(args.ENDIP), "guest_ip_end") + params.Add(jsonutils.NewInt(args.NETMASK), "guest_ip_mask") + if len(args.Gateway) > 0 { + params.Add(jsonutils.NewString(args.Gateway), "guest_gateway") + } + if args.VlanId > 0 { + params.Add(jsonutils.NewInt(args.VlanId), "vlan_id") + } + if len(args.ServerType) > 0 { + params.Add(jsonutils.NewString(args.ServerType), "server_type") + } + if len(args.AllocPolicy) > 0 { + params.Add(jsonutils.NewString(args.AllocPolicy), "alloc_policy") + } + if len(args.Desc) > 0 { + params.Add(jsonutils.NewString(args.Desc), "description") + } + net, e := modules.Networks.CreateInContext(s, params, &modules.Wires, args.WIRE) + if e != nil { + return e + } + printObject(net) + return nil + }) + + type NetworkSplitOptions struct { + NETWORK string `help:"ID or name of network to split"` + IP string `help:"Start ip of the split network"` + Name string `help:"Name of the new network"` + } + R(&NetworkSplitOptions{}, "network-split", "Split a network at the specified IP address", func(s *mcclient.ClientSession, args *NetworkSplitOptions) error { + params := jsonutils.NewDict() + params.Add(jsonutils.NewString(args.IP), "split_ip") + if len(args.Name) > 0 { + params.Add(jsonutils.NewString(args.Name), "name") + } + net, err := modules.Networks.PerformAction(s, args.NETWORK, "split", params) + if err != nil { + return err + } + printObject(net) + return nil + }) + + type NetworkMergeOptions struct { + FROM string `help:"ID or name of merge network from"` + TARGET string `help:"ID or name of merge network target"` + } + R(&NetworkMergeOptions{}, "network-merge", "Merge two network to be one", func(s *mcclient.ClientSession, args *NetworkMergeOptions) error { + params := jsonutils.NewDict() + params.Add(jsonutils.NewString(args.TARGET), "target") + net, err := modules.Networks.PerformAction(s, args.FROM, "merge", params) + if err != nil { + return err + } + printObject(net) + return nil + }) + +} diff --git a/cmd/climc/shell/nodes.go b/cmd/climc/shell/nodes.go new file mode 100644 index 0000000000..52da799c3b --- /dev/null +++ b/cmd/climc/shell/nodes.go @@ -0,0 +1,165 @@ +package shell + +import ( + "strings" + "github.com/yunionio/jsonutils" + "github.com/yunionio/mcclient" + "github.com/yunionio/mcclient/modules" +) + +func init() { + + /** + * 查看所有的监控节点 | 列出匹配标签的节点列表 + */ + type NodeListOptions struct { + BaseListOptions + Labels []string `help:"Node labels"` + } + R(&NodeListOptions{}, "node-list", "List all nodes", func(s *mcclient.ClientSession, args *NodeListOptions) error { + params := FetchPagingParams(args.BaseListOptions) + if len(args.Labels) > 0 { + for _, f := range args.Labels { + parts := strings.Split(f, "=") + params.Add(jsonutils.NewString(parts[1]), parts[0]) + } + } + + result, err := modules.Nodes.List(s, params) + if err != nil { + return err + } + printList(result, modules.Nodes.GetColumns(s)) + return nil + }) + + /** + * 查看节点的标签 + */ + type NodeBaseOptions struct { + ID string `help:"ID of the node"` + } + R(&NodeBaseOptions{}, "list-labels-for-node", "List labels for the node", func(s *mcclient.ClientSession, args *NodeBaseOptions) error { + result, err := modules.Labels.ListInContext(s, nil, &modules.Nodes, args.ID) + if err != nil { + return err + } + printList(result, modules.Labels.GetColumns(s)) + return nil + }) + + /** + * 新增标签 + */ + type NodeLabelsAddOptions struct { + ID string `help:"ID of node"` + LABELS []string `help:"Node labels"` + } + R(&NodeLabelsAddOptions{}, "add-labels-to-node", "Add labels to node", func(s *mcclient.ClientSession, args *NodeLabelsAddOptions) error { + labels := jsonutils.NewDict() + for _, f := range args.LABELS { + parts := strings.Split(f, "=") + labels.Add(jsonutils.NewString(parts[1]), parts[0]) + } + + params := jsonutils.NewDict() + params.Add(labels, "labels") + + _, err := modules.Nodes.PerformAction(s, args.ID, "add-labels", params) + if err != nil { + return err + } + return nil + }) + + /** + * 批量新增标签 + */ + type NodeLabelsBatchOptions struct { + NAMES []string `help:"Node names"` + Labels []string `help:"Node labels" nargs:"+"` + } + R(&NodeLabelsBatchOptions{}, "batch-add-labels-to-node", "Batch add labels to nodes", func(s *mcclient.ClientSession, args *NodeLabelsBatchOptions) error { + nodes := jsonutils.NewArray() + labels := jsonutils.NewDict() + + for _, n := range args.NAMES { + nodes.Add(jsonutils.NewString(n)) + } + + for _, l := range args.Labels { + parts := strings.Split(l, "=") + labels.Add(jsonutils.NewString(parts[1]), parts[0]) + } + + params := jsonutils.NewDict() + params.Add(nodes, "nodes") + params.Add(labels, "labels") + + ret := modules.Nodes.BatchPerformActionInContexts(s, args.NAMES, "add-labels", params, nil) + printBatchResults(ret, modules.Nodes.GetColumns(s)) + return nil + }) + + /** + * 移除标签 + */ + type NodeLabelRemoveOptions struct { + ID string `help:"ID of node"` + LABELS []string `help:"Node labels"` + } + R(&NodeLabelRemoveOptions{}, "remove-labels-from-node", "Remove labels from node", func(s *mcclient.ClientSession, args *NodeLabelRemoveOptions) error { + labels := jsonutils.NewDict() + for _, f := range args.LABELS { + parts := strings.Split(f, "=") + labels.Add(jsonutils.NewString(parts[1]), parts[0]) + } + + params := jsonutils.NewDict() + params.Add(labels, "labels") + + _, err := modules.Nodes.PerformAction(s, args.ID, "remove-labels", params) + if err != nil { + return err + } + return nil + }) + + /** + * 批量移除标签 + */ + R(&NodeLabelsBatchOptions{}, "batch-remove-labels-from-node", "Batch remove labels from nodes", func(s *mcclient.ClientSession, args *NodeLabelsBatchOptions) error { + nodes := jsonutils.NewArray() + labels := jsonutils.NewDict() + + for _, n := range args.NAMES { + nodes.Add(jsonutils.NewString(n)) + } + + for _, l := range args.Labels { + parts := strings.Split(l, "=") + labels.Add(jsonutils.NewString(parts[1]), parts[0]) + } + + params := jsonutils.NewDict() + params.Add(nodes, "nodes") + params.Add(labels, "labels") + + ret := modules.Nodes.BatchPerformActionInContexts(s, args.NAMES, "remove-labels", params, nil) + printBatchResults(ret, modules.Nodes.GetColumns(s)) + return nil + }) + + type NodeCreateOptions struct { + NAME string `help:"Node name"` + IP string `help:"Node IP"` + } + R(&NodeCreateOptions{}, "node-create", "Create a monitor node record", func(s *mcclient.ClientSession, args *NodeCreateOptions) error { + data, err := modules.Nodes.NewNode(s, args.NAME, args.IP) + if err != nil { + return err + } + printObject(data) + return nil + }) +} diff --git a/cmd/climc/shell/notification.go b/cmd/climc/shell/notification.go new file mode 100644 index 0000000000..2ed9459172 --- /dev/null +++ b/cmd/climc/shell/notification.go @@ -0,0 +1,86 @@ +package shell + +import ( + //"strings" + "github.com/yunionio/jsonutils" + "github.com/yunionio/mcclient" + "github.com/yunionio/mcclient/modules" +) + +func init() { + + /** + * 新建一个通知发送任务 + */ + type NotificationCreateOptions struct { + UID string `help:"The user you wanna sent to (Keystone User ID)"` + CONTACTTYPE string `help:"User's contacts type, maybe email|mobile|dingtalk" choices:"email|mobile|dingtalk"` + TOPIC string `help:"Title or topic of the notification"` + PRIORITY string `help:"Priority of the notification maybe normal|important|fatal" choices:"normal|important|fatal"` + MSG string `help:"The content of the notification"` + Remark string `help:"Remark or description of the notification"` + Group bool `help:"Send to group"` + } + R(&NotificationCreateOptions{}, "notify", "Send a notification to sb", func(s *mcclient.ClientSession, args *NotificationCreateOptions) error { + params := jsonutils.NewDict() + if args.Group { + params.Add(jsonutils.NewString(args.UID), "gid") + } else { + params.Add(jsonutils.NewString(args.UID), "uid") + } + params.Add(jsonutils.NewString(args.CONTACTTYPE), "contact_type") + params.Add(jsonutils.NewString(args.TOPIC), "topic") + params.Add(jsonutils.NewString(args.PRIORITY), "priority") + params.Add(jsonutils.NewString(args.MSG), "msg") + if len(args.Remark) > 0 { + params.Add(jsonutils.NewString(args.Remark), "remark") + } + + notification, err := modules.Notifications.Create(s, params) + if err != nil { + return err + } + printObject(notification) + return nil + }) + + /** + * 修改通知发送任务的状态 + */ + type NotificationUpdateCallbackOptions struct { + ID string `help:"ID of the notification send task"` + STATUS string `help:"Notification send status" choices:"sent_ok|send_fail"` + Remark string `help:"Remark or description of the operation or fail reason"` + } + R(&NotificationUpdateCallbackOptions{}, "notification-update-callback", "Update send status of the notification task", func(s *mcclient.ClientSession, args *NotificationUpdateCallbackOptions) error { + params := jsonutils.NewDict() + params.Add(jsonutils.NewString(args.STATUS), "status") + if len(args.Remark) > 0 { + params.Add(jsonutils.NewString(args.Remark), "remark") + } + + notification, err := modules.Notifications.Put(s, args.ID, params) + if err != nil { + return err + } + printObject(notification) + return nil + }) + + /** + * 查询已发送的通知任务 + */ + type NotificationListOptions struct { + BaseListOptions + } + R(&NotificationListOptions{}, "notify-list", "List notification history", func(s *mcclient.ClientSession, args *NotificationListOptions) error { + result, err := modules.Notifications.List(s, nil) + if err != nil { + return err + } + + printList(result, modules.Notifications.GetColumns(s)) + return nil + }) + +} diff --git a/cmd/climc/shell/operations.go b/cmd/climc/shell/operations.go new file mode 100644 index 0000000000..9e05757050 --- /dev/null +++ b/cmd/climc/shell/operations.go @@ -0,0 +1,119 @@ +package shell + +import ( + "github.com/yunionio/jsonutils" + "github.com/yunionio/mcclient" + "github.com/yunionio/mcclient/modules" +) + +func init() { + type OperationListOptions struct { + BaseListOptions + } + R(&OperationListOptions{}, "operation-list", "List operations", func(s *mcclient.ClientSession, suboptions *OperationListOptions) error { + params := FetchPagingParams(suboptions.BaseListOptions) + result, err := modules.Operations.List(s, params) + if err != nil { + return err + } + printList(result, modules.Operations.GetColumns(s)) + return nil + }) + + type OperationUpdateOptions struct { + TASK_ID string `help:"TASK_ID of process" ` + Content string `help:"Content of process" default:""` + Result string `help:"Result of process" default:""` + } + R(&OperationUpdateOptions{}, "operation-update", "Update operation", func(s *mcclient.ClientSession, args *OperationUpdateOptions) error { + params := jsonutils.NewDict() + + // params.Add(jsonutils.NewString(args.TASK_ID), "task_id") + params.Add(jsonutils.NewString(args.Content), "content") + params.Add(jsonutils.NewString(args.Result), "result") + + obj, err := modules.Operations.Put(s, args.TASK_ID, params) + if err != nil { + return err + } + printObject(obj) + + return nil + }) + + type OperationShowOptions struct { + INSTANCE_ID string `help:"INSTANCE_ID of process" ` + } + + R(&OperationShowOptions{}, "operation-show", "Show operation details", func(s *mcclient.ClientSession, args *OperationShowOptions) error { + result, err := modules.Operations.Get(s, args.INSTANCE_ID, nil) + if err != nil { + return err + } + printObject(result) + return nil + }) + + type OperationCreateOptions struct { + DeviceCode string `help:"DeviceCode of process"` + ResourceSum int64 `help:"ResourceSum of process, default: 0" default:"0"` + TemplateId string `help:"TemplateId of process" ` + Cpu int64 `help:"Cpu of process, default: 0" default:"0"` + Memery int64 `help:"Memery of process, default: 0" default:"0"` + Disk int64 `help:"Disk of process, default: 0" default:"0"` + ProjectId string `help:"ProjectId of process" ` + Remark string `help:"Remark of process" ` + OPERATE_TYPE string `help:"OPERATE_TYPE of process" choices:"apply|config|template|delete"` + Schedule string `help:"Schedule of process"` + } + + R(&OperationCreateOptions{}, "operation-create", "Create a operation", func(s *mcclient.ClientSession, args *OperationCreateOptions) error { + params := jsonutils.NewDict() + + params.Add(jsonutils.NewString(args.OPERATE_TYPE), "operate_type") + + if len(args.DeviceCode) > 0 { + params.Add(jsonutils.NewString(args.DeviceCode), "device_code") + } + + if args.ResourceSum > 0 { + params.Add(jsonutils.NewInt(args.ResourceSum), "resource_sum") + } + + if len(args.TemplateId) > 0 { + params.Add(jsonutils.NewString(args.TemplateId), "template_id") + } + + if args.Cpu > 0 { + params.Add(jsonutils.NewInt(args.Cpu), "cpu") + } + + if args.Memery > 0 { + params.Add(jsonutils.NewInt(args.Memery), "memery") + } + + if args.Disk > 0 { + params.Add(jsonutils.NewInt(args.Disk), "disk") + } + + if len(args.ProjectId) > 0 { + params.Add(jsonutils.NewString(args.ProjectId), "project_id") + } + + if len(args.Remark) > 0 { + params.Add(jsonutils.NewString(args.Remark), "remark") + } + + if len(args.Schedule) > 0 { + params.Add(jsonutils.NewString(args.Schedule), "schedule") + } + + operation, err := modules.Operations.Create(s, params) + if err != nil { + return err + } + printObject(operation) + return nil + }) + +} diff --git a/cmd/climc/shell/performances.go b/cmd/climc/shell/performances.go new file mode 100644 index 0000000000..25869434ca --- /dev/null +++ b/cmd/climc/shell/performances.go @@ -0,0 +1,24 @@ +package shell + +import ( + "github.com/yunionio/jsonutils" + "github.com/yunionio/mcclient" + "github.com/yunionio/mcclient/modules" +) + +func init() { + type Top5Options struct { + NODE_LABELS string `help:"Service tree tree-node labels"` + } + R(&Top5Options{}, "performance-top5", "Show performance top5", func(s *mcclient.ClientSession, args *Top5Options) error { + params := jsonutils.NewDict() + params.Add(jsonutils.NewString(args.NODE_LABELS), "node_labels") + + result, err := modules.Performances.GetTop5(s, params) + if err != nil { + return err + } + printObject(result) + return nil + }) +} diff --git a/cmd/climc/shell/processes.go b/cmd/climc/shell/processes.go new file mode 100644 index 0000000000..437b217844 --- /dev/null +++ b/cmd/climc/shell/processes.go @@ -0,0 +1,33 @@ +package shell + +import ( + "github.com/yunionio/mcclient" + "github.com/yunionio/mcclient/modules" +) + +func init() { + type TaskListOptions struct { + BaseListOptions + } + R(&TaskListOptions{}, "process-list", "List processes", func(s *mcclient.ClientSession, suboptions *TaskListOptions) error { + params := FetchPagingParams(suboptions.BaseListOptions) + result, err := modules.Processes.List(s, params) + if err != nil { + return err + } + printList(result, modules.Processes.GetColumns(s)) + return nil + }) + + type ProcessShowOptions struct { + ID string `help:"ID or Name of the process to show"` + } + R(&ProcessShowOptions{}, "process-show", "Show process details", func(s *mcclient.ClientSession, args *ProcessShowOptions) error { + result, err := modules.Processes.Get(s, args.ID, nil) + if err != nil { + return err + } + printObject(result) + return nil + }) +} diff --git a/cmd/climc/shell/processlogs.go b/cmd/climc/shell/processlogs.go new file mode 100644 index 0000000000..39b64c4920 --- /dev/null +++ b/cmd/climc/shell/processlogs.go @@ -0,0 +1,21 @@ +package shell + +import ( + "github.com/yunionio/mcclient" + "github.com/yunionio/mcclient/modules" +) + +func init() { + type TaskListOptions struct { + BaseListOptions + } + R(&TaskListOptions{}, "prosesslog-list", "List processlogs", func(s *mcclient.ClientSession, suboptions *TaskListOptions) error { + params := FetchPagingParams(suboptions.BaseListOptions) + result, err := modules.Processlogs.List(s, params) + if err != nil { + return err + } + printList(result, modules.Processlogs.GetColumns(s)) + return nil + }) +} diff --git a/cmd/climc/shell/project_admin.go b/cmd/climc/shell/project_admin.go new file mode 100644 index 0000000000..33d3036ae3 --- /dev/null +++ b/cmd/climc/shell/project_admin.go @@ -0,0 +1,28 @@ +package shell + +import ( + "github.com/yunionio/mcclient" + "github.com/yunionio/mcclient/modules" +) + +func init() { + + /** + * 列出所有监控指标 + */ + type ProjectAdminListOptions struct { + BaseListOptions + } + R(&ProjectAdminListOptions{}, "projectadmin-list", "List all Project Admins", func(s *mcclient.ClientSession, args *ProjectAdminListOptions) error { + params := FetchPagingParams(args.BaseListOptions) + + result, err := modules.ProjectAdmin.List(s, params) + if err != nil { + return err + } + + printList(result, modules.ProjectAdmin.GetColumns(s)) + return nil + }) + +} diff --git a/cmd/climc/shell/project_admin_candidates.go b/cmd/climc/shell/project_admin_candidates.go new file mode 100644 index 0000000000..89032010f7 --- /dev/null +++ b/cmd/climc/shell/project_admin_candidates.go @@ -0,0 +1,28 @@ +package shell + +import ( + "github.com/yunionio/mcclient" + "github.com/yunionio/mcclient/modules" +) + +func init() { + + /** + * 列出所有监控指标 + */ + type ProjectAdminCandidateListOptions struct { + BaseListOptions + } + R(&ProjectAdminCandidateListOptions{}, "projectadmincandidate-list", "List all Project Admin Candidates", func(s *mcclient.ClientSession, args *ProjectAdminCandidateListOptions) error { + params := FetchPagingParams(args.BaseListOptions) + + result, err := modules.ProjectAdminCandidate.List(s, params) + if err != nil { + return err + } + + printList(result, modules.ProjectAdminCandidate.GetColumns(s)) + return nil + }) + +} diff --git a/cmd/climc/shell/projects.go b/cmd/climc/shell/projects.go new file mode 100644 index 0000000000..760b065320 --- /dev/null +++ b/cmd/climc/shell/projects.go @@ -0,0 +1,353 @@ +package shell + +import ( + "github.com/yunionio/jsonutils" + "github.com/yunionio/mcclient" + "github.com/yunionio/mcclient/modules" +) + +func init() { + type ProjectListOptions struct { + Domain string `help:"Domain ID or Name"` + Search string `help:"Search project name"` + Limit int64 `help:"Items per page" default:"20"` + Offset int64 `help:"Offset"` + } + R(&ProjectListOptions{}, "project-list", "List projects", func(s *mcclient.ClientSession, args *ProjectListOptions) error { + params := jsonutils.NewDict() + if len(args.Domain) > 0 { + domainId, err := modules.Domains.GetId(s, args.Domain, nil) + if err != nil { + return err + } + params.Add(jsonutils.NewString(domainId), "domain_id") + } + if len(args.Search) > 0 { + params.Add(jsonutils.NewString(args.Search), "name__icontains") + } + if args.Limit > 0 { + params.Add(jsonutils.NewInt(args.Limit), "limit") + } + if args.Offset > 0 { + params.Add(jsonutils.NewInt(args.Offset), "offset") + } + result, err := modules.Projects.List(s, params) + if err != nil { + return err + } + printList(result, modules.Projects.GetColumns(s)) + return nil + }) + type ProjectShowOptions struct { + ID string `help:"ID or Name of project"` + Domain string `help:"Domain"` + } + R(&ProjectShowOptions{}, "project-show", "Show details of project", func(s *mcclient.ClientSession, args *ProjectShowOptions) error { + query := jsonutils.NewDict() + if len(args.Domain) > 0 { + domainId, err := modules.Domains.GetId(s, args.Domain, nil) + if err != nil { + return err + } + query.Add(jsonutils.NewString(domainId), "domain_id") + } + result, err := modules.Projects.Get(s, args.ID, query) + if err != nil { + return err + } + printObject(result) + return nil + }) + R(&ProjectShowOptions{}, "project-delete", "Delete a project", func(s *mcclient.ClientSession, args *ProjectShowOptions) error { + query := jsonutils.NewDict() + if len(args.Domain) > 0 { + domainId, err := modules.Domains.GetId(s, args.Domain, nil) + if err != nil { + return err + } + query.Add(jsonutils.NewString(domainId), "domain_id") + } + projectId, err := modules.Projects.GetId(s, args.ID, query) + if err != nil { + return err + } + _, err = modules.Projects.Delete(s, projectId, nil) + if err != nil { + return err + } + return nil + }) + + type ProjectCreateOptions struct { + NAME string `help:"Name of new project"` + Domain string `help:"Domain"` + Desc string `help:"Description"` + Enabled bool `help:"Project is enabled"` + Disabled bool `help:"Project is disabled"` + } + R(&ProjectCreateOptions{}, "project-create", "Create a project", func(s *mcclient.ClientSession, args *ProjectCreateOptions) error { + params := jsonutils.NewDict() + params.Add(jsonutils.NewString(args.NAME), "name") + if len(args.Domain) > 0 { + domainId, err := modules.Domains.GetId(s, args.Domain, nil) + if err != nil { + return err + } + params.Add(jsonutils.NewString(domainId), "domain_id") + } + if args.Enabled && !args.Disabled { + params.Add(jsonutils.JSONTrue, "enabled") + } else if !args.Enabled && args.Disabled { + params.Add(jsonutils.JSONTrue, "disabled") + } + if len(args.Desc) > 0 { + params.Add(jsonutils.NewString(args.Desc), "description") + } + result, err := modules.Projects.Create(s, params) + if err != nil { + return err + } + printObject(result) + return nil + }) + + type ProjectUpdateOptions struct { + ID string `help:"ID or name of the project to update"` + Domain string `help:"Domain of the project if name is given"` + Name string `help:"New name of the project"` + Desc string `help:"Description"` + Enabled bool `help:"Project is enabled"` + Disabled bool `help:"Project is disabled"` + } + R(&ProjectUpdateOptions{}, "project-update", "Update a project", func(s *mcclient.ClientSession, args *ProjectUpdateOptions) error { + query := jsonutils.NewDict() + if len(args.Domain) > 0 { + domainId, err := modules.Domains.GetId(s, args.Domain, nil) + if err != nil { + return err + } + query.Add(jsonutils.NewString(domainId), "domain_id") + } + pId, err := modules.Projects.GetId(s, args.ID, query) + if err != nil { + return err + } + params := jsonutils.NewDict() + if len(args.Name) > 0 { + params.Add(jsonutils.NewString(args.Name), "name") + } + if args.Enabled && !args.Disabled { + params.Add(jsonutils.JSONTrue, "enabled") + } else if !args.Enabled && args.Disabled { + params.Add(jsonutils.JSONTrue, "disabled") + } + if len(args.Desc) > 0 { + params.Add(jsonutils.NewString(args.Desc), "description") + } + project, err := modules.Projects.Patch(s, pId, params) + if err != nil { + return err + } + printObject(project) + return nil + }) + + type ProjectUserRoleOptions struct { + PROJECT string `help:"ID or Name of Project"` + USER string `help:"ID or Name of User"` + ROLE string `help:"ID or Name of Role"` + UserDomain string `help:"Domain of user"` + ProjectDomain string `help:"Domain of project"` + RoleDomain string `help:"Domain of role"` + } + R(&ProjectUserRoleOptions{}, "project-add-user", "Add user to project with role", func(s *mcclient.ClientSession, args *ProjectUserRoleOptions) error { + uid, err := getUserId(s, args.USER, args.UserDomain) + if err != nil { + return err + } + pid, err := getProjectId(s, args.PROJECT, args.ProjectDomain) + if err != nil { + return err + } + rid, err := getRoleId(s, args.ROLE, args.RoleDomain) + if err != nil { + return err + } + _, err = modules.RolesV3.PutInContexts(s, rid, nil, []modules.ManagerContext{{InstanceManager: &modules.Projects, InstanceId: pid}, {InstanceManager: &modules.UsersV3, InstanceId: uid}}) + if err != nil { + return err + } + return nil + }) + R(&ProjectUserRoleOptions{}, "project-has-user", "Check a user in a project with a role", func(s *mcclient.ClientSession, args *ProjectUserRoleOptions) error { + uid, err := getUserId(s, args.USER, args.UserDomain) + if err != nil { + return err + } + pid, err := getProjectId(s, args.PROJECT, args.ProjectDomain) + if err != nil { + return err + } + rid, err := getRoleId(s, args.ROLE, args.RoleDomain) + if err != nil { + return err + } + + _, err = modules.RolesV3.HeadInContexts(s, rid, nil, []modules.ManagerContext{{InstanceManager: &modules.Projects, InstanceId: pid}, {InstanceManager: &modules.UsersV3, InstanceId: uid}}) + if err != nil { + return err + } + return nil + }) + R(&ProjectUserRoleOptions{}, "project-remove-user", "Remove a user role from a project", func(s *mcclient.ClientSession, args *ProjectUserRoleOptions) error { + uid, err := getUserId(s, args.USER, args.UserDomain) + if err != nil { + return err + } + pid, err := getProjectId(s, args.PROJECT, args.ProjectDomain) + if err != nil { + return err + } + rid, err := getRoleId(s, args.ROLE, args.RoleDomain) + if err != nil { + return err + } + _, err = modules.RolesV3.DeleteInContexts(s, rid, nil, []modules.ManagerContext{{InstanceManager: &modules.Projects, InstanceId: pid}, {InstanceManager: &modules.UsersV3, InstanceId: uid}}) + if err != nil { + return err + } + return nil + }) + + type ProjectUserRolesListOptions struct { + PROJECT string `help:"ID or Name of Project"` + USER string `help:"ID or Name of User"` + UserDomain string `help:"Domain of user"` + ProjectDomain string `help:"Domain of project"` + } + R(&ProjectUserRolesListOptions{}, "project-user-roles", "Get roles of a user in a project", func(s *mcclient.ClientSession, args *ProjectUserRolesListOptions) error { + uid, err := getUserId(s, args.USER, args.UserDomain) + if err != nil { + return err + } + pid, err := getProjectId(s, args.PROJECT, args.ProjectDomain) + if err != nil { + return err + } + result, err := modules.RolesV3.ListInContexts(s, nil, []modules.ManagerContext{{InstanceManager: &modules.Projects, InstanceId: pid}, {InstanceManager: &modules.UsersV3, InstanceId: uid}}) + if err != nil { + return err + } + printList(result, modules.RolesV3.GetColumns(s)) + return nil + }) + + type ProjectGroupRoleOptions struct { + PROJECT string `help:"ID or Name of Project"` + GROUP string `help:"ID or Name of Group"` + ROLE string `help:"ID or Name of Role"` + GroupDomain string `help:"Domain of group"` + ProjectDomain string `help:"Domain of project"` + RoleDomain string `help:"Domain of role"` + } + R(&ProjectGroupRoleOptions{}, "project-add-group", "Add group to project with role", func(s *mcclient.ClientSession, args *ProjectGroupRoleOptions) error { + gid, err := getGroupId(s, args.GROUP, args.GroupDomain) + if err != nil { + return err + } + pid, err := getProjectId(s, args.PROJECT, args.ProjectDomain) + if err != nil { + return err + } + rid, err := getRoleId(s, args.ROLE, args.RoleDomain) + if err != nil { + return err + } + _, err = modules.RolesV3.PutInContexts(s, rid, nil, []modules.ManagerContext{{InstanceManager: &modules.Projects, InstanceId: pid}, {InstanceManager: &modules.Groups, InstanceId: gid}}) + if err != nil { + return err + } + return nil + }) + R(&ProjectGroupRoleOptions{}, "project-has-group", "Check a group in a project with a role", func(s *mcclient.ClientSession, args *ProjectGroupRoleOptions) error { + gid, err := getGroupId(s, args.GROUP, args.GroupDomain) + if err != nil { + return err + } + pid, err := getProjectId(s, args.PROJECT, args.ProjectDomain) + if err != nil { + return err + } + rid, err := getRoleId(s, args.ROLE, args.RoleDomain) + if err != nil { + return err + } + _, err = modules.RolesV3.HeadInContexts(s, rid, nil, []modules.ManagerContext{{InstanceManager: &modules.Projects, InstanceId: pid}, {InstanceManager: &modules.Groups, InstanceId: gid}}) + if err != nil { + return err + } + return nil + }) + R(&ProjectGroupRoleOptions{}, "project-remove-group", "Remove a role for a group in a project", func(s *mcclient.ClientSession, args *ProjectGroupRoleOptions) error { + gid, err := getGroupId(s, args.GROUP, args.GroupDomain) + if err != nil { + return err + } + pid, err := getProjectId(s, args.PROJECT, args.ProjectDomain) + if err != nil { + return err + } + rid, err := getRoleId(s, args.ROLE, args.RoleDomain) + if err != nil { + return err + } + _, err = modules.RolesV3.DeleteInContexts(s, rid, nil, []modules.ManagerContext{{InstanceManager: &modules.Projects, InstanceId: pid}, {InstanceManager: &modules.Groups, InstanceId: gid}}) + if err != nil { + return err + } + return nil + }) + type ProjectGroupRolesListOptions struct { + PROJECT string `help:"ID or Name of Project"` + GROUP string `help:"ID or Name of Group"` + GroupDomain string `help:"Domain of group"` + ProjectDomain string `help:"Domain of project"` + } + R(&ProjectGroupRolesListOptions{}, "project-group-roles", "Get roles for group in project", func(s *mcclient.ClientSession, args *ProjectGroupRolesListOptions) error { + gid, err := getGroupId(s, args.GROUP, args.GroupDomain) + if err != nil { + return err + } + pid, err := getProjectId(s, args.PROJECT, args.ProjectDomain) + if err != nil { + return err + } + result, err := modules.RolesV3.ListInContexts(s, nil, []modules.ManagerContext{{InstanceManager: &modules.Projects, InstanceId: pid}, {InstanceManager: &modules.Groups, InstanceId: gid}}) + if err != nil { + return err + } + printList(result, modules.RolesV3.GetColumns(s)) + return nil + }) + + R(&ProjectShowOptions{}, "project-shared-images", "Show shared images of a project", func(s *mcclient.ClientSession, args *ProjectShowOptions) error { + query := jsonutils.NewDict() + if len(args.Domain) > 0 { + domainId, err := modules.Domains.GetId(s, args.Domain, nil) + if err != nil { + return err + } + query.Add(jsonutils.NewString(domainId), "domain_id") + } + projectId, err := modules.Projects.GetId(s, args.ID, query) + if err != nil { + return err + } + imgs, err := modules.Images.ListSharedImages(s, projectId) + if err != nil { + return err + } + printList(imgs, modules.Images.GetColumns(s)) + return nil + }) +} diff --git a/cmd/climc/shell/quotas.go b/cmd/climc/shell/quotas.go new file mode 100644 index 0000000000..92ff47dc4c --- /dev/null +++ b/cmd/climc/shell/quotas.go @@ -0,0 +1,110 @@ +package shell + +import ( + "github.com/yunionio/jsonutils" + "github.com/yunionio/mcclient" + "github.com/yunionio/mcclient/modules" +) + +type QuotaBaseOptions struct { + Cpu int64 `help:"CPU count"` + Memory int64 `help:"Memory size in MB"` + Storage int64 `help:"Storage size in MB"` + Port int64 `help:"Internal NIC count"` + Eport int64 `help:"External NIC count"` + Bw int64 `help:"Internal bandwidth in Mbps"` + Ebw int64 `help:"External bandwidth in Mbps"` + Image int64 `help:"Template count"` + IsolatedDevice int64 `help:"Isolated device count"` +} + +func quotaArgs2Params(args *QuotaBaseOptions) *jsonutils.JSONDict { + params := jsonutils.NewDict() + if args.Cpu > 0 { + params.Add(jsonutils.NewInt(args.Cpu), "cpu") + } + if args.Memory > 0 { + params.Add(jsonutils.NewInt(args.Memory), "memory") + } + if args.Storage > 0 { + params.Add(jsonutils.NewInt(args.Storage), "storage") + } + if args.Image > 0 { + params.Add(jsonutils.NewInt(args.Image), "image") + } + if args.Port > 0 { + params.Add(jsonutils.NewInt(args.Port), "port") + } + if args.Eport > 0 { + params.Add(jsonutils.NewInt(args.Eport), "eport") + } + if args.Bw > 0 { + params.Add(jsonutils.NewInt(args.Bw), "bw") + } + if args.Ebw > 0 { + params.Add(jsonutils.NewInt(args.Ebw), "ebw") + } + if args.IsolatedDevice > 0 { + params.Add(jsonutils.NewInt(args.IsolatedDevice), "isolated_device") + } + return params +} + +func init() { + type QuotaOptions struct { + Tenant string `help:"Tenant name of ID"` + User string `help:"User name of ID"` + } + R(&QuotaOptions{}, "quota", "Show quota for current user or tenant", func(s *mcclient.ClientSession, args *QuotaOptions) error { + params := jsonutils.NewDict() + if len(args.Tenant) > 0 { + params.Add(jsonutils.NewString(args.Tenant), "tenant") + } + if len(args.User) > 0 { + params.Add(jsonutils.NewString(args.User), "user") + } + result, err := modules.Quotas.GetQuota(s, params) + if err != nil { + return err + } + printObject(result) + return nil + }) + + type QuotaSetOptions struct { + Tenant string `help:"Tenant name or ID to set quota"` + User string `help:"User name of ID"` + QuotaBaseOptions + } + R(&QuotaSetOptions{}, "quota-set", "Set quota for tenant", func(s *mcclient.ClientSession, args *QuotaSetOptions) error { + params := quotaArgs2Params(&args.QuotaBaseOptions) + if len(args.Tenant) > 0 { + params.Add(jsonutils.NewString(args.Tenant), "tenant") + } + if len(args.User) > 0 { + params.Add(jsonutils.NewString(args.User), "user") + } + result, e := modules.Quotas.DoQuotaSet(s, params) + if e != nil { + return e + } + printObject(result) + return nil + }) + + type QuotaCheckOptions struct { + TENANT string `help:"Tenant name or ID to check quota"` + QuotaBaseOptions + } + R(&QuotaCheckOptions{}, "quota-check", "Check quota for tenant", func(s *mcclient.ClientSession, args *QuotaCheckOptions) error { + params := quotaArgs2Params(&args.QuotaBaseOptions) + params.Add(jsonutils.NewString(args.TENANT), "tenant") + result, e := modules.Quotas.DoQuotaCheck(s, params) + if e != nil { + return e + } + printObject(result) + return nil + }) + +} diff --git a/cmd/climc/shell/rates.go b/cmd/climc/shell/rates.go new file mode 100644 index 0000000000..ebf8233898 --- /dev/null +++ b/cmd/climc/shell/rates.go @@ -0,0 +1,152 @@ +package shell + +import ( + "github.com/yunionio/jsonutils" + "github.com/yunionio/mcclient" + "github.com/yunionio/mcclient/modules" +) + +func init() { + /** + * 列出列表 + */ + type RateListOptions struct { + BaseListOptions + RESTYPE string `"help":"res_type of the rate"` + ACTION string `"help":"action of list :querygroup or queryhistory"` + SubResType string `"help":"query the subResType"` + Id string `"help":"ID of rate"` + } + R(&RateListOptions{}, "rate-list", "List all rates ", func(s *mcclient.ClientSession, args *RateListOptions) error { + params := FetchPagingParams(args.BaseListOptions) + + params.Add(jsonutils.NewString(args.RESTYPE), "res_type") + params.Add(jsonutils.NewString(args.ACTION), "action") + + if len(args.SubResType) > 0 { + params.Add(jsonutils.NewString(args.SubResType), "sub_res_type") + } + if len(args.Id) > 0 { + params.Add(jsonutils.NewString(args.Id), "id") + } + + result, err := modules.Rates.List(s, params) + if err != nil { + return err + } + + printList(result, modules.Rates.GetColumns(s)) + return nil + }) + + /** + * 根据ID查询详情 + */ + type RateShowOptions struct { + ID string `help:"ID of the rate to show"` + } + R(&RateShowOptions{}, "rate-show", "Show rate details", func(s *mcclient.ClientSession, args *RateShowOptions) error { + result, err := modules.Rates.Get(s, args.ID, nil) + if err != nil { + return err + } + printObject(result) + return nil + }) + + /** + * 删除 + */ + type RateDeleteOptions struct { + ID string `help:"ID of rate"` + } + R(&RateDeleteOptions{}, "rate-delete", "Delete a rate", func(s *mcclient.ClientSession, args *RateDeleteOptions) error { + rate, e := modules.Rates.Delete(s, args.ID, nil) + if e != nil { + return e + } + printObject(rate) + return nil + }) + + /** + * 创建 + */ + type RateCreateOptions struct { + RESTYPE string `help:"RESTYPE of the rate"` + SubResType string `help:"sub_res_type of the rate"` + DURATION string `help:"DURATION of the rate"` + UNIT string `help:"UNIT of the rate"` + Spec string `help:"Spec of the rate"` + RATE string `help:"RATE of the rate"` + EFFECTIVEDATE string `help:"EFFECTIVEDATE of the rate"` + Platform string `help:"Platform of the rate"` + } + + R(&RateCreateOptions{}, "rate-create", "Create a rate", func(s *mcclient.ClientSession, args *RateCreateOptions) error { + params := jsonutils.NewDict() + params.Add(jsonutils.NewString(args.RESTYPE), "res_type") + params.Add(jsonutils.NewString(args.SubResType), "sub_res_type") + params.Add(jsonutils.NewString(args.DURATION), "duration") + params.Add(jsonutils.NewString(args.UNIT), "unit") + params.Add(jsonutils.NewString(args.Spec), "spec") + params.Add(jsonutils.NewString(args.RATE), "rate") + params.Add(jsonutils.NewString(args.EFFECTIVEDATE), "effective_date") + params.Add(jsonutils.NewString(args.Platform), "platform") + + rate, err := modules.Rates.Create(s, params) + if err != nil { + return err + } + printObject(rate) + return nil + }) + + /** + * 修改 + */ + type RateUpdateOptions struct { + ID string `help:"ID of the rate"` + ResType string `help:"ResType of the rate"` + SubResType string `help:"SubResType of the rate"` + Duration string `help:"Duration of the rate"` + Unit string `help:"Unit of the rate"` + Spec string `help:"Spec of the rate"` + Rate string `help:"Rate of the rate"` + EffectiveDate string `help:"Effective Date of the rate"` + Platform string `help:"Platform of the rate"` + } + R(&RateUpdateOptions{}, "rate-update", "Update a rate", func(s *mcclient.ClientSession, args *RateUpdateOptions) error { + params := jsonutils.NewDict() + if len(args.ResType) > 0 { + params.Add(jsonutils.NewString(args.ResType), "res_type") + } + if len(args.SubResType) > 0 { + params.Add(jsonutils.NewString(args.SubResType), "sub_res_type") + } + if len(args.Duration) > 0 { + params.Add(jsonutils.NewString(args.Duration), "duration") + } + if len(args.Unit) > 0 { + params.Add(jsonutils.NewString(args.Unit), "unit") + } + if len(args.Spec) > 0 { + params.Add(jsonutils.NewString(args.Spec), "spec") + } + if len(args.Rate) > 0 { + params.Add(jsonutils.NewString(args.Rate), "rate") + } + if len(args.EffectiveDate) > 0 { + params.Add(jsonutils.NewString(args.EffectiveDate), "effective_date") + } + if len(args.Platform) > 0 { + params.Add(jsonutils.NewString(args.Platform), "platform") + } + rate, err := modules.Rates.Put(s, args.ID, params) + if err != nil { + return err + } + printObject(rate) + return nil + }) +} diff --git a/cmd/climc/shell/recipient.go b/cmd/climc/shell/recipient.go new file mode 100644 index 0000000000..b6acf9376f --- /dev/null +++ b/cmd/climc/shell/recipient.go @@ -0,0 +1,95 @@ +package shell + +import ( + "github.com/yunionio/jsonutils" + "github.com/yunionio/mcclient" + "github.com/yunionio/mcclient/modules" +) + +func init() { + + /** + * 向服务树节点添加报警接收人 + */ + type TreeNodeRecipientsCreateOptions struct { + NODE_LABELS string `help:"Labels for tree-node(split by comma)"` + USER_TYPE string `help:"User type, user|group "` + RECIPIENT_ID string `help:"User id or group id"` + RECIPIENT_TYPE string `help:"junior(slight) or senior(serious)"` + } + R(&TreeNodeRecipientsCreateOptions{}, "treenode-recipient-create", "Add recipients to tree-node", func(s *mcclient.ClientSession, args *TreeNodeRecipientsCreateOptions) error { + arr := jsonutils.NewArray() + tmpObj := jsonutils.NewDict() + tmpObj.Add(jsonutils.NewString(args.RECIPIENT_ID), "recipient_id") + tmpObj.Add(jsonutils.NewString(args.USER_TYPE), "type") + arr.Add(tmpObj) + + params := jsonutils.NewDict() + params.Add(jsonutils.NewString(args.NODE_LABELS), "node_labels") + params.Add(jsonutils.NewString(args.RECIPIENT_TYPE), "recipient_type") + params.Add(arr, "recipients") + + rst, err := modules.Recipients.Create(s, params) + + if err != nil { + return err + } + + printObject(rst) + return nil + }) + + /** + * 从服务树节点移除报警接收人 + */ + type TreeNodeRecipientsDeleteOptions struct { + NODE_LABELS string `help:"Labels for tree-node(split by comma)"` + USER_TYPE string `help:"User type, user|group "` + RECIPIENT_ID string `help:"User id or group id"` + RECIPIENT_TYPE string `help:"junior(slight) or senior(serious)"` + } + R(&TreeNodeRecipientsDeleteOptions{}, "treenode-recipient-delete", "Remove recipients from tree-node", func(s *mcclient.ClientSession, args *TreeNodeRecipientsDeleteOptions) error { + arr := jsonutils.NewArray() + tmpObj := jsonutils.NewDict() + tmpObj.Add(jsonutils.NewString(args.RECIPIENT_ID), "recipient_id") + tmpObj.Add(jsonutils.NewString(args.RECIPIENT_TYPE), "recipient_type") + tmpObj.Add(jsonutils.NewString(args.USER_TYPE), "type") + arr.Add(tmpObj) + + params := jsonutils.NewDict() + params.Add(jsonutils.NewString(args.NODE_LABELS), "node_labels") + params.Add(arr, "recipients") + + rst, err := modules.Recipients.DoDeleteRecipient(s, params) + + if err != nil { + return err + } + + printObject(rst) + return nil + }) + + /** + * 查询树节点的报警接收人信息 + */ + type TreeNodeRecipientsListOptions struct { + BaseListOptions + LIST_TYPE string `help:"Type of list: junior|senior"` + LABELS string `help:"Labels for tree-node(split by comma)"` + } + R(&TreeNodeRecipientsListOptions{}, "treenode-recipient-list", "List recipient for the tree-node ", func(s *mcclient.ClientSession, args *TreeNodeRecipientsListOptions) error { + params := FetchPagingParams(args.BaseListOptions) + params.Add(jsonutils.NewString(args.LIST_TYPE), "type") + params.Add(jsonutils.NewString(args.LABELS), "node_labels") + + result, err := modules.Recipients.List(s, params) + if err != nil { + return err + } + + printList(result, modules.Recipients.GetColumns(s)) + return nil + }) + +} diff --git a/cmd/climc/shell/regions.go b/cmd/climc/shell/regions.go new file mode 100644 index 0000000000..66c0d128ce --- /dev/null +++ b/cmd/climc/shell/regions.go @@ -0,0 +1,109 @@ +package shell + +import ( + "fmt" + "github.com/yunionio/jsonutils" + "github.com/yunionio/mcclient" + "github.com/yunionio/mcclient/modules" +) + +func init() { + type RegionListOptions struct { + Limit int64 `help:"Limit, default 0, i.e. no limit" default:"20"` + Offset int64 `help:"Offset, default 0, i.e. no offset"` + Search string `help:"Search by name"` + } + R(&RegionListOptions{}, "region-list", "List regions", func(s *mcclient.ClientSession, args *RegionListOptions) error { + query := jsonutils.NewDict() + if args.Limit > 0 { + query.Add(jsonutils.NewInt(args.Limit), "limit") + } + if args.Offset > 0 { + query.Add(jsonutils.NewInt(args.Offset), "offset") + } + if len(args.Search) > 0 { + query.Add(jsonutils.NewString(args.Search), "id__icontains") + } + result, err := modules.Regions.List(s, query) + if err != nil { + return err + } + printList(result, modules.Regions.GetColumns(s)) + return nil + }) + + type RegionShowOptions struct { + REGION string `help:"ID of region"` + Zone string `help:"ID of region"` + } + R(&RegionShowOptions{}, "region-show", "Show details of region", func(s *mcclient.ClientSession, args *RegionShowOptions) error { + ID := mcclient.RegionID(args.REGION, args.Zone) + result, err := modules.Regions.Get(s, ID, nil) + if err != nil { + return err + } + printObject(result) + return nil + }) + R(&RegionShowOptions{}, "region-delete", "Delete region", func(s *mcclient.ClientSession, args *RegionShowOptions) error { + ID := mcclient.RegionID(args.REGION, args.Zone) + _, err := modules.Regions.Delete(s, ID, nil) + if err != nil { + return err + } + return nil + }) + + type RegionCreateOptions struct { + REGION string `help:"ID of the region"` + Zone string `help:"ID of the zone"` + Name string `help:"Name of the region"` + Desc string `help:"Description"` + } + R(&RegionCreateOptions{}, "region-create", "Create a region", func(s *mcclient.ClientSession, args *RegionCreateOptions) error { + params := jsonutils.NewDict() + ID := mcclient.RegionID(args.REGION, args.Zone) + params.Add(jsonutils.NewString(ID), "id") + if len(args.Name) > 0 { + params.Add(jsonutils.NewString(args.Name), "name") + } + if len(args.Desc) > 0 { + params.Add(jsonutils.NewString(args.Desc), "description") + } + if len(args.Zone) > 0 { + params.Add(jsonutils.NewString(args.REGION), "parent_region_id") + } + region, err := modules.Regions.Create(s, params) + if err != nil { + return err + } + printObject(region) + return nil + }) + + type RegionUpdateOptions struct { + REGION string `help:"ID of region"` + Zone string `help:"Zone"` + Name string `help:"New name of the region"` + Desc string `help:"New description of the region"` + } + R(&RegionUpdateOptions{}, "region-update", "Update a region", func(s *mcclient.ClientSession, args *RegionUpdateOptions) error { + ID := mcclient.RegionID(args.REGION, args.Zone) + params := jsonutils.NewDict() + if len(args.Name) > 0 { + params.Add(jsonutils.NewString(args.Name), "name") + } + if len(args.Desc) > 0 { + params.Add(jsonutils.NewString(args.Desc), "description") + } + if params.Size() == 0 { + return fmt.Errorf("No data to update") + } + region, err := modules.Regions.Patch(s, ID, params) + if err != nil { + return err + } + printObject(region) + return nil + }) +} diff --git a/cmd/climc/shell/reservedips.go b/cmd/climc/shell/reservedips.go new file mode 100644 index 0000000000..1561337da2 --- /dev/null +++ b/cmd/climc/shell/reservedips.go @@ -0,0 +1,59 @@ +package shell + +import ( + "github.com/yunionio/jsonutils" + "github.com/yunionio/mcclient" + "github.com/yunionio/mcclient/modules" +) + +func init() { + type NetworkReserveIPOptions struct { + NETWORK string `help:"IP or name of network"` + IP string `help:"IP to reserve"` + NOTES string `help:"Why reserve this IP"` + } + R(&NetworkReserveIPOptions{}, "network-reserve-ip", "Reserve an IP address from pool", func(s *mcclient.ClientSession, args *NetworkReserveIPOptions) error { + params := jsonutils.NewDict() + params.Add(jsonutils.NewString(args.IP), "ip") + params.Add(jsonutils.NewString(args.NOTES), "notes") + net, err := modules.Networks.PerformAction(s, args.NETWORK, "reserve-ip", params) + if err != nil { + return err + } + printObject(net) + return nil + }) + + type NetworkReleaseReservedIPOptions struct { + NETWORK string `help:"IP or name of network"` + IP string `help:"IP to release"` + } + R(&NetworkReleaseReservedIPOptions{}, "network-release-reserved-ip", "Release a reserved IP into pool", func(s *mcclient.ClientSession, args *NetworkReleaseReservedIPOptions) error { + params := jsonutils.NewDict() + params.Add(jsonutils.NewString(args.IP), "ip") + net, err := modules.Networks.PerformAction(s, args.NETWORK, "release-reserved-ip", params) + if err != nil { + return err + } + printObject(net) + return nil + }) + + type ReservedIPListOptions struct { + BaseListOptions + Network string `help:"Network filter"` + } + R(&ReservedIPListOptions{}, "reserved-ip-list", "Show all reserved IPs for any network", func(s *mcclient.ClientSession, args *ReservedIPListOptions) error { + params := FetchPagingParams(args.BaseListOptions) + if len(args.Network) > 0 { + params.Add(jsonutils.NewString(args.Network), "network") + } + result, err := modules.ReservedIPs.List(s, params) + if err != nil { + return err + } + printList(result, modules.ReservedIPs.GetColumns(s)) + return nil + }) + +} diff --git a/cmd/climc/shell/resource_details.go b/cmd/climc/shell/resource_details.go new file mode 100644 index 0000000000..f3fbb806d5 --- /dev/null +++ b/cmd/climc/shell/resource_details.go @@ -0,0 +1,35 @@ +package shell + +import ( + "github.com/yunionio/jsonutils" + "github.com/yunionio/mcclient" + "github.com/yunionio/mcclient/modules" +) + +func init() { + /** + * 列出列表 + */ + type ResourceDetailListOptions struct { + BaseListOptions + QUERYTYPE string `"help":"query type of the resource_detail"` + ProjectId string `"help":"project id of the resource_detail"` + } + R(&ResourceDetailListOptions{}, "resourcedetail-list", "List all resource details", func(s *mcclient.ClientSession, args *ResourceDetailListOptions) error { + params := FetchPagingParams(args.BaseListOptions) + if len(args.QUERYTYPE) > 0 { + params.Add(jsonutils.NewString(args.QUERYTYPE), "query_type") + } + if len(args.ProjectId) > 0 { + params.Add(jsonutils.NewString(args.ProjectId), "project_Iid") + } + + result, err := modules.ResourceDetails.List(s, params) + if err != nil { + return err + } + + printList(result, modules.ResourceDetails.GetColumns(s)) + return nil + }) +} diff --git a/cmd/climc/shell/resource_fees.go b/cmd/climc/shell/resource_fees.go new file mode 100644 index 0000000000..43779f1d26 --- /dev/null +++ b/cmd/climc/shell/resource_fees.go @@ -0,0 +1,50 @@ +package shell + +import ( + "github.com/yunionio/jsonutils" + "github.com/yunionio/mcclient" + "github.com/yunionio/mcclient/modules" +) + +func init() { + /** + * 列出列表 + */ + type ResourceFeeListOptions struct { + BaseListOptions + STATTYPE string `"help":"stat type of the resource_fee"` + STATMONTH string `"help":"stat month of the resource_fee"` + ProjectId string `"help":"project id of the resource_fee"` + StartDay string `"help":"start day of the resource_fee"` + EndDay string `"help":"end day of the resource_fee"` + } + R(&ResourceFeeListOptions{}, "resourcefee-list", "List all resource fees", func(s *mcclient.ClientSession, args *ResourceFeeListOptions) error { + params := FetchPagingParams(args.BaseListOptions) + if len(args.STATTYPE) > 0 { + params.Add(jsonutils.NewString(args.STATTYPE), "stat_type") + } + if len(args.STATMONTH) > 0 { + params.Add(jsonutils.NewString(args.STATMONTH), "stat_month") + } + + if len(args.ProjectId) > 0 { + params.Add(jsonutils.NewString(args.ProjectId), "project_id") + } + + if len(args.StartDay) > 0 { + params.Add(jsonutils.NewString(args.StartDay), "start_day") + } + + if len(args.EndDay) > 0 { + params.Add(jsonutils.NewString(args.EndDay), "end_day") + } + + result, err := modules.ResourceFees.List(s, params) + if err != nil { + return err + } + + printList(result, modules.ResourceFees.GetColumns(s)) + return nil + }) +} diff --git a/cmd/climc/shell/role_assignments.go b/cmd/climc/shell/role_assignments.go new file mode 100644 index 0000000000..9eeff8148c --- /dev/null +++ b/cmd/climc/shell/role_assignments.go @@ -0,0 +1,70 @@ +package shell + +import ( + "github.com/yunionio/jsonutils" + "github.com/yunionio/mcclient" + "github.com/yunionio/mcclient/modules" +) + +func init() { + type RoleAssignmentsOptions struct { + Effective bool `help:"Include role assignment of group members"` + Domain string `help:"Role assignments for domain"` + User string `help:"For user"` + UserDomain string `help:"Domain for user"` + Group string `help:"For group"` + GroupDomain string `help:"Domain for group"` + Project string `help:"Role assignments for project"` + ProjectDomain string `help:"Domain for project"` + Role string `help:"Role assignments for role"` + RoleDomain string `help:"Domain for role"` + } + R(&RoleAssignmentsOptions{}, "role-assignments", "List all role assignments", func(s *mcclient.ClientSession, args *RoleAssignmentsOptions) error { + query := jsonutils.NewDict() + query.Add(jsonutils.JSONNull, "include_names") + if args.Effective { + query.Add(jsonutils.JSONNull, "effective") + } + if len(args.Domain) > 0 { + domainId, err := modules.Domains.GetId(s, args.Domain, nil) + if err != nil { + return err + } + query.Add(jsonutils.NewString(domainId), "scope", "domain", "id") + } + if len(args.Project) > 0 { + pid, err := getProjectId(s, args.Project, args.ProjectDomain) + if err != nil { + return err + } + query.Add(jsonutils.NewString(pid), "scope", "project", "id") + } + if len(args.User) > 0 { + uid, err := getUserId(s, args.User, args.UserDomain) + if err != nil { + return err + } + query.Add(jsonutils.NewString(uid), "user", "id") + } + if len(args.Group) > 0 { + gid, err := getGroupId(s, args.Group, args.GroupDomain) + if err != nil { + return err + } + query.Add(jsonutils.NewString(gid), "group", "id") + } + if len(args.Role) > 0 { + rid, err := getRoleId(s, args.Role, args.RoleDomain) + if err != nil { + return err + } + query.Add(jsonutils.NewString(rid), "role", "id") + } + result, err := modules.RoleAssignments.List(s, query) + if err != nil { + return err + } + printList(result, modules.RoleAssignments.GetColumns(s)) + return nil + }) +} diff --git a/cmd/climc/shell/roles.go b/cmd/climc/shell/roles.go new file mode 100644 index 0000000000..897a94b43f --- /dev/null +++ b/cmd/climc/shell/roles.go @@ -0,0 +1,158 @@ +package shell + +import ( + "github.com/yunionio/jsonutils" + "github.com/yunionio/mcclient" + "github.com/yunionio/mcclient/modules" +) + +func init() { + type RoleListOptions struct { + Name string `help:"Name filter"` + Domain string `help:"Domain filter"` + Limit int64 `help:"Items per page" default:"20"` + Offset int64 `help:"Offset"` + Search string `help:"search text"` + } + R(&RoleListOptions{}, "role-list", "List keystone Roles", func(s *mcclient.ClientSession, args *RoleListOptions) error { + mod, err := modules.GetModule(s, "roles") + if err != nil { + return err + } + query := jsonutils.NewDict() + if len(args.Name) > 0 { + query.Add(jsonutils.NewString(args.Name), "name") + } + if len(args.Domain) > 0 { + domainId, err := modules.Domains.GetId(s, args.Domain, nil) + if err != nil { + return err + } + query.Add(jsonutils.NewString(domainId), "domain_id") + } + if args.Limit > 0 { + query.Add(jsonutils.NewInt(args.Limit), "limit") + } + if args.Offset > 0 { + query.Add(jsonutils.NewInt(args.Offset), "offset") + } + if len(args.Search) > 0 { + query.Add(jsonutils.NewString(args.Search), "name__icontains") + } + result, err := mod.List(s, query) + if err != nil { + return err + } + printList(result, mod.GetColumns(s)) + return nil + }) + + type RoleDetailOptions struct { + ID string `help:"ID or name of role"` + Domain string `help:"Domain"` + } + R(&RoleDetailOptions{}, "role-show", "Show details of a role", func(s *mcclient.ClientSession, args *RoleDetailOptions) error { + mod, err := modules.GetModule(s, "roles") + if err != nil { + return err + } + query := jsonutils.NewDict() + if len(args.Domain) > 0 { + domainId, err := modules.Domains.GetId(s, args.Domain, nil) + if err != nil { + return err + } + query.Add(jsonutils.NewString(domainId), "domain_id") + } + role, err := mod.Get(s, args.ID, query) + if err != nil { + return err + } + printObject(role) + return nil + }) + R(&RoleDetailOptions{}, "role-delete", "Delete a role", func(s *mcclient.ClientSession, args *RoleDetailOptions) error { + query := jsonutils.NewDict() + if len(args.Domain) > 0 { + domainId, err := modules.Domains.GetId(s, args.Domain, nil) + if err != nil { + return err + } + query.Add(jsonutils.NewString(domainId), "domain_id") + } + mod, err := modules.GetModule(s, "roles") + if err != nil { + return err + } + rid, err := mod.GetId(s, args.ID, query) + if err != nil { + return err + } + role, err := mod.Delete(s, rid, nil) + if err != nil { + return err + } + printObject(role) + return nil + }) + + type RoleCreateOptions struct { + NAME string `help:"Role name"` + Domain string `help:"Domain"` + } + R(&RoleCreateOptions{}, "role-create", "Create a new role", func(s *mcclient.ClientSession, args *RoleCreateOptions) error { + params := jsonutils.NewDict() + params.Add(jsonutils.NewString(args.NAME), "name") + if len(args.Domain) > 0 { + domainId, err := modules.Domains.GetId(s, args.Domain, nil) + if err != nil { + return err + } + params.Add(jsonutils.NewString(domainId), "domain_id") + } + mod, err := modules.GetModule(s, "roles") + if err != nil { + return err + } + role, err := mod.Create(s, params) + if err != nil { + return err + } + printObject(role) + return nil + }) + + type RoleUpdateOptions struct { + ID string `help:"Role ID or Name"` + Domain string `help:"Domain"` + Name string `help:"Name to alter"` + } + R(&RoleUpdateOptions{}, "role-update", "Update role", func(s *mcclient.ClientSession, args *RoleUpdateOptions) error { + query := jsonutils.NewDict() + if len(args.Domain) > 0 { + domainId, err := modules.Domains.GetId(s, args.Domain, nil) + if err != nil { + return err + } + query.Add(jsonutils.NewString(domainId), "domain_id") + } + mod, err := modules.GetModule(s, "roles") + if err != nil { + return err + } + rid, err := mod.GetId(s, args.ID, query) + if err != nil { + return err + } + params := jsonutils.NewDict() + if len(args.Name) > 0 { + params.Add(jsonutils.NewString(args.Name), "name") + } + role, err := mod.Patch(s, rid, params) + if err != nil { + return err + } + printObject(role) + return nil + }) +} diff --git a/cmd/climc/shell/schedtaghosts.go b/cmd/climc/shell/schedtaghosts.go new file mode 100644 index 0000000000..a8672e51d4 --- /dev/null +++ b/cmd/climc/shell/schedtaghosts.go @@ -0,0 +1,53 @@ +package shell + +import ( + "github.com/yunionio/mcclient" + "github.com/yunionio/mcclient/modules" +) + +func init() { + type SchedtagHostListOptions struct { + BaseListOptions + Schedtag string `help:"ID or Name of schedtag"` + } + R(&SchedtagHostListOptions{}, "schedtag-host-list", "List all scheduler tag and host pairs", func(s *mcclient.ClientSession, args *SchedtagHostListOptions) error { + mod, err := modules.GetJointModule2(s, &modules.Schedtags, &modules.Hosts) + if err != nil { + return err + } + params := FetchPagingParams(args.BaseListOptions) + var result *modules.ListResult + if len(args.Schedtag) > 0 { + result, err = mod.ListDescendent(s, args.Schedtag, params) + } else { + result, err = mod.List(s, params) + } + if err != nil { + return err + } + printList(result, mod.GetColumns(s)) + return nil + }) + + type SchedtagHostPair struct { + SCHEDTAG string `help:"Scheduler tag"` + HOST string `help:"Host"` + } + R(&SchedtagHostPair{}, "schedtag-host-add", "Add a schedtag to a host", func(s *mcclient.ClientSession, args *SchedtagHostPair) error { + schedtag, err := modules.Schedtaghosts.Attach(s, args.SCHEDTAG, args.HOST, nil) + if err != nil { + return err + } + printObject(schedtag) + return nil + }) + + R(&SchedtagHostPair{}, "schedtag-host-remove", "Remove a schedtag from a host", func(s *mcclient.ClientSession, args *SchedtagHostPair) error { + schedtag, err := modules.Schedtaghosts.Detach(s, args.SCHEDTAG, args.HOST) + if err != nil { + return err + } + printObject(schedtag) + return nil + }) +} diff --git a/cmd/climc/shell/schedtags.go b/cmd/climc/shell/schedtags.go new file mode 100644 index 0000000000..a032832645 --- /dev/null +++ b/cmd/climc/shell/schedtags.go @@ -0,0 +1,99 @@ +package shell + +import ( + "fmt" + "github.com/yunionio/jsonutils" + "github.com/yunionio/mcclient" + "github.com/yunionio/mcclient/modules" +) + +func init() { + type SchedtagListOptions struct { + BaseListOptions + } + R(&SchedtagListOptions{}, "schedtag-list", "List schedule tags", func(s *mcclient.ClientSession, suboptions *SchedtagListOptions) error { + params := FetchPagingParams(suboptions.BaseListOptions) + result, err := modules.Schedtags.List(s, params) + if err != nil { + return err + } + printList(result, modules.Schedtags.GetColumns(s)) + return nil + }) + + type SchedtagShowOptions struct { + ID string `help:"ID or Name of the scheduler tag to show"` + } + R(&SchedtagShowOptions{}, "schedtag-show", "Show scheduler tag details", func(s *mcclient.ClientSession, args *SchedtagShowOptions) error { + result, err := modules.Schedtags.Get(s, args.ID, nil) + if err != nil { + return err + } + printObject(result) + return nil + }) + + R(&SchedtagShowOptions{}, "schedtag-delete", "Delete a scheduler tag", func(s *mcclient.ClientSession, args *SchedtagShowOptions) error { + result, err := modules.Schedtags.Delete(s, args.ID, nil) + if err != nil { + return err + } + printObject(result) + return nil + }) + + type SchedtagCreateOptions struct { + NAME string `help:"Name of new schedtag"` + Strategy string `help:"Policy" choices:"require|exclude|prefer|avoid"` + Desc string `help:"Description"` + } + R(&SchedtagCreateOptions{}, "schedtag-create", "Create a schedule tag", func(s *mcclient.ClientSession, args *SchedtagCreateOptions) error { + params := jsonutils.NewDict() + params.Add(jsonutils.NewString(args.NAME), "name") + if len(args.Strategy) > 0 { + params.Add(jsonutils.NewString(args.Strategy), "default_strategy") + } + if len(args.Desc) > 0 { + params.Add(jsonutils.NewString(args.Desc), "description") + } + schedtag, err := modules.Schedtags.Create(s, params) + if err != nil { + return err + } + printObject(schedtag) + return nil + }) + + type SchedtagUpdateOptions struct { + ID string `help:"ID or Name of schetag"` + Name string `help:"New name of schedtag"` + Strategy string `help:"Policy" choices:"require|exclude|prefer|avoid"` + Desc string `help:"Description"` + ClearStrategy bool `help:"Clear default schedule policy"` + } + R(&SchedtagUpdateOptions{}, "schedtag-update", "Update a schedule tag", func(s *mcclient.ClientSession, args *SchedtagUpdateOptions) error { + params := jsonutils.NewDict() + if len(args.Name) > 0 { + params.Add(jsonutils.NewString(args.Name), "name") + } + if len(args.Strategy) > 0 { + params.Add(jsonutils.NewString(args.Strategy), "default_strategy") + } + if len(args.Desc) > 0 { + params.Add(jsonutils.NewString(args.Desc), "description") + } + if args.ClearStrategy { + params.Add(jsonutils.NewString(""), "default_strategy") + } + if params.Size() == 0 { + return fmt.Errorf("No valid data to update") + } + schedtag, err := modules.Schedtags.Update(s, args.ID, params) + if err != nil { + return err + } + printObject(schedtag) + return nil + }) + +} diff --git a/cmd/climc/shell/schedulers.go b/cmd/climc/shell/schedulers.go new file mode 100644 index 0000000000..9f6ef475ed --- /dev/null +++ b/cmd/climc/shell/schedulers.go @@ -0,0 +1,219 @@ +package shell + +import ( + "fmt" + + "github.com/yunionio/jsonutils" + "github.com/yunionio/mcclient" + "github.com/yunionio/mcclient/modules" +) + +func init() { + type SchedulerTestOptions struct { + Mem int64 `help:"Memory size (MB), default 512" metavar:"MEMORY" default:"512"` + Ncpu int64 `help:"#CPU cores of VM server, default 1" default:"1" metavar:""` + Disk []string `help:"Disk descriptions" nargs:"+"` + BaremetalDiskConfig []string `help:"Baremetal disk layout configuration"` + Net []string `help:"Network descriptions" metavar:"NETWORK"` + IsolatedDevice []string `help:"Isolated device model or ID" metavar:"ISOLATED_DEVICE"` + Group []string `help:"Group of virtual server"` + SchedTag []string `help:"Schedule policy, key = SchedTag name, value = require|exclude|prefer|avoid" metavar:""` + Zone string `help:"Preferred zone where virtual server should be created"` + Host string `help:"Preferred host where virtual server should be created"` + Project string `help:"Owner project ID or Name"` + Hypervisor string `help:"Hypervisor type" choices:"kvm|esxi|baremetal|container|aliyun"` + Count int64 `help:"Create multiple simultaneously, default 1" default:"1"` + Log bool `help:"Record to schedule history"` + SuggestionLimit int64 `help:"Number of schedule candidate informations" default:"50"` + SuggestionAll bool `help:"Show all schedule candidate informations"` + Details bool `help:"Show suggestion details"` + } + R(&SchedulerTestOptions{}, "scheduler-test", "Emulate schedule process", + func(s *mcclient.ClientSession, args *SchedulerTestOptions) error { + params := jsonutils.NewDict() + data := jsonutils.NewDict() + params.Add(jsonutils.JSONTrue, "suggestion") + if args.Mem > 0 { + data.Add(jsonutils.NewInt(args.Mem), "vmem_size") + } + if args.Ncpu > 0 { + data.Add(jsonutils.NewInt(args.Ncpu), "vcpu_count") + } + for i, d := range args.Disk { + data.Add(jsonutils.NewString(d), fmt.Sprintf("disk.%d", i)) + } + for i, n := range args.Net { + data.Add(jsonutils.NewString(n), fmt.Sprintf("net.%d", i)) + } + for i, g := range args.IsolatedDevice { + data.Add(jsonutils.NewString(g), fmt.Sprintf("isolated_device.%d", i)) + } + if len(args.Group) > 0 { + for i, g := range args.Group { + data.Add(jsonutils.NewString(g), fmt.Sprintf("group.%d", i)) + } + } + if len(args.Host) > 0 { + data.Add(jsonutils.NewString(args.Host), "prefer_host") + } else { + if len(args.Zone) > 0 { + data.Add(jsonutils.NewString(args.Zone), "prefer_zone") + } + if len(args.SchedTag) > 0 { + for i, aggr := range args.SchedTag { + data.Add(jsonutils.NewString(aggr), fmt.Sprintf("aggregate.%d", i)) + } + } + } + if len(args.Project) > 0 { + data.Add(jsonutils.NewString(args.Project), "tenant") + } + if len(args.Hypervisor) > 0 { + data.Add(jsonutils.NewString(args.Hypervisor), "hypervisor") + if args.Hypervisor == "baremetal" { + for i, c := range args.BaremetalDiskConfig { + params.Add(jsonutils.NewString(c), fmt.Sprintf("baremetal_disk_config.%d", i)) + } + } + } + params.Add(jsonutils.NewInt(args.Count), "count") + if args.Log { + params.Add(jsonutils.JSONTrue, "record_to_history") + } else { + params.Add(jsonutils.JSONFalse, "record_to_history") + } + params.Add(jsonutils.NewInt(args.SuggestionLimit), "suggestion_limit") + if args.SuggestionAll { + params.Add(jsonutils.JSONTrue, "suggestion_all") + } else { + params.Add(jsonutils.JSONFalse, "suggestion_all") + } + + if args.Details { + params.Add(jsonutils.JSONTrue, "suggestion_details") + } else { + params.Add(jsonutils.JSONFalse, "suggestion_details") + } + params.Add(data, "scheduler") + result, err := modules.SchedManager.Test(s, params) + if err != nil { + return err + } + + listFields := []string{"id", "name", "capacity", "count", "score"} + if args.Details { + listFields = append(listFields, "capacity_details", "score_details") + } + + printList(modules.JSON2ListResult(result), listFields) + return nil + }) + + type SchedulerCandidateListOptions struct { + Type string `help:"Sched type filter" choices:"baremetal|host"` + Zone string `help:"Zone ID"` + Limit int `default:"50" help:"Page limit"` + Offset int `default:"0" help:"Page offset"` + } + R(&SchedulerCandidateListOptions{}, "scheduler-candidate-list", "List scheduler candidates", + func(s *mcclient.ClientSession, args *SchedulerCandidateListOptions) error { + params := jsonutils.NewDict() + if args.Limit > 0 { + params.Add(jsonutils.NewInt(int64(args.Limit)), "limit") + } + if args.Offset > 0 { + params.Add(jsonutils.NewInt(int64(args.Offset)), "offset") + } + if len(args.Zone) > 0 { + params.Add(jsonutils.NewString(args.Zone), "zone") + } + if len(args.Type) > 0 { + params.Add(jsonutils.NewString(args.Type), "type") + } + result, err := modules.SchedManager.CandidateList(s, params) + if err != nil { + return err + } + printList(modules.JSON2ListResult(result), []string{ + "id", "name", "host_type", "cpu(free/reserverd/total)", + "mem(free/reserverd/total)", "storage(free/reserverd/total)", + "status", "host_status", "enable_status"}) + return nil + }) + + type SchedulerCandidateShowOptions struct { + ID string `help:"ID or name of host"` + } + R(&SchedulerCandidateShowOptions{}, "scheduler-candidate-show", "Show candidate detail", + func(s *mcclient.ClientSession, args *SchedulerCandidateShowOptions) error { + params := jsonutils.NewDict() + result, err := modules.SchedManager.CandidateDetail(s, args.ID, params) + if err != nil { + return err + } + fmt.Println(result.YAMLString()) + return nil + }) + + type SchedulerHistoryListOptions struct { + Limit int `default:"50" help:"Page limit"` + Offset int `default:"0" help:"Page offset"` + All bool `help:"Show all histories, including scheduler-test"` + } + R(&SchedulerHistoryListOptions{}, "scheduler-history-list", "Show scheduler history list", + func(s *mcclient.ClientSession, args *SchedulerHistoryListOptions) error { + params := jsonutils.NewDict() + if args.Limit == 0 { + params.Add(jsonutils.NewInt(1024), "limit") + } else { + params.Add(jsonutils.NewInt(int64(args.Limit)), "limit") + } + if args.Offset > 0 { + params.Add(jsonutils.NewInt(int64(args.Offset)), "offset") + } + if args.All { + params.Add(jsonutils.JSONTrue, "all") + } else { + params.Add(jsonutils.JSONFalse, "all") + } + result, err := modules.SchedManager.HistoryList(s, params) + if err != nil { + return err + } + printList(modules.JSON2ListResult(result), []string{ + "session_id", "time", "status", "consuming", + }) + return nil + }) + + type SchedulerHistoryShowOptions struct { + ID string `help:"Session or guest ID"` + Log bool `help:"Show schedule process log"` + Raw bool `help:"Show raw data"` + Format string `help:"Output format" choices:"json|yaml"` + } + R(&SchedulerHistoryShowOptions{}, "scheduler-history-show", "Show scheduler history detail", + func(s *mcclient.ClientSession, args *SchedulerHistoryShowOptions) error { + params := jsonutils.NewDict() + if args.Log { + params.Add(jsonutils.JSONTrue, "log") + } else { + params.Add(jsonutils.JSONFalse, "log") + } + if args.Raw { + params.Add(jsonutils.JSONTrue, "raw") + } else { + params.Add(jsonutils.JSONFalse, "false") + } + result, err := modules.SchedManager.HistoryShow(s, args.ID, params) + if err != nil { + return err + } + if args.Format == "json" { + fmt.Println(result.PrettyString()) + } else { + fmt.Println(result.YAMLString()) + } + return nil + }) +} diff --git a/cmd/climc/shell/secgrouprules.go b/cmd/climc/shell/secgrouprules.go new file mode 100644 index 0000000000..82461a98ed --- /dev/null +++ b/cmd/climc/shell/secgrouprules.go @@ -0,0 +1,147 @@ +package shell + +import ( + "github.com/yunionio/jsonutils" + "github.com/yunionio/mcclient" + "github.com/yunionio/mcclient/modules" +) + +func init() { + type SecGroupRulesListOptions struct { + BaseListOptions + Secgroup string `help:"Secgroup ID or Name"` + Direction string `help:"filter Direction of rule" choices:"in|out"` + Protocol string `help:"filter Protocol of rule" choices:"any|tcp|udp|icmp"` + Action string `help:"filter Actin of rule" choices:"allow|deny"` + } + + R(&SecGroupRulesListOptions{}, "secgroup-rule-list", "List all security group", func(s *mcclient.ClientSession, args *SecGroupRulesListOptions) error { + params := FetchPagingParams(args.BaseListOptions) + if len(args.Secgroup) > 0 { + params.Add(jsonutils.NewString(args.Secgroup), "secgroup") + } + if len(args.Direction) > 0 { + params.Add(jsonutils.NewString(args.Direction), "direction") + } + if len(args.Protocol) > 0 { + params.Add(jsonutils.NewString(args.Protocol), "protocol") + } + if len(args.Action) > 0 { + params.Add(jsonutils.NewString(args.Action), "action") + } + result, err := modules.SecGroupRules.List(s, params) + if err != nil { + return err + } + printList(result, modules.SecGroupRules.GetColumns(s)) + return nil + }) + + type SecGroupRuleDetailOptions struct { + ID string `help:"ID or Name of security group rule"` + } + R(&SecGroupRuleDetailOptions{}, "secgroup-rule-show", "Show details of rule", func(s *mcclient.ClientSession, args *SecGroupRuleDetailOptions) error { + if rule, e := modules.SecGroupRules.Get(s, args.ID, nil); e != nil { + return e + } else { + printObject(rule) + } + return nil + }) + + R(&SecGroupRuleDetailOptions{}, "secgroup-rule-delete", "Delete a disk", func(s *mcclient.ClientSession, args *SecGroupRuleDetailOptions) error { + if rule, e := modules.SecGroupRules.Delete(s, args.ID, nil); e != nil { + return e + } else { + printObject(rule) + } + return nil + }) + + type SecGroupRulesCreateOptions struct { + NAME string `help:"Name of security group rule to create"` + SECGROUP string `help:"Secgroup ID or Name" metavar:"Secgroup"` + Direction string `help:"Direction of rule" choices:"in|out"` + Action string `help:"Action of rule" choices:"allow|deny"` + Protocol string `help:"Protocol of rule" choices:"tcp|udp|icmp|any"` + Ports string `help:"Ports of rule"` + Cidr string `help:"Cidr of rule"` + Priority int64 `help:"priority of Rule"` + Desc string `help:"Description"` + } + + R(&SecGroupRulesCreateOptions{}, "secgroup-rule-create", "Create all security group rule", func(s *mcclient.ClientSession, args *SecGroupRulesCreateOptions) error { + params := jsonutils.NewDict() + params.Add(jsonutils.NewString(args.NAME), "name") + if len(args.Desc) > 0 { + params.Add(jsonutils.NewString(args.Desc), "description") + } + if args.Priority > 0 { + params.Add(jsonutils.NewInt(args.Priority), "priority") + } + if len(args.Direction) > 0 { + params.Add(jsonutils.NewString(args.Direction), "direction") + } + if len(args.Action) > 0 { + params.Add(jsonutils.NewString(args.Action), "action") + } + if len(args.Protocol) > 0 { + params.Add(jsonutils.NewString(args.Protocol), "protocol") + } + if len(args.Ports) > 0 { + params.Add(jsonutils.NewString(args.Ports), "ports") + } + if len(args.Cidr) > 0 { + params.Add(jsonutils.NewString(args.Cidr), "cidr") + } + params.Add(jsonutils.NewString(args.SECGROUP), "secgroup") + secgrouprules, err := modules.SecGroupRules.Create(s, params) + if err != nil { + return err + } + printObject(secgrouprules) + return nil + }) + + type SecGroupRulesUpdateOptions struct { + ID string `help:"ID or name of rule"` + Name string `help:"New name of rule"` + Priority int64 `help:"priority of Rule"` + Protocol string `help:"Protocol of rule" choices:"any|tcp|udp|icmp"` + Ports string `help:"Ports of rule"` + Cidr string `help:"Cidr of rule"` + Action string `help:"filter Actin of rule" choices:"allow|deny"` + Desc string `help:"Description" metavar:"Description"` + } + + R(&SecGroupRulesUpdateOptions{}, "secgroup-rule-update", "Update property of a security group rule", func(s *mcclient.ClientSession, args *SecGroupRulesUpdateOptions) error { + params := jsonutils.NewDict() + if len(args.Name) > 0 { + params.Add(jsonutils.NewString(args.Name), "name") + } + if len(args.Desc) > 0 { + params.Add(jsonutils.NewString(args.Desc), "description") + } + if args.Priority > 0 { + params.Add(jsonutils.NewInt(args.Priority), "priority") + } + if len(args.Protocol) > 0 { + params.Add(jsonutils.NewString(args.Protocol), "protocol") + } + if len(args.Ports) > 0 { + params.Add(jsonutils.NewString(args.Ports), "ports") + } + if len(args.Cidr) > 0 { + params.Add(jsonutils.NewString(args.Cidr), "cidr") + } + if len(args.Action) > 0 { + params.Add(jsonutils.NewString(args.Action), "action") + } + if rule, e := modules.SecGroupRules.Update(s, args.ID, params); e != nil { + return e + } else { + printObject(rule) + } + return nil + }) +} diff --git a/cmd/climc/shell/secgroups.go b/cmd/climc/shell/secgroups.go new file mode 100644 index 0000000000..18eaa6cd6a --- /dev/null +++ b/cmd/climc/shell/secgroups.go @@ -0,0 +1,157 @@ +package shell + +import ( + "fmt" + + "github.com/yunionio/jsonutils" + "github.com/yunionio/mcclient" + "github.com/yunionio/mcclient/modules" +) + +func init() { + type SecGroupsListOptions struct { + BaseListOptions + } + + R(&SecGroupsListOptions{}, "secgroup-list", "List all security group", func(s *mcclient.ClientSession, args *SecGroupsListOptions) error { + params := FetchPagingParams(args.BaseListOptions) + result, err := modules.SecGroups.List(s, params) + if err != nil { + return err + } + printList(result, modules.SecGroups.GetColumns(s)) + return nil + }) + + type SecGroupsCreateOptions struct { + NAME string `help:"Name of security group to create"` + RULES []string `help:"security rule to create"` + Desc string `help:"Description"` + } + + R(&SecGroupsCreateOptions{}, "secgroup-create", "Create a security group", func(s *mcclient.ClientSession, args *SecGroupsCreateOptions) error { + params := jsonutils.NewDict() + params.Add(jsonutils.NewString(args.NAME), "name") + if len(args.Desc) > 0 { + params.Add(jsonutils.NewString(args.Desc), "description") + } + for i, a := range args.RULES { + params.Add(jsonutils.NewString(a), fmt.Sprintf("rule.%d", i)) + } + secgroups, err := modules.SecGroups.Create(s, params) + if err != nil { + return err + } + printObject(secgroups) + return nil + + }) + + type SecGroupsDetailOptions struct { + ID string `help:"ID or Name of security group"` + } + R(&SecGroupsDetailOptions{}, "secgroup-show", "Show details of a security group", func(s *mcclient.ClientSession, args *SecGroupsDetailOptions) error { + result, err := modules.SecGroups.Get(s, args.ID, nil) + if err != nil { + return err + } + printObject(result) + return nil + }) + R(&SecGroupsDetailOptions{}, "secgroup-delete", "Delete a security group", func(s *mcclient.ClientSession, args *SecGroupsDetailOptions) error { + secgroups, err := modules.SecGroups.Delete(s, args.ID, nil) + if err != nil { + return err + } + printObject(secgroups) + return nil + }) + + R(&SecGroupsDetailOptions{}, "secgroup-public", "Make a security group publicly available", func(s *mcclient.ClientSession, args *SecGroupsDetailOptions) error { + result, err := modules.SecGroups.PerformAction(s, args.ID, "public", nil) + if err != nil { + return err + } + printObject(result) + return nil + }) + + R(&SecGroupsDetailOptions{}, "secgroup-private", "Make a security group private", func(s *mcclient.ClientSession, args *SecGroupsDetailOptions) error { + result, err := modules.SecGroups.PerformAction(s, args.ID, "private", nil) + if err != nil { + return err + } + printObject(result) + return nil + }) + + type SecGroupsUpdateOptions struct { + ID string `help:"ID of security group"` + Name string `help:"Name of security group to update"` + Desc string `help:"Description of security groups"` + } + R(&SecGroupsUpdateOptions{}, "secgroup-update", "Update details of a security group", func(s *mcclient.ClientSession, args *SecGroupsUpdateOptions) error { + params := jsonutils.NewDict() + if len(args.Name) > 0 { + params.Add(jsonutils.NewString(args.Name), "name") + } + if len(args.Desc) > 0 { + params.Add(jsonutils.NewString(args.Desc), "description") + } + secgroups, err := modules.SecGroups.Update(s, args.ID, params) + if err != nil { + return err + } + printObject(secgroups) + return nil + }) + type SecGroupsUpdateRulesOptions struct { + ID string `help:"ID or Name of security group"` + RULES []string `help:"security rule to create"` + } + + R(&SecGroupsUpdateRulesOptions{}, "secgroup-add-rules", "Add security rules to a security group", func(s *mcclient.ClientSession, args *SecGroupsUpdateRulesOptions) error { + params := jsonutils.NewDict() + if len(args.RULES) > 0 { + for i, a := range args.RULES { + params.Add(jsonutils.NewString(a), fmt.Sprintf("rule.%d", i)) + } + } + result, err := modules.SecGroups.PerformAction(s, args.ID, "add-rules", params) + if err != nil { + return err + } + printObject(result) + return nil + }) + + R(&SecGroupsUpdateRulesOptions{}, "secgroup-remove-rules", "Remove security rules from a security group", func(s *mcclient.ClientSession, args *SecGroupsUpdateRulesOptions) error { + params := jsonutils.NewDict() + if len(args.RULES) > 0 { + for i, a := range args.RULES { + params.Add(jsonutils.NewString(a), fmt.Sprintf("rule.%d", i)) + } + } + result, err := modules.SecGroups.PerformAction(s, args.ID, "remove-rules", params) + if err != nil { + return err + } + printObject(result) + return nil + }) + + R(&SecGroupsUpdateRulesOptions{}, "secgroup-set-rules", "Set security rules from a security group", func(s *mcclient.ClientSession, args *SecGroupsUpdateRulesOptions) error { + params := jsonutils.NewDict() + if len(args.RULES) > 0 { + for i, a := range args.RULES { + params.Add(jsonutils.NewString(a), fmt.Sprintf("rule.%d", i)) + } + } + result, err := modules.SecGroups.PerformAction(s, args.ID, "set-rules", params) + if err != nil { + return err + } + printObject(result) + return nil + }) +} diff --git a/cmd/climc/shell/serverdisks.go b/cmd/climc/shell/serverdisks.go new file mode 100644 index 0000000000..a1d81109ed --- /dev/null +++ b/cmd/climc/shell/serverdisks.go @@ -0,0 +1,136 @@ +package shell + +import ( + "fmt" + "github.com/yunionio/jsonutils" + "github.com/yunionio/mcclient" + "github.com/yunionio/mcclient/modules" +) + +func init() { + type ServerDiskListOptions struct { + BaseListOptions + Server string `help:"ID or Name of Server"` + } + R(&ServerDiskListOptions{}, "server-disk-list", "List server disk pairs", func(s *mcclient.ClientSession, args *ServerDiskListOptions) error { + params := FetchPagingParams(args.BaseListOptions) + var result *modules.ListResult + var err error + if len(args.Server) > 0 { + result, err = modules.Serverdisks.ListDescendent(s, args.Server, params) + } else { + result, err = modules.Serverdisks.List(s, params) + } + if err != nil { + return err + } + printList(result, modules.Serverdisks.GetColumns(s)) + return nil + }) + + type ServerDiskDetailOptions struct { + SERVER string `help:"ID or Name of Server"` + DISK string `help:"ID or Name of Disk"` + } + R(&ServerDiskDetailOptions{}, "server-disk-show", "Show server disk details", func(s *mcclient.ClientSession, args *ServerDiskDetailOptions) error { + result, err := modules.Serverdisks.Get(s, args.SERVER, args.DISK, nil) + if err != nil { + return err + } + printObject(result) + return nil + }) + + type ServerDiskUpdateOptions struct { + SERVER string `help:"ID or Name of server"` + DISK string `help:"ID or Name of Disk"` + Driver string `help:"Driver of vDisk" choices:"virtio|ide|scsi|pvscsi"` + Cache string `help:"Cache mode of vDisk" choices:"writethrough|none|writeback"` + Aio string `help:"Asynchronous IO mode of vDisk" choices:"native|threads"` + Index int64 `help:"Index of vDisk" default:"-1"` + } + R(&ServerDiskUpdateOptions{}, "server-disk-update", "Update details of a virtual disk of a virtual server", func(s *mcclient.ClientSession, args *ServerDiskUpdateOptions) error { + params := jsonutils.NewDict() + if len(args.Driver) > 0 { + params.Add(jsonutils.NewString(args.Driver), "driver") + } + if len(args.Cache) > 0 { + params.Add(jsonutils.NewString(args.Cache), "cache_mode") + } + if len(args.Aio) > 0 { + params.Add(jsonutils.NewString(args.Aio), "aio_mode") + } + if args.Index >= 0 { + params.Add(jsonutils.NewInt(args.Index), "index") + } + if params.Size() == 0 { + return InvalidUpdateError() + } + srv, err := modules.Serverdisks.Update(s, args.SERVER, args.DISK, params) + if err != nil { + return err + } + printObject(srv) + return nil + }) + + type ServerCreateDiskOptions struct { + SERVER string `help:"ID or Name of server"` + DISK []string `help:"Disk description of a virtual disk"` + } + R(&ServerCreateDiskOptions{}, "server-create-disk", "Create a disk and attach it to a virtual server", func(s *mcclient.ClientSession, args *ServerCreateDiskOptions) error { + params := jsonutils.NewDict() + for i, d := range args.DISK { + params.Add(jsonutils.NewString(d), fmt.Sprintf("disk.%d", i)) + } + srv, err := modules.Servers.PerformAction(s, args.SERVER, "createdisk", params) + if err != nil { + return err + } + printObject(srv) + return nil + }) + + type ServerAttachDiskOptions struct { + SERVER string `help:"ID or name of server"` + DISK string `help:"ID of name of disk to attach"` + Driver string `help:"Driver" choices:"virtio|ide|scsi"` + Cache string `help:"Cache mode" choices:"writeback|none|writethrought"` + } + R(&ServerAttachDiskOptions{}, "server-attach-disk", "Attach an existing virtual disks to a virtual server", func(s *mcclient.ClientSession, args *ServerAttachDiskOptions) error { + params := jsonutils.NewDict() + params.Add(jsonutils.NewString(args.DISK), "disk_id") + if len(args.Driver) > 0 { + params.Add(jsonutils.NewString(args.Driver), "driver") + } + if len(args.Cache) > 0 { + params.Add(jsonutils.NewString(args.Cache), "cache") + } + srv, err := modules.Servers.PerformAction(s, args.SERVER, "attachdisk", params) + if err != nil { + return err + } + printObject(srv) + return nil + }) + + type ServerDetachDiskOptions struct { + SERVER string `help:"ID or name of server"` + DISK string `help:"ID or name of disk to detach"` + DeleteDisk bool `help:"Delete disk if the disk not has flag of auto_delete when detached"` + } + R(&ServerDetachDiskOptions{}, "server-detach-disk", "Detach a disk from a virtual server", func(s *mcclient.ClientSession, args *ServerDetachDiskOptions) error { + params := jsonutils.NewDict() + params.Add(jsonutils.NewString(args.DISK), "disk_id") + if args.DeleteDisk { + params.Add(jsonutils.NewInt(0), "keep_disk") + } + srv, err := modules.Servers.PerformAction(s, args.SERVER, "detachdisk", params) + if err != nil { + return err + } + printObject(srv) + return nil + }) + +} diff --git a/cmd/climc/shell/serverisolatedevices.go b/cmd/climc/shell/serverisolatedevices.go new file mode 100644 index 0000000000..fdb22333ad --- /dev/null +++ b/cmd/climc/shell/serverisolatedevices.go @@ -0,0 +1,43 @@ +package shell + +import ( + "github.com/yunionio/jsonutils" + "github.com/yunionio/mcclient" + "github.com/yunionio/mcclient/modules" +) + +func init() { + type ServerAttachDeviceOptions struct { + SERVER string `help:"ID or name of server"` + DEVICE string `help:"ID of isolated device to attach"` + Type string `help:"Device type" choices:"GPU-HPC|GPU-VGA|PCI"` + } + R(&ServerAttachDeviceOptions{}, "server-attach-isolated-device", "Attach an existing isolated device to a virtual server", func(s *mcclient.ClientSession, args *ServerAttachDeviceOptions) error { + params := jsonutils.NewDict() + params.Add(jsonutils.NewString(args.DEVICE), "device") + if len(args.Type) > 0 { + params.Add(jsonutils.NewString(args.Type), "dev_type") + } + srv, err := modules.Servers.PerformAction(s, args.SERVER, "attach-isolated-device", params) + if err != nil { + return err + } + printObject(srv) + return nil + }) + + type ServerDetachDeviceOptions struct { + SERVER string `help:"ID or name of server"` + DEVICE string `help:"ID of isolated device to attach"` + } + R(&ServerDetachDeviceOptions{}, "server-detach-isolated-device", "Detach a isolated device from a virtual server", func(s *mcclient.ClientSession, args *ServerDetachDeviceOptions) error { + params := jsonutils.NewDict() + params.Add(jsonutils.NewString(args.DEVICE), "device") + srv, err := modules.Servers.PerformAction(s, args.SERVER, "detach-isolated_device", params) + if err != nil { + return err + } + printObject(srv) + return nil + }) +} diff --git a/cmd/climc/shell/servernetworks.go b/cmd/climc/shell/servernetworks.go new file mode 100644 index 0000000000..21f94653fa --- /dev/null +++ b/cmd/climc/shell/servernetworks.go @@ -0,0 +1,135 @@ +package shell + +import ( + "github.com/yunionio/jsonutils" + "github.com/yunionio/mcclient" + "github.com/yunionio/mcclient/modules" +) + +func init() { + type ServerNetworkListOptions struct { + BaseListOptions + Server string `help:"ID or Name of Server"` + Mac string `help:"search the MAC address"` + Ip string `help:"search the IP address"` + Network string `help:"Network ID or name"` + } + R(&ServerNetworkListOptions{}, "server-network-list", "List server network pairs", func(s *mcclient.ClientSession, args *ServerNetworkListOptions) error { + params := FetchPagingParams(args.BaseListOptions) + if len(args.Mac) > 0 { + params.Add(jsonutils.NewString(args.Mac), "mac_addr") + } + if len(args.Ip) > 0 { + params.Add(jsonutils.NewString(args.Ip), "ip_addr") + } + if len(args.Network) > 0 { + params.Add(jsonutils.NewString(args.Network), "network_id") + } + var result *modules.ListResult + var err error + if len(args.Server) > 0 { + result, err = modules.Servernetworks.ListDescendent(s, args.Server, params) + } else { + result, err = modules.Servernetworks.List(s, params) + } + if err != nil { + return err + } + printList(result, modules.Servernetworks.GetColumns(s)) + return nil + }) + + type ServerNetworkDetailOptions struct { + SERVER string `help:"ID or Name of Server"` + NETWORK string `help:"ID or Name of Network"` + } + R(&ServerNetworkDetailOptions{}, "server-network-show", "Show server network details", func(s *mcclient.ClientSession, args *ServerNetworkDetailOptions) error { + result, err := modules.Servernetworks.Get(s, args.SERVER, args.NETWORK, nil) + if err != nil { + return err + } + printObject(result) + return nil + }) + + type ServerNetworkUpdateOptions struct { + SERVER string `help:"ID or Name of Server"` + NETWORK string `help:"ID or Name of Wire"` + Driver string `help:"Driver model of vNIC" choices:"virtio|e1000|vmxnet3|rtl8139"` + Index int64 `help:"Index of NIC" default:"-1"` + Ifname string `help:"Interface name of vNIC on host"` + } + R(&ServerNetworkUpdateOptions{}, "server-network-update", "Update server network settings", func(s *mcclient.ClientSession, args *ServerNetworkUpdateOptions) error { + params := jsonutils.NewDict() + if len(args.Driver) > 0 { + params.Add(jsonutils.NewString(args.Driver), "driver") + } + if args.Index >= 0 { + params.Add(jsonutils.NewInt(args.Index), "index") + } + if len(args.Ifname) > 0 { + params.Add(jsonutils.NewString(args.Ifname), "ifname") + } + if params.Size() == 0 { + return InvalidUpdateError() + } + result, err := modules.Servernetworks.Update(s, args.SERVER, args.NETWORK, params) + if err != nil { + return err + } + printObject(result) + return nil + }) + + type ServerNetworkBWOptions struct { + SERVER string `help:"ID or Name of server"` + INDEX int64 `help:"Index of NIC"` + BW int64 `help:"Bandwidth in Mbps"` + } + R(&ServerNetworkBWOptions{}, "server-change-bandwidth", "Change server network bandwidth in Mbps", func(s *mcclient.ClientSession, args *ServerNetworkBWOptions) error { + params := jsonutils.NewDict() + params.Add(jsonutils.NewInt(args.INDEX), "index") + params.Add(jsonutils.NewInt(args.BW), "bandwidth") + server, err := modules.Servers.PerformAction(s, args.SERVER, "change-bandwidth", params) + if err != nil { + return err + } + printObject(server) + return nil + }) + + type ServerAttachNetworkOptions struct { + SERVER string `help:"ID or Name of server"` + NETDESC string `help:"Network description"` + } + R(&ServerAttachNetworkOptions{}, "server-attach-network", "Attach a server to a virtual network", func(s *mcclient.ClientSession, args *ServerAttachNetworkOptions) error { + params := jsonutils.NewDict() + params.Add(jsonutils.NewString(args.NETDESC), "net_desc") + srv, err := modules.Servers.PerformAction(s, args.SERVER, "attachnetwork", params) + if err != nil { + return err + } + printObject(srv) + return nil + }) + + type ServerDetachNetworkOptions struct { + SERVER string `help:"ID or Name of server"` + NETWORK string `help:"ID or Name of network to detach"` + Reserve bool `help:"Put the release IP address into reserved address pool"` + } + R(&ServerDetachNetworkOptions{}, "server-detach-network", "Detach the virtual network fron a virtual server", func(s *mcclient.ClientSession, args *ServerDetachNetworkOptions) error { + params := jsonutils.NewDict() + params.Add(jsonutils.NewString(args.NETWORK), "net_id") + if args.Reserve { + params.Add(jsonutils.JSONTrue, "reserve") + } + srv, err := modules.Servers.PerformAction(s, args.SERVER, "detachnetwork", params) + if err != nil { + return err + } + printObject(srv) + return nil + }) + +} diff --git a/cmd/climc/shell/servers.go b/cmd/climc/shell/servers.go new file mode 100644 index 0000000000..d5166d11aa --- /dev/null +++ b/cmd/climc/shell/servers.go @@ -0,0 +1,681 @@ +package shell + +import ( + "fmt" + "io/ioutil" + "strings" + + "github.com/yunionio/jsonutils" + "github.com/yunionio/mcclient" + "github.com/yunionio/mcclient/modules" +) + +type ServerDeployInfo struct { + Action string + Path string + Content string +} + +func parseDeployInfo(info string) (ServerDeployInfo, error) { + sdi := ServerDeployInfo{} + colonPos := strings.IndexByte(info, ':') + if colonPos <= 0 { + return sdi, fmt.Errorf("Malformed deploy string") + } + if info[0] == '+' { + sdi.Action = "append" + sdi.Path = info[1:colonPos] + } else { + sdi.Action = "create" + sdi.Path = info[:colonPos] + } + content := info[colonPos+1:] + bytes, e := ioutil.ReadFile(content) + if e != nil { + sdi.Content = content + } else { + sdi.Content = string(bytes) + } + return sdi, nil +} + +func parseDeployList(list []string, params *jsonutils.JSONDict) error { + for i, info := range list { + ret, e := parseDeployInfo(info) + if e != nil { + return e + } + params.Add(jsonutils.NewString(ret.Action), fmt.Sprintf("deploy.%d.action", i)) + params.Add(jsonutils.NewString(ret.Path), fmt.Sprintf("deploy.%d.path", i)) + params.Add(jsonutils.NewString(ret.Content), fmt.Sprintf("deploy.%d.content", i)) + } + return nil +} + +func init() { + type ServerListOptions struct { + Zone string `help:"Zone ID or Name"` + Wire string `help:"Wire ID or Name"` + Network string `help:"Network ID or Name"` + Disk string `help:"Disk ID or Name"` + Host string `help:"Host ID or Name"` + Baremetal bool `help:"Show baremetal servers"` + Gpu bool `help:"Show gpu servers"` + Secgroup string `help:"Secgroup ID or Name"` + AdminSecgroup string `help:"AdminSecgroup ID or Name"` + Hypervisor string `help:"Show server of hypervisor" choices:"kvm|esxi|container|baremetal|aliyun"` + BaseListOptions + } + R(&ServerListOptions{}, "server-list", "List virtual servers", func(s *mcclient.ClientSession, args *ServerListOptions) error { + params := FetchPagingParams(args.BaseListOptions) + if len(args.Zone) > 0 { + params.Add(jsonutils.NewString(args.Zone), "zone") + } + if len(args.Disk) > 0 { + params.Add(jsonutils.NewString(args.Disk), "disk") + } + if len(args.Wire) > 0 { + params.Add(jsonutils.NewString(args.Wire), "wire") + } + if len(args.Network) > 0 { + params.Add(jsonutils.NewString(args.Network), "network") + } + if len(args.Host) > 0 { + params.Add(jsonutils.NewString(args.Host), "host") + } + if args.Baremetal { + params.Add(jsonutils.JSONTrue, "baremetal") + } + if args.Gpu { + params.Add(jsonutils.JSONTrue, "gpu") + } + if len(args.Secgroup) > 0 { + params.Add(jsonutils.NewString(args.Secgroup), "secgroup") + } + if len(args.AdminSecgroup) > 0 { + params.Add(jsonutils.NewString(args.AdminSecgroup), "admin_secgroup") + } + if len(args.Hypervisor) > 0 { + params.Add(jsonutils.NewString(args.Hypervisor), "hypervisor") + } + result, err := modules.Servers.List(s, params) + if err != nil { + return err + } + printList(result, modules.Servers.GetColumns(s)) + return nil + }) + + type ServerShowOptions struct { + ID string `help:"ID or name of the server"` + WithMeta bool `help:"With meta data"` + } + R(&ServerShowOptions{}, "server-show", "Show details of a server", func(s *mcclient.ClientSession, args *ServerShowOptions) error { + params := jsonutils.NewDict() + if args.WithMeta { + params.Add(jsonutils.JSONTrue, "with_meta") + } + result, err := modules.Servers.Get(s, args.ID, params) + if err != nil { + return err + } + printObject(result) + return nil + }) + + R(&ServerShowOptions{}, "server-metadata", "Show metadata of a server", func(s *mcclient.ClientSession, args *ServerShowOptions) error { + result, err := modules.Servers.GetMetadata(s, args.ID, nil) + if err != nil { + return err + } + printObject(result) + return nil + }) + + type ServerCreateOptions struct { + NAME string `help:"Name of server"` + MEM string `help:"Memory size" metavar:"MEMORY"` + Disk []string `help:"Disk descriptions" nargs:"+"` + Net []string `help:"Network descriptions" metavar:"NETWORK"` + IsolatedDevice []string `help:"Isolated device model or ID" metavar:"ISOLATED_DEVICE"` + Keypair string `help:"SSH Keypair"` + Iso string `help:"ISO image ID" metavar:"IMAGE_ID"` + Ncpu int64 `help:"#CPU cores of VM server, default 1" default:"1" metavar:""` + Vga string `help:"VGA driver" choices:"std|vmware|cirrus|qxl"` + Vdi string `help:"VDI protocool" choices:"vnc|spice"` + Bios string `help:"BIOS" choices:"BIOS|UEFI"` + Desc string `help:"Description" metavar:""` + Boot string `help:"Boot device" metavar:"" choices:"disk|cdrom"` + NoAccountInit bool `help:"Not reset account password"` + AllowDelete bool `help:"Unlock server to allow deleting"` + ShutdownBehavior string `help:"Behavior after VM server shutdown, stop or terminate server" metavar:"" choices:"stop|terminate"` + AutoStart bool `help:"Auto start server after it is created"` + Zone string `help:"Preferred zone where virtual server should be created"` + Host string `help:"Preferred host where virtual server should be created"` + SchedTag []string `help:"Schedule policy, key = aggregate name, value = require|exclude|prefer|avoid" metavar:""` + Deploy []string `help:"Specify deploy files in virtual server file system"` + Group []string `help:"Group of virtual server"` + Project string `help:"'Owner project ID or Name"` + User string `help:"Owner user ID or Name"` + System bool `help:"Create a system VM, sysadmin ONLY option"` + Hypervisor string `help:"Hypervisor type" choices:"kvm|esxi|baremetal|container|aliyun"` + TaskNotify bool `help:"Setup task notify"` + Count int `help:"Create multiple simultaneously" default:"1"` + DryRun bool `help:"Dry run to test scheduler"` + RaidConfig []string `help:"Baremetal raid config"` + } + R(&ServerCreateOptions{}, "server-create", "Create a server", func(s *mcclient.ClientSession, args *ServerCreateOptions) error { + params := jsonutils.NewDict() + params.Add(jsonutils.NewString(args.NAME), "name") + params.Add(jsonutils.NewString(args.MEM), "vmem_size") + for i, d := range args.Disk { + params.Add(jsonutils.NewString(d), fmt.Sprintf("disk.%d", i)) + } + for i, n := range args.Net { + params.Add(jsonutils.NewString(n), fmt.Sprintf("net.%d", i)) + } + for i, g := range args.IsolatedDevice { + params.Add(jsonutils.NewString(g), fmt.Sprintf("isolated_device.%d", i)) + } + for i, t := range args.SchedTag { + params.Add(jsonutils.NewString(t), fmt.Sprintf("schedtag.%d", i)) + } + if args.Ncpu > 0 { + params.Add(jsonutils.NewInt(args.Ncpu), "vcpu_count") + } + if len(args.Iso) > 0 { + params.Add(jsonutils.NewString(args.Iso), "cdrom") + } + if len(args.Vga) > 0 { + params.Add(jsonutils.NewString(args.Vga), "vga") + } + if args.NoAccountInit { + params.Add(jsonutils.JSONFalse, "reset_password") + } + if len(args.Vdi) > 0 { + params.Add(jsonutils.NewString(args.Vdi), "vdi") + } + if len(args.Bios) > 0 { + params.Add(jsonutils.NewString(args.Bios), "bios") + } + if len(args.Deploy) > 0 { + err := parseDeployList(args.Deploy, params) + if err != nil { + return err + } + } + if len(args.Boot) > 0 { + if args.Boot == "disk" { + params.Add(jsonutils.NewString("cdn"), "boot_order") + } else { + params.Add(jsonutils.NewString("dcn"), "boot_order") + } + } + if len(args.Desc) > 0 { + params.Add(jsonutils.NewString(args.Desc), "description") + } + if args.AllowDelete { + params.Add(jsonutils.JSONFalse, "disable_delete") + } + if len(args.ShutdownBehavior) > 0 { + params.Add(jsonutils.NewString(args.ShutdownBehavior), "shutdown_behavior") + } + if args.AutoStart { + params.Add(jsonutils.JSONTrue, "auto_start") + } + if len(args.Group) > 0 { + for i, g := range args.Group { + params.Add(jsonutils.NewString(g), fmt.Sprintf("group.%d", i)) + } + } + if len(args.Host) > 0 { + params.Add(jsonutils.NewString(args.Host), "prefer_host") + } else { + if len(args.Zone) > 0 { + params.Add(jsonutils.NewString(args.Zone), "prefer_zone") + } + } + if len(args.Project) > 0 { + params.Add(jsonutils.NewString(args.Project), "tenant") + } + if len(args.User) > 0 { + params.Add(jsonutils.NewString(args.User), "user") + } + if args.System { + params.Add(jsonutils.JSONTrue, "is_system") + } + if len(args.Hypervisor) > 0 { + params.Add(jsonutils.NewString(args.Hypervisor), "hypervisor") + } + if len(args.RaidConfig) > 0 { + if args.Hypervisor != "baremetal" { + return fmt.Errorf("RaidConfig is applicable to baremetal ONLY") + } + for i, conf := range args.RaidConfig { + params.Add(jsonutils.NewString(conf), fmt.Sprintf("baremetal_disk_config.%d", i)) + } + } + if args.DryRun { + params.Add(jsonutils.JSONTrue, "suggestion") + results, err := modules.SchedManager.DoScheduleListResult(s, params, args.Count) + if err != nil { + return err + } + printList(results, []string{"id", "name", "rank", "capacity", "error"}) + } else { + if args.TaskNotify { + s.PrepareTask() + } + if args.Count > 1 { + results := modules.Servers.BatchCreate(s, params, args.Count) + printBatchResults(results, modules.Servers.GetColumns(s)) + } else { + server, err := modules.Servers.Create(s, params) + if err != nil { + return err + } + printObject(server) + } + if args.TaskNotify { + s.WaitTaskNotify() + } + } + return nil + }) + + R(&ServerShowOptions{}, "server-logininfo", "Get login info of a server", func(s *mcclient.ClientSession, args *ServerShowOptions) error { + srvid, e := modules.Servers.GetId(s, args.ID, nil) + if e != nil { + return e + } + i, e := modules.Servers.GetLoginInfo(s, srvid, nil) + if e != nil { + return e + } + printObject(i) + return nil + }) + + type ServerOpsOptions struct { + ID []string `help:"ID of servers to operate" metavar:"SERVER"` + } + R(&ServerOpsOptions{}, "server-start", "Start servers", func(s *mcclient.ClientSession, args *ServerOpsOptions) error { + ret := modules.Servers.BatchPerformAction(s, args.ID, "start", nil) + printBatchResults(ret, modules.Servers.GetColumns(s)) + return nil + }) + + R(&ServerOpsOptions{}, "server-syncstatus", "Sync servers status", func(s *mcclient.ClientSession, args *ServerOpsOptions) error { + ret := modules.Servers.BatchPerformAction(s, args.ID, "syncstatus", nil) + printBatchResults(ret, modules.Servers.GetColumns(s)) + return nil + }) + + R(&ServerOpsOptions{}, "server-sync", "Sync servers status", func(s *mcclient.ClientSession, args *ServerOpsOptions) error { + ret := modules.Servers.BatchPerformAction(s, args.ID, "sync", nil) + printBatchResults(ret, modules.Servers.GetColumns(s)) + return nil + }) + + type ServerStopOptions struct { + ID []string `help:"ID or Name of server"` + Force bool `help:"Stop server forcefully"` + } + R(&ServerStopOptions{}, "server-stop", "Stop servers", func(s *mcclient.ClientSession, args *ServerStopOptions) error { + params := jsonutils.NewDict() + if args.Force { + params.Add(jsonutils.JSONTrue, "is_force") + } else { + params.Add(jsonutils.JSONFalse, "is_force") + } + ret := modules.Servers.BatchPerformAction(s, args.ID, "stop", params) + printBatchResults(ret, modules.Servers.GetColumns(s)) + return nil + }) + + R(&ServerOpsOptions{}, "server-suspend", "Suspend servers", func(s *mcclient.ClientSession, args *ServerOpsOptions) error { + ret := modules.Servers.BatchPerformAction(s, args.ID, "suspend", nil) + printBatchResults(ret, modules.Servers.GetColumns(s)) + return nil + }) + + R(&ServerOpsOptions{}, "server-reset", "Reset servers", func(s *mcclient.ClientSession, args *ServerOpsOptions) error { + ret := modules.Servers.BatchPerformAction(s, args.ID, "reset", nil) + printBatchResults(ret, modules.Servers.GetColumns(s)) + return nil + }) + + R(&ServerOpsOptions{}, "server-purge", "Purge obsolete servers", func(s *mcclient.ClientSession, args *ServerOpsOptions) error { + ret := modules.Servers.BatchPerformAction(s, args.ID, "purge", nil) + printBatchResults(ret, modules.Servers.GetColumns(s)) + return nil + }) + + type ServerDeleteOptions struct { + OverridePendingDelete bool `help:"Delete server directly instead of pending delete"` + ServerOpsOptions + } + R(&ServerDeleteOptions{}, "server-delete", "Delete servers", func(s *mcclient.ClientSession, args *ServerDeleteOptions) error { + params := jsonutils.NewDict() + if args.OverridePendingDelete { + params.Add(jsonutils.JSONTrue, "override_pending_delete") + } + ret := modules.Servers.BatchDeleteWithParam(s, args.ID, params, nil) + printBatchResults(ret, modules.Servers.GetColumns(s)) + return nil + }) + + R(&ServerOpsOptions{}, "server-cancel-delete", "Cancel pending delete servers", func(s *mcclient.ClientSession, args *ServerOpsOptions) error { + ret := modules.Servers.BatchPerformAction(s, args.ID, "cancel-delete", nil) + printBatchResults(ret, modules.Servers.GetColumns(s)) + return nil + }) + + R(&ServerShowOptions{}, "server-vnc", "Show vnc info of server", func(s *mcclient.ClientSession, args *ServerShowOptions) error { + ret, e := modules.Servers.GetSpecific(s, args.ID, "vnc", nil) + if e != nil { + return e + } + printObject(ret) + return nil + }) + + R(&ServerShowOptions{}, "server-desc", "Show desc info of server", func(s *mcclient.ClientSession, args *ServerShowOptions) error { + ret, e := modules.Servers.GetSpecific(s, args.ID, "desc", nil) + if e != nil { + return e + } + printObject(ret) + return nil + }) + + R(&ServerShowOptions{}, "server-status", "Show status of server", func(s *mcclient.ClientSession, args *ServerShowOptions) error { + ret, e := modules.Servers.GetSpecific(s, args.ID, "status", nil) + if e != nil { + return e + } + printObject(ret) + return nil + }) + + type ServerUpdateOptions struct { + ID []string `help:"IDs or Names of servers to update"` + Name string `help:"New name to change"` + Vmem string `help:"Memory size"` + Ncpu int64 `help:"CPU count"` + Vga string `help:"VGA driver" choices:"std|vmware|cirrus|qxl"` + Vdi string `help:"VDI protocol" choices:"vnc|spice"` + Bios string `help:"BIOS" choices:"BIOS|UEFI"` + Desc string `help:"Description"` + Boot string `help:"Boot device" choices:"disk|cdrom"` + Delete string `help:"Lock server to prevent from deleting" choices:"enable|disable"` + ShutdownBehavior string `help:"Behavior after VM server shutdown, stop or terminate server" choices:"stop|terminate"` + } + R(&ServerUpdateOptions{}, "server-update", "Update servers", func(s *mcclient.ClientSession, args *ServerUpdateOptions) error { + params := jsonutils.NewDict() + if len(args.Name) > 0 { + params.Add(jsonutils.NewString(args.Name), "name") + } + if args.Ncpu > 0 { + params.Add(jsonutils.NewInt(args.Ncpu), "vcpu_count") + } + if len(args.Vmem) > 0 { + params.Add(jsonutils.NewString(args.Vmem), "vmem_size") + } + if len(args.Vga) > 0 { + params.Add(jsonutils.NewString(args.Vga), "vga") + } + if len(args.Vdi) > 0 { + params.Add(jsonutils.NewString(args.Vdi), "vdi") + } + if len(args.Bios) > 0 { + params.Add(jsonutils.NewString(args.Bios), "bios") + } + if len(args.Desc) > 0 { + params.Add(jsonutils.NewString(args.Desc), "description") + } + if len(args.Boot) > 0 { + if args.Boot == "disk" { + params.Add(jsonutils.NewString("cdn"), "boot_order") + } else { + params.Add(jsonutils.NewString("dcn"), "boot_order") + } + } + if len(args.Delete) > 0 { + if args.Delete == "disable" { + params.Add(jsonutils.JSONTrue, "disable_delete") + } else { + params.Add(jsonutils.JSONFalse, "disable_delete") + } + } + if len(args.ShutdownBehavior) > 0 { + params.Add(jsonutils.NewString(args.ShutdownBehavior), "shutdown_behavior") + } + if params.Size() == 0 { + return InvalidUpdateError() + } + result := modules.Servers.BatchPut(s, args.ID, params) + printBatchResults(result, modules.Servers.GetColumns(s)) + return nil + }) + + type ServerSendKeyOptions struct { + SERVER string `help:"ID of virtual server to get monitor info"` + KEYS string `help:"Special keys to send, eg. ctrl, alt, f12, shift, etc, separated by \"-\""` + Hold int64 `help:"Hold key for specified milliseconds"` + } + R(&ServerSendKeyOptions{}, "server-send-keys", "Send keys to server", func(s *mcclient.ClientSession, args *ServerSendKeyOptions) error { + params := jsonutils.NewDict() + params.Add(jsonutils.NewString(args.KEYS), "keys") + if args.Hold > 0 { + params.Add(jsonutils.NewInt(args.Hold), "duration") + } + srv, err := modules.Servers.PerformAction(s, args.SERVER, "sendkeys", params) + if err != nil { + return err + } + printObject(srv) + return nil + }) + + type ServerDeployOptions struct { + ID string `help:"ID or Name of server"` + Keypair string `help:"ssh Keypair used for login"` + DeleteKeypair bool `help:"Remove ssh Keypairs"` + Deploy []string `help:"Specify deploy files in virtual server file system"` + ResetPassword bool `help:"Force reset password"` + } + R(&ServerDeployOptions{}, "server-deploy", "Deploy hostname and keypair to a stopped virtual server", func(s *mcclient.ClientSession, args *ServerDeployOptions) error { + params := jsonutils.NewDict() + if args.DeleteKeypair { + params.Add(jsonutils.JSONTrue, "__delete_keypair__") + } else if len(args.Keypair) > 0 { + params.Add(jsonutils.NewString(args.Keypair), "keypair") + } + if len(args.Deploy) > 0 { + e := parseDeployList(args.Deploy, params) + if e != nil { + return e + } + } + if args.ResetPassword { + params.Add(jsonutils.JSONTrue, "reset_password") + } + srv, e := modules.Servers.PerformAction(s, args.ID, "deploy", params) + if e != nil { + return e + } + printObject(srv) + return nil + }) + + type ServerSecGroupOptions struct { + ID string `help:"ID or Name of server" metavar:"Guest"` + SecGrp string `help:"ID of Security Group" metavar:"Security Group" optional:"false"` + } + + R(&ServerSecGroupOptions{}, "server-assign-secgroup", "Assign security group to a VM", func(s *mcclient.ClientSession, args *ServerSecGroupOptions) error { + params := jsonutils.NewDict() + params.Add(jsonutils.NewString(args.SecGrp), "secgrp") + srv, e := modules.Servers.PerformAction(s, args.ID, "assign-secgroup", params) + if e != nil { + return e + } + printObject(srv) + return nil + }) + + R(&ServerSecGroupOptions{}, "server-assign-admin-secgroup", "Assign administrative security group to a VM", func(s *mcclient.ClientSession, args *ServerSecGroupOptions) error { + params := jsonutils.NewDict() + params.Add(jsonutils.NewString(args.SecGrp), "secgrp") + srv, e := modules.Servers.PerformAction(s, args.ID, "assign-admin-secgroup", params) + if e != nil { + return e + } + printObject(srv) + return nil + }) + + type ServerRevokeSecGroupOptions struct { + ID string `help:"ID or Name of server" metavar:"Guest"` + } + + R(&ServerRevokeSecGroupOptions{}, "server-revoke-secgroup", "Assign security group to a VM", func(s *mcclient.ClientSession, args *ServerRevokeSecGroupOptions) error { + srv, e := modules.Servers.PerformAction(s, args.ID, "revoke-secgroup", nil) + if e != nil { + return e + } + printObject(srv) + return nil + }) + + R(&ServerRevokeSecGroupOptions{}, "server-revoke-admin-secgroup", "Assign administrative security group to a VM", func(s *mcclient.ClientSession, args *ServerRevokeSecGroupOptions) error { + srv, e := modules.Servers.PerformAction(s, args.ID, "revoke-admin-secgroup", nil) + if e != nil { + return e + } + printObject(srv) + return nil + }) + + type ServerMonitorOptions struct { + SERVER string `help:"ID or Name of server"` + CMD string `help:"Qemu Monitor command to send"` + } + R(&ServerMonitorOptions{}, "server-monitor", "Send commands to qemu monitor", func(s *mcclient.ClientSession, args *ServerMonitorOptions) error { + query := jsonutils.NewDict() + query.Add(jsonutils.NewString(args.CMD), "command") + ret, err := modules.Servers.GetSpecific(s, args.SERVER, "monitor", query) + if err != nil { + return err + } + result, err := ret.GetString("results") + if err != nil { + return err + } + fmt.Println(result) + return nil + }) + + type ServerSaveImageOptions struct { + SERVER string `help:"ID or name of server"` + IMAGE string `help:"Image name"` + Public bool `help:"Make the image public available"` + Format string `help:"image format" choices:"vmdk|qcow2"` + Notes string `help:"Notes about the image"` + } + R(&ServerSaveImageOptions{}, "server-save-image", "Save root disk to new image and upload to glance.", func(s *mcclient.ClientSession, args *ServerSaveImageOptions) error { + params := jsonutils.NewDict() + params.Add(jsonutils.NewString(args.IMAGE), "name") + if args.Public { + params.Add(jsonutils.JSONTrue, "is_public") + } else { + params.Add(jsonutils.JSONFalse, "is_public") + } + if len(args.Format) > 0 { + params.Add(jsonutils.NewString(args.Format), "format") + } + if len(args.Notes) > 0 { + params.Add(jsonutils.NewString(args.Notes), "notes") + } + srv, err := modules.Servers.PerformAction(s, args.SERVER, "save-image", params) + if err != nil { + return err + } + printObject(srv) + return nil + }) + + type ServerChangeOwnerOptions struct { + SERVER string `help:"Server to change owner"` + PROJECT string `help:"Project ID or change"` + RawId bool `help:"User raw ID, instead of name"` + } + R(&ServerChangeOwnerOptions{}, "server-change-owner", "Change owner porject of a server", func(s *mcclient.ClientSession, args *ServerChangeOwnerOptions) error { + params := jsonutils.NewDict() + if args.RawId { + projid, err := modules.Projects.GetId(s, args.PROJECT, nil) + if err != nil { + return err + } + params.Add(jsonutils.NewString(projid), "tenant") + params.Add(jsonutils.JSONTrue, "raw_id") + } else { + params.Add(jsonutils.NewString(args.PROJECT), "tenant") + } + srv, err := modules.Servers.PerformAction(s, args.SERVER, "change-owner", params) + if err != nil { + return err + } + printObject(srv) + return nil + }) + + type ServerRebuildRootOptions struct { + SERVER string `help:"Server to rebuild root"` + Image string `help:"New root Image template ID"` + } + R(&ServerRebuildRootOptions{}, "server-rebuild-root", "Rebuild VM root image with new template", func(s *mcclient.ClientSession, args *ServerRebuildRootOptions) error { + params := jsonutils.NewDict() + if len(args.Image) > 0 { + params.Add(jsonutils.NewString(args.Image), "image_id") + } + srv, err := modules.Servers.PerformAction(s, args.SERVER, "rebuild-root", params) + if err != nil { + return err + } + printObject(srv) + return nil + }) + + type ServerChangeConfigOptions struct { + SERVER string `help:"Server to rebuild root"` + Ncpu int64 `help:"New number of Virtual CPU cores"` + Vmem string `help:"New memory size"` + Disk []string `help:"Data disk description, from the 1st data disk to the last one, empty string if no change for this data disk"` + } + R(&ServerChangeConfigOptions{}, "server-change-config", "Change configuration of VM", func(s *mcclient.ClientSession, args *ServerChangeConfigOptions) error { + params := jsonutils.NewDict() + if args.Ncpu > 0 { + params.Add(jsonutils.NewInt(args.Ncpu), "vcpu_count") + } + if len(args.Vmem) > 0 { + params.Add(jsonutils.NewString(args.Vmem), "vmem_size") + } + if len(args.Disk) > 0 { + for idx, disk := range args.Disk { + params.Add(jsonutils.NewString(disk), fmt.Sprintf("disk.%d", (idx+1))) + } + } + if params.Size() == 0 { + return InvalidUpdateError() + } + srv, err := modules.Servers.PerformAction(s, args.SERVER, "change-config", params) + if err != nil { + return err + } + printObject(srv) + return nil + }) + +} diff --git a/cmd/climc/shell/service_hosts.go b/cmd/climc/shell/service_hosts.go new file mode 100644 index 0000000000..1207bbcf23 --- /dev/null +++ b/cmd/climc/shell/service_hosts.go @@ -0,0 +1,93 @@ +package shell + +import ( + "github.com/yunionio/jsonutils" + "github.com/yunionio/mcclient" + "github.com/yunionio/mcclient/modules" +) + +func init() { + + /** + * 向指定的服务树节点添加机器 + */ + type ServiceHostCreateOptions struct { + LABELS string `help:"Labels for tree-node(split by comma)"` + HOST_NAME []string `help:"Host names to add to"` + } + R(&ServiceHostCreateOptions{}, "servicehost-create", "Add host to tree-node", func(s *mcclient.ClientSession, args *ServiceHostCreateOptions) error { + params := jsonutils.NewDict() + params.Add(jsonutils.NewString(args.LABELS), "node_labels") + arr := jsonutils.NewArray() + if len(args.HOST_NAME) > 0 { + for _, f := range args.HOST_NAME { + tmpObj := jsonutils.NewDict() + tmpObj.Add(jsonutils.NewString(f), "host_name") + arr.Add(tmpObj) + } + } + params.Add(arr, "service_hosts") + + rst, err := modules.ServiceHosts.Create(s, params) + + if err != nil { + return err + } + + printObject(rst) + return nil + }) + + /** + * 从服务树节点删除机器 + */ + type ServiceHostDeleteOptions struct { + LABELS string `help:"Labels for tree-node(split by comma)"` + HOST_NAME []string `help:"Host names to remove from"` + } + R(&ServiceHostDeleteOptions{}, "servicehost-delete", "Remove host from tree-node", func(s *mcclient.ClientSession, args *ServiceHostDeleteOptions) error { + params := jsonutils.NewDict() + params.Add(jsonutils.NewString(args.LABELS), "node_labels") + arr := jsonutils.NewArray() + if len(args.HOST_NAME) > 0 { + for _, f := range args.HOST_NAME { + tmpObj := jsonutils.NewDict() + tmpObj.Add(jsonutils.NewString(f), "host_name") + arr.Add(tmpObj) + } + } + params.Add(arr, "service_hosts") + + rst, err := modules.ServiceHosts.DoDeleteServiceHost(s, params) + + if err != nil { + return err + } + + printObject(rst) + return nil + }) + + /** + * 查看指定服务树节点的机器 + */ + type ServiceHostListOptions struct { + BaseListOptions + Labels string `help:"Labels for tree-node(split by comma)"` + } + R(&ServiceHostListOptions{}, "servicehost-list", "List all hosts for the tree-node", func(s *mcclient.ClientSession, args *ServiceHostListOptions) error { + params := FetchPagingParams(args.BaseListOptions) + if len(args.Labels) > 0 { + params.Add(jsonutils.NewString(args.Labels), "node_labels") + } + + result, err := modules.ServiceHosts.List(s, params) + if err != nil { + return err + } + + printList(result, modules.ServiceHosts.GetColumns(s)) + return nil + }) + +} diff --git a/cmd/climc/shell/service_name_suggestions.go b/cmd/climc/shell/service_name_suggestions.go new file mode 100644 index 0000000000..9b80a8fee5 --- /dev/null +++ b/cmd/climc/shell/service_name_suggestions.go @@ -0,0 +1,28 @@ +package shell + +import ( + "github.com/yunionio/mcclient" + "github.com/yunionio/mcclient/modules" +) + +func init() { + + /** + * 列出所有监控指标 + */ + type ServiceNameSuggestionListOptions struct { + BaseListOptions + } + R(&ServiceNameSuggestionListOptions{}, "servicenamesuggestion-list", "List all serviceNameSuggestion", func(s *mcclient.ClientSession, args *ServiceNameSuggestionListOptions) error { + params := FetchPagingParams(args.BaseListOptions) + + result, err := modules.ServiceNameSuggestion.List(s, params) + if err != nil { + return err + } + + printList(result, modules.ServiceNameSuggestion.GetColumns(s)) + return nil + }) + +} diff --git a/cmd/climc/shell/services.go b/cmd/climc/shell/services.go new file mode 100644 index 0000000000..5db8b71b3f --- /dev/null +++ b/cmd/climc/shell/services.go @@ -0,0 +1,148 @@ +package shell + +import ( + "github.com/yunionio/jsonutils" + "github.com/yunionio/mcclient" + "github.com/yunionio/mcclient/modules" +) + +func init() { + type ServiceListOptions struct { + Limit int64 `help:"Limit, default 0, i.e. no limit" default:"20"` + Offset int64 `help:"Offset, default 0, i.e. no offset"` + Name string `help:"Search by name"` + Type string `help:"Search by type"` + } + R(&ServiceListOptions{}, "service-list", "List services", func(s *mcclient.ClientSession, args *ServiceListOptions) error { + mod, err := modules.GetModule(s, "services") + if err != nil { + return err + } + query := jsonutils.NewDict() + if args.Limit > 0 { + query.Add(jsonutils.NewInt(args.Limit), "limit") + } + if args.Offset > 0 { + query.Add(jsonutils.NewInt(args.Offset), "offset") + } + if len(args.Name) > 0 { + query.Add(jsonutils.NewString(args.Name), "name__icontains") + } + if len(args.Type) > 0 { + query.Add(jsonutils.NewString(args.Type), "type__icontains") + } + result, err := mod.List(s, query) + if err != nil { + return err + } + printList(result, mod.GetColumns(s)) + return nil + }) + + type ServiceShowOptions struct { + ID string `help:"ID of service"` + } + R(&ServiceShowOptions{}, "service-show", "Show details of a service", func(s *mcclient.ClientSession, args *ServiceShowOptions) error { + mod, err := modules.GetModule(s, "services") + if err != nil { + return err + } + srvId, err := mod.GetId(s, args.ID, nil) + if err != nil { + return err + } + result, err := mod.Get(s, srvId, nil) + if err != nil { + return err + } + printObject(result) + return nil + }) + R(&ServiceShowOptions{}, "service-delete", "Delete a service", func(s *mcclient.ClientSession, args *ServiceShowOptions) error { + mod, err := modules.GetModule(s, "services") + if err != nil { + return err + } + srvId, err := mod.GetId(s, args.ID, nil) + if err != nil { + return err + } + result, err := mod.Delete(s, srvId, nil) + if err != nil { + return err + } + printObject(result) + return nil + }) + + type ServiceCreateOptions struct { + TYPE string `help:"Service type"` + NAME string `help:"Service name"` + Desc string `help:"Description"` + Enabled bool `help:"Enabeld"` + Disabled bool `help:"Disabled"` + } + R(&ServiceCreateOptions{}, "service-create", "Create a service", func(s *mcclient.ClientSession, args *ServiceCreateOptions) error { + params := jsonutils.NewDict() + params.Add(jsonutils.NewString(args.TYPE), "type") + params.Add(jsonutils.NewString(args.NAME), "name") + if len(args.Desc) > 0 { + params.Add(jsonutils.NewString(args.Desc), "description") + } + if args.Enabled && !args.Disabled { + params.Add(jsonutils.JSONTrue, "enabled") + } else if !args.Enabled && args.Disabled { + params.Add(jsonutils.JSONFalse, "enabled") + } + mod, err := modules.GetModule(s, "services") + if err != nil { + return err + } + srv, err := mod.Create(s, params) + if err != nil { + return err + } + printObject(srv) + return nil + }) + + type ServiceUpdateOptions struct { + ID string `help:"ID or name of the service"` + Type string `help:"Service type"` + Name string `help:"Service name"` + Desc string `help:"Description"` + Enabled bool `help:"Enabeld"` + Disabled bool `help:"Disabled"` + } + R(&ServiceUpdateOptions{}, "service-update", "Update a service", func(s *mcclient.ClientSession, args *ServiceUpdateOptions) error { + mod, err := modules.GetModule(s, "services") + if err != nil { + return err + } + srvId, err := mod.GetId(s, args.ID, nil) + if err != nil { + return err + } + params := jsonutils.NewDict() + if len(args.Type) > 0 { + params.Add(jsonutils.NewString(args.Type), "type") + } + if len(args.Name) > 0 { + params.Add(jsonutils.NewString(args.Name), "name") + } + if len(args.Desc) > 0 { + params.Add(jsonutils.NewString(args.Desc), "description") + } + if args.Enabled && !args.Disabled { + params.Add(jsonutils.JSONTrue, "enabled") + } else if !args.Enabled && args.Disabled { + params.Add(jsonutils.JSONFalse, "enabled") + } + srv, err := mod.Patch(s, srvId, params) + if err != nil { + return err + } + printObject(srv) + return nil + }) +} diff --git a/cmd/climc/shell/servicetrees.go b/cmd/climc/shell/servicetrees.go new file mode 100644 index 0000000000..414825a84e --- /dev/null +++ b/cmd/climc/shell/servicetrees.go @@ -0,0 +1,109 @@ +package shell + +import ( + "github.com/yunionio/jsonutils" + "github.com/yunionio/mcclient" + "github.com/yunionio/mcclient/modules" +) + +func init() { + + /** + * 创建新的服务树 + */ + type ServiceTreeCreateOptions struct { + NAME string `help:"Name of the new service tree"` + STRUCT string `help:"Struct of the service tree"` + Remark string `help:"Remark or description of the new service tree"` + } + R(&ServiceTreeCreateOptions{}, "servicetree-create", "Create a service tree", func(s *mcclient.ClientSession, args *ServiceTreeCreateOptions) error { + params := jsonutils.NewDict() + params.Add(jsonutils.NewString(args.NAME), "service_tree_name") + params.Add(jsonutils.NewString(args.STRUCT), "service_tree_struct") + if len(args.Remark) > 0 { + params.Add(jsonutils.NewString(args.Remark), "remark") + } + serviceTree, err := modules.ServiceTrees.Create(s, params) + if err != nil { + return err + } + printObject(serviceTree) + return nil + }) + + /** + * 删除一个服务树 + */ + type ServiceTreeDeleteOptions struct { + ID string `help:"ID of alarm template"` + } + R(&ServiceTreeDeleteOptions{}, "servicetree-delete", "Delete a service tree", func(s *mcclient.ClientSession, args *ServiceTreeDeleteOptions) error { + serviceTree, e := modules.ServiceTrees.Delete(s, args.ID, nil) + if e != nil { + return e + } + printObject(serviceTree) + return nil + }) + + /** + * 修改服务树的配置信息 + */ + type ServiceTreeUpdateOptions struct { + ID string `help:"ID of the service tree"` + Name string `help:"Name of the service-tree"` + Struct string `help:"Struct of the service-tree"` + Remark string `help:"Remark or description of the service-tree"` + } + R(&ServiceTreeUpdateOptions{}, "servicetree-update", "Update a service tree", func(s *mcclient.ClientSession, args *ServiceTreeUpdateOptions) error { + params := jsonutils.NewDict() + if len(args.Name) > 0 { + params.Add(jsonutils.NewString(args.Name), "service_tree_name") + } + if len(args.Struct) > 0 { + params.Add(jsonutils.NewString(args.Struct), "service_tree_struct") + } + if len(args.Remark) > 0 { + params.Add(jsonutils.NewString(args.Remark), "remark") + } + + serviceTree, err := modules.ServiceTrees.Patch(s, args.ID, params) + if err != nil { + return err + } + printObject(serviceTree) + return nil + }) + + /** + * 列出服务树 + */ + type ServiceTreeListOptions struct { + BaseListOptions + } + R(&ServiceTreeListOptions{}, "servicetree-list", "List all service tree", func(s *mcclient.ClientSession, args *ServiceTreeListOptions) error { + params := FetchPagingParams(args.BaseListOptions) + result, err := modules.ServiceTrees.List(s, params) + if err != nil { + return err + } + printList(result, modules.ServiceTrees.GetColumns(s)) + return nil + }) + + /** + * 查看服务树配置详情 + */ + type ServiceTreeShowOptions struct { + ID string `help:"ID of the service-tree"` + } + R(&ServiceTreeShowOptions{}, "servicetree-show", "Show service tree details", func(s *mcclient.ClientSession, args *ServiceTreeShowOptions) error { + result, err := modules.ServiceTrees.Get(s, args.ID, nil) + if err != nil { + return err + } + printObject(result) + return nil + }) + +} diff --git a/cmd/climc/shell/shell.go b/cmd/climc/shell/shell.go new file mode 100644 index 0000000000..6d131513c3 --- /dev/null +++ b/cmd/climc/shell/shell.go @@ -0,0 +1,110 @@ +package shell + +import ( + "fmt" + "github.com/yunionio/jsonutils" +) + +type CMD struct { + Options interface{} + Command string + Desc string + Callback interface{} +} + +var CommandTable []CMD = make([]CMD, 0) + +func R(options interface{}, command string, desc string, callback interface{}) { + CommandTable = append(CommandTable, CMD{options, command, desc, callback}) +} + +type BaseListOptions struct { + Limit int `default:"20" help:"Page limit"` + Offset int `default:"0" help:"Page offset"` + OrderBy string `help:"Name of the field to be ordered by"` + Order string `help:"List order" choices:"desc|asc"` + Details bool `help:"Show more details"` + Search string `help:"Filter results by a simple keyword search"` + Meta bool `help:"Piggyback metadata information"` + Filter []string `help:"Filters"` + FilterAny bool `help:"If true, match if any of the filters matches; otherwise, match if all of the filters match"` + Admin bool `help:"Is an admin call?"` + Tenant string `help:"Tenant ID or Name"` + User string `help:"User ID or Name"` + System bool `help:"Show system resource"` + PendingDelete bool `help:"Show pending deleted resource"` + Field []string `help:"Show only specified fields"` +} + +func FetchPagingParams(options BaseListOptions) *jsonutils.JSONDict { + params := jsonutils.NewDict() + if options.Limit > 0 { + params.Add(jsonutils.NewInt(int64(options.Limit)), "limit") + } + if options.Offset > 0 { + params.Add(jsonutils.NewInt(int64(options.Offset)), "offset") + } + if len(options.OrderBy) > 0 { + params.Add(jsonutils.NewString(options.OrderBy), "order_by") + } + if len(options.Order) > 0 { + params.Add(jsonutils.NewString(options.Order), "order") + } + if options.Details { + params.Add(jsonutils.JSONTrue, "details") + } else { + params.Add(jsonutils.JSONFalse, "details") + } + if len(options.Search) > 0 { + params.Add(jsonutils.NewString(options.Search), "search") + } + if options.Meta { + params.Add(jsonutils.JSONTrue, "with_meta") + } + if len(options.Filter) > 0 { + arr := jsonutils.NewArray() + for _, f := range options.Filter { + arr.Add(jsonutils.NewString(f)) + } + params.Add(arr, "filter") + if options.FilterAny { + params.Add(jsonutils.JSONTrue, "filter_any") + } + } + if options.Admin { + params.Add(jsonutils.JSONTrue, "admin") + } + if len(options.Tenant) > 0 { + params.Add(jsonutils.NewString(options.Tenant), "tenant") + if !options.Admin { + params.Add(jsonutils.JSONTrue, "admin") + } + } + if len(options.User) > 0 { + params.Add(jsonutils.NewString(options.User), "user") + } + if options.System { + params.Add(jsonutils.JSONTrue, "system") + if !options.Admin { + params.Add(jsonutils.JSONTrue, "admin") + } + } + if options.PendingDelete { + params.Add(jsonutils.JSONTrue, "pending_delete") + if !options.Admin { + params.Add(jsonutils.JSONTrue, "admin") + } + } + if len(options.Field) > 0 { + arr := jsonutils.NewArray() + for _, f := range options.Field { + arr.Add(jsonutils.NewString(f)) + } + params.Add(arr, "field") + } + return params +} + +func InvalidUpdateError() error { + return fmt.Errorf("No valid update data") +} diff --git a/cmd/climc/shell/sms_configs.go b/cmd/climc/shell/sms_configs.go new file mode 100644 index 0000000000..84696d55ed --- /dev/null +++ b/cmd/climc/shell/sms_configs.go @@ -0,0 +1,109 @@ +package shell + +import ( + "github.com/yunionio/jsonutils" + "github.com/yunionio/mcclient" + "github.com/yunionio/mcclient/modules" +) + +func init() { + + /** + * 查询短信配置信息 + */ + type SmsConfigShowOptions struct { + TYPE string `help:"type "` + } + R(&SmsConfigShowOptions{}, "sms-config-show", "Show sms config details", + func(s *mcclient.ClientSession, args *SmsConfigShowOptions) error { + result, err := modules.SmsConfigs.Get(s, args.TYPE, nil) + if err != nil { + return err + } + printObject(result) + return nil + }) + + /** + * 增加短信配置信息 + */ + type SmsConfigCreateOptions struct { + TYPE string `help:"sms vendor"` + ACCESSKEYID string `help:"ACCESSKEYID for sms vendor"` + ACCESSKEYSECRET string `help:"ACCESSKEYSECRET for sms vendor"` + SIGNATURE string `help:"SIGNATURE for sms vendor"` + SmsTemplateOne string `help:"Sms TemplateOne"` + SmsTemplateTwo string `help:"Sms TemplateTwo"` + SmsTemplateThree string `help:"Sms TemplateThree"` + SmsCheckCode string `help:"Sms Check Code "` + } + + R(&SmsConfigCreateOptions{}, "sms-config-create", "Create a sms Config", + func(s *mcclient.ClientSession, args *SmsConfigCreateOptions) error { + params := jsonutils.NewDict() + params.Add(jsonutils.NewString(args.TYPE), "type") + params.Add(jsonutils.NewString(args.ACCESSKEYID), "access_key_id") + params.Add(jsonutils.NewString(args.ACCESSKEYSECRET), "access_key_secret") + params.Add(jsonutils.NewString(args.SIGNATURE), "signature") + params.Add(jsonutils.NewString(args.SmsTemplateOne), "sms_template_one") + params.Add(jsonutils.NewString(args.SmsTemplateTwo), "sms_template_two") + params.Add(jsonutils.NewString(args.SmsTemplateThree), "sms_template_three") + params.Add(jsonutils.NewString(args.SmsCheckCode), "sms_check_code") + + result, err := modules.SmsConfigs.Create(s, params) + if err != nil { + return err + } + printObject(result) + return nil + }) + + /** + * 修改 + */ + type SmsConfigUpdateOptions struct { + TYPE string `help:"sms vendor"` + ACCESSKEYID string `help:"ACCESSKEYID for sms vendor"` + ACCESSKEYSECRET string `help:"ACCESSKEYSECRET for sms vendor"` + SIGNATURE string `help:"SIGNATURE for sms vendor"` + SmsTemplateOne string `help:"Sms TemplateOne"` + SmsTemplateTwo string `help:"Sms TemplateTwo"` + SmsTemplateThree string `help:"Sms TemplateThree"` + SmsCheckCode string `help:"Sms Check Code "` + } + R(&SmsConfigUpdateOptions{}, "sms-config-update", "Update a sms-config", func(s *mcclient.ClientSession, args *SmsConfigUpdateOptions) error { + params := jsonutils.NewDict() + + params.Add(jsonutils.NewString(args.TYPE), "type") + params.Add(jsonutils.NewString(args.ACCESSKEYID), "access_key_id") + params.Add(jsonutils.NewString(args.ACCESSKEYSECRET), "access_key_secret") + params.Add(jsonutils.NewString(args.SIGNATURE), "signature") + params.Add(jsonutils.NewString(args.SmsTemplateOne), "sms_template_one") + params.Add(jsonutils.NewString(args.SmsTemplateTwo), "sms_template_two") + params.Add(jsonutils.NewString(args.SmsTemplateThree), "sms_template_three") + params.Add(jsonutils.NewString(args.SmsCheckCode), "sms_check_code") + + result, err := modules.SmsConfigs.Put(s, args.TYPE, params) + if err != nil { + return err + } + printObject(result) + return nil + }) + + /** + * 删除 + */ + type SmsConfigDeleteOptions struct { + TYPE string `help:"sms vendor"` + } + R(&SmsConfigDeleteOptions{}, "sms-config-delete", "Delete a sms config", func(s *mcclient.ClientSession, args *SmsConfigDeleteOptions) error { + result, e := modules.SmsConfigs.Delete(s, args.TYPE, nil) + if e != nil { + return e + } + printObject(result) + return nil + }) + +} diff --git a/cmd/climc/shell/specs.go b/cmd/climc/shell/specs.go new file mode 100644 index 0000000000..f4c64b52d0 --- /dev/null +++ b/cmd/climc/shell/specs.go @@ -0,0 +1,111 @@ +package shell + +import ( + "fmt" + + "github.com/yunionio/jsonutils" + "github.com/yunionio/mcclient" + "github.com/yunionio/mcclient/modules" +) + +func init() { + type ListOptions struct { + BaseListOptions + Model string `help:"Specified model specs" choices:"hosts|isolated_devices|guests"` + HostType string `help:"Host type filter" choices:"baremetal|hypervisor|esxi|kubelet|hyperv"` + Gpu bool `help:"Only show gpu devices"` + } + R(&ListOptions{}, "spec", "List all kinds of model specs", func(s *mcclient.ClientSession, args *ListOptions) error { + params := FetchPagingParams(args.BaseListOptions) + model := "" + if len(args.Model) != 0 { + model = args.Model + } + if len(args.HostType) > 0 { + params.Add(jsonutils.NewString(args.HostType), "host_type") + } + if args.Gpu { + params.Add(jsonutils.JSONTrue, "gpu") + } + result, err := modules.Specs.GetModelSpecs(s, model, params) + if err != nil { + return err + } + printObject(result) + return nil + }) + + type HostsQueryOptions struct { + BaseListOptions + HostType string `help:"Host type filter" choices:"baremetal|hypervisor|esxi|kubelet|hyperv"` + Ncpu int64 `help:"#CPU count of host" metavar:""` + MemSize string `help:"Memory GB size"` + DiskSpec []string `help:"Disk spec string, like 'Linux_adapter0_HDD_111Gx4'"` + Nic int64 `help:"#Nics count of host" metavar:""` + GpuModel []string `help:"GPU model, like 'GeForce GTX 1050 Ti'"` + } + R(&HostsQueryOptions{}, "spec-hosts-list", "List hosts according by specs", func(s *mcclient.ClientSession, args *HostsQueryOptions) error { + newHostSpecKeys := func() []string { + keys := []string{} + if args.Ncpu > 0 { + keys = append(keys, fmt.Sprintf("cpu:%d", args.Ncpu)) + } + if len(args.MemSize) != 0 { + keys = append(keys, fmt.Sprintf("mem:%s", args.MemSize)) + } + for _, gm := range args.GpuModel { + keys = append(keys, fmt.Sprintf("gpu_model:%s", gm)) + } + for _, ds := range args.DiskSpec { + keys = append(keys, fmt.Sprintf("disk:%s", ds)) + } + return keys + } + params := FetchPagingParams(args.BaseListOptions) + if len(args.HostType) > 0 { + params.Add(jsonutils.NewString(args.HostType), "host_type") + } + specKeys := newHostSpecKeys() + resp, err := modules.Specs.SpecsQueryModelObjects(s, "hosts", specKeys, params) + if err != nil { + return err + } + hosts, err := resp.GetArray() + if err != nil { + return err + } + data := &modules.ListResult{Data: hosts, Total: len(hosts)} + printList(data, []string{"ID", "Name", "Mem", "CPU", "Storage_Info"}) + return nil + }) + + type IsoDevQueryOptions struct { + BaseListOptions + Model string `help:"Device model name"` + Vendor string `help:"Device vendor name"` + } + R(&IsoDevQueryOptions{}, "spec-isolated-devices-list", "List isolated devices according by specs", func(s *mcclient.ClientSession, args *IsoDevQueryOptions) error { + newSpecKeys := func() []string { + keys := []string{} + if len(args.Vendor) != 0 { + keys = append(keys, fmt.Sprintf("vendor:%s", args.Vendor)) + } + if len(args.Model) != 0 { + keys = append(keys, fmt.Sprintf("model:%s", args.Model)) + } + return keys + } + params := FetchPagingParams(args.BaseListOptions) + resp, err := modules.Specs.SpecsQueryModelObjects(s, "isolated_devices", newSpecKeys(), params) + if err != nil { + return err + } + devs, err := resp.GetArray() + if err != nil { + return err + } + data := &modules.ListResult{Data: devs, Total: len(devs)} + printList(data, []string{"ID", "Addr", "Dev_Type", "Model", "Vendor_Device_Id"}) + return nil + }) +} diff --git a/cmd/climc/shell/storagecachedimages.go b/cmd/climc/shell/storagecachedimages.go new file mode 100644 index 0000000000..c4a91055d6 --- /dev/null +++ b/cmd/climc/shell/storagecachedimages.go @@ -0,0 +1,66 @@ +package shell + +import ( + "github.com/yunionio/jsonutils" + "github.com/yunionio/mcclient" + "github.com/yunionio/mcclient/modules" +) + +func init() { + type StorageCachedImageListOptions struct { + BaseListOptions + Storagecache string `help:"ID or Name of Storage"` + Image string `help:"ID or Name of image"` + } + R(&StorageCachedImageListOptions{}, "storage-cached-image-list", "List storage cached image pairs", func(s *mcclient.ClientSession, args *StorageCachedImageListOptions) error { + params := FetchPagingParams(args.BaseListOptions) + var result *modules.ListResult + var err error + if len(args.Storagecache) > 0 { + result, err = modules.Storagecachedimages.ListDescendent(s, args.Storagecache, params) + } else if len(args.Image) > 0 { + result, err = modules.Storagecachedimages.ListDescendent2(s, args.Image, params) + } else { + result, err = modules.Storagecachedimages.List(s, params) + } + if err != nil { + return err + } + printList(result, modules.Storagecachedimages.GetColumns(s)) + return nil + }) + + type StorageCachedImageUpdateOptions struct { + STORAGECACHE string `help:"ID or Name of Storage cache"` + IMAGE string `help:"ID or name of image"` + Status string `help:"Status"` + } + R(&StorageCachedImageUpdateOptions{}, "storage-cached-image-update", "Update storage cached image", func(s *mcclient.ClientSession, args *StorageCachedImageUpdateOptions) error { + params := jsonutils.NewDict() + if len(args.Status) > 0 { + params.Add(jsonutils.NewString(args.Status), "status") + } + if params.Size() == 0 { + return InvalidUpdateError() + } + result, err := modules.Storagecachedimages.Update(s, args.STORAGECACHE, args.IMAGE, params) + if err != nil { + return err + } + printObject(result) + return nil + }) + + type StorageCachedImageShowOptions struct { + STORAGECACHE string `help:"ID or Name of Storage cache"` + IMAGE string `help:"ID or name of image"` + } + R(&StorageCachedImageShowOptions{}, "storage-cached-image-show", "Show storage cached image", func(s *mcclient.ClientSession, args *StorageCachedImageShowOptions) error { + result, err := modules.Storagecachedimages.Get(s, args.STORAGECACHE, args.IMAGE, nil) + if err != nil { + return err + } + printObject(result) + return nil + }) +} diff --git a/cmd/climc/shell/storagecaches.go b/cmd/climc/shell/storagecaches.go new file mode 100644 index 0000000000..0f2e817a94 --- /dev/null +++ b/cmd/climc/shell/storagecaches.go @@ -0,0 +1,34 @@ +package shell + +import ( + "github.com/yunionio/mcclient" + "github.com/yunionio/mcclient/modules" +) + +func init() { + type StoragecacheListOptions struct { + BaseListOptions + } + R(&StoragecacheListOptions{}, "storage-cache-list", "List storage caches", func(s *mcclient.ClientSession, args *StoragecacheListOptions) error { + params := FetchPagingParams(args.BaseListOptions) + result, err := modules.Storagecaches.List(s, params) + if err != nil { + return err + } + printList(result, modules.Storagecaches.GetColumns(s)) + return nil + }) + + type StoragecacheShowptions struct { + ID string `help:"ID or Name of storagecache"` + } + R(&StoragecacheShowptions{}, "storage-cache-show", "Show details of storage caches", func(s *mcclient.ClientSession, args *StoragecacheShowptions) error { + result, err := modules.Storagecaches.Get(s, args.ID, nil) + if err != nil { + return err + } + printObject(result) + return nil + }) + +} diff --git a/cmd/climc/shell/storages.go b/cmd/climc/shell/storages.go new file mode 100644 index 0000000000..6c4d229d83 --- /dev/null +++ b/cmd/climc/shell/storages.go @@ -0,0 +1,196 @@ +package shell + +import ( + "fmt" + + "github.com/yunionio/jsonutils" + "github.com/yunionio/mcclient" + "github.com/yunionio/mcclient/modules" +) + +func init() { + type StorageListOptions struct { + BaseListOptions + Share bool `help:"Share storage list"` + Local bool `help:"Local storage list"` + Usable bool `help:"Usable storage list"` + } + R(&StorageListOptions{}, "storage-list", "List storages", func(s *mcclient.ClientSession, args *StorageListOptions) error { + params := FetchPagingParams(args.BaseListOptions) + if args.Share { + params.Add(jsonutils.JSONTrue, "share") + } + if args.Local { + params.Add(jsonutils.JSONTrue, "local") + } + if args.Usable { + params.Add(jsonutils.JSONTrue, "usable") + } + result, err := modules.Storages.List(s, params) + if err != nil { + return err + } + printList(result, modules.Storages.GetColumns(s)) + return nil + }) + + type StorageUpdateOptions struct { + ID string `help:"ID or Name of storage to update"` + Name string `help:"New Name of storage"` + Desc string `help:"Description" metavar:""` + CommitBound float64 `help:"Upper bound of storage overcommit rate"` + StorageType string `help:"Storage type" choices:"local|nas|vsan|rbd|baremetal"` + MediumType string `help:"Medium type, either ssd or rotate" choices:"ssd|rotate"` + Reserved string `help:"Reserved storage space"` + } + R(&StorageUpdateOptions{}, "storage-update", "Update a storage", func(s *mcclient.ClientSession, args *StorageUpdateOptions) error { + params := jsonutils.NewDict() + if len(args.Name) > 0 { + params.Add(jsonutils.NewString(args.Name), "name") + } + if len(args.Desc) > 0 { + params.Add(jsonutils.NewString(args.Desc), "description") + } + if args.CommitBound > 0 { + params.Add(jsonutils.NewFloat(args.CommitBound), "cmtbound") + } + if len(args.StorageType) > 0 { + params.Add(jsonutils.NewString(args.StorageType), "storage_type") + } + if len(args.MediumType) > 0 { + params.Add(jsonutils.NewString(args.MediumType), "medium_type") + } + if len(args.Reserved) > 0 { + params.Add(jsonutils.NewString(args.Reserved), "reserved") + } + result, err := modules.Storages.Update(s, args.ID, params) + if err != nil { + return err + } + printObject(result) + return nil + }) + + type StorageCreateOptions struct { + NAME string `help:"Name of the Storage"` + Capacity int64 `help:"Capacity of the Storage"` + MediumType string `help:"Medium type, either ssd or rotate" choices:"ssd|rotate"` + StorageType string `help:"Storage type" choices:"local|nas|vsan|rbd|baremetal"` + MonHost string `helo:"Ceph mon_host config"` + Key string `helo:"Ceph key config"` + Pool string `helo:"Ceph Poll Name"` + } + R(&StorageCreateOptions{}, "storage-create", "Create a Storage", func(s *mcclient.ClientSession, args *StorageCreateOptions) error { + params := jsonutils.NewDict() + params.Add(jsonutils.NewString(args.NAME), "name") + params.Add(jsonutils.NewInt(args.Capacity), "capacity") + params.Add(jsonutils.NewString(args.StorageType), "storage_type") + params.Add(jsonutils.NewString(args.MediumType), "medium_type") + if args.StorageType == "rbd" { + if args.MonHost == "" || args.Key == "" || args.Pool == "" { + return fmt.Errorf("Not enough arguments, missing mon_host、key or pool") + } + params.Add(jsonutils.NewString(args.MonHost), "rbd_mon_host") + params.Add(jsonutils.NewString(args.Key), "rbd_key") + params.Add(jsonutils.NewString(args.Pool), "rbd_pool") + } + storage, err := modules.Storages.Create(s, params) + if err != nil { + return err + } + printObject(storage) + return nil + }) + + type StorageShowOptions struct { + ID string `help:"ID or Name of the storage to show"` + } + R(&StorageShowOptions{}, "storage-show", "Show storage details", func(s *mcclient.ClientSession, args *StorageShowOptions) error { + result, err := modules.Storages.Get(s, args.ID, nil) + if err != nil { + return err + } + printObject(result) + return nil + }) + + R(&StorageShowOptions{}, "storage-delete", "Delete a storage", func(s *mcclient.ClientSession, args *StorageShowOptions) error { + result, err := modules.Storages.Delete(s, args.ID, nil) + if err != nil { + return err + } + printObject(result) + return nil + }) + + R(&StorageShowOptions{}, "storage-enable", "Enable a storage", func(s *mcclient.ClientSession, args *StorageShowOptions) error { + result, err := modules.Storages.PerformAction(s, args.ID, "enable", nil) + if err != nil { + return err + } + printObject(result) + return nil + }) + + R(&StorageShowOptions{}, "storage-disable", "Disable a storage", func(s *mcclient.ClientSession, args *StorageShowOptions) error { + result, err := modules.Storages.PerformAction(s, args.ID, "disable", nil) + if err != nil { + return err + } + printObject(result) + return nil + }) + + R(&StorageShowOptions{}, "storage-enable", "Enable a storage", func(s *mcclient.ClientSession, args *StorageShowOptions) error { + result, err := modules.Storages.PerformAction(s, args.ID, "enable", nil) + if err != nil { + return err + } + printObject(result) + return nil + }) + + R(&StorageShowOptions{}, "storage-disable", "Disable a storage", func(s *mcclient.ClientSession, args *StorageShowOptions) error { + result, err := modules.Storages.PerformAction(s, args.ID, "disable", nil) + if err != nil { + return err + } + printObject(result) + return nil + }) + + type StorageCacheImageActionOptions struct { + ID string `help:"ID or name of storage"` + IMAGE string `help:"ID or name of image"` + Force bool `help:"Force refresh cache, even if the image exists in cache"` + } + R(&StorageCacheImageActionOptions{}, "storage-cache-image", "Ask a storage to cache a image", func(s *mcclient.ClientSession, args *StorageCacheImageActionOptions) error { + params := jsonutils.NewDict() + params.Add(jsonutils.NewString(args.IMAGE), "image") + if args.Force { + params.Add(jsonutils.JSONTrue, "is_force") + } + storage, err := modules.Storages.PerformAction(s, args.ID, "cache-image", params) + if err != nil { + return err + } + printObject(storage) + return nil + }) + + type StorageUncacheImageActionOptions struct { + ID string `help:"ID or name of storage"` + IMAGE string `help:"ID or name of image"` + } + R(&StorageUncacheImageActionOptions{}, "storage-uncache-image", "Ask a storage to remove image from its cache", func(s *mcclient.ClientSession, args *StorageUncacheImageActionOptions) error { + params := jsonutils.NewDict() + params.Add(jsonutils.NewString(args.IMAGE), "image") + storage, err := modules.Storages.PerformAction(s, args.ID, "uncache-image", params) + if err != nil { + return err + } + printObject(storage) + return nil + }) + +} diff --git a/cmd/climc/shell/tasks.go b/cmd/climc/shell/tasks.go new file mode 100644 index 0000000000..98f57a5f1e --- /dev/null +++ b/cmd/climc/shell/tasks.go @@ -0,0 +1,43 @@ +package shell + +import ( + "github.com/yunionio/mcclient" + "github.com/yunionio/mcclient/modules" +) + +func init() { + type TaskListOptions struct { + BaseListOptions + } + R(&TaskListOptions{}, "task-list", "List taskman", func(s *mcclient.ClientSession, suboptions *TaskListOptions) error { + params := FetchPagingParams(suboptions.BaseListOptions) + result, err := modules.Tasks.List(s, params) + if err != nil { + return err + } + printList(result, modules.Tasks.GetColumns(s)) + return nil + }) + + R(&TaskListOptions{}, "region-task-list", "List tasks on region server", func(s *mcclient.ClientSession, suboptions *TaskListOptions) error { + params := FetchPagingParams(suboptions.BaseListOptions) + result, err := modules.ComputeTasks.List(s, params) + if err != nil { + return err + } + printList(result, modules.ComputeTasks.GetColumns(s)) + return nil + }) + + type TaskShowOptions struct { + ID string `help:"ID or name of the task"` + } + R(&TaskShowOptions{}, "region-task-show", "Show details of a region task", func(s *mcclient.ClientSession, args *TaskShowOptions) error { + result, err := modules.ComputeTasks.Get(s, args.ID, nil) + if err != nil { + return err + } + printObject(result) + return nil + }) +} diff --git a/cmd/climc/shell/tenants.go b/cmd/climc/shell/tenants.go new file mode 100644 index 0000000000..12a1ae51d6 --- /dev/null +++ b/cmd/climc/shell/tenants.go @@ -0,0 +1,19 @@ +package shell + +import ( + "github.com/yunionio/mcclient" + "github.com/yunionio/mcclient/modules" +) + +func init() { + type TenantListOptions struct { + } + R(&TenantListOptions{}, "tenant-list", "List tenants", func(s *mcclient.ClientSession, args *TenantListOptions) error { + result, err := modules.Tenants.List(s, nil) + if err != nil { + return err + } + printList(result, modules.Tenants.GetColumns(s)) + return nil + }) +} diff --git a/cmd/climc/shell/treenodes.go b/cmd/climc/shell/treenodes.go new file mode 100644 index 0000000000..5aeb321211 --- /dev/null +++ b/cmd/climc/shell/treenodes.go @@ -0,0 +1,177 @@ +package shell + +import ( + "fmt" + "strconv" + + "github.com/yunionio/jsonutils" + "github.com/yunionio/mcclient" + "github.com/yunionio/mcclient/modules" +) + +func init() { + + /** + * 创建新的服务树节点 + */ + type ServiceTreeCreateOptions struct { + NAME string `help:"Name of the new service-tree node"` + Pid int64 `help:"PID of the service-tree node" default:"-1"` + Label []string `help:"Labels to this node"` + Project string `help:"Project id of the if create PDL node"` + Remark string `help:"Remark or description of the new service-tree node"` + } + R(&ServiceTreeCreateOptions{}, "servicetree-node-create", "Create a service-tree node", func(s *mcclient.ClientSession, args *ServiceTreeCreateOptions) error { + params := jsonutils.NewDict() + params.Add(jsonutils.NewString(args.NAME), "name") + pid := args.Pid + var err error + if pid < 0 { + if len(args.Label) <= 0 { + return fmt.Errorf("Must provide either pid or labels") + } + pid, err = modules.TreeNodes.GetNodeIDByLabels(s, args.Label) + if err != nil { + return err + } + if pid < 0 { + return fmt.Errorf("Invalid labels: %s", args.Label) + } + } + params.Add(jsonutils.NewInt(pid), "pid") + if len(args.Project) > 0 { + projId, err := modules.Projects.GetId(s, args.Project, nil) + if err != nil { + return err + } + params.Add(jsonutils.NewString(projId), "project_id") + } + if len(args.Remark) > 0 { + params.Add(jsonutils.NewString(args.Remark), "remark") + } + serviceTree, err := modules.TreeNodes.Create(s, params) + if err != nil { + return err + } + printObject(serviceTree) + return nil + }) + + type ServiceTreeNodeListOptions struct { + BaseListOptions + Label string `help:"Label of node"` + Pid int64 `help:"Pid of node" default:"-1"` + } + R(&ServiceTreeNodeListOptions{}, "servicetree-node-list", "List servicetree nodes", func(s *mcclient.ClientSession, args *ServiceTreeNodeListOptions) error { + params := FetchPagingParams(args.BaseListOptions) + if args.Pid >= 0 { + params.Add(jsonutils.NewInt(args.Pid), "pid") + } + if len(args.Label) >= 0 { + params.Add(jsonutils.NewString(args.Label), "name") + } + result, err := modules.TreeNodes.List(s, params) + if err != nil { + return err + } + printList(result, modules.TreeNodes.GetColumns(s)) + return nil + }) + + /** + * 查看服务树节点配置详情 + */ + type ServiceTreeNodeShowOptions struct { + Id int64 `help:"ID of tree node"` + Label []string `help:"Labels to this tree node"` + } + R(&ServiceTreeNodeShowOptions{}, "servicetree-node-show", "Show details of a servicetree node", func(s *mcclient.ClientSession, args *ServiceTreeNodeShowOptions) error { + pid := args.Id + var err error + if pid <= 0 { + pid, err = modules.TreeNodes.GetNodeIDByLabels(s, args.Label) + if err != nil { + return err + } + if pid <= 0 { + return fmt.Errorf("Invalid tree node ID") + } + } + idstr := strconv.Itoa(int(pid)) + result, err := modules.TreeNodes.Get(s, idstr, nil) + if err != nil { + return err + } + printObject(result) + return nil + }) + + /** + * 修改服务树节点配置信息 + */ + type ServiceTreeNodeUpdateOptions struct { + ServiceTreeNodeShowOptions + Name string `help:"Name of the service-tree"` + Project string `help:"Project associate with this tree node"` + Remark string `help:"Remark or description of the service-tree"` + } + R(&ServiceTreeNodeUpdateOptions{}, "servicetree-node-update", "Update a servicetree node", func(s *mcclient.ClientSession, args *ServiceTreeNodeUpdateOptions) error { + pid := args.Id + var err error + if pid <= 0 { + pid, err = modules.TreeNodes.GetNodeIDByLabels(s, args.Label) + if err != nil { + return err + } + if pid <= 0 { + return fmt.Errorf("Invalid tree node ID") + } + } + idstr := strconv.Itoa(int(pid)) + params := jsonutils.NewDict() + if len(args.Name) > 0 { + params.Add(jsonutils.NewString(args.Name), "name") + } + if len(args.Project) > 0 { + projId, err := modules.Projects.GetId(s, args.Project, nil) + if err != nil { + return err + } + params.Add(jsonutils.NewString(projId), "project_id") + } + if len(args.Remark) > 0 { + params.Add(jsonutils.NewString(args.Remark), "remark") + } + result, err := modules.TreeNodes.Update(s, idstr, params) + if err != nil { + return err + } + printObject(result) + return nil + }) + + /** + * 删除一个服务树节点 + */ + R(&ServiceTreeNodeShowOptions{}, "servicetree-node-delete", "Delete a servicetree node", func(s *mcclient.ClientSession, args *ServiceTreeNodeShowOptions) error { + pid := args.Id + var err error + if pid <= 0 { + pid, err = modules.TreeNodes.GetNodeIDByLabels(s, args.Label) + if err != nil { + return err + } + if pid <= 0 { + return fmt.Errorf("Invalid tree node ID") + } + } + idstr := strconv.Itoa(int(pid)) + result, err := modules.TreeNodes.Delete(s, idstr, nil) + if err != nil { + return err + } + printObject(result) + return nil + }) + +} diff --git a/cmd/climc/shell/usages.go b/cmd/climc/shell/usages.go new file mode 100644 index 0000000000..86be776571 --- /dev/null +++ b/cmd/climc/shell/usages.go @@ -0,0 +1,83 @@ +package shell + +import ( + "github.com/yunionio/jsonutils" + "github.com/yunionio/mcclient" + "github.com/yunionio/mcclient/modules" +) + +type GeneralUsageOptions struct { + HostType []string `help:"Host types" choices:"hypervisor|baremetal|esxi|xen|kubelet|hyperv"` +} + +func fetchHostTypeOptions(args *GeneralUsageOptions) *jsonutils.JSONDict { + params := jsonutils.NewDict() + if len(args.HostType) > 0 { + params.Add(jsonutils.NewStringArray(args.HostType), "host_type") + } + return params +} + +func init() { + R(&GeneralUsageOptions{}, "usage", "Show general usage", func(s *mcclient.ClientSession, args *GeneralUsageOptions) error { + params := fetchHostTypeOptions(args) + result, err := modules.Usages.GetGeneralUsage(s, params) + if err != nil { + return err + } + printObject(result) + return nil + }) + + type ResourceUsageOptions struct { + GeneralUsageOptions + ID string `help:"ID or name of resource"` + } + R(&ResourceUsageOptions{}, "zone-usage", "Show general usage of zone", func(s *mcclient.ClientSession, args *ResourceUsageOptions) error { + params := fetchHostTypeOptions(&args.GeneralUsageOptions) + params.Add(jsonutils.NewString("zones"), "range_type") + params.Add(jsonutils.NewString(args.ID), "range_id") + result, err := modules.Usages.GetGeneralUsage(s, params) + if err != nil { + return err + } + printObject(result) + return nil + }) + + R(&ResourceUsageOptions{}, "wire-usage", "Show general usage of wire", func(s *mcclient.ClientSession, args *ResourceUsageOptions) error { + params := fetchHostTypeOptions(&args.GeneralUsageOptions) + params.Add(jsonutils.NewString("wires"), "range_type") + params.Add(jsonutils.NewString(args.ID), "range_id") + result, err := modules.Usages.GetGeneralUsage(s, params) + if err != nil { + return err + } + printObject(result) + return nil + }) + + R(&ResourceUsageOptions{}, "vcenter-usage", "Show general usage of vcenter", func(s *mcclient.ClientSession, args *ResourceUsageOptions) error { + params := fetchHostTypeOptions(&args.GeneralUsageOptions) + params.Add(jsonutils.NewString("vcenters"), "range_type") + params.Add(jsonutils.NewString(args.ID), "range_id") + result, err := modules.Usages.GetGeneralUsage(s, params) + if err != nil { + return err + } + printObject(result) + return nil + }) + + R(&ResourceUsageOptions{}, "schedtag-usage", "Show general usage of a scheduler tag", func(s *mcclient.ClientSession, args *ResourceUsageOptions) error { + params := fetchHostTypeOptions(&args.GeneralUsageOptions) + params.Add(jsonutils.NewString("schedtags"), "range_type") + params.Add(jsonutils.NewString(args.ID), "range_id") + result, err := modules.Usages.GetGeneralUsage(s, params) + if err != nil { + return err + } + printObject(result) + return nil + }) +} diff --git a/cmd/climc/shell/users.go b/cmd/climc/shell/users.go new file mode 100644 index 0000000000..2bca371c84 --- /dev/null +++ b/cmd/climc/shell/users.go @@ -0,0 +1,320 @@ +package shell + +import ( + "github.com/yunionio/jsonutils" + "github.com/yunionio/mcclient" + "github.com/yunionio/mcclient/modules" +) + +func init() { + type UserListOptions struct { + Domain string `help:"Filter by domain"` + Name string `help:"Filter by name"` + Limit int64 `help:"Limit, default 0, i.e. no limit"` + Offset int64 `help:"Offset, default 0, i.e. no offset"` + Search string `help:"Search by name"` + } + R(&UserListOptions{}, "user-list", "List users", func(s *mcclient.ClientSession, args *UserListOptions) error { + mod, err := modules.GetModule(s, "users") + if err != nil { + return err + } + params := jsonutils.NewDict() + if len(args.Domain) > 0 { + domainId, err := modules.Domains.GetId(s, args.Domain, nil) + if err != nil { + return err + } + params.Add(jsonutils.NewString(domainId), "domain_id") + } + if len(args.Name) > 0 { + params.Add(jsonutils.NewString(args.Name), "name") + } + if len(args.Search) > 0 { + params.Add(jsonutils.NewString(args.Search), "name__icontains") + } + if args.Limit > 0 { + params.Add(jsonutils.NewInt(args.Limit), "limit") + } + if args.Offset > 0 { + params.Add(jsonutils.NewInt(args.Offset), "offset") + } + result, err := mod.List(s, params) + if err != nil { + return err + } + printList(result, mod.GetColumns(s)) + return nil + }) + + type UserDetailOptions struct { + ID string `help:"ID of user"` + Domain string `help:"Domain"` + } + R(&UserDetailOptions{}, "user-show", "Show details of user", func(s *mcclient.ClientSession, args *UserDetailOptions) error { + mod, e := modules.GetModule(s, "users") + if e != nil { + return e + } + query := jsonutils.NewDict() + if len(args.Domain) > 0 { + domainId, err := modules.Domains.GetId(s, args.Domain, nil) + if err != nil { + return err + } + query.Add(jsonutils.NewString(domainId), "domain_id") + } + user, e := mod.Get(s, args.ID, query) + if e != nil { + return e + } + printObject(user) + return nil + }) + R(&UserDetailOptions{}, "user-delete", "Delete user", func(s *mcclient.ClientSession, args *UserDetailOptions) error { + mod, e := modules.GetModule(s, "users") + if e != nil { + return e + } + query := jsonutils.NewDict() + if len(args.Domain) > 0 { + domainId, err := modules.Domains.GetId(s, args.Domain, nil) + if err != nil { + return err + } + query.Add(jsonutils.NewString(domainId), "domain_id") + } + uid, e := mod.GetId(s, args.ID, query) + if e != nil { + return e + } + _, e = mod.Delete(s, uid, nil) + if e != nil { + return e + } + return nil + }) + + R(&UserDetailOptions{}, "user-project-list", "List projects of user", func(s *mcclient.ClientSession, args *UserDetailOptions) error { + query := jsonutils.NewDict() + if len(args.Domain) > 0 { + domainId, err := modules.Domains.GetId(s, args.Domain, nil) + if err != nil { + return err + } + query.Add(jsonutils.NewString(domainId), "domain_id") + } + uid, err := modules.UsersV3.GetId(s, args.ID, query) + if err != nil { + return err + } + projects, e := modules.UsersV3.GetProjects(s, uid) + if e != nil { + return e + } + printList(projects, modules.Projects.GetColumns(s)) + return nil + }) + + R(&UserDetailOptions{}, "user-group-list", "List groups of user", func(s *mcclient.ClientSession, args *UserDetailOptions) error { + query := jsonutils.NewDict() + if len(args.Domain) > 0 { + domainId, err := modules.Domains.GetId(s, args.Domain, nil) + if err != nil { + return err + } + query.Add(jsonutils.NewString(domainId), "domain_id") + } + uid, err := modules.UsersV3.GetId(s, args.ID, query) + if err != nil { + return err + } + projects, e := modules.UsersV3.GetGroups(s, uid) + if e != nil { + return e + } + printList(projects, modules.Groups.GetColumns(s)) + return nil + }) + + type UserTenantRoleOptions struct { + ID string `help:"ID of user"` + Tenant string `help:"ID of tenant"` + } + R(&UserTenantRoleOptions{}, "user-role-list", "List roles of user", func(s *mcclient.ClientSession, args *UserTenantRoleOptions) error { + params := jsonutils.NewDict() + params.Add(jsonutils.NewString(args.ID), "id") + if len(args.Tenant) > 0 { + params.Add(jsonutils.NewString(args.Tenant), "tenantId") + } + result, err := modules.Users.GetTenantRoleList(s, params) + if err != nil { + return err + } + printList(modules.JSON2ListResult(result), nil) + return nil + }) + + type UserCreateOptions struct { + NAME string `help:"Name of the new user"` + Domain string `help:"Domain"` + Desc string `help:"Description"` + Password string `help:"Password"` + Displayname string `help:"Displayname"` + Email string `help:"Email"` + Mobile string `help:"Mobile"` + Enabled bool `help:"Enabled"` + Disabled bool `help:"Disabled"` + } + R(&UserCreateOptions{}, "user-create", "Create a user", func(s *mcclient.ClientSession, args *UserCreateOptions) error { + mod, err := modules.GetModule(s, "users") + if err != nil { + return err + } + params := jsonutils.NewDict() + params.Add(jsonutils.NewString(args.NAME), "name") + if len(args.Domain) > 0 { + domainId, err := modules.Domains.GetId(s, args.Domain, nil) + if err != nil { + return err + } + params.Add(jsonutils.NewString(domainId), "domain_id") + } + if len(args.Password) > 0 { + params.Add(jsonutils.NewString(args.Password), "password") + } + if len(args.Displayname) > 0 { + params.Add(jsonutils.NewString(args.Displayname), "displayname") + } + if len(args.Desc) > 0 { + params.Add(jsonutils.NewString(args.Desc), "description") + } + if len(args.Email) > 0 { + params.Add(jsonutils.NewString(args.Email), "email") + } + if len(args.Mobile) > 0 { + params.Add(jsonutils.NewString(args.Mobile), "mobile") + } + if args.Enabled && !args.Disabled { + params.Add(jsonutils.JSONTrue, "enabled") + } else if !args.Enabled && args.Disabled { + params.Add(jsonutils.JSONFalse, "enabled") + } + user, err := mod.Create(s, params) + if err != nil { + return err + } + printObject(user) + return nil + }) + + type UserUpdateOptions struct { + ID string `help:"ID or name of the user"` + Domain string `help:"Domain"` + Name string `help:"New name of the user"` + Password string `help:"New password"` + Desc string `help:"Description"` + Displayname string `help:"Displayname"` + Email string `help:"Email"` + Mobile string `help:"Mobile"` + Enabled bool `help:"Enabled"` + Disabled bool `help:"Disabled"` + // Option []string `help:"User options"` + } + R(&UserUpdateOptions{}, "user-update", "Update a user", func(s *mcclient.ClientSession, args *UserUpdateOptions) error { + query := jsonutils.NewDict() + if len(args.Domain) > 0 { + domainId, err := modules.Domains.GetId(s, args.Domain, nil) + if err != nil { + return err + } + query.Add(jsonutils.NewString(domainId), "domain_id") + } + uid, err := modules.UsersV3.GetId(s, args.ID, query) + if err != nil { + return err + } + params := jsonutils.NewDict() + if len(args.Name) > 0 { + params.Add(jsonutils.NewString(args.Name), "name") + } + if len(args.Password) > 0 { + params.Add(jsonutils.NewString(args.Password), "password") + } + if len(args.Displayname) > 0 { + params.Add(jsonutils.NewString(args.Displayname), "displayname") + } + if len(args.Desc) > 0 { + params.Add(jsonutils.NewString(args.Desc), "description") + } + if len(args.Email) > 0 { + params.Add(jsonutils.NewString(args.Email), "email") + } + if len(args.Mobile) > 0 { + params.Add(jsonutils.NewString(args.Mobile), "mobile") + } + if args.Enabled && !args.Disabled { + params.Add(jsonutils.JSONTrue, "enabled") + } else if !args.Enabled && args.Disabled { + params.Add(jsonutils.JSONFalse, "enabled") + } + /* + if len(args.Option) > 0 { + uoptions := jsonutils.NewDict() + for _, opt := range args.Option { + pos := strings.IndexByte(opt, ':') + key := opt[:pos] + val := opt[pos+1:] + uoptions.Add(jsonutils.NewString(val), key) + } + params.Add(uoptions, "_resource_options") + } + */ + user, err := modules.UsersV3.Patch(s, uid, params) + if err != nil { + return err + } + printObject(user) + return nil + }) + + type UserGroupOptions struct { + USER string `help:"User ID or Name"` + GROUP string `help:"group ID or Name"` + Domain string `help:"Domain"` + } + R(&UserGroupOptions{}, "user-join-group", "Add a user to a group", func(s *mcclient.ClientSession, args *UserGroupOptions) error { + uid, gid, err := getUserGroupId(s, args.USER, args.GROUP, args.Domain) + if err != nil { + return err + } + _, err = modules.UsersV3.PutInContext(s, uid, nil, &modules.Groups, gid) + if err != nil { + return err + } + return nil + }) + R(&UserGroupOptions{}, "user-in-group", "Check whether a user belongs a group", func(s *mcclient.ClientSession, args *UserGroupOptions) error { + uid, gid, err := getUserGroupId(s, args.USER, args.GROUP, args.Domain) + if err != nil { + return err + } + _, err = modules.UsersV3.HeadInContext(s, uid, nil, &modules.Groups, gid) + if err != nil { + return err + } + return nil + }) + R(&UserGroupOptions{}, "user-leave-group", "Remove a user from a group", func(s *mcclient.ClientSession, args *UserGroupOptions) error { + uid, gid, err := getUserGroupId(s, args.USER, args.GROUP, args.Domain) + if err != nil { + return err + } + _, err = modules.UsersV3.DeleteInContext(s, uid, nil, &modules.Groups, gid) + if err != nil { + return err + } + return nil + }) + +} diff --git a/cmd/climc/shell/utils.go b/cmd/climc/shell/utils.go new file mode 100644 index 0000000000..69da039a5f --- /dev/null +++ b/cmd/climc/shell/utils.go @@ -0,0 +1,19 @@ +package shell + +import ( + "github.com/yunionio/jsonutils" + "github.com/yunionio/mcclient/modules" + "github.com/yunionio/pkg/util/printjson" +) + +func printList(list *modules.ListResult, columns []string) { + printjson.PrintList(list, columns) +} + +func printObject(obj jsonutils.JSONObject) { + printjson.PrintObject(obj) +} + +func printBatchResults(results []modules.SubmitResult, columns []string) { + printjson.PrintBatchResults(results, columns) +} diff --git a/cmd/climc/shell/vcenters.go b/cmd/climc/shell/vcenters.go new file mode 100644 index 0000000000..f6791b4938 --- /dev/null +++ b/cmd/climc/shell/vcenters.go @@ -0,0 +1,118 @@ +package shell + +import ( + "github.com/yunionio/jsonutils" + "github.com/yunionio/mcclient" + "github.com/yunionio/mcclient/modules" +) + +func init() { + type VCenterListOptions struct { + BaseListOptions + } + R(&VCenterListOptions{}, "vcenter-list", "List VMWare vcenters", func(s *mcclient.ClientSession, args *VCenterListOptions) error { + params := FetchPagingParams(args.BaseListOptions) + result, err := modules.VCenters.List(s, params) + if err != nil { + return err + } + printList(result, modules.VCenters.GetColumns(s)) + return nil + }) + + type VCenterCreateOptions struct { + NAME string `help:"Name of vcenter"` + HOST string `help:"Hostname or IP of vcenter server"` + Port int64 `help:"Port number" default:"443"` + USER string `help:"User account name"` + PASSWD string `help:"Password"` + Desc string `help:"Description" metavar:"DESCRIPTION"` + } + R(&VCenterCreateOptions{}, "vcenter-create", "Create a vcenter", func(s *mcclient.ClientSession, args *VCenterCreateOptions) error { + params := jsonutils.NewDict() + params.Add(jsonutils.NewString(args.NAME), "name") + params.Add(jsonutils.NewString(args.HOST), "hostname") + params.Add(jsonutils.NewString(args.USER), "account") + params.Add(jsonutils.NewString(args.PASSWD), "password") + if args.Port > 0 { + params.Add(jsonutils.NewInt(args.Port), "port") + } + vc, err := modules.VCenters.Create(s, params) + if err != nil { + return err + } + printObject(vc) + return nil + }) + + type VCenterDetailOptions struct { + ID string `help:"ID or name of vcenter"` + } + + R(&VCenterDetailOptions{}, "vcenter-show", "Show details of a vcenter", func(s *mcclient.ClientSession, args *VCenterDetailOptions) error { + vc, err := modules.VCenters.Get(s, args.ID, nil) + if err != nil { + return err + } + printObject(vc) + return nil + }) + + R(&VCenterDetailOptions{}, "vcenter-delete", "Delete a vcenter", func(s *mcclient.ClientSession, args *VCenterDetailOptions) error { + vc, err := modules.VCenters.Delete(s, args.ID, nil) + if err != nil { + return err + } + printObject(vc) + return nil + }) + + type VCenteSyncOptions struct { + ID string `help:"Sync vcenter ID or name"` + SyncHost string `help:"Also full sync the host information"` + SyncAllHosts bool `help:"Sync all hosts"` + Force bool `help:"Force sync, disregard status"` + } + R(&VCenteSyncOptions{}, "vcenter-sync", "Sync a vcenter", func(s *mcclient.ClientSession, args *VCenteSyncOptions) error { + params := jsonutils.NewDict() + if args.SyncAllHosts { + params.Add(jsonutils.JSONTrue, "sync_host") + } else if len(args.SyncHost) > 0 { + params.Add(jsonutils.NewString(args.SyncHost), "sync_host_ip") + } + if args.Force { + params.Add(jsonutils.JSONTrue, "force") + } + vc, err := modules.VCenters.PerformAction(s, args.ID, "sync", params) + if err != nil { + return err + } + printObject(vc) + return nil + }) + + type VCenterUpdateCredentialOptions struct { + ID string `help:"ID or name of vcenter"` + User string `help:"New Account"` + Password string `help:"New password"` + } + R(&VCenterUpdateCredentialOptions{}, "vcenter-update-credential", "Update account and password information of a vcenter", func(s *mcclient.ClientSession, args *VCenterUpdateCredentialOptions) error { + params := jsonutils.NewDict() + if len(args.User) > 0 { + params.Add(jsonutils.NewString(args.User), "account") + } + if len(args.Password) > 0 { + params.Add(jsonutils.NewString(args.Password), "password") + } + if params.Size() == 0 { + return InvalidUpdateError() + } + vc, err := modules.VCenters.PerformAction(s, args.ID, "update-credential", params) + if err != nil { + return err + } + printObject(vc) + return nil + }) + +} diff --git a/cmd/climc/shell/verification.go b/cmd/climc/shell/verification.go new file mode 100644 index 0000000000..bd9bb615d7 --- /dev/null +++ b/cmd/climc/shell/verification.go @@ -0,0 +1,32 @@ +package shell + +import ( + "github.com/yunionio/jsonutils" + "github.com/yunionio/mcclient" + "github.com/yunionio/mcclient/modules" +) + +func init() { + + /** + * 通信地址验证 + */ + type ContactsVerifyOptions struct { + ID string `help:"Verification process ID"` + TOKEN string `help:"Temporary token issued to the user when the validation is triggered"` + } + R(&ContactsVerifyOptions{}, "contact-verify", "Trigger contact verify", func(s *mcclient.ClientSession, args *ContactsVerifyOptions) error { + params := jsonutils.NewDict() + params.Add(jsonutils.NewString(args.TOKEN), "token") + + result, err := modules.Verifications.Get(s, args.ID, params) + + if err != nil { + return err + } + + printObject(result) + return nil + }) + +} diff --git a/cmd/climc/shell/version.go b/cmd/climc/shell/version.go new file mode 100644 index 0000000000..22157f1bbe --- /dev/null +++ b/cmd/climc/shell/version.go @@ -0,0 +1,21 @@ +package shell + +import ( + "fmt" + "github.com/yunionio/mcclient" + "github.com/yunionio/mcclient/modules" +) + +func init() { + type VersionOptions struct { + SERVICE string `help:"Service type"` + } + R(&VersionOptions{}, "version-show", "Show version of a backend service", func(s *mcclient.ClientSession, args *VersionOptions) error { + body, err := modules.GetVersion(s, args.SERVICE) + if err != nil { + return err + } + fmt.Println(body) + return nil + }) +} diff --git a/cmd/climc/shell/vncproxy.go b/cmd/climc/shell/vncproxy.go new file mode 100644 index 0000000000..3cf292beac --- /dev/null +++ b/cmd/climc/shell/vncproxy.go @@ -0,0 +1,26 @@ +package shell + +import ( + "github.com/yunionio/jsonutils" + "github.com/yunionio/mcclient" + "github.com/yunionio/mcclient/modules" +) + +func init() { + type VNCConnectOptions struct { + ID string `help:"ID of server to connect"` + Baremetal bool `help:"Connect to baremetal"` + } + R(&VNCConnectOptions{}, "vnc-connect", "Show the VNC console of given server", func(s *mcclient.ClientSession, args *VNCConnectOptions) error { + params := jsonutils.NewDict() + if args.Baremetal { + params.Add(jsonutils.NewString("hosts"), "objtype") + } + result, err := modules.VNCProxy.DoConnect(s, args.ID, params) + if err != nil { + return err + } + printObject(result) + return nil + }) +} diff --git a/cmd/climc/shell/vpcs.go b/cmd/climc/shell/vpcs.go new file mode 100644 index 0000000000..81516ca28e --- /dev/null +++ b/cmd/climc/shell/vpcs.go @@ -0,0 +1,119 @@ +package shell + +import ( + "github.com/yunionio/jsonutils" + "github.com/yunionio/mcclient" + "github.com/yunionio/mcclient/modules" +) + +func init() { + type VpcListOptions struct { + BaseListOptions + Region string `help:"ID or Name of region"` + } + R(&VpcListOptions{}, "vpc-list", "List VPCs", func(s *mcclient.ClientSession, args *VpcListOptions) error { + params := FetchPagingParams(args.BaseListOptions) + var result *modules.ListResult + var err error + if len(args.Region) > 0 { + result, err = modules.Vpcs.ListInContext(s, params, &modules.Cloudregions, args.Region) + } else { + result, err = modules.Vpcs.List(s, params) + } + if err != nil { + return err + } + printList(result, modules.Vpcs.GetColumns(s)) + return nil + }) + + type VpcCreateOptions struct { + REGION string `help:"ID or name of the region where the VPC is created"` + Id string `help:"ID of the new VPC"` + NAME string `help:"Name of the VPC"` + Desc string `help:"Description of the VPC"` + } + R(&VpcCreateOptions{}, "vpc-create", "Create a VPC", func(s *mcclient.ClientSession, args *VpcCreateOptions) error { + params := jsonutils.NewDict() + params.Add(jsonutils.NewString(args.NAME), "name") + if len(args.Id) > 0 { + params.Add(jsonutils.NewString(args.Id), "id") + } + if len(args.Desc) > 0 { + params.Add(jsonutils.NewString(args.Desc), "description") + } + results, err := modules.Vpcs.CreateInContext(s, params, &modules.Cloudregions, args.REGION) + if err != nil { + return err + } + printObject(results) + return nil + }) + + type VpcShowOptions struct { + ID string `help:"ID or name of the region"` + } + R(&VpcShowOptions{}, "vpc-show", "Show a VPC", func(s *mcclient.ClientSession, args *VpcShowOptions) error { + results, err := modules.Vpcs.Get(s, args.ID, nil) + if err != nil { + return err + } + printObject(results) + return nil + }) + + R(&VpcShowOptions{}, "vpc-delete", "Delete a VPC", func(s *mcclient.ClientSession, args *VpcShowOptions) error { + results, err := modules.Vpcs.Delete(s, args.ID, nil) + if err != nil { + return err + } + printObject(results) + return nil + }) + + type VpcUpdateOptions struct { + ID string `help:"ID or name of the VPC"` + Name string `help:"New name of the VPC"` + Desc string `help:"Description of the VPC"` + } + R(&VpcUpdateOptions{}, "vpc-update", "Update a VPC", func(s *mcclient.ClientSession, args *VpcUpdateOptions) error { + params := jsonutils.NewDict() + if len(args.Name) > 0 { + params.Add(jsonutils.NewString(args.Name), "name") + } + if len(args.Desc) > 0 { + params.Add(jsonutils.NewString(args.Desc), "description") + } + results, err := modules.Vpcs.Update(s, args.ID, params) + if err != nil { + return err + } + printObject(results) + return nil + }) + + type VpcUpdateStatusOptions struct { + ID string `help:"ID or name of the VPC"` + } + R(&VpcUpdateStatusOptions{}, "vpc-available", "Make vpc status available", func(s *mcclient.ClientSession, args *VpcUpdateStatusOptions) error { + params := jsonutils.NewDict() + params.Add(jsonutils.NewString("available"), "status") + result, err := modules.Vpcs.PerformAction(s, args.ID, "status", params) + if err != nil { + return err + } + printObject(result) + return nil + }) + + R(&VpcUpdateStatusOptions{}, "vpc-pending", "Make vpc status pending", func(s *mcclient.ClientSession, args *VpcUpdateStatusOptions) error { + params := jsonutils.NewDict() + params.Add(jsonutils.NewString("pending"), "status") + result, err := modules.Vpcs.PerformAction(s, args.ID, "status", params) + if err != nil { + return err + } + printObject(result) + return nil + }) +} diff --git a/cmd/climc/shell/wires.go b/cmd/climc/shell/wires.go new file mode 100644 index 0000000000..60588d922b --- /dev/null +++ b/cmd/climc/shell/wires.go @@ -0,0 +1,94 @@ +package shell + +import ( + "github.com/yunionio/jsonutils" + "github.com/yunionio/mcclient" + "github.com/yunionio/mcclient/modules" +) + +func init() { + type WireListOptions struct { + BaseListOptions + } + R(&WireListOptions{}, "wire-list", "List wires", func(s *mcclient.ClientSession, args *WireListOptions) error { + params := FetchPagingParams(args.BaseListOptions) + result, err := modules.Wires.List(s, params) + if err != nil { + return err + } + printList(result, modules.Wires.GetColumns(s)) + return nil + }) + + type WireUpdateOptions struct { + ID string `help:"ID or Name of zone to update"` + Name string `help:"Name of wire"` + Desc string `metavar:"" help:"Description"` + Bw int64 `help:"Bandwidth in mbps"` + } + R(&WireUpdateOptions{}, "wire-update", "Update wire", func(s *mcclient.ClientSession, args *WireUpdateOptions) error { + params := jsonutils.NewDict() + if len(args.Name) > 0 { + params.Add(jsonutils.NewString(args.Name), "name") + } + if len(args.Desc) > 0 { + params.Add(jsonutils.NewString(args.Desc), "description") + } + if args.Bw > 0 { + params.Add(jsonutils.NewInt(args.Bw), "bandwidth") + } + if params.Size() == 0 { + return InvalidUpdateError() + } + result, err := modules.Wires.Update(s, args.ID, params) + if err != nil { + return err + } + printObject(result) + return nil + }) + + type WireCreateOptions struct { + ZONE string `help:"Zone ID or Name"` + Vpc string `help:"VPC ID or Name" default:"default"` + NAME string `help:"Name of wire"` + BW int64 `help:"Bandwidth in mbps"` + Desc string `metavar:"" help:"Description"` + } + R(&WireCreateOptions{}, "wire-create", "Create a wire", func(s *mcclient.ClientSession, args *WireCreateOptions) error { + params := jsonutils.NewDict() + params.Add(jsonutils.NewString(args.NAME), "name") + params.Add(jsonutils.NewInt(args.BW), "bandwidth") + params.Add(jsonutils.NewString(args.Vpc), "vpc") + if len(args.Desc) > 0 { + params.Add(jsonutils.NewString(args.Desc), "description") + } + result, err := modules.Wires.CreateInContext(s, params, &modules.Zones, args.ZONE) + if err != nil { + return err + } + printObject(result) + return nil + }) + + type WireShowOptions struct { + ID string `help:"ID or Name of the wire to show"` + } + R(&WireShowOptions{}, "wire-show", "Show wire details", func(s *mcclient.ClientSession, args *WireShowOptions) error { + result, err := modules.Wires.Get(s, args.ID, nil) + if err != nil { + return err + } + printObject(result) + return nil + }) + + R(&WireShowOptions{}, "wire-delete", "Delete wire", func(s *mcclient.ClientSession, args *WireShowOptions) error { + result, err := modules.Wires.Delete(s, args.ID, nil) + if err != nil { + return err + } + printObject(result) + return nil + }) +} diff --git a/cmd/climc/shell/zones.go b/cmd/climc/shell/zones.go new file mode 100644 index 0000000000..b633fd7a3f --- /dev/null +++ b/cmd/climc/shell/zones.go @@ -0,0 +1,102 @@ +package shell + +import ( + "github.com/yunionio/jsonutils" + "github.com/yunionio/mcclient" + "github.com/yunionio/mcclient/modules" +) + +func init() { + type ZoneListOptions struct { + BaseListOptions + } + R(&ZoneListOptions{}, "zone-list", "List zones", func(s *mcclient.ClientSession, suboptions *ZoneListOptions) error { + params := FetchPagingParams(suboptions.BaseListOptions) + result, err := modules.Zones.List(s, params) + if err != nil { + return err + } + printList(result, modules.Zones.GetColumns(s)) + return nil + }) + + type ZoneUpdateOptions struct { + ID string `help:"ID or Name of zone to update"` + Name string `help:"Name of zone"` + NameCN string `help:"Name in Chinese"` + Desc string `metavar:"" help:"Description"` + Location string `help:"Location"` + } + R(&ZoneUpdateOptions{}, "zone-update", "Update zone", func(s *mcclient.ClientSession, args *ZoneUpdateOptions) error { + params := jsonutils.NewDict() + if len(args.Name) > 0 { + params.Add(jsonutils.NewString(args.Name), "name") + } + if len(args.NameCN) > 0 { + params.Add(jsonutils.NewString(args.NameCN), "name_cn") + } + if len(args.Desc) > 0 { + params.Add(jsonutils.NewString(args.Desc), "description") + } + if len(args.Location) > 0 { + params.Add(jsonutils.NewString(args.Location), "location") + } + if params.Size() == 0 { + return InvalidUpdateError() + } + result, err := modules.Zones.Update(s, args.ID, params) + if err != nil { + return err + } + printObject(result) + return nil + }) + + type ZoneShowOptions struct { + ID string `help:"ID or Name of the zone to show"` + } + R(&ZoneShowOptions{}, "zone-show", "Show zone details", func(s *mcclient.ClientSession, args *ZoneShowOptions) error { + result, err := modules.Zones.Get(s, args.ID, nil) + if err != nil { + return err + } + printObject(result) + return nil + }) + + R(&ZoneShowOptions{}, "zone-delete", "Delete zone", func(s *mcclient.ClientSession, args *ZoneShowOptions) error { + result, err := modules.Zones.Delete(s, args.ID, nil) + if err != nil { + return err + } + printObject(result) + return nil + }) + + type ZoneCreateOptions struct { + NAME string `help:"Name of zone"` + NameCN string `help:"Name in Chinese"` + Desc string `metavar:"" help:"Description"` + Location string `help:"Location"` + } + R(&ZoneCreateOptions{}, "zone-create", "Create a zone", func(s *mcclient.ClientSession, args *ZoneCreateOptions) error { + params := jsonutils.NewDict() + params.Add(jsonutils.NewString(args.NAME), "name") + if len(args.NameCN) > 0 { + params.Add(jsonutils.NewString(args.NameCN), "name_cn") + } + if len(args.Desc) > 0 { + params.Add(jsonutils.NewString(args.Desc), "description") + } + if len(args.Location) > 0 { + params.Add(jsonutils.NewString(args.Location), "location") + } + zone, err := modules.Zones.Create(s, params) + if err != nil { + return err + } + printObject(zone) + return nil + }) + +}