25a8b506da8140afc19930493d43eb55006cbf3e
[arvados.git] / sdk / cli / bin / arv-copy
1 #! /usr/bin/env python
2
3 # arv-copy [--recursive] [--no-recursive] object-uuid src dst
4 #
5 # Copies an object from Arvados instance src to instance dst.
6 #
7 # By default, arv-copy recursively copies any dependent objects
8 # necessary to make the object functional in the new instance
9 # (e.g. for a pipeline instance, arv-copy copies the pipeline
10 # template, input collection, docker images, git repositories). If
11 # --no-recursive is given, arv-copy copies only the single record
12 # identified by object-uuid.
13 #
14 # The user must have files $HOME/.config/arvados/{src}.conf and
15 # $HOME/.config/arvados/{dst}.conf with valid login credentials for
16 # instances src and dst.  If either of these files is not found,
17 # arv-copy will issue an error.
18
19 import argparse
20 import hashlib
21 import os
22 import re
23 import string
24 import sys
25 import logging
26
27 import arvados
28 import arvados.config
29
30 def main():
31     logger = logging.getLogger('arvados.arv-copy')
32
33     parser = argparse.ArgumentParser(
34         description='Copy a pipeline instance from one Arvados instance to another.')
35
36     parser.add_argument('--recursive', dest='recursive', action='store_true')
37     parser.add_argument('--no-recursive', dest='recursive', action='store_false')
38     parser.add_argument('object_uuid')
39     parser.add_argument('source_arvados')
40     parser.add_argument('destination_arvados')
41     parser.set_defaults(recursive=True)
42
43     args = parser.parse_args()
44
45     # Create API clients for the source and destination instances
46     src_arv = api_for_instance(args.source_arvados)
47     dst_arv = api_for_instance(args.destination_arvados)
48
49     # And now for the copying.
50     t = uuid_type(args.object_uuid)
51     if t == 'collection':
52         copy_collection(args.object_uuid, src=src_arv, dst=dst_arv)
53     elif t == 'pipeline_instance':
54         copy_pipeline_instance(args.object_uuid, src=src_arv, dst=dst_arv)
55     elif t == 'pipeline_template':
56         new_pt = copy_pipeline_template(args.object_uuid, src=src_arv, dst=dst_arv)
57         print new_pt
58     else:
59         abort("cannot copy object {} of type {}".format(args.object_uuid, t))
60
61     exit(0)
62
63 # Creates an API client for the Arvados instance identified by
64 # instance_name.  Looks in $HOME/.config/arvados/instance_name.conf
65 # for credentials.
66 #
67 def api_for_instance(instance_name):
68     if '/' in instance_name:
69         abort('illegal instance name {}'.format(instance_name))
70     config_file = os.path.join(os.environ['HOME'], '.config', 'arvados', "{}.conf".format(instance_name))
71     cfg = arvados.config.load(config_file)
72
73     if 'ARVADOS_API_HOST' in cfg and 'ARVADOS_API_TOKEN' in cfg:
74         api_is_insecure = (
75             cfg.get('ARVADOS_API_HOST_INSECURE', '').lower() in set(
76                 ['1', 't', 'true', 'y', 'yes']))
77         client = arvados.api('v1',
78                              host=cfg['ARVADOS_API_HOST'],
79                              token=cfg['ARVADOS_API_TOKEN'],
80                              insecure=api_is_insecure,
81                              cache=False)
82     else:
83         abort('need ARVADOS_API_HOST and ARVADOS_API_TOKEN for {}'.format(instance_name))
84     return client
85
86 def copy_collection(obj_uuid, src=None, dst=None):
87     raise NotImplementedError
88
89 def copy_pipeline_instance(obj_uuid, src=None, dst=None):
90     raise NotImplementedError
91
92 def copy_pipeline_template(obj_uuid, src=None, dst=None):
93     # fetch the pipeline template from the source instance
94     old_pt = src.pipeline_templates().get(uuid=obj_uuid).execute()
95     old_pt['name'] = old_pt['name'] + ' copy'
96     del old_pt['uuid']
97     del old_pt['owner_uuid']
98     return dst.pipeline_templates().create(body=old_pt).execute()
99
100 uuid_type_map = {
101     "4zz18": "collection",
102     "d1hrv": "pipeline_instance",
103     "p5p6p": "pipeline_template",
104 }
105
106 def uuid_type(object_uuid):
107     type_str = object_uuid.split('-')[1]
108     return uuid_type_map.get(type_str, None)
109
110 def abort(msg, code=1):
111     print >>sys.stderr, "arv-copy:", msg
112     exit(code)
113
114 if __name__ == '__main__':
115     main()