much better cli
This commit is contained in:
parent
c4cf097b99
commit
d045d70609
11 changed files with 210 additions and 121 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -2,3 +2,4 @@ venv/
|
||||||
.idea/
|
.idea/
|
||||||
.vscode/
|
.vscode/
|
||||||
.env
|
.env
|
||||||
|
__pycache__/
|
||||||
|
|
1
Pipfile
1
Pipfile
|
@ -9,6 +9,7 @@ verify_ssl = true
|
||||||
requests = "*"
|
requests = "*"
|
||||||
python-decouple = "*"
|
python-decouple = "*"
|
||||||
pyotp = "*"
|
pyotp = "*"
|
||||||
|
click = "*"
|
||||||
|
|
||||||
[requires]
|
[requires]
|
||||||
python_version = "3.7"
|
python_version = "3.7"
|
||||||
|
|
10
Pipfile.lock
generated
10
Pipfile.lock
generated
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"_meta": {
|
"_meta": {
|
||||||
"hash": {
|
"hash": {
|
||||||
"sha256": "e9d4e4efe74bd8386357563e682181c69cbbc66d40fc02931fd0f730ae6053e4"
|
"sha256": "1f6e0448a1e04906885393b4ff57423363593680a7b6f73a5ed1f514496bb1f3"
|
||||||
},
|
},
|
||||||
"pipfile-spec": 6,
|
"pipfile-spec": 6,
|
||||||
"requires": {
|
"requires": {
|
||||||
|
@ -30,6 +30,14 @@
|
||||||
],
|
],
|
||||||
"version": "==3.0.4"
|
"version": "==3.0.4"
|
||||||
},
|
},
|
||||||
|
"click": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:2335065e6395b9e67ca716de5f7526736bfa6ceead690adf616d925bdc622b13",
|
||||||
|
"sha256:5b94b49521f6456670fdb30cd82a4eca9412788a93fa6dd6df72c94d5a8ff2d7"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==7.0"
|
||||||
|
},
|
||||||
"idna": {
|
"idna": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407",
|
"sha256:c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407",
|
||||||
|
|
0
commands/__init__
Normal file
0
commands/__init__
Normal file
30
commands/host.py
Normal file
30
commands/host.py
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
import click
|
||||||
|
import json
|
||||||
|
import requests
|
||||||
|
|
||||||
|
from decouple import config
|
||||||
|
from helper import OTPCredentials
|
||||||
|
|
||||||
|
|
||||||
|
@click.group()
|
||||||
|
def host():
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@host.command("add")
|
||||||
|
@click.option("--name", required=True)
|
||||||
|
@click.option("--realm", required=True)
|
||||||
|
@click.option("--seed", required=True)
|
||||||
|
@click.option("--specs", required=True)
|
||||||
|
@click.option("--hostname", required=True)
|
||||||
|
def add_host(name, realm, seed, specs, hostname):
|
||||||
|
with open(specs, "r") as specs_f:
|
||||||
|
specs = json.loads(specs_f.read())
|
||||||
|
data = {
|
||||||
|
**OTPCredentials(name, realm, seed).get_json(),
|
||||||
|
"specs": specs,
|
||||||
|
"hostname": hostname,
|
||||||
|
}
|
||||||
|
r = requests.post(f"{config('UCLOUD_API_SERVER')}/host/create", json=data)
|
||||||
|
|
||||||
|
print(json.loads(r.content))
|
30
commands/image.py
Normal file
30
commands/image.py
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
import click
|
||||||
|
import json
|
||||||
|
import requests
|
||||||
|
|
||||||
|
from decouple import config
|
||||||
|
from helper import OTPCredentials
|
||||||
|
|
||||||
|
|
||||||
|
@click.group()
|
||||||
|
def image():
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@image.command("list")
|
||||||
|
@click.option("--public", is_flag=True)
|
||||||
|
@click.option("--private", is_flag=True)
|
||||||
|
def list(public, private):
|
||||||
|
if public:
|
||||||
|
r = requests.get(f"{config('UCLOUD_API_SERVER')}/image/list-public")
|
||||||
|
print(json.loads(r.content))
|
||||||
|
|
||||||
|
|
||||||
|
@image.command("create-from-file")
|
||||||
|
@click.option("--name", required=True)
|
||||||
|
@click.option("--uuid", required=True)
|
||||||
|
@click.option("--image_store_name", required=True)
|
||||||
|
def create_from_file(name, uuid, image_store_name):
|
||||||
|
data = {"name": name, "uuid": uuid, "image_store": image_store_name}
|
||||||
|
r = requests.post(f"{config('UCLOUD_API_SERVER')}/image/create", data)
|
||||||
|
print(r.content.decode("utf-8"))
|
31
commands/user.py
Normal file
31
commands/user.py
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
import click
|
||||||
|
import json
|
||||||
|
import requests
|
||||||
|
|
||||||
|
from decouple import config
|
||||||
|
from helper import OTPCredentials
|
||||||
|
|
||||||
|
|
||||||
|
@click.group()
|
||||||
|
def user():
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@user.command("list-files")
|
||||||
|
@click.option("--name", required=True)
|
||||||
|
@click.option("--realm", required=True)
|
||||||
|
@click.option("--seed", required=True)
|
||||||
|
def list_files(name, realm, seed):
|
||||||
|
data = OTPCredentials(name, realm, seed).get_json()
|
||||||
|
r = requests.get(f"{config('UCLOUD_API_SERVER')}/user/files", json=data)
|
||||||
|
print(json.loads(r.content))
|
||||||
|
|
||||||
|
|
||||||
|
@user.command("list-vms")
|
||||||
|
@click.option("--name", required=True)
|
||||||
|
@click.option("--realm", required=True)
|
||||||
|
@click.option("--seed", required=True)
|
||||||
|
def list_vms(name, realm, seed):
|
||||||
|
data = OTPCredentials(name, realm, seed).get_json()
|
||||||
|
r = requests.get(f"{config('UCLOUD_API_SERVER')}/user/vms", json=data)
|
||||||
|
print(json.loads(r.content))
|
75
commands/vm.py
Normal file
75
commands/vm.py
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
import click
|
||||||
|
import json
|
||||||
|
import requests
|
||||||
|
|
||||||
|
from decouple import config
|
||||||
|
from helper import OTPCredentials
|
||||||
|
|
||||||
|
|
||||||
|
def vm_action(action, otp, vmid):
|
||||||
|
data = {**otp.get_json(), "vmid": vmid}
|
||||||
|
r = requests.post(f"{config('UCLOUD_API_SERVER')}/vm/{action}", json=data)
|
||||||
|
return r
|
||||||
|
|
||||||
|
|
||||||
|
@click.group()
|
||||||
|
def vm():
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@vm.command("create")
|
||||||
|
@click.option("--name", required=True)
|
||||||
|
@click.option("--realm", required=True)
|
||||||
|
@click.option("--seed", required=True)
|
||||||
|
@click.option("--specs", required=True)
|
||||||
|
@click.option("--image_uuid", required=True)
|
||||||
|
def create(name, realm, seed, specs, image_uuid):
|
||||||
|
with open(specs, "r") as specs_f:
|
||||||
|
specs = json.loads(specs_f.read())
|
||||||
|
data = {
|
||||||
|
**OTPCredentials(name, realm, seed).get_json(),
|
||||||
|
"specs": specs,
|
||||||
|
"image_uuid": image_uuid,
|
||||||
|
}
|
||||||
|
r = requests.post(f"{config('UCLOUD_API_SERVER')}/vm/create", json=data)
|
||||||
|
print(json.loads(r.content))
|
||||||
|
|
||||||
|
|
||||||
|
@vm.command("start")
|
||||||
|
@click.option("--name", required=True)
|
||||||
|
@click.option("--realm", required=True)
|
||||||
|
@click.option("--seed", required=True)
|
||||||
|
@click.option("--vmid", required=True)
|
||||||
|
def start(name, realm, seed, vmid):
|
||||||
|
r = vm_action("start", OTPCredentials(name, realm, seed), vmid)
|
||||||
|
print(json.loads(r.content))
|
||||||
|
|
||||||
|
|
||||||
|
@vm.command("suspend")
|
||||||
|
@click.option("--name", required=True)
|
||||||
|
@click.option("--realm", required=True)
|
||||||
|
@click.option("--seed", required=True)
|
||||||
|
@click.option("--vmid", required=True)
|
||||||
|
def suspend(name, realm, seed, vmid):
|
||||||
|
r = vm_action("suspend", OTPCredentials(name, realm, seed), vmid)
|
||||||
|
print(json.loads(r.content))
|
||||||
|
|
||||||
|
|
||||||
|
@vm.command("resume")
|
||||||
|
@click.option("--name", required=True)
|
||||||
|
@click.option("--realm", required=True)
|
||||||
|
@click.option("--seed", required=True)
|
||||||
|
@click.option("--vmid", required=True)
|
||||||
|
def resume(name, realm, seed, vmid):
|
||||||
|
r = vm_action("resume", OTPCredentials(name, realm, seed), vmid)
|
||||||
|
print(json.loads(r.content))
|
||||||
|
|
||||||
|
|
||||||
|
@vm.command("shutdown")
|
||||||
|
@click.option("--name", required=True)
|
||||||
|
@click.option("--realm", required=True)
|
||||||
|
@click.option("--seed", required=True)
|
||||||
|
@click.option("--vmid", required=True)
|
||||||
|
def shutdown(name, realm, seed, vmid):
|
||||||
|
r = vm_action("shutdown", OTPCredentials(name, realm, seed), vmid)
|
||||||
|
print(json.loads(r.content))
|
15
helper.py
Normal file
15
helper.py
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
import click
|
||||||
|
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from pyotp import TOTP
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class OTPCredentials:
|
||||||
|
name: str
|
||||||
|
realm: str
|
||||||
|
seed: str
|
||||||
|
|
||||||
|
def get_json(self):
|
||||||
|
r = {"name": self.name, "realm": self.realm, "token": TOTP(self.seed).now()}
|
||||||
|
return r
|
4
specs.json
Normal file
4
specs.json
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
{
|
||||||
|
"cpu": 2,
|
||||||
|
"ram": "2GB"
|
||||||
|
}
|
134
ucloud.py
134
ucloud.py
|
@ -1,127 +1,21 @@
|
||||||
import argparse
|
import argparse
|
||||||
import requests
|
import click
|
||||||
import json
|
|
||||||
|
|
||||||
from decouple import config
|
from commands.vm import vm
|
||||||
from pyotp import TOTP
|
from commands.user import user
|
||||||
|
from commands.host import host
|
||||||
def add_otp(parser):
|
from commands.image import image
|
||||||
parser.add_argument("--name", required=True)
|
|
||||||
parser.add_argument("--realm", required=True)
|
|
||||||
parser.add_argument("--seed", required=True)
|
|
||||||
return parser
|
|
||||||
|
|
||||||
def add_vmid(parser):
|
|
||||||
parser.add_argument("--vmid", required=True)
|
|
||||||
return parser
|
|
||||||
|
|
||||||
argparser = argparse.ArgumentParser()
|
|
||||||
subparser = argparser.add_subparsers(dest="command")
|
|
||||||
|
|
||||||
create_image_parser = subparser.add_parser("create-image-from-file")
|
|
||||||
create_image_parser.add_argument("--uuid", required=True)
|
|
||||||
create_image_parser.add_argument("--name", required=True)
|
|
||||||
create_image_parser.add_argument("--image-store",
|
|
||||||
dest="image_store_name",
|
|
||||||
required=True)
|
|
||||||
|
|
||||||
images_parser = subparser.add_parser("images")
|
|
||||||
images_parser.add_argument("--list",
|
|
||||||
choices=["public", "private"],
|
|
||||||
required=True)
|
|
||||||
|
|
||||||
user_parser = subparser.add_parser("user")
|
|
||||||
user_subparser = user_parser.add_subparsers(dest="usercommand")
|
|
||||||
|
|
||||||
user_list_vms_parser = user_subparser.add_parser("list")
|
|
||||||
user_list_vms_parser.add_argument("--files", action='store_true')
|
|
||||||
user_list_vms_parser.add_argument("--vms", action='store_true')
|
|
||||||
add_otp(user_list_vms_parser)
|
|
||||||
|
|
||||||
vm_parser = subparser.add_parser("vm")
|
|
||||||
vm_subparser = vm_parser.add_subparsers(dest="vmcommand")
|
|
||||||
|
|
||||||
vm_create_parser = vm_subparser.add_parser("create")
|
|
||||||
add_otp(vm_create_parser)
|
|
||||||
vm_create_parser.add_argument("--specs_file", required=True)
|
|
||||||
vm_create_parser.add_argument("--image_uuid", required=True)
|
|
||||||
|
|
||||||
|
|
||||||
vm_start_parser = vm_subparser.add_parser("start")
|
@click.group()
|
||||||
vm_suspend_parser = vm_subparser.add_parser("suspend")
|
def entry_point():
|
||||||
vm_resume_parser = vm_subparser.add_parser("resume")
|
pass
|
||||||
vm_shutdown_parser = vm_subparser.add_parser("shutdown")
|
|
||||||
vm_status_parser = vm_subparser.add_parser("status")
|
|
||||||
|
|
||||||
add_vmid(add_otp(vm_start_parser))
|
|
||||||
add_vmid(add_otp(vm_suspend_parser))
|
|
||||||
add_vmid(add_otp(vm_resume_parser))
|
|
||||||
add_vmid(add_otp(vm_shutdown_parser))
|
|
||||||
add_vmid(add_otp(vm_status_parser))
|
|
||||||
|
|
||||||
args = argparser.parse_args()
|
entry_point.add_command(vm)
|
||||||
|
entry_point.add_command(user)
|
||||||
|
entry_point.add_command(image)
|
||||||
|
entry_point.add_command(host)
|
||||||
|
|
||||||
if args.command == "create-image-from-file":
|
if __name__ == "__main__":
|
||||||
name = args.name
|
entry_point()
|
||||||
uuid = args.uuid
|
|
||||||
image_store_name = args.image_store_name
|
|
||||||
data = {
|
|
||||||
"name": args.name,
|
|
||||||
"uuid": uuid,
|
|
||||||
"image_store": image_store_name
|
|
||||||
}
|
|
||||||
r = requests.post(f"{config('UCLOUD_API_SERVER')}/image/create", data)
|
|
||||||
print(r.content.decode("utf-8"))
|
|
||||||
|
|
||||||
elif args.command == "images":
|
|
||||||
if args.list == "public":
|
|
||||||
r = requests.get(f"{config('UCLOUD_API_SERVER')}/image/list-public")
|
|
||||||
print(json.loads(r.content))
|
|
||||||
|
|
||||||
elif args.command == "vm":
|
|
||||||
if args.vmcommand == "create":
|
|
||||||
with open(args.specs_file, "r") as specs_f:
|
|
||||||
specs = json.loads(specs_f.read())
|
|
||||||
data = {
|
|
||||||
"name": args.name,
|
|
||||||
"realm": args.realm,
|
|
||||||
"token": TOTP(args.seed).now(),
|
|
||||||
"specs": specs,
|
|
||||||
"image_uuid": args.image_uuid
|
|
||||||
}
|
|
||||||
r = requests.post(f"{config('UCLOUD_API_SERVER')}/vm/create",
|
|
||||||
json=data)
|
|
||||||
print(json.loads(r.content))
|
|
||||||
elif args.vmcommand in ["start", "suspend", "resume",
|
|
||||||
"status", "shutdown"]:
|
|
||||||
data = {
|
|
||||||
"name": args.name,
|
|
||||||
"realm": args.realm,
|
|
||||||
"token": TOTP(args.seed).now(),
|
|
||||||
"vmid": args.vmid,
|
|
||||||
}
|
|
||||||
if args.vmcommand == "status":
|
|
||||||
r = requests.get(f"{config('UCLOUD_API_SERVER')}/vm/{args.vmcommand}", json=data)
|
|
||||||
else:
|
|
||||||
r = requests.post(f"{config('UCLOUD_API_SERVER')}/vm/{args.vmcommand}", json=data)
|
|
||||||
print(json.loads(r.content))
|
|
||||||
|
|
||||||
elif args.command == "user":
|
|
||||||
if args.usercommand == "list" and args.vms:
|
|
||||||
data = {
|
|
||||||
"name": args.name,
|
|
||||||
"realm": args.realm,
|
|
||||||
"token": TOTP(args.seed).now()
|
|
||||||
}
|
|
||||||
r = requests.get(f"{config('UCLOUD_API_SERVER')}/user/vms",
|
|
||||||
json=data)
|
|
||||||
print(json.loads(r.content))
|
|
||||||
elif args.usercommand == "list" and args.files:
|
|
||||||
data = {
|
|
||||||
"name": args.name,
|
|
||||||
"realm": args.realm,
|
|
||||||
"token": TOTP(args.seed).now()
|
|
||||||
}
|
|
||||||
r = requests.get(f"{config('UCLOUD_API_SERVER')}/user/files",
|
|
||||||
json=data)
|
|
||||||
print(json.loads(r.content))
|
|
||||||
|
|
Loading…
Reference in a new issue