diff --git a/README.org b/README.org index 2241f14150c1a67b49611224f4c74cda3ed47b96..3c0b9e62bd05c8e0a7106f123d423900887fbdba 100644 --- a/README.org +++ b/README.org @@ -33,7 +33,7 @@ conform with the Grid5000 API models (with an 's'!) * Comparison with ... -- [[https://api.grid5000.fr/doc/4.0/tools/restfully.html][RESTfully]]: +- [[https://api.grid5000.fr/doc/4.0/tools/restfully.html][RESTfully]]: It consumes REST API following the [[https://en.m.wikipedia.org/wiki/HATEOAS][HATEOAS]] principles. This allows the client to fully discover the resources and actions available. Most of the G5K API follow theses principles but, for instance the [[https://www.grid5000.fr/mediawiki/index.php/Storage_Manager][Storage API]] don't. Thus @@ -41,7 +41,7 @@ conform with the Grid5000 API models (with an 's'!) It's a ruby library. Python-grid5000 borrows the friendly syntax for resource browsing, but in python. -- [[http://execo.gforge.inria.fr][Execo]]: +- [[http://execo.gforge.inria.fr][Execo]]: Written in Python. The api module gathers a lot of utils functions leveraging the Grid'5000 API. Resources aren't exposed in a syntax friendly manner, instead functions for some classical operations are exposed (mainly getters). @@ -49,13 +49,13 @@ conform with the Grid5000 API models (with an 's'!) wrapper around the Grid'5000 that seeks 100% coverage. Python-grid5000 is resource oriented. -- [[http://docs.python-requests.org][Raw requests]]: +- [[http://docs.python-requests.org][Raw requests]]: *The* reference for HTTP library in python. Good for prototyping but low-level. python-grid5000 encapsulates this library. * Installation and examples -- Please refer to [[https://api.grid5000.fr/doc/4.0/reference/spec.html]] for +- Please refer to [[https://api.grid5000.fr/doc/4.0/reference/spec.html]] for the complete specification. - All the examples are exported in the examples subdirectory so you can @@ -100,12 +100,12 @@ pip install python-grid5000 #+BEGIN_EXAMPLE $) grid5000 -Python 3.6.5 (default, Jun 17 2018, 21:32:15) +Python 3.6.5 (default, Jun 17 2018, 21:32:15) Type 'copyright', 'credits' or 'license' for more information IPython 7.3.0 -- An enhanced Interactive Python. Type '?' for help. -In [1]: gk.sites.list() -Out[1]: +In [1]: gk.sites.list() +Out[1]: [<Site uid:grenoble>, <Site uid:lille>, <Site uid:luxembourg>, @@ -115,7 +115,7 @@ Out[1]: <Site uid:rennes>, <Site uid:sophia>] -In [2]: # gk is your entry point +In [2]: # gk is your entry point #+END_EXAMPLE @@ -447,7 +447,7 @@ In [2]: # gk is your entry point from grid5000 import Grid5000 - + logging.basicConfig(level=logging.DEBUG) @@ -477,7 +477,7 @@ In [2]: # gk is your entry point job.refresh() print("Waiting the job [%s] to be runnning" % job.uid) time.sleep(5) - + vlanid = job.resources_by_type["vlans"][0] # we hard code the interface but this can be discovered in the node info @@ -589,14 +589,14 @@ In [2]: # gk is your entry point logging.basicConfig(level=logging.DEBUG) NAME = "pyg5k" - + conf_file = os.path.join(os.environ.get("HOME"), ".python-grid5000.yaml") gk = Grid5000.from_yaml(conf_file) sites = gk.sites.list() site = gk.sites["rennes"] sites = [gk.sites["rennes"], gk.sites["nancy"], gk.sites["grenoble"]] - + # creates some jobs jobs = [] for site in sites: @@ -687,17 +687,16 @@ In [2]: # gk is your entry point print(clusters) #+END_SRC - *** Using Grid'5000 client certificates - + ~python-grid5000~ can also be used as a trusted client with Grid'5000 -internal certificate. In this mode users can pass the ~g5k_user~ argument -to most calls to specify which user the API call should be made as. In -cases where ~g5k_user~ is not specified API calls will be made as the +internal certificate. In this mode users can pass the ~g5k_user~ argument +to most calls to specify which user the API call should be made as. In +cases where ~g5k_user~ is not specified API calls will be made as the ~anonymous~ user whose access is limited to the Grid'5000 reference API. In this mode ~python-grid5000~ does not store any login information, so -~g5k_user~ most be provided explicitly provided on every call that requires -one. +~g5k_user~ must be provided explicitly provided on every call that requires +one. #+BEGIN_SRC python :exports code :tangle examples/certificate.py import logging @@ -718,7 +717,7 @@ one. "command": "sleep 3600"}, g5k_user = "auser1") - + # Since the 'anonymous' user can not inspect jobs the following call will raise exception # python-grid5000.exceptions.Grid5000AuthenticationError: 401 Unauthorized job.refresh() @@ -728,7 +727,7 @@ one. job.refresh(g5k_user='auser2') # Some operations can only be performed by the jobs creator. - # The following call will raise exception + # The following call will raise exception # pyg5k.exceptions.Grid5000DeleteError: 403 Unauthorized job.delete(g5k_user='auser2') @@ -737,7 +736,7 @@ one. #+END_SRC - + * Appendix :noexport: ** How to export this file @@ -749,4 +748,3 @@ one. - Produce python example scripts. Do ~C-c C-v t~ or ~M-x org-babel-tangle~. The scripts are available under available under ~examples~. - diff --git a/README.rst b/README.rst index 3136caab65cf5b8934fea3d7575ac09c807c4aa9..011f87e0201a61e4eb44a31156646c125c4668a5 100644 --- a/README.rst +++ b/README.rst @@ -34,7 +34,7 @@ conform with the Grid5000 API models (with an ’s’!) 3 Comparison with ... --------------------- -- `RESTfully <https://api.grid5000.fr/doc/4.0/tools/restfully.html>`_: +- `RESTfully <https://api.grid5000.fr/doc/4.0/tools/restfully.html>`_: It consumes REST API following the `HATEOAS <https://en.m.wikipedia.org/wiki/HATEOAS>`_ principles. This allows the client to fully discover the resources and actions available. Most of the G5K API follow theses principles but, for instance the `Storage API <https://www.grid5000.fr/mediawiki/index.php/Storage_Manager>`_ don’t. Thus @@ -42,7 +42,7 @@ conform with the Grid5000 API models (with an ’s’!) It’s a ruby library. Python-grid5000 borrows the friendly syntax for resource browsing, but in python. -- `Execo <http://execo.gforge.inria.fr>`_: +- `Execo <http://execo.gforge.inria.fr>`_: Written in Python. The api module gathers a lot of utils functions leveraging the Grid’5000 API. Resources aren’t exposed in a syntax friendly manner, instead functions for some classical operations are exposed (mainly getters). @@ -50,14 +50,14 @@ conform with the Grid5000 API models (with an ’s’!) wrapper around the Grid’5000 that seeks 100% coverage. Python-grid5000 is resource oriented. -- `Raw requests <http://docs.python-requests.org>`_: +- `Raw requests <http://docs.python-requests.org>`_: **The** reference for HTTP library in python. Good for prototyping but low-level. python-grid5000 encapsulates this library. 4 Installation and examples --------------------------- -- Please refer to `https://api.grid5000.fr/doc/4.0/reference/spec.html <https://api.grid5000.fr/doc/4.0/reference/spec.html>`_ for +- Please refer to `https://api.grid5000.fr/doc/4.0/reference/spec.html <https://api.grid5000.fr/doc/4.0/reference/spec.html>`_ for the complete specification. - All the examples are exported in the examples subdirectory so you can @@ -105,12 +105,12 @@ Before starting, the file ``$HOME/.python-grid5000.yaml`` will be loaded. $) grid5000 - Python 3.6.5 (default, Jun 17 2018, 21:32:15) + Python 3.6.5 (default, Jun 17 2018, 21:32:15) Type 'copyright', 'credits' or 'license' for more information IPython 7.3.0 -- An enhanced Interactive Python. Type '?' for help. - In [1]: gk.sites.list() - Out[1]: + In [1]: gk.sites.list() + Out[1]: [<Site uid:grenoble>, <Site uid:lille>, <Site uid:luxembourg>, @@ -120,7 +120,7 @@ Before starting, the file ``$HOME/.python-grid5000.yaml`` will be loaded. <Site uid:rennes>, <Site uid:sophia>] - In [2]: # gk is your entry point + In [2]: # gk is your entry point 4.2 Reference API ~~~~~~~~~~~~~~~~~ @@ -253,7 +253,7 @@ Before starting, the file ``$HOME/.python-grid5000.yaml`` will be loaded. site = gk.sites["rennes"] job = site.jobs.create({"name": "pyg5k", - "command": "sleep 3600"}) + "command": "sleep 3600"}) while job.state != "running": job.refresh() @@ -287,8 +287,8 @@ Before starting, the file ``$HOME/.python-grid5000.yaml`` will be loaded. site = gk.sites["rennes"] job = site.jobs.create({"name": "pyg5k", - "command": "sleep 3600", - "types": ["deploy"]}) + "command": "sleep 3600", + "types": ["deploy"]}) while job.state != "running": job.refresh() @@ -298,7 +298,7 @@ Before starting, the file ``$HOME/.python-grid5000.yaml`` will be loaded. print("Assigned nodes : %s" % job.assigned_nodes) deployment = site.deployments.create({"nodes": job.assigned_nodes, - "environment": "debian9-x64-min"}) + "environment": "debian9-x64-min"}) # To get SSH access to your nodes you can pass your public key # # from pathlib import Path @@ -358,8 +358,8 @@ Before starting, the file ``$HOME/.python-grid5000.yaml`` will be loaded. site = gk.sites["rennes"] job = site.jobs.create({"name": "pyg5k", - "command": "sleep 3600", - "resources": "slash_22=1+nodes=1"}) + "command": "sleep 3600", + "resources": "slash_22=1+nodes=1"}) while job.state != "running": job.refresh() @@ -371,8 +371,8 @@ Before starting, the file ``$HOME/.python-grid5000.yaml`` will be loaded. # create acces for all ips in the subnet access = site.storage["msimonin"].access.create({"ipv4": ip_network, - "termination": {"job": job.uid, - "site": site.uid}}) + "termination": {"job": job.uid, + "site": site.uid}}) 4.7 Vlan API ~~~~~~~~~~~~ @@ -434,9 +434,9 @@ Before starting, the file ``$HOME/.python-grid5000.yaml`` will be loaded. site = gk.sites["rennes"] job = site.jobs.create({"name": "pyg5k", - "command": "sleep 3600", - "resources": "{type='kavlan'}/vlan=1+nodes=1", - "types": ["deploy"]}) + "command": "sleep 3600", + "resources": "{type='kavlan'}/vlan=1+nodes=1", + "types": ["deploy"]}) while job.state != "running": job.refresh() @@ -444,8 +444,8 @@ Before starting, the file ``$HOME/.python-grid5000.yaml`` will be loaded. time.sleep(5) deployment = site.deployments.create({"nodes": job.assigned_nodes, - "environment": "debian9-x64-min", - "vlan": job.resources_by_type["vlans"][0]}) + "environment": "debian9-x64-min", + "vlan": job.resources_by_type["vlans"][0]}) while deployment.status != "terminated": deployment.refresh() @@ -485,9 +485,9 @@ Before starting, the file ``$HOME/.python-grid5000.yaml`` will be loaded. site = gk.sites["rennes"] job = site.jobs.create({"name": "pyg5k", - "command": "sleep 3600", - "resources": "{type='kavlan'}/vlan=1+{cluster='paranoia'}nodes=1", - "types": ["deploy"] + "command": "sleep 3600", + "resources": "{type='kavlan'}/vlan=1+{cluster='paranoia'}nodes=1", + "types": ["deploy"] }) while job.state != "running": @@ -555,16 +555,16 @@ For this example you’ll need ``matplotlib``, ``seaborn`` and ``pandas``. value = timeserie.values measurement = timeserie.uid df = pd.concat([df, pd.DataFrame({ - "timestamp": timestamp, - "value": value, - "measurement": [measurement]*len(timestamp) + "timestamp": timestamp, + "value": value, + "measurement": [measurement]*len(timestamp) })]) sns.relplot(data=df, - x="timestamp", - y="value", - hue="measurement", - kind="line") + x="timestamp", + y="value", + hue="measurement", + kind="line") plt.show() 4.9 More snippets @@ -594,8 +594,8 @@ For this example you’ll need ``matplotlib``, ``seaborn`` and ``pandas``. candidates = site.clusters.list() matching = [c.uid for c in candidates if c.uid in clusters] if len(matching) == 1: - matches.append((site, matching[0])) - clusters.remove(matching[0]) + matches.append((site, matching[0])) + clusters.remove(matching[0]) print("We found the following matches %s" % matches) 4.9.2 Get all job with a given name on all the sites @@ -625,13 +625,13 @@ For this example you’ll need ``matplotlib``, ``seaborn`` and ``pandas``. jobs = [] for site in sites: job = site.jobs.create({"name": "pyg5k", - "command": "sleep 3600"}) + "command": "sleep 3600"}) jobs.append(job) _jobs = [] for site in sites: _jobs.append((site.uid, site.jobs.list(name=NAME, - state="waiting,launching,running"))) + state="waiting,launching,running"))) print("We found %s" % _jobs) @@ -674,13 +674,13 @@ cross-processes cache) and give you control on the cached object. Enough talking def get_api_client(): """Gets the reference to the API cient (singleton).""" with _api_lock: - global _api_client - if not _api_client: - conf_file = os.path.join(os.environ.get("HOME"), - ".python-grid5000.yaml") - _api_client = Grid5000.from_yaml(conf_file) + global _api_client + if not _api_client: + conf_file = os.path.join(os.environ.get("HOME"), + ".python-grid5000.yaml") + _api_client = Grid5000.from_yaml(conf_file) - return _api_client + return _api_client @ring.disk(storage) @@ -696,8 +696,8 @@ cross-processes cache) and give you control on the cached object. Enough talking sites = get_sites_obj() clusters = [] for site in sites: - # should we cache the list aswell ? - clusters.extend(site.clusters.list()) + # should we cache the list aswell ? + clusters.extend(site.clusters.list()) return clusters @@ -715,13 +715,13 @@ cross-processes cache) and give you control on the cached object. Enough talking ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ``python-grid5000`` can also be used as a trusted client with Grid’5000 -internal certificate. In this mode users can pass the ``g5k_user`` argument -to most calls to specify which user the API call should be made as. In -cases where ``g5k_user`` is not specified API calls will be made as the +internal certificate. In this mode users can pass the ``g5k_user`` argument +to most calls to specify which user the API call should be made as. In +cases where ``g5k_user`` is not specified API calls will be made as the ``anonymous`` user whose access is limited to the Grid’5000 reference API. In this mode ``python-grid5000`` does not store any login information, so -``g5k_user`` most be provided explicitly provided on every call that requires -one. +``g5k_user`` must be provided explicitly provided on every call that requires +one. .. code:: python @@ -740,8 +740,8 @@ one. gk.sites.list() job = site.jobs.create({"name": "pyg5k", - "command": "sleep 3600"}, - g5k_user = "auser1") + "command": "sleep 3600"}, + g5k_user = "auser1") # Since the 'anonymous' user can not inspect jobs the following call will raise exception @@ -753,7 +753,7 @@ one. job.refresh(g5k_user='auser2') # Some operations can only be performed by the jobs creator. - # The following call will raise exception + # The following call will raise exception # pyg5k.exceptions.Grid5000DeleteError: 403 Unauthorized job.delete(g5k_user='auser2') diff --git a/examples/certificate.py b/examples/certificate.py index 8977ccec8f964f8f509cbd2de732a4124f8a356c..09867467512b4cc15beadd0c622e55fcf28f2a2a 100644 --- a/examples/certificate.py +++ b/examples/certificate.py @@ -26,7 +26,7 @@ job.refresh(g5k_user='auser1') job.refresh(g5k_user='auser2') # Some operations can only be performed by the jobs creator. -# The following call will raise exception +# The following call will raise exception # pyg5k.exceptions.Grid5000DeleteError: 403 Unauthorized job.delete(g5k_user='auser2')