Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add OptionalType click parameter type #1406

Merged
merged 23 commits into from
Aug 18, 2023

Conversation

kimjinmyeong
Copy link
Contributor

@kimjinmyeong kimjinmyeong commented Jul 21, 2023

This PR resolves #1393 , and includes minor fixes to execute follow commands:

  • ./backend.ai sesstpl create -f {template_filepath}
  • ./backend.ai session create-from-template {template_id}

Implement OptionalType class

  • OptionalType serves as a type wrapper that checks for undefined types.

Revise to support for YAML format files and enable the creation of multiple templates.

  • To create multiple templates and iterate through a for loop when importing YAML file, the safe_load function should be replaced with the safe_load_all function.
  • To use the same code for creating query in both YAML and JSON formats, the JSON file should be modified as :
example_session_template.json
[
  {
    "id": "c1b8441a-ba46-4a83-8727-de6645f521b4",
    "is_active": true,
    "domain_name": "default",
    "group_id": "2de2b969-1d04-48a6-af16-0bc8adb3c831",
    "user_uuid": "f38dea23-50fa-42a0-b5ae-338f5f4693f4",
    "type": "TASK",
    "name": "python_x86",
    "template": {
      "api_version": "6",
      "kind": "task_template",
      "metadata": {
        "name": "cr.backend.ai/multiarch/python",
        "tag": "3.10-ubuntu20.04"
      },
      "spec": {
        "session_type": "interactive",
        "kernel": {
          "image": "cr.backend.ai/multiarch/python:3.10-ubuntu20.04",
          "environ": {},
          "architecture": "x86_64",
          "run": null,
          "git": null
        },
        "scaling_group": "default",
        "mounts": {
        },
        "resources": {
          "cpu": "2",
          "mem": "4g"
        }
      }
    }
  },
  {
    "id": "59062449-4f57-4434-975d-add2a593438c",
    "is_active": true,
    "domain_name": "default",
    "group_id": "2de2b969-1d04-48a6-af16-0bc8adb3c831",
    "user_uuid": "f38dea23-50fa-42a0-b5ae-338f5f4693f4",
    "type": "TASK",
    "name": "python_arch64",
    "template": {
      "api_version": "6",
      "kind": "task_template",
      "metadata": {
        "name": "cr.backend.ai/multiarch/python",
        "tag": "3.10-ubuntu20.04"
      },
      "spec": {
        "session_type": "interactive",
        "kernel": {
          "image": "cr.backend.ai/multiarch/python:3.10-ubuntu20.04",
          "environ": {},
          "architecture": "aarch64",
          "run": null,
          "git": null
        },
        "scaling_group": "default",
        "mounts": {
        },
        "resources": {
          "cpu": "2",
          "mem": "4g"
        }
      }
    }
  }
]
example_session_template.yaml
---
id: c1b8441a-ba46-4a83-8727-de6645f521b4
is_active: true
domain_name: default
group_id: 2de2b969-1d04-48a6-af16-0bc8adb3c831
user_uuid: f38dea23-50fa-42a0-b5ae-338f5f4693f4
type: TASK
name: python_x86
template:
  api_version: '6'
  kind: task_template
  metadata:
    name: cr.backend.ai/multiarch/python
    tag: 3.10-ubuntu20.04
  spec:
    session_type: interactive
    kernel:
      image: cr.backend.ai/multiarch/python:3.10-ubuntu20.04
      environ: {}
      architecture: x86_64
      run: null
      git: null
    scaling_group: default
    mounts: {}
    resources:
      cpu: '2'
      mem: 4g
---
id: 59062449-4f57-4434-975d-add2a593438c
is_active: true
domain_name: default
group_id: 2de2b969-1d04-48a6-af16-0bc8adb3c831
user_uuid: f38dea23-50fa-42a0-b5ae-338f5f4693f4
type: TASK
name: python_arch64
template:
  api_version: '6'
  kind: task_template
  metadata:
    name: cr.backend.ai/multiarch/python
    tag: 3.10-ubuntu20.04
  spec:
    session_type: interactive
    kernel:
      image: cr.backend.ai/multiarch/python:3.10-ubuntu20.04
      environ: {}
      architecture: aarch64
      run: null
      git: null
    scaling_group: default
    mounts: {}
    resources:
      cpu: '2'
      mem: 4g

In src/ai/backend/client/func/session_template.py, I modifed cls() argument to return the log with multiple template_id like this:

Task template 868647ae08f94da38a2cf1a30bddb6e6, 76e7bed57f58487e934f5746dc5fdcb1 created and ready

Minor fixes

  • revise the incorrect parameter order

ai/backend/manager/utils.py

async def query_userinfo(
    conn: SAConnection,
    requester_uuid: UUID,
    requester_access_key: AccessKey,
    requester_role: UserRole,

before ai/backend/manager/api/session.py

return await _query_userinfo(
            conn,
            request["user"]["uuid"],
            request["user"]["role"],
            request["keypair"]["access_key"],
  • add the missing argument callback_url in src/ai/backend/client/func/session.py

ai/backend/client/cli/session.py

        with Session() as session:
            try:
                compute_session = session.ComputeSession.create_from_template(
                    template_id,
                    image=image,
                    name=name,
                    type_=type_,
                    starts_at=starts_at,
                    enqueue_only=enqueue_only,
                    max_wait=max_wait,
                    no_reuse=no_reuse,
                    dependencies=depends,
                    callback_url=callback_url,
                    cluster_size=cluster_size,

before ai/backend/client/func/session.py

async def create_from_template(
        cls,
        template_id: str,
        *,
        name: str | Undefined = undefined,
        type_: str | Undefined = undefined,
        starts_at: str = None,
        enqueue_only: bool | Undefined = undefined,
        max_wait: int | Undefined = undefined,
        # missing callback_url
        dependencies: Sequence[str] = None,  # cannot be stored in templates
        no_reuse: bool | Undefined = undefined,

@kimjinmyeong kimjinmyeong added type:feature Add new features comp:manager Related to Manager component comp:cli Related to CLI component effort:easy Need to understand only a specific region of codes (good first issue, easy). size:M 30~100 LoC labels Jul 21, 2023
@kimjinmyeong kimjinmyeong self-assigned this Jul 21, 2023
@cla-assistant
Copy link

cla-assistant bot commented Jul 21, 2023

CLA assistant check
All committers have signed the CLA.

@cla-assistant
Copy link

cla-assistant bot commented Jul 21, 2023

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.


JinMyeong Kim seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please add the email address used for this commit to your account.
You have signed the CLA already but the status is still pending? Let us recheck it.

@github-actions github-actions bot added comp:client Related to Client component type:bug Reports about that are not working type:refactor Refactor codes or add tests. urgency:2 With time limit, it should be finished within it; otherwise, resolve it when no other chores. labels Jul 21, 2023
Copy link
Member

@fregataa fregataa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your commitment!
I left some reviews

Comment on lines 6 to 12







Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove this blank new lines.
And we write news fragment in one line. Please refer other merged PR's news fragment files.
Fragment files are listed in the release notes and read by users. Please note that!

async with root_ctx.db.begin() as conn:
user_uuid, group_id, _ = await query_userinfo(request, params, conn)
log.debug("Params: {0}", params)
try:
body = json.loads(params["payload"])
except json.JSONDecodeError:
try:
body = yaml.safe_load(params["payload"])
body = yaml.safe_load_all(params["payload"])
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

Comment on lines 176 to 181
def convert(self, value, param, ctx):
try:
if isinstance(value, (str, int)) or value == undefined:
return value
except ValueError as e:
self.fail(repr(e), param, ctx)
Copy link
Member

@fregataa fregataa Jul 21, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
def convert(self, value, param, ctx):
try:
if isinstance(value, (str, int)) or value == undefined:
return value
except ValueError as e:
self.fail(repr(e), param, ctx)
def __init__(self, type_: type) -> None:
super().__init__()
self.type_ = type_
def convert(self, value: Any, param, ctx):
if isinstance(value, self.type_) or value is undefined:
return value
self.fail(f"{value!r} is not valid `{self.type_}` or `undefined`", param, ctx)

Let OptionalType handle not only str and int types, but also Any given type.
And it is good to pass detail failure messages.
Then, OptionalType can be used like below

# example
@click.option("--name", type=OptionalType(str), default=undefined, help="Example option.")

@kimjinmyeong kimjinmyeong requested a review from fregataa July 25, 2023 06:49
Copy link
Member

@fregataa fregataa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@fregataa
Copy link
Member

it would be nice to embed an example yaml file to test session template!

@kimjinmyeong
Copy link
Contributor Author

kimjinmyeong commented Jul 26, 2023

@fregataa Okay!

Comment on lines 384 to -390
tx.AliasedKey(["image", "lang"], default=undefined): UndefChecker | t.Null | t.String,
tx.AliasedKey(["arch", "architecture"], default=DEFAULT_IMAGE_ARCH)
>> "architecture": t.String,
tx.AliasedKey(["type", "sessionType"], default="interactive")
>> "session_type": tx.Enum(SessionTypes),
Copy link
Contributor Author

@kimjinmyeong kimjinmyeong Aug 3, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When a default value is set in here, the configuration value of the template gets overwritten by this default value.

@kimjinmyeong kimjinmyeong marked this pull request as draft August 16, 2023 03:24
@kimjinmyeong kimjinmyeong marked this pull request as ready for review August 16, 2023 08:07
@@ -538,7 +550,8 @@ def _create_from_template_cmd(docs: str = None):
"-g",
"--group",
metavar="GROUP_NAME",
default=None,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If a None value is passed, the group value gets overwritten with None, leading to an error.

collected an error log [ERROR] "ai.backend.manager.api.exceptions.InvalidAPIParameters: Missing or invalid API parameters. (Invalid group)" from manager

@kyujin-cho kyujin-cho added this to the 23.09 milestone Aug 16, 2023
@kyujin-cho kyujin-cho changed the title feat: Add OptionalType class to handle undefined value at cli argument feat: Add OptionalType click parameter type Aug 18, 2023
@kyujin-cho kyujin-cho changed the title feat: Add OptionalType click parameter type feat: add OptionalType click parameter type Aug 18, 2023
@kyujin-cho kyujin-cho added this pull request to the merge queue Aug 18, 2023
Merged via the queue into main with commit f78995c Aug 18, 2023
@kyujin-cho kyujin-cho deleted the fix/handle-undefined-click-argument-type branch August 18, 2023 04:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
comp:cli Related to CLI component comp:client Related to Client component comp:manager Related to Manager component effort:easy Need to understand only a specific region of codes (good first issue, easy). size:M 30~100 LoC type:bug Reports about that are not working type:feature Add new features type:refactor Refactor codes or add tests. urgency:2 With time limit, it should be finished within it; otherwise, resolve it when no other chores.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Let the client CLI accept 'undefined' as-is when the Click argument type is explicitly set
3 participants