Skip to content

Commit

Permalink
Merge pull request #18 from CloudVE/add_vm_type_listing
Browse files Browse the repository at this point in the history
Add vm type listing
  • Loading branch information
nuwang committed Aug 22, 2020
2 parents 4436eff + d0042b6 commit c4fce93
Show file tree
Hide file tree
Showing 5 changed files with 258 additions and 13 deletions.
47 changes: 47 additions & 0 deletions cloudlaunch_cli/api/endpoints.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@
except ImportError: # python 2
from urlparse import urlparse

try:
from types import SimpleNamespace
except: # Python 2
from argparse import Namespace as SimpleNamespace

import coreapi

from . import resources
Expand Down Expand Up @@ -220,3 +225,45 @@ class Clouds(CoreAPIBasedAPIEndpoint):
path = ['infrastructure', 'clouds']
resource_type = resources.Cloud
id_param_name = 'id'
_regions = None

@property
def regions(self):
if not self._regions:
self._regions = Regions(self.api_config)
return self._regions


class Regions(CoreAPIBasedAPIEndpoint):
path = ['infrastructure', 'clouds', 'regions']
resource_type = resources.Region
parent_url_kwarg = 'cloud_pk'
id_param_name = 'id'
_zones = None

@property
def zones(self):
if not self._zones:
self._zones = Zones(self.api_config)
return self._zones


class Zones(CoreAPIBasedAPIEndpoint):
path = ['infrastructure', 'clouds', 'regions', 'zones']
resource_type = resources.Zone
parent_url_kwarg = 'region_pk'
id_param_name = 'id'
_vm_types = None

@property
def vm_types(self):
if not self._vm_types:
self._vm_types = VmTypes(self.api_config)
return self._vm_types


class VmTypes(CoreAPIBasedAPIEndpoint):
path = ['infrastructure', 'clouds', 'regions', 'zones', 'compute', 'vm_types']
resource_type = resources.VmType
parent_url_kwarg = 'zone_pk'
id_param_name = 'id'
24 changes: 24 additions & 0 deletions cloudlaunch_cli/api/resources.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,26 @@ def run_delete(self):
class Cloud(APIResource):
id_field_name = 'id'

@property
def regions(self):
return self.subroute_for(Region)


class Region(APIResource):
id_field_name = 'region_id'

@property
def zones(self):
return self.subroute_for(Zone)


class Zone(APIResource):
id_field_name = 'zone_id'

@property
def vm_types(self):
return self.subroute_for(VmType)


class DeploymentTarget(APIResource):
id_field_name = 'id'
Expand Down Expand Up @@ -176,3 +196,7 @@ class Application(APIResource):
'versions': ApplicationVersion
}
id_field_name = 'slug'


class VmType(APIResource):
id_field_name = 'id'
110 changes: 105 additions & 5 deletions cloudlaunch_cli/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -183,10 +183,65 @@ def _print_applications(applications):


@click.group()
def clouds():
@click.pass_context
def clouds(ctx):
ctx.obj = ctx.obj or {}


@clouds.group()
@click.option('--cloud_id', help='Cloud ID')
@click.pass_context
def regions(ctx, cloud_id):
ctx.obj['cloud_id'] = cloud_id


@regions.command(name='list')
@click.pass_context
def list_regions(ctx):
cloud = create_api_client().infrastructure.clouds.get(ctx.obj['cloud_id'])
_print_regions(cloud.regions.list())


@regions.group()
@click.option('--region_id', help='Region ID')
@click.pass_context
def zones(ctx, region_id):
ctx.obj['region_id'] = region_id


@zones.group()
@click.option('--zone_id', help='Zone ID')
@click.pass_context
def compute(ctx, zone_id):
ctx.obj['zone_id'] = zone_id


@compute.group()
@click.pass_context
def vm_types(ctx):
pass


@vm_types.command(name='list')
@click.option('--min_vcpus', help='Min CPUs', default=0)
@click.option('--min_ram', help='Min RAM', default=0)
@click.option('--prefix', help='Prefix of instance family', default="")
@click.pass_context
def list_vm_types(ctx, min_vcpus, min_ram, prefix):
cloud = create_api_client().infrastructure.clouds.get(ctx.obj['cloud_id'])
region = cloud.regions.get(ctx.obj['region_id'])
zone = region.zones.get(ctx.obj['zone_id'])
_print_vm_types(zone.vm_types.list(min_vcpus=min_vcpus, min_ram=min_ram, vm_type_prefix=prefix))


@zones.command(name='list')
@click.pass_context
def list_zones(ctx):
cloud = create_api_client().infrastructure.clouds.get(ctx.obj['cloud_id'])
region = cloud.regions.get(ctx.obj['region_id'])
_print_zones(region.zones.list())


@click.command()
def list_clouds():
clouds = create_api_client().infrastructure.clouds.list()
Expand All @@ -196,19 +251,64 @@ def list_clouds():
def _print_clouds(clouds):
id_width = max([len(cloud.id) for cloud in clouds]) + 1
if len(clouds) > 0:
header_format = "{{:{id_width!s}s}} {{:20s}} {{:12s}} {{:20s}}"\
header_format = "{{:{id_width!s}s}} {{:30s}} {{:20s}}"\
.format(id_width=id_width)
print(header_format.format(
"Id", "Name", "Cloud Type", "Region"))
"Id", "Name", "Cloud Type"))
else:
print("No clouds found.")
row_format = "{{id:{id_width!s}.{id_width!s}s}} {{name:20.20s}} "\
"{{resourcetype:12.12}} {{region_name:20.20s}}"\
row_format = "{{id:{id_width!s}.{id_width!s}s}} {{name:30.30s}} "\
"{{resourcetype:20.20}}"\
.format(id_width=id_width)
for cloud in clouds:
print(row_format.format(**cloud.asdict()))


def _print_regions(regions):
id_width = max([len(region.id) for region in regions]) + 1
if len(regions) > 0:
header_format = "{{:{id_width!s}s}} {{:30s}}"\
.format(id_width=id_width)
print(header_format.format(
"Id", "Name"))
else:
print("No regions found.")
row_format = "{{region_id:{id_width!s}.{id_width!s}s}} {{name:30.30s}}" \
.format(id_width=id_width)
for region in regions:
print(row_format.format(**region.asdict()))


def _print_zones(zones):
id_width = max([len(zone.id) for zone in zones]) + 1
if len(zones) > 0:
header_format = "{{:{id_width!s}s}} {{:30s}}"\
.format(id_width=id_width)
print(header_format.format(
"Id", "Name"))
else:
print("No zones found.")
row_format = "{{zone_id:{id_width!s}.{id_width!s}s}} {{name}}" \
.format(id_width=id_width)
for zone in zones:
print(row_format.format(**zone.asdict()))


def _print_vm_types(vm_types):
id_width = max([len(vm_type.id) for vm_type in vm_types]) + 1
if len(vm_types) > 0:
header_format = "{{:{id_width!s}s}} {{:30s}} {{:20s}} {{:20s}}"\
.format(id_width=id_width)
print(header_format.format(
"Id", "Name", "CPUs", "RAM"))
else:
print("No vm types found.")
row_format = "{{id:{id_width!s}.{id_width!s}s}} {{name:30.30s}} {{vcpus:20.20s}} {{ram:20.20s}}" \
.format(id_width=id_width)
for vm_type in vm_types:
print(row_format.format(**vm_type.asdict()))


client.add_command(deployments)
client.add_command(applications)
client.add_command(clouds)
Expand Down
16 changes: 8 additions & 8 deletions tests/fixtures/initial_test_data.json
Original file line number Diff line number Diff line change
Expand Up @@ -214,35 +214,35 @@
"model": "djcloudbridge.zone",
"pk": 1,
"fields": {
"zone_id": "",
"name": "Default",
"zone_id": "default",
"name": "",
"region": 1
}
},
{
"model": "djcloudbridge.zone",
"pk": 2,
"fields": {
"zone_id": "",
"name": "Default",
"zone_id": "default",
"name": "",
"region": 2
}
},
{
"model": "djcloudbridge.zone",
"pk": 3,
"fields": {
"zone_id": "",
"name": "Default",
"zone_id": "default",
"name": "",
"region": 3
}
},
{
"model": "djcloudbridge.zone",
"pk": 4,
"fields": {
"zone_id": "",
"name": "Default",
"zone_id": "default",
"name": "",
"region": 4
}
},
Expand Down
74 changes: 74 additions & 0 deletions tests/test_cloudlaunch_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,11 @@ class TestCloudlaunch_cli(unittest.TestCase):

def setUp(self):
"""Set up test fixtures, if any."""
pass

def tearDown(self):
"""Tear down test fixtures, if any."""
pass

def _get_test_resource(self, filename):
return os.path.join(self._get_test_resource_path(), filename)
Expand Down Expand Up @@ -65,3 +67,75 @@ def test_create_deployments(self):
result.exit_code, 0,
msg="create deployment failed: " + str(result.exception))
assert('cli-test-app' in result.output)

def test_list_clouds(self):
"""Test listing applications via CLI"""
runner = CliRunner()
result = runner.invoke(cloudlaunch_cli.main.client,
args=["clouds", "list"])
self.assertEqual(
result.exit_code, 0,
msg="listing clouds failed: " + str(result.exception))
# Verify result columns are in list output
assert 'aws' in result.output

def test_list_regions(self):
"""Test listing applications via CLI"""
runner = CliRunner()
result = runner.invoke(cloudlaunch_cli.main.client,
args=["clouds", "regions",
"--cloud_id", "aws", "list"])
self.assertEqual(
result.exit_code, 0,
msg="listing regions failed: " + str(result.exception))
# Verify result columns are in list output
assert 'us-east-1' in result.output
assert 'amazon-us-east' in result.output

def test_list_zones(self):
"""Test listing applications via CLI"""
runner = CliRunner()
result = runner.invoke(cloudlaunch_cli.main.client,
args=["clouds", "regions",
"--cloud_id", "aws",
"zones", "--region_id", "amazon-us-east",
"list"])
self.assertEqual(
result.exit_code, 0,
msg="listing zones failed: " + str(result.exception))
# Verify result columns are in list output
assert 'default' in result.output

def test_list_vm_types(self):
"""Test listing applications via CLI"""
runner = CliRunner()
result = runner.invoke(cloudlaunch_cli.main.client,
args=["clouds", "regions",
"--cloud_id", "aws",
"zones", "--region_id", "amazon-us-east",
"compute", "--zone_id", "default",
"vm-types", "list"])
self.assertEqual(
result.exit_code, 0,
msg="listing vm_types failed: " + str(result.exception))
# Verify result columns are in list output
assert 'm5.xlarge' in result.output
assert 'c5.xlarge' in result.output

def test_filter_vm_types(self):
"""Test listing applications via CLI"""
runner = CliRunner()
result = runner.invoke(cloudlaunch_cli.main.client,
args=["clouds", "regions",
"--cloud_id", "aws",
"zones", "--region_id", "amazon-us-east",
"compute", "--zone_id", "default",
"vm-types", "list", "--min_ram", "384",
"--prefix", "m5"])
self.assertEqual(
result.exit_code, 0,
msg="listing vm_types failed: " + str(result.exception))
# Verify result columns are in list output
assert 'm5.xlarge' not in result.output
assert 'c5.xlarge' not in result.output
assert 'm5.24xlarge' in result.output

0 comments on commit c4fce93

Please sign in to comment.