diff --git a/deploy/aliyun_host.py b/deploy/aliyun_host.py index 7bba478..b5d7e5a 100644 --- a/deploy/aliyun_host.py +++ b/deploy/aliyun_host.py @@ -216,15 +216,18 @@ def create_params(cfg): raise CloudError( "creation requires approved image/type/VSwitch/security group/SSH KeyPair" ) + spot_strategy = cfg.get("spot_strategy", "SpotWithPriceLimit") + if spot_strategy not in ("SpotWithPriceLimit", "SpotAsPriceGo"): + raise CloudError("spot_strategy must be SpotWithPriceLimit or SpotAsPriceGo") price = cfg.get("spot_price_limit") - if ( + if spot_strategy == "SpotWithPriceLimit" and ( isinstance(price, bool) or not isinstance(price, (int, float)) or not math.isfinite(price) or price <= 0 ): raise CloudError( - "a positive, finite spot_price_limit approved by the owner is required" + "a positive, finite spot_price_limit is required for SpotWithPriceLimit" ) disk = cfg.get("system_disk_gib", 40) if isinstance(disk, bool) or not isinstance(disk, int) or not 40 <= disk <= 200: @@ -241,14 +244,15 @@ def create_params(cfg): "InstanceName": cfg["project_tag"], "InstanceChargeType": "PostPaid", "InternetMaxBandwidthOut": 0, - "SpotStrategy": "SpotWithPriceLimit", - "SpotPriceLimit": price, + "SpotStrategy": spot_strategy, "SystemDisk.Category": cfg.get("system_disk_category", "cloud_essd"), "SystemDisk.Size": disk, "SystemDisk.PerformanceLevel": cfg.get("system_disk_performance_level", "PL1"), "Tag.1.Key": "project", "Tag.1.Value": cfg["project_tag"], } + if spot_strategy == "SpotWithPriceLimit": + params["SpotPriceLimit"] = price user_data_file = cfg.get("user_data_file") if user_data_file is not None: if not isinstance(user_data_file, str) or not user_data_file.strip(): diff --git a/tests/test_deployment.py b/tests/test_deployment.py index 90dae3d..c97a3ba 100644 --- a/tests/test_deployment.py +++ b/tests/test_deployment.py @@ -138,6 +138,14 @@ class CloudTests(unittest.TestCase): self.assertEqual(params["SystemDisk.PerformanceLevel"], "PL1") self.assertEqual(api.mutations(), ["RunInstances", "AssociateEipAddress"]) + def test_automatic_spot_price_omits_price_limit(self): + cfg = config() + cfg["spot_strategy"] = "SpotAsPriceGo" + cfg.pop("spot_price_limit") + params = cloud.create_params(cfg) + self.assertEqual(params["SpotStrategy"], "SpotAsPriceGo") + self.assertNotIn("SpotPriceLimit", params) + def test_user_data_is_base64_encoded_without_logging_content(self): with tempfile.TemporaryDirectory() as d: user_data = Path(d) / "bootstrap.sh"