{"action":"created","comment":{"url":"https://api.github.com/repos/BD2KGenomics/toil-scripts/pulls/comments/56044466","id":56044466,"diff_hunk":"@@ -220,110 +218,179 @@ def get_cluster_size(cluster_name):\n     \"\"\"\n     Returns the number of running toil-worker nodes\n     \"\"\"\n-    return len(list_workers(cluster_name))\n+    return len(list_nodes(cluster_name))\n \n \n-def list_workers(cluster_name):\n+def list_nodes(cluster_name, role='toil-worker'):\n     \"\"\"\n     Returns list of dictionaries, each dictionary representing a worker node. Each dictinoary has the following keys:\n     cluster_name, role_name, ordinal, cluster_ordinal, private_ip_address, ip_address, instance_id, instance_type,\n     launch_time, state and zone\n     \"\"\"\n-    return parse_cgcloud_list_output(subprocess.check_output(['cgcloud', 'list', '-c', cluster_name, 'toil-worker']))\n+    return parse_cgcloud_list_output(check_output(['cgcloud', 'list', '-c', cluster_name, role]))\n \n \n def parse_cgcloud_list_output(output):\n     return [row for row in csv.DictReader(StringIO(output), delimiter='\\t')]\n \n \n-def get_desired_cluster_size(conn, dom):\n-    nodes_per_sample = Samples.load(conn, dom)\n+def get_desired_cluster_size(domain):\n+    nodes_per_sample = Samples.load(domain)\n     return sum(map(lambda x: x[1], nodes_per_sample.samples.values()))\n \n \n-def update_cluster_size(conn, dom, n):\n-    ClusterSize.change_size(conn, dom, n)\n+def update_cluster_size(domain, n):\n+    \"\"\"\n+    Only to be invoked by the uberscript\n+    \"\"\"\n+    with cluster_size_lock:\n+        cluster_size = ClusterSize.load(domain)\n+        cluster_size.value = n\n+        # Holding the lock should prevent concurrent modifications\n+        cluster_size.save()\n \n \n-def grow_cluster(nodes, instance_type, cluster_name, etc):\n+def grow_cluster(num_nodes, instance_type, cluster_name, cluster_type='toil', *options):\n     \"\"\"\n-    Grow the cluster by n nodes\n+    Grow a cluster by a given number of nodes\n     \"\"\"\n-    nodes_left = nodes\n-    while nodes_left > 0:\n-        log.info('Attempting to grow cluster by %i node(s) of type: %s', nodes_left, instance_type)\n-\n-        output = ''\n+    nodes = []\n+    num_nodes_left = num_nodes\n+    while num_nodes_left > 0:\n+        log.info('Attempting to grow cluster by %i node(s) of type: %s', num_nodes_left, instance_type)\n         cmd = (['cgcloud',\n                 'grow-cluster',\n                 '--list',\n                 '--instance-type', instance_type,\n-                '--num-workers', str(nodes_left),\n+                '--num-workers', str(num_nodes_left),\n                 '--cluster-name', cluster_name] +\n-               etc +\n-               ['toil'])\n+               list(options) +\n+               [cluster_type])\n         try:\n-            output = subprocess.check_output(cmd)\n-        except subprocess.CalledProcessError as cpe:\n-            log.warn('Running command %s returned with error code %d.',\n-                     ' '.join(cmd),\n-                     cpe.returncode)\n-            output = cpe.output\n-\n-        added_nodes = len(parse_cgcloud_list_output(output))\n-        if added_nodes == 0:\n+            output = check_output(cmd)\n+        except CalledProcessError as e:\n+            log.warn('Command %r failed with status code %d.', cmd, e.returncode)\n+            output = e.output\n+        nodes_added = parse_cgcloud_list_output(output)\n+        nodes.extend(nodes_added)\n+        num_nodes_added = len(nodes_added)\n+        if num_nodes_added == 0:\n             log.warn(\"Wasn't able to add any nodes. Wating 5 min.\")\n             time.sleep(5 * 60)\n-        assert added_nodes <= nodes_left\n-        nodes_left -= added_nodes\n-        log.info('Added %d node(s), %d node(s) left.', added_nodes, nodes_left)\n-    log.info('Successfully grew cluster by %i node(s) of type %s.', nodes, instance_type)\n+        assert num_nodes_added <= num_nodes_left\n+        num_nodes_left -= num_nodes_added\n+        log.info('Added %d node(s), %d node(s) left.', num_nodes_added, num_nodes_left)\n+    assert len(nodes) == num_nodes\n+    log.info('Successfully grew cluster by %i node(s) of type %s.', num_nodes, instance_type)\n+    return nodes\n \n \n def manage_metrics_and_cluster_scaling(params):\n     conn = boto.sdb.connect_to_region(aws_region)\n     dom = conn.get_domain('{0}--files'.format(params.jobstore))\n-    grow_cluster_thread = threading.Thread(target=monitor_cluster_size, args=(params, conn, dom))\n-    metric_collection_thread = threading.Thread(target=collect_realtime_metrics, args=(params, conn, dom))\n+    grow_cluster_thread = threading.Thread(target=manage_toil_cluster, args=(params, conn, dom))\n+    metric_collection_thread = threading.Thread(target=collect_realtime_metrics, args=(params,))\n     grow_cluster_thread.start()\n     metric_collection_thread.start()\n     grow_cluster_thread.join()\n     metric_collection_thread.join()\n \n \n-def monitor_cluster_size(params, conn, dom):\n+def role_options(params):\n     \"\"\"\n-    Monitors cluster size and grows it if the desired size is larger than the current size\n+    :type params: argparse.Namespace\n     \"\"\"\n-\n-    # if user provides a string to add to /etc/hosts, let's pass that through\n-    etc = []\n+    options = []\n     if params.add_to_etc_hosts:\n-        etc = ['-O', 'etc_hosts_entries=%s' % params.add_to_etc_hosts]\n+        options.extend(['-O', 'etc_hosts_entries=%s' % params.add_to_etc_hosts])\n+    return options\n+\n \n-    log.info('Cluster size monitor has started.')\n+@contextmanager\n+def throttle(interval):\n+    \"\"\"\n+    A context manager for ensuring that the execution of its body takes at least a given amount of time, sleeping if\n+    necessary.\n+    \"\"\"\n+    start = time.time()\n+    yield\n+    duration = time.time() - start\n+    remainder = interval - duration\n+    if remainder > 0:\n+        time.sleep(remainder)\n+\n+\n+def manage_toil_cluster(params, domain):\n+    log.info('Auto-scaling of Toil cluster has started.')\n     time.sleep(scaling_initial_wait_period_in_seconds)\n     while True:\n-        size_check_time = time.time()\n-        # If cluster is too small, grow it\n-        cluster_size = get_cluster_size(params.cluster_name)\n-        desired_cluster_size = get_desired_cluster_size(conn, dom) + 1\n-        if cluster_size < desired_cluster_size:\n-            with cluster_size_lock:\n-                grow_cluster(desired_cluster_size - cluster_size, params.instance_type, params.cluster_name, etc)\n-                update_cluster_size(conn, dom, desired_cluster_size)\n+        with throttle(cluster_scaling_interval_in_seconds):\n+            cluster_size = len(list_nodes(params.cluster_name))\n+            desired_cluster_size = get_desired_cluster_size(domain) + 1\n+            if cluster_size < desired_cluster_size:\n+                with cluster_size_lock:\n+                    num_nodes = desired_cluster_size - cluster_size\n+                    grow_cluster(num_nodes, params.instance_type, params.cluster_name, *role_options(params))\n+                    update_cluster_size(domain, desired_cluster_size)\n+            cluster_size = len(list_nodes(params.cluster_name))\n+            log.info('Toil cluster is now at %i node(s).', cluster_size)\n \n-        # Sleep\n-        resize_time = time.time() - size_check_time\n-        log.info('Cluster is {} nodes as of {}'.format(get_cluster_size(params.cluster_name), resize_time))\n-        wait_time = cluster_scaling_interval_in_seconds - resize_time\n-        if wait_time > 0:\n-            time.sleep(wait_time)\n \n+standalone_spark_semaphore_name = 'standalone_spark_sample_slots'\n \n-# FIXME: unused parameters conn and dom\n \n-def collect_realtime_metrics(params, conn, dom, threshold=0.5, region='us-west-2'):\n+def manage_standalone_spark_cluster(params, domain):\n+    semaphore = Semaphore.create(domain=domain,\n+                                 name=standalone_spark_semaphore_name,\n+                                 value=params.spark_sample_slots)\n+    while True:\n+        with throttle(cluster_scaling_interval_in_seconds):\n+            # How many samples are being computed (or waiting to be computed) on the Spark cluster? ...\n+            num_unused_sample_slots = semaphore.value\n+            num_samples = params.spark_sample_slots - num_unused_sample_slots\n+            assert num_samples >= 0\n+            if num_samples:\n+                # ... At least one sample is. How many Spark workers are needed for all of them.\n+                spark_workers_per_sample = params.spark_nodes - 1\n+                num_desired_workers = num_samples * spark_workers_per_sample\n+                num_workers = len(list_nodes(params.cluster_name, role='spark-slave'))\n+                num_masters = len(list_nodes(params.cluster_name, role='spark-master'))\n+                if num_masters == 0:\n+                    # Absence of master indicates absence of cluster, so create it now.\n+                    assert num_workers == 0, 'Orphaned Spark workers detected'\n+                    output = check_output(['cgcloud',\n+                                           'create-cluster',\n+                                           '--list',\n+                                           '--zone', aws_region + 'a',\n+                                           '--cluster-name', params.cluster_name,\n+                                           '--leader-instance-type', params.spark_master_type or params.leader_type,\n+                                           '--instance-type', params.spark_instance_type or params.instance_type,\n+                                           '--num-workers', str(num_desired_workers),  # TODO: spot options","path":"src/toil_scripts/adam_uberscript/adam_uberscript.py","position":377,"original_position":377,"commit_id":"9505a652e423896573c743e55fb8088799c9d0c6","original_commit_id":"9505a652e423896573c743e55fb8088799c9d0c6","user":{"login":"hannes-ucsc","id":5143256,"avatar_url":"https://avatars.githubusercontent.com/u/5143256?v=3","gravatar_id":"","url":"https://api.github.com/users/hannes-ucsc","html_url":"https://github.com/hannes-ucsc","followers_url":"https://api.github.com/users/hannes-ucsc/followers","following_url":"https://api.github.com/users/hannes-ucsc/following{/other_user}","gists_url":"https://api.github.com/users/hannes-ucsc/gists{/gist_id}","starred_url":"https://api.github.com/users/hannes-ucsc/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/hannes-ucsc/subscriptions","organizations_url":"https://api.github.com/users/hannes-ucsc/orgs","repos_url":"https://api.github.com/users/hannes-ucsc/repos","events_url":"https://api.github.com/users/hannes-ucsc/events{/privacy}","received_events_url":"https://api.github.com/users/hannes-ucsc/received_events","type":"User","site_admin":false},"body":"https://github.com/BD2KGenomics/toil-scripts/issues/174","created_at":"2016-03-14T17:51:20Z","updated_at":"2016-03-14T17:51:20Z","html_url":"https://github.com/BD2KGenomics/toil-scripts/pull/157#discussion_r56044466","pull_request_url":"https://api.github.com/repos/BD2KGenomics/toil-scripts/pulls/157","_links":{"self":{"href":"https://api.github.com/repos/BD2KGenomics/toil-scripts/pulls/comments/56044466"},"html":{"href":"https://github.com/BD2KGenomics/toil-scripts/pull/157#discussion_r56044466"},"pull_request":{"href":"https://api.github.com/repos/BD2KGenomics/toil-scripts/pulls/157"}}},"pull_request":{"url":"https://api.github.com/repos/BD2KGenomics/toil-scripts/pulls/157","id":62032840,"html_url":"https://github.com/BD2KGenomics/toil-scripts/pull/157","diff_url":"https://github.com/BD2KGenomics/toil-scripts/pull/157.diff","patch_url":"https://github.com/BD2KGenomics/toil-scripts/pull/157.patch","issue_url":"https://api.github.com/repos/BD2KGenomics/toil-scripts/issues/157","number":157,"state":"open","locked":false,"title":"Auto-scaling of standalone Spark cluster (resolves #152)","user":{"login":"hannes-ucsc","id":5143256,"avatar_url":"https://avatars.githubusercontent.com/u/5143256?v=3","gravatar_id":"","url":"https://api.github.com/users/hannes-ucsc","html_url":"https://github.com/hannes-ucsc","followers_url":"https://api.github.com/users/hannes-ucsc/followers","following_url":"https://api.github.com/users/hannes-ucsc/following{/other_user}","gists_url":"https://api.github.com/users/hannes-ucsc/gists{/gist_id}","starred_url":"https://api.github.com/users/hannes-ucsc/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/hannes-ucsc/subscriptions","organizations_url":"https://api.github.com/users/hannes-ucsc/orgs","repos_url":"https://api.github.com/users/hannes-ucsc/repos","events_url":"https://api.github.com/users/hannes-ucsc/events{/privacy}","received_events_url":"https://api.github.com/users/hannes-ucsc/received_events","type":"User","site_admin":false},"body":"Resolves #152 \r\n\r\nWe now distinguish between *dynamic* (\"Spark-on-Toil\") and *static* clusters. Within the latter we further distinguish between *standalone* and *external*. A standalone cluster is managed by the überscript. This PR obsoletes the `--add-to-etc-hosts` parameter and replaces it with `--master_ip=auto` to indicate standalone clusters. That special string is resolved in the Toil scripts using SimpleDB (the SparkMasterAddress model) and injected into the driver containers via Docker's `--add-host` option. For that I had to dig a little deeper into my OO magic bag of trick. Apologies for that.\r\n\r\nThis PR creates the standalone Spark master when it is needed. This has the advantage that it will be recreated if needed and that it does not sit idle during alignment.\r\n\r\nThis has not been tested. The doctests pass, though, needless to say.","created_at":"2016-03-08T07:05:18Z","updated_at":"2016-03-14T17:51:20Z","closed_at":null,"merged_at":null,"merge_commit_sha":"54f34d6b158f94d6c60d2a9223e2ccc00011fc06","assignee":{"login":"fnothaft","id":3752466,"avatar_url":"https://avatars.githubusercontent.com/u/3752466?v=3","gravatar_id":"","url":"https://api.github.com/users/fnothaft","html_url":"https://github.com/fnothaft","followers_url":"https://api.github.com/users/fnothaft/followers","following_url":"https://api.github.com/users/fnothaft/following{/other_user}","gists_url":"https://api.github.com/users/fnothaft/gists{/gist_id}","starred_url":"https://api.github.com/users/fnothaft/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/fnothaft/subscriptions","organizations_url":"https://api.github.com/users/fnothaft/orgs","repos_url":"https://api.github.com/users/fnothaft/repos","events_url":"https://api.github.com/users/fnothaft/events{/privacy}","received_events_url":"https://api.github.com/users/fnothaft/received_events","type":"User","site_admin":false},"milestone":null,"commits_url":"https://api.github.com/repos/BD2KGenomics/toil-scripts/pulls/157/commits","review_comments_url":"https://api.github.com/repos/BD2KGenomics/toil-scripts/pulls/157/comments","review_comment_url":"https://api.github.com/repos/BD2KGenomics/toil-scripts/pulls/comments{/number}","comments_url":"https://api.github.com/repos/BD2KGenomics/toil-scripts/issues/157/comments","statuses_url":"https://api.github.com/repos/BD2KGenomics/toil-scripts/statuses/9505a652e423896573c743e55fb8088799c9d0c6","head":{"label":"BD2KGenomics:issues/152-autoscale-external-spark-cluster","ref":"issues/152-autoscale-external-spark-cluster","sha":"9505a652e423896573c743e55fb8088799c9d0c6","user":{"login":"BD2KGenomics","id":8701293,"avatar_url":"https://avatars.githubusercontent.com/u/8701293?v=3","gravatar_id":"","url":"https://api.github.com/users/BD2KGenomics","html_url":"https://github.com/BD2KGenomics","followers_url":"https://api.github.com/users/BD2KGenomics/followers","following_url":"https://api.github.com/users/BD2KGenomics/following{/other_user}","gists_url":"https://api.github.com/users/BD2KGenomics/gists{/gist_id}","starred_url":"https://api.github.com/users/BD2KGenomics/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/BD2KGenomics/subscriptions","organizations_url":"https://api.github.com/users/BD2KGenomics/orgs","repos_url":"https://api.github.com/users/BD2KGenomics/repos","events_url":"https://api.github.com/users/BD2KGenomics/events{/privacy}","received_events_url":"https://api.github.com/users/BD2KGenomics/received_events","type":"Organization","site_admin":false},"repo":{"id":39923176,"name":"toil-scripts","full_name":"BD2KGenomics/toil-scripts","owner":{"login":"BD2KGenomics","id":8701293,"avatar_url":"https://avatars.githubusercontent.com/u/8701293?v=3","gravatar_id":"","url":"https://api.github.com/users/BD2KGenomics","html_url":"https://github.com/BD2KGenomics","followers_url":"https://api.github.com/users/BD2KGenomics/followers","following_url":"https://api.github.com/users/BD2KGenomics/following{/other_user}","gists_url":"https://api.github.com/users/BD2KGenomics/gists{/gist_id}","starred_url":"https://api.github.com/users/BD2KGenomics/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/BD2KGenomics/subscriptions","organizations_url":"https://api.github.com/users/BD2KGenomics/orgs","repos_url":"https://api.github.com/users/BD2KGenomics/repos","events_url":"https://api.github.com/users/BD2KGenomics/events{/privacy}","received_events_url":"https://api.github.com/users/BD2KGenomics/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/BD2KGenomics/toil-scripts","description":"A collection of scripts that use Toil to implement genomics pipelines","fork":false,"url":"https://api.github.com/repos/BD2KGenomics/toil-scripts","forks_url":"https://api.github.com/repos/BD2KGenomics/toil-scripts/forks","keys_url":"https://api.github.com/repos/BD2KGenomics/toil-scripts/keys{/key_id}","collaborators_url":"https://api.github.com/repos/BD2KGenomics/toil-scripts/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/BD2KGenomics/toil-scripts/teams","hooks_url":"https://api.github.com/repos/BD2KGenomics/toil-scripts/hooks","issue_events_url":"https://api.github.com/repos/BD2KGenomics/toil-scripts/issues/events{/number}","events_url":"https://api.github.com/repos/BD2KGenomics/toil-scripts/events","assignees_url":"https://api.github.com/repos/BD2KGenomics/toil-scripts/assignees{/user}","branches_url":"https://api.github.com/repos/BD2KGenomics/toil-scripts/branches{/branch}","tags_url":"https://api.github.com/repos/BD2KGenomics/toil-scripts/tags","blobs_url":"https://api.github.com/repos/BD2KGenomics/toil-scripts/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/BD2KGenomics/toil-scripts/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/BD2KGenomics/toil-scripts/git/refs{/sha}","trees_url":"https://api.github.com/repos/BD2KGenomics/toil-scripts/git/trees{/sha}","statuses_url":"https://api.github.com/repos/BD2KGenomics/toil-scripts/statuses/{sha}","languages_url":"https://api.github.com/repos/BD2KGenomics/toil-scripts/languages","stargazers_url":"https://api.github.com/repos/BD2KGenomics/toil-scripts/stargazers","contributors_url":"https://api.github.com/repos/BD2KGenomics/toil-scripts/contributors","subscribers_url":"https://api.github.com/repos/BD2KGenomics/toil-scripts/subscribers","subscription_url":"https://api.github.com/repos/BD2KGenomics/toil-scripts/subscription","commits_url":"https://api.github.com/repos/BD2KGenomics/toil-scripts/commits{/sha}","git_commits_url":"https://api.github.com/repos/BD2KGenomics/toil-scripts/git/commits{/sha}","comments_url":"https://api.github.com/repos/BD2KGenomics/toil-scripts/comments{/number}","issue_comment_url":"https://api.github.com/repos/BD2KGenomics/toil-scripts/issues/comments{/number}","contents_url":"https://api.github.com/repos/BD2KGenomics/toil-scripts/contents/{+path}","compare_url":"https://api.github.com/repos/BD2KGenomics/toil-scripts/compare/{base}...{head}","merges_url":"https://api.github.com/repos/BD2KGenomics/toil-scripts/merges","archive_url":"https://api.github.com/repos/BD2KGenomics/toil-scripts/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/BD2KGenomics/toil-scripts/downloads","issues_url":"https://api.github.com/repos/BD2KGenomics/toil-scripts/issues{/number}","pulls_url":"https://api.github.com/repos/BD2KGenomics/toil-scripts/pulls{/number}","milestones_url":"https://api.github.com/repos/BD2KGenomics/toil-scripts/milestones{/number}","notifications_url":"https://api.github.com/repos/BD2KGenomics/toil-scripts/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/BD2KGenomics/toil-scripts/labels{/name}","releases_url":"https://api.github.com/repos/BD2KGenomics/toil-scripts/releases{/id}","deployments_url":"https://api.github.com/repos/BD2KGenomics/toil-scripts/deployments","created_at":"2015-07-30T00:42:23Z","updated_at":"2016-02-03T15:09:01Z","pushed_at":"2016-03-14T17:35:28Z","git_url":"git://github.com/BD2KGenomics/toil-scripts.git","ssh_url":"git@github.com:BD2KGenomics/toil-scripts.git","clone_url":"https://github.com/BD2KGenomics/toil-scripts.git","svn_url":"https://github.com/BD2KGenomics/toil-scripts","homepage":"","size":528,"stargazers_count":8,"watchers_count":8,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":7,"mirror_url":null,"open_issues_count":54,"forks":7,"open_issues":54,"watchers":8,"default_branch":"master"}},"base":{"label":"BD2KGenomics:master","ref":"master","sha":"8ebc2bfa20ca7444a3fd3578b40266d4a00f1e21","user":{"login":"BD2KGenomics","id":8701293,"avatar_url":"https://avatars.githubusercontent.com/u/8701293?v=3","gravatar_id":"","url":"https://api.github.com/users/BD2KGenomics","html_url":"https://github.com/BD2KGenomics","followers_url":"https://api.github.com/users/BD2KGenomics/followers","following_url":"https://api.github.com/users/BD2KGenomics/following{/other_user}","gists_url":"https://api.github.com/users/BD2KGenomics/gists{/gist_id}","starred_url":"https://api.github.com/users/BD2KGenomics/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/BD2KGenomics/subscriptions","organizations_url":"https://api.github.com/users/BD2KGenomics/orgs","repos_url":"https://api.github.com/users/BD2KGenomics/repos","events_url":"https://api.github.com/users/BD2KGenomics/events{/privacy}","received_events_url":"https://api.github.com/users/BD2KGenomics/received_events","type":"Organization","site_admin":false},"repo":{"id":39923176,"name":"toil-scripts","full_name":"BD2KGenomics/toil-scripts","owner":{"login":"BD2KGenomics","id":8701293,"avatar_url":"https://avatars.githubusercontent.com/u/8701293?v=3","gravatar_id":"","url":"https://api.github.com/users/BD2KGenomics","html_url":"https://github.com/BD2KGenomics","followers_url":"https://api.github.com/users/BD2KGenomics/followers","following_url":"https://api.github.com/users/BD2KGenomics/following{/other_user}","gists_url":"https://api.github.com/users/BD2KGenomics/gists{/gist_id}","starred_url":"https://api.github.com/users/BD2KGenomics/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/BD2KGenomics/subscriptions","organizations_url":"https://api.github.com/users/BD2KGenomics/orgs","repos_url":"https://api.github.com/users/BD2KGenomics/repos","events_url":"https://api.github.com/users/BD2KGenomics/events{/privacy}","received_events_url":"https://api.github.com/users/BD2KGenomics/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/BD2KGenomics/toil-scripts","description":"A collection of scripts that use Toil to implement genomics pipelines","fork":false,"url":"https://api.github.com/repos/BD2KGenomics/toil-scripts","forks_url":"https://api.github.com/repos/BD2KGenomics/toil-scripts/forks","keys_url":"https://api.github.com/repos/BD2KGenomics/toil-scripts/keys{/key_id}","collaborators_url":"https://api.github.com/repos/BD2KGenomics/toil-scripts/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/BD2KGenomics/toil-scripts/teams","hooks_url":"https://api.github.com/repos/BD2KGenomics/toil-scripts/hooks","issue_events_url":"https://api.github.com/repos/BD2KGenomics/toil-scripts/issues/events{/number}","events_url":"https://api.github.com/repos/BD2KGenomics/toil-scripts/events","assignees_url":"https://api.github.com/repos/BD2KGenomics/toil-scripts/assignees{/user}","branches_url":"https://api.github.com/repos/BD2KGenomics/toil-scripts/branches{/branch}","tags_url":"https://api.github.com/repos/BD2KGenomics/toil-scripts/tags","blobs_url":"https://api.github.com/repos/BD2KGenomics/toil-scripts/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/BD2KGenomics/toil-scripts/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/BD2KGenomics/toil-scripts/git/refs{/sha}","trees_url":"https://api.github.com/repos/BD2KGenomics/toil-scripts/git/trees{/sha}","statuses_url":"https://api.github.com/repos/BD2KGenomics/toil-scripts/statuses/{sha}","languages_url":"https://api.github.com/repos/BD2KGenomics/toil-scripts/languages","stargazers_url":"https://api.github.com/repos/BD2KGenomics/toil-scripts/stargazers","contributors_url":"https://api.github.com/repos/BD2KGenomics/toil-scripts/contributors","subscribers_url":"https://api.github.com/repos/BD2KGenomics/toil-scripts/subscribers","subscription_url":"https://api.github.com/repos/BD2KGenomics/toil-scripts/subscription","commits_url":"https://api.github.com/repos/BD2KGenomics/toil-scripts/commits{/sha}","git_commits_url":"https://api.github.com/repos/BD2KGenomics/toil-scripts/git/commits{/sha}","comments_url":"https://api.github.com/repos/BD2KGenomics/toil-scripts/comments{/number}","issue_comment_url":"https://api.github.com/repos/BD2KGenomics/toil-scripts/issues/comments{/number}","contents_url":"https://api.github.com/repos/BD2KGenomics/toil-scripts/contents/{+path}","compare_url":"https://api.github.com/repos/BD2KGenomics/toil-scripts/compare/{base}...{head}","merges_url":"https://api.github.com/repos/BD2KGenomics/toil-scripts/merges","archive_url":"https://api.github.com/repos/BD2KGenomics/toil-scripts/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/BD2KGenomics/toil-scripts/downloads","issues_url":"https://api.github.com/repos/BD2KGenomics/toil-scripts/issues{/number}","pulls_url":"https://api.github.com/repos/BD2KGenomics/toil-scripts/pulls{/number}","milestones_url":"https://api.github.com/repos/BD2KGenomics/toil-scripts/milestones{/number}","notifications_url":"https://api.github.com/repos/BD2KGenomics/toil-scripts/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/BD2KGenomics/toil-scripts/labels{/name}","releases_url":"https://api.github.com/repos/BD2KGenomics/toil-scripts/releases{/id}","deployments_url":"https://api.github.com/repos/BD2KGenomics/toil-scripts/deployments","created_at":"2015-07-30T00:42:23Z","updated_at":"2016-02-03T15:09:01Z","pushed_at":"2016-03-14T17:35:28Z","git_url":"git://github.com/BD2KGenomics/toil-scripts.git","ssh_url":"git@github.com:BD2KGenomics/toil-scripts.git","clone_url":"https://github.com/BD2KGenomics/toil-scripts.git","svn_url":"https://github.com/BD2KGenomics/toil-scripts","homepage":"","size":528,"stargazers_count":8,"watchers_count":8,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":7,"mirror_url":null,"open_issues_count":54,"forks":7,"open_issues":54,"watchers":8,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/BD2KGenomics/toil-scripts/pulls/157"},"html":{"href":"https://github.com/BD2KGenomics/toil-scripts/pull/157"},"issue":{"href":"https://api.github.com/repos/BD2KGenomics/toil-scripts/issues/157"},"comments":{"href":"https://api.github.com/repos/BD2KGenomics/toil-scripts/issues/157/comments"},"review_comments":{"href":"https://api.github.com/repos/BD2KGenomics/toil-scripts/pulls/157/comments"},"review_comment":{"href":"https://api.github.com/repos/BD2KGenomics/toil-scripts/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/BD2KGenomics/toil-scripts/pulls/157/commits"},"statuses":{"href":"https://api.github.com/repos/BD2KGenomics/toil-scripts/statuses/9505a652e423896573c743e55fb8088799c9d0c6"}}}}