From 2af2cd8dbea8cde3a943feb74b57d5c212a5e0bf Mon Sep 17 00:00:00 2001 From: Sebastian Quintero Date: Fri, 15 Mar 2024 13:33:50 -0500 Subject: [PATCH 1/4] Fix release workflow for Go type without plugins --- .nextmv/update_apps.py | 4 ++-- .nextmv/workflow-configuration.yml | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/.nextmv/update_apps.py b/.nextmv/update_apps.py index ffd9d3c..74955f9 100644 --- a/.nextmv/update_apps.py +++ b/.nextmv/update_apps.py @@ -232,8 +232,8 @@ def update_app(name: str, version: str): with open(os.path.join(os.getcwd(), "..", name, "VERSION"), "w") as f: f.write(version + "\n") - if workflow_info["type"] == "go": - sdk_version = workflow_info["sdk_version"] + sdk_version = workflow_info.get("sdk_version") or None + if workflow_info["type"] == "go" and sdk_version is not None: if sdk_version != "latest" and "v" not in sdk_version: sdk_version = f"v{sdk_version}" diff --git a/.nextmv/workflow-configuration.yml b/.nextmv/workflow-configuration.yml index db90c82..76f271a 100644 --- a/.nextmv/workflow-configuration.yml +++ b/.nextmv/workflow-configuration.yml @@ -41,7 +41,6 @@ apps: description: Solve a knapsack problem using Pyomo. - name: nextroute type: go - sdk_version: latest app_id: nextroute marketplace_app_id: nextroute description: Solve a vehicle routing problem using Nextmv’s Nextroute. From 4a53ce2e4b78c9d44379527a8bef61ca2aeb5c81 Mon Sep 17 00:00:00 2001 From: Sebastian Quintero Date: Fri, 15 Mar 2024 14:36:01 -0500 Subject: [PATCH 2/4] Handle license activation with AMPL --- .nextmv/golden/knapsack-ampl/main_test.go | 1 - knapsack-ampl/README.md | 7 +-- knapsack-ampl/main.py | 58 +++++++++++++++++------ 3 files changed, 47 insertions(+), 19 deletions(-) diff --git a/.nextmv/golden/knapsack-ampl/main_test.go b/.nextmv/golden/knapsack-ampl/main_test.go index a4a636c..f0d2d45 100644 --- a/.nextmv/golden/knapsack-ampl/main_test.go +++ b/.nextmv/golden/knapsack-ampl/main_test.go @@ -13,7 +13,6 @@ func TestMain(m *testing.M) { } func TestGolden(t *testing.T) { - t.Skip("skipping until we have a fix for ample license on x64") golden.FileTests( t, "inputs", diff --git a/knapsack-ampl/README.md b/knapsack-ampl/README.md index 7b479f7..f485258 100644 --- a/knapsack-ampl/README.md +++ b/knapsack-ampl/README.md @@ -24,10 +24,11 @@ The most important files created are `main.py`, `input.json`, and * If you have an AMPL license, remove the `.template` extension and replace the contents with your actual license key to be left with a file named `ampl_license_uuid`. Modify the `app.yaml` file to include the - `ampl_license_uuid` in the files list. + `ampl_license_uuid` in the files list. Note: when running on Nextmv Cloud, + you should use a premium execution class to use your own AMPL license. * If you are just testing and don’t have an AMPL license, you don’t need to - do anything, as this community app ships with a special license that allows - you to test AMPL with limits per AMPL's website. + do anything, as this community app ships with logic that allows you to test + AMPL with limits per AMPL’s website. Follow these steps to run locally. diff --git a/knapsack-ampl/main.py b/knapsack-ampl/main.py index 7b5248e..73d739a 100644 --- a/knapsack-ampl/main.py +++ b/knapsack-ampl/main.py @@ -4,8 +4,10 @@ import argparse import json +import os import sys import time +from platform import uname from typing import Any from amplpy import AMPL, ErrorHandler, OutputHandler, modules @@ -22,6 +24,9 @@ "xpress": "timelimit", } +# Open source solvers. +OSS_SOLVERS = ["cbc", "gcg", "gecode", "highs", "scip"] + # Status of the solver after optimizing. STATUS = [ @@ -99,14 +104,7 @@ def solve(input_data: dict[str, Any], duration: int, provider: str) -> dict[str, start_time = time.time() # Activate license. - modules.activate("nextmv") - - # If you have an AMPL license, uncomment the following block. - # try: - # license = read_license_uuid() - # modules.activate(license) - # except Exception: - # log("Using default AMPL license for Nextmv") + license_used = activate_license() # Defines the model. ampl = AMPL() @@ -179,6 +177,9 @@ def solve(input_data: dict[str, Any], duration: int, provider: str) -> dict[str, }, "run": { "duration": time.time() - start_time, + "custom": { + "license_used": license_used, + }, }, "schema": "v1", } @@ -189,6 +190,40 @@ def solve(input_data: dict[str, Any], duration: int, provider: str) -> dict[str, } +def activate_license() -> str: + """ + Activates de AMPL license based on the use case for the app. If there is a + license configured in the file, and it is different from the template + message, it activates the license. Otherwise, use a special module if + running on Nextmv Cloud. No further action required for testing locally. + + Returns: + str: The license that was activated: "license", "nextmv" or + "not_activated". + """ + + # Check if the ampl_license_uuid file exists. NOTE: When running in Nextmv + # Cloud with a valid license, make sure to run on a premium execution + # class. Contact support for more information. + if os.path.isfile("ampl_license_uuid"): + with open("ampl_license_uuid") as file: + license = file.read().strip() + + # If the license is not the template message, activate it. + if license != "secret-key-123": + modules.activate(license) + return "license" + + # A valid AMPL license has not been configured. When running on Nextmv + # Cloud, use a special module. + system_info = uname() + if system_info.system == "Linux" and "aarch64" in system_info.machine: + modules.activate("nextmv") + return "nextmv" + + return "demo" + + def log(message: str) -> None: """Logs a message. We need to use stderr since stdout is used for the solution.""" @@ -220,12 +255,5 @@ def write_output(output_path, output) -> None: print(content) -def read_license_uuid() -> str: - """Reads the license needed to authenticate.""" - - with open("ampl_license_uuid") as file: - return file.read().strip() - - if __name__ == "__main__": main() From 16183788877d0ed166b8f7a0a7ea967c573c6640 Mon Sep 17 00:00:00 2001 From: Sebastian Quintero Date: Fri, 15 Mar 2024 14:36:59 -0500 Subject: [PATCH 3/4] OSS_SOLVERS are not needed --- knapsack-ampl/main.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/knapsack-ampl/main.py b/knapsack-ampl/main.py index 73d739a..75c44ac 100644 --- a/knapsack-ampl/main.py +++ b/knapsack-ampl/main.py @@ -24,9 +24,6 @@ "xpress": "timelimit", } -# Open source solvers. -OSS_SOLVERS = ["cbc", "gcg", "gecode", "highs", "scip"] - # Status of the solver after optimizing. STATUS = [ From 25d3dabfb56ff8cc5e3673edf68e8c135f745e30 Mon Sep 17 00:00:00 2001 From: Sebastian Quintero Date: Fri, 15 Mar 2024 14:40:46 -0500 Subject: [PATCH 4/4] Update golden expectation for AMPL --- .nextmv/golden/knapsack-ampl/inputs/input.json.golden | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.nextmv/golden/knapsack-ampl/inputs/input.json.golden b/.nextmv/golden/knapsack-ampl/inputs/input.json.golden index 120809d..197d4fe 100644 --- a/.nextmv/golden/knapsack-ampl/inputs/input.json.golden +++ b/.nextmv/golden/knapsack-ampl/inputs/input.json.golden @@ -57,6 +57,9 @@ "value": 444 }, "run": { + "custom": { + "license_used": "demo" + }, "duration": 0.123 }, "schema": "v1"