Skip to content

Commit

Permalink
fixing sort of prices for select (#23)
Browse files Browse the repository at this point in the history
* fixing sort of prices for select
Signed-off-by: vsoch <vsoch@users.noreply.github.com>
  • Loading branch information
vsoch authored Feb 27, 2023
1 parent 035afca commit 2afafe4
Show file tree
Hide file tree
Showing 18 changed files with 24 additions and 27 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ and **Merged pull requests**. Critical items to know are:
The versions coincide with releases on pip. Only major versions will be released as tags on Github.

## [0.0.x](https://github.com/converged-computing/cloud-select/tree/main) (0.0.x)
- bugfix for sorting by prices with select (0.0.18)
- selector class (with interactive or automated select) (0.0.17)
- support for `--efa` flag to find AWS instances that support it (0.0.16)
- exponential backoff added for using aws products/prices api (0.0.15)
Expand Down
1 change: 0 additions & 1 deletion cloud_select/client/cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@


def main(args, parser, extra, subparser):

utils.ensure_no_extra(extra)

cli = Client(
Expand Down
1 change: 0 additions & 1 deletion cloud_select/client/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@


def main(args, parser, extra, subparser):

cloud_select.utils.ensure_no_extra(extra)

# If nothing provided, show help
Expand Down
1 change: 0 additions & 1 deletion cloud_select/client/dbshell.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@


def main(args, parser, extra, subparser):

cloud_select.utils.ensure_no_extra(extra)
lookup = {"ipython": ipython, "python": python, "bpython": bpython}
shells = ["ipython", "python", "bpython"]
Expand Down
1 change: 0 additions & 1 deletion cloud_select/client/instance.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@


def main(args, parser, extra, subparser):

utils.ensure_no_extra(extra)

cli = Client(
Expand Down
2 changes: 0 additions & 2 deletions cloud_select/client/shell.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@


def main(args, parser, extra, subparser):

cloud_select.utils.ensure_no_extra(extra)
lookup = {"ipython": ipython, "python": python, "bpython": bpython}
shells = ["ipython", "python", "bpython"]
Expand All @@ -32,7 +31,6 @@ def main(args, parser, extra, subparser):


def create_client(args):

cli = Client(
quiet=args.quiet,
settings_file=args.settings_file,
Expand Down
1 change: 0 additions & 1 deletion cloud_select/logger.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ def add_prefix(msg, char=">>"):


class ColorizingStreamHandler(_logging.StreamHandler):

BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE = range(8)
RESET_SEQ = LogColors.ENDC
COLOR_SEQ = "\033[%dm"
Expand Down
4 changes: 0 additions & 4 deletions cloud_select/main/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,6 @@ def get_clouds(self, force=False, lookup=False):
# We should always be able to get cloud classes, even without auth
# The class knows how to parse the data types into a standard space
for cloud_name, CloudClass in self._cloudclass.items():

# Regions default to settings then defaults
cloud_settings = getattr(self.settings, cloud_name)
self._clouds[cloud_name] = CloudClass(
Expand Down Expand Up @@ -102,7 +101,6 @@ def load_cache(self, key):
"""
items = {}
for cloud in self.get_clouds():

# Assume we don't find data
data = None

Expand Down Expand Up @@ -140,7 +138,6 @@ def update_from_cache(self, items, datatype):
"""
# For every cloud class we have...
for cloud in self.get_clouds():

# We have the data and it's expired OR we don't have it - update it
if cloud.name not in items or self.cache.is_expired(cloud.name, datatype):
func = getattr(cloud, datatype, None)
Expand Down Expand Up @@ -195,7 +192,6 @@ def prepare_database(self, **kwargs):
# 1. write mapping of common features into functions
# 2. filter down to desired set based on these common functions
for cloud_name, instance_group in instances.items():

# Give a warning about properties that aren't supported
instance_group.Instance.check_attributes(
properties, self.settings.allow_missing_attributes
Expand Down
2 changes: 0 additions & 2 deletions cloud_select/main/cloud/aws/instance.py
Original file line number Diff line number Diff line change
Expand Up @@ -227,10 +227,8 @@ def add_instance_prices(self, prices):

# Add prices to instances we have prices for
for instance in self.data:

# Set to unreasonably high so it's not a choice
if instance["InstanceType"] in lookup:

# Make a list of prices that matches regions
region_prices = {}
for region in instance["Regions"]:
Expand Down
1 change: 0 additions & 1 deletion cloud_select/main/cloud/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ class CloudProvider:
name = "cloud"

def __init__(self):

# If we weren't created with settings, add empty
if not hasattr(self, "settings"):
from cloud_select.main.settings import Settings
Expand Down
3 changes: 1 addition & 2 deletions cloud_select/main/cloud/google/instance.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ def add_instance_prices(self, prices):
return

logger.warning(
"Google Cloud instance prices derived from the web are limited to Iowa (us-centra-1)"
"Google Cloud instance prices derived from the web are limited to Iowa (us-central1)"
)

# Get actual machine types and convert web listing to types
Expand All @@ -148,7 +148,6 @@ def add_instance_prices(self, prices):
if not row:
continue
if row[0] in actual_types:

# Find price index
idx = [
i
Expand Down
3 changes: 0 additions & 3 deletions cloud_select/main/oras.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ def download_layer(self, cloud_name, datatype, manifest, root, package):
# Find the layer of interest! Currently we look for presence of the string
# e.g., "prices" can come from "prices" or "prices-web"
for layer in manifest.get("layers", []):

# E.g., google.prices or google.prices-web or aws.prices
contents = layer["mediaType"].split("cloud-select.")[-1]
cloud_found, data_found = contents.split(".")
Expand All @@ -61,7 +60,6 @@ def download_layer(self, cloud_name, datatype, manifest, root, package):

# This gives flexibility to support different variances of prices, etc.
if datatype in data_found:

logger.debug(f"Downloading data file for {datatype} from ORAS cache...")
artifact = layer["annotations"]["org.opencontainers.image.title"]

Expand All @@ -82,7 +80,6 @@ def push(self, container, archives: list):

# Upload files as blobs
for item in archives:

blob = item.get("path")
media_type = item.get("media_type") or defaults.default_media_type
annots = item.get("annotations", {})
Expand Down
22 changes: 21 additions & 1 deletion cloud_select/main/selectors.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,14 @@ def select_instance(

instances = self.cli.instance_select(**resources)
subset = [x for x in instances if x.get(sort_by) not in [None, ""]]

# If sort by price, need to set price to be float
if sort_by == "price":
for item in subset:
if sort_by not in item:
continue
item[sort_by] = float(item[sort_by])

selection = sorted(subset, key=lambda x: x[sort_by], reverse=not ascending)

# If not interactive, just return selection
Expand All @@ -90,13 +98,25 @@ def select_instance(

return instance

def get_options(self, selection, default=None, allow_exit=True):
def get_options(
self,
selection,
default=None,
allow_exit=True,
):
"""
Get options for cloud select
"""
options = []
if default:
options = [f" Use default {default}"]

for instance in selection:
name = instance["name"].rjust(15)
description = instance["description"].ljust(5)
option = f"{name} {description} at {instance['price']} $/hour"
options.append(option)

options += [
f"{x['name'].rjust(15)} {x['description']} at {x['price']} $/hour"
for x in selection
Expand Down
2 changes: 0 additions & 2 deletions cloud_select/main/table.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,6 @@ def ensure_complete_list(self):
# Ensure fields are present
for entry in self.data:
for field in fields:

if field not in entry:
entry[field] = ""

Expand Down Expand Up @@ -104,7 +103,6 @@ def table_rows(self, columns, limit=25):
# All keys are lowercase
column_width = self.available_width(columns)
for i, row in enumerate(self.data):

# have we gone over the limit?
if limit and i > limit:
return
Expand Down
2 changes: 0 additions & 2 deletions cloud_select/tests/test_instance.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,6 @@ def test_instance_filters(tmp_path, cloud, prices_file, instances_file, region):

# Set cache data to memory cache (a copy so we can edit it)
def reset_data():

client.cache.memory_set(cloud, copy.deepcopy(prices_sample), "prices")
client.cache.memory_set(cloud, copy.deepcopy(instances_sample), "instances")

Expand Down Expand Up @@ -169,7 +168,6 @@ def reset_data():

# Test args for each property - not min and max (will be tested separately)
for prop, _ in schemas.instance_properties.items():

# Skip min and max for now - will be tested separately
if "min" in prop or "max" in prop or prop in skips:
continue
Expand Down
1 change: 0 additions & 1 deletion cloud_select/tests/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ def test_write_bad_json(tmp_path):


def test_write_json(tmp_path):

good_json = {"Wakkawakkawakka": [True, "2", 3]}
tmpfile = str(tmp_path / "good_json_file.txt")

Expand Down
2 changes: 1 addition & 1 deletion cloud_select/version.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
#
# SPDX-License-Identifier: (MIT)

__version__ = "0.0.17"
__version__ = "0.0.18"
AUTHOR = "Vanessa Sochat"
EMAIL = "vsoch@users.noreply.github.com"
NAME = "cloud-select-tool"
Expand Down
1 change: 0 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,6 @@ def get_reqs(lookup=None, key="INSTALL_REQUIRES"):
################################################################################

if __name__ == "__main__":

INSTALL_REQUIRES = get_reqs(lookup)
TESTS_REQUIRES = get_reqs(lookup, "TESTS_REQUIRES")
INSTALL_REQUIRES_ALL = get_reqs(lookup, "INSTALL_REQUIRES_ALL")
Expand Down

0 comments on commit 2afafe4

Please sign in to comment.