{"id":18825339,"url":"https://github.com/grycap/oscar_python","last_synced_at":"2025-06-28T01:35:42.566Z","repository":{"id":62045100,"uuid":"551400779","full_name":"grycap/oscar_python","owner":"grycap","description":"A Python client to interact with OSCAR clusters and services","archived":false,"fork":false,"pushed_at":"2025-03-20T13:04:00.000Z","size":120,"stargazers_count":1,"open_issues_count":1,"forks_count":1,"subscribers_count":8,"default_branch":"main","last_synced_at":"2025-03-27T15:49:20.504Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://pypi.org/project/oscar-python/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/grycap.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-10-14T10:28:53.000Z","updated_at":"2025-03-06T11:13:46.000Z","dependencies_parsed_at":"2025-02-03T10:30:14.572Z","dependency_job_id":"8e11de6f-b961-43eb-b17e-a65103fa4068","html_url":"https://github.com/grycap/oscar_python","commit_stats":null,"previous_names":[],"tags_count":15,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/grycap%2Foscar_python","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/grycap%2Foscar_python/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/grycap%2Foscar_python/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/grycap%2Foscar_python/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/grycap","download_url":"https://codeload.github.com/grycap/oscar_python/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248807564,"owners_count":21164708,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-08T00:59:09.422Z","updated_at":"2025-06-28T01:35:42.560Z","avatar_url":"https://github.com/grycap.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"## Python OSCAR client\n\n[![Build](https://github.com/grycap/oscar_python/actions/workflows/release.yaml/badge.svg)](https://github.com/grycap/oscar_python/actions/workflows/main.yaml)\n![PyPI](https://img.shields.io/pypi/v/oscar_python)\n\nThis package provides a client to interact with OSCAR (https://oscar.grycap.net) clusters and services. It is available on Pypi with the name [oscar-python](https://pypi.org/project/oscar-python/).\n\n### Contents\n- [Python OSCAR client](#python-oscar-client)\n  - [Contents](#contents)\n  - [Client](#client)\n    - [Initialize a client with basic authentication](#initialize-a-client-with-basic-authentication)\n    - [Initialize a client OIDC authentication](#initialize-a-client-oidc-authentication)\n  - [Sample usage](#sample-usage)\n  - [Client methods](#client-methods)\n    - [Cluster methods](#cluster-methods)\n    - [Service methods](#service-methods)\n    - [Logs methods](#logs-methods)\n    - [Storage usage](#storage-usage)\n\n### Client\n\n#### Initialize a client with basic authentication\n``` python\n  options_basic_auth = {'cluster_id':'cluster-id',\n                'endpoint':'https://cluster-endpoint',\n                'user':'username',\n                'password':'password',\n                'ssl':'True'}\n\n  client = Client(options = options_basic_auth)\n```\n#### Initialize a client OIDC authentication\n\nIf you want to use OIDC tokens to authenticate with EGI Check-In, you can use the [OIDC Agent](https://indigo-dc.gitbook.io/oidc-agent/) to create an account configuration for the EGI issuer (https://aai.egi.eu/auth/realms/egi/) and then initialize the client specifying the `shortname` of your account like follows.\n\n``` python\n  options_oidc_auth = {'cluster_id':'cluster-id',\n                'endpoint':'https://cluster-endpoint',\n                'shortname':'oidc-agent-shortname',\n                'ssl':'True'}\n                \n  client = Client(options = options_oidc_auth)\n```\n\nIf you already have a valid token, you can use the parameter `oidc_token` instead.\n\n``` python\n  options_oidc_auth = {'cluster_id':'cluster-id',\n                'endpoint':'https://cluster-endpoint',\n                'oidc_token':'token',\n                'ssl':'True'}\n                \n  client = Client(options = options_oidc_auth)\n```\nAn example of using a generated token is if you want to use EGI Notebooks. Since you can't use oidc-agent on the Notebook, you can make use of the generated token that EGI provides on path `/var/run/secrets/egi.eu/access_token`.\n\nIf you have a valid refresh token (long live token), you can use the parameter `refresh_token` instead.\n\n``` python\n  options_oidc_auth = {'cluster_id':'cluster-id',\n                'endpoint':'https://cluster-endpoint',\n                'refresh_token':'token',\n                'ssl':'True'}\n                \n  client = Client(options = options_oidc_auth)\n```\n\nYou can get a refresh token from EGI Check-In using the [Token Portal](https://aai.egi.eu/token).\n\nIn case of using other OIDC provider you must provide two additional parameters `token_endpoint`\nand `scopes`:\n\n``` python\n  options_oidc_auth = {'cluster_id':'cluster-id',\n                'endpoint':'https://cluster-endpoint',\n                'refresh_token':'token',\n                'scopes': [\"openid\", \"profile\", \"email\"],\n                'token_endpoint': \"http://issuer.com/token\",\n                'ssl':'True'}\n                \n  client = Client(options = options_oidc_auth)\n```\n\n### Sample usage\n\n- Sample code that creates a client and gets information about the cluster\n\n``` python\nfrom oscar_python.client import Client\n\noptions_basic_auth = {'cluster_id':'cluster-id',\n              'endpoint':'https://cluster-endpoint',\n              'user':'username',\n              'password':'password',\n              'ssl':'True'}\n\nclient = Client(options = options)\n\n# get the cluster information\ntry:\n  info = client.get_cluster_info()\n  print(info.text)\nexcept Exception as err:\n  print(\"Failed with: \", err)\n```\n\n- Sample code to create a simple service with the [cowsay example](https://github.com/grycap/oscar/tree/master/examples/cowsay) and make a synchronous invocation.\n\n``` python\nfrom oscar_python.client import Client\n\noptions_basic_auth = {'cluster_id':'cluster-id',\n              'endpoint':'https://cluster-endpoint',\n              'user':'username',\n              'password':'password',\n              'ssl':'True'}\n\nclient = Client(options = options)\n\ntry:\n  client.create_service(\"/absolute_path/cowsay.yaml\")\n  response = client.run_service(\"cowsay\", input = '{\"message\": \"Hi there\"}')   \n  if response.status_code == 200:\n      print(response.text)\nexcept Exception as err:\n  print(\"Failed with: \", err)\n```\n\n### Client methods\n\n#### Cluster methods\n\n**get_cluster_info**\n``` python\n# get the cluster information\ninfo = client.get_cluster_info() # returns an HTTP response or an HTTPError\n```\n\n**get_cluster_config**\n``` python\n# get the cluster config\nconfig = client.get_cluster_config() # returns an http response or an HTTPError\n```\n\n#### Service methods\n\n**get_service**\n``` python\n# get the definition of a service \nservice = client.get_service(\"service_name\") # returns an http response or an HTTPError\n```\n\n**list_services**\n``` python\n# get a list of all the services deployed \nservices = client.list_services() # returns an http response or an HTTPError\n```\n\n\u003e _Note_ : Both `path_to_fdl` and the script path inside the fdl must be absolute.\n\n**create_service**\n``` python\n# create a service \nerr = client.create_service(\"path_to_fdl\" | \"JSON_definition\") # returns nothing if the service is created or an error if something goes wrong\n```\n\n**update_service**\n``` python\n# update a service \nerr = client.update_service(\"service_name\",\"path_to_fdl\" | \"JSON_definition\") # returns nothing if the service is created or an error if something goes wrong\n```\n\n**remove_service**\n``` python\n# remove a service \nresponse = client.remove_service(\"service_name\") # returns an http response\n```\n\n**run_service**\n\n *`input`, `output` and `timeout` are optional parameters.*\n\n``` python\n# make a synchronous execution \nresponse = client.run_service(\"service_name\", input=\"input\", output=\"out.png\", timeout=100) # returns an http response\n\n# make an asynchronous execution\nresponse = client.run_service(\"service_name\", input=\"input\", async_call=True) # returns an http response\n```\n\n#### Logs methods\n\n**get_job_logs**\n``` python\n# get logs of a job\nlogs = client.get_job_logs(\"service_name\", \"job_id\") # returns an http response\n```\n\n**list_jobs**\n``` python\n# get a list of jobs in a service\nlog_list = client.list_jobs(\"service_name\") # returns an http response\n```\n\n**remove_job**\n``` python\n# remove a job of a service\nresponse = client.remove_job(\"service_name\", \"job_id\") # returns an http response\n```\n\n**remove_all_jobs**\n``` python\n# remove all jobs in a service\nresponse = client.remove_all_jobs(\"service_name\") # returns an http response\n```\n\n#### Storage usage\n\nYou can create a storage object to operate over the different storage providers defined on a service with the method `create_storage_client`. This constructor returns a storage object with methos to interact with the storage providers.\n\nThe default constructor, seen as follows, will create a provider to interact with the default MinIO instance through the user's credentials. \n\n``` python\nstorage_service = client.create_storage_client() # returns a storage object\n```\nAdditionally, if you need to interact with specific storage providers defined on a service, the constructor accepts a `svc` parameter where you can state the service name from which to search for additional credentials.\n\n``` python\nstorage_service = client.create_storage_client(\"service_name\") # returns a storage object\n```\n\n\u003e _Note_ : The `storage_provider` parameter on the storage methods follows the format: `[\"storage_provider_type\"].[\"storage_provider_name\"]` where `storage_provider_type` is one of the suported storage providers (minIO, S3, Onedata or webdav) and `storage_provider_name` is the identifier _(ex: minio.default)_\n\n**list_files_from_path**\n\nThis method returns a JSON with the info except for OneData, which returns an HTTP response.\n\n``` python\n# get a list of the files of one of the service storage provider \nfiles = storage_service.list_files_from_path(\"storage_provider\", \"remote_path\") # returns json\n```\n\n**upload_file**\n``` python\n# upload a file from a local path to a remote path \nresponse = storage_service.upload_file(\"storage_provider\", \"local_path\", \"remote_path\")\n```\n\n**download_file**\n``` python\n# download a file from a remote path to a local path \nresponse = storage_service.download_file(\"storage_provider\", \"local_path\", \"remote_path\")\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgrycap%2Foscar_python","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgrycap%2Foscar_python","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgrycap%2Foscar_python/lists"}