{"action":"created","comment":{"url":"https://api.github.com/repos/GoogleCloudPlatform/PerfKitBenchmarker/pulls/comments/32867231","id":32867231,"diff_hunk":"@@ -0,0 +1,662 @@\n+# Copyright 2015 Google Inc. All rights reserved.\n+#\n+# Licensed under the Apache License, Version 2.0 (the \"License\");\n+# you may not use this file except in compliance with the License.\n+# You may obtain a copy of the License at\n+#\n+#   http://www.apache.org/licenses/LICENSE-2.0\n+#\n+# Unless required by applicable law or agreed to in writing, software\n+# distributed under the License is distributed on an \"AS IS\" BASIS,\n+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n+# See the License for the specific language governing permissions and\n+# limitations under the License.\n+\n+\"\"\"Module containing mixin classes for linux virtual machines.\n+\n+These classes allow installation on both Debian and RHEL based linuxes.\n+They also handle some intial setup (especially on RHEL based linuxes\n+since by default sudo commands without a tty don't work) and\n+can restore the VM to the state it was in before packages were\n+installed.\n+\n+To install a package on a VM, just call vm.Install(package_name).\n+The package name is just the name of the package module (i.e. the\n+file name minus .py). The framework will take care of all cleanup\n+for you.\n+\"\"\"\n+\n+import logging\n+import os\n+import pipes\n+import re\n+import threading\n+import time\n+import uuid\n+\n+from perfkitbenchmarker import disk\n+from perfkitbenchmarker import errors\n+from perfkitbenchmarker import flags\n+from perfkitbenchmarker import packages\n+from perfkitbenchmarker import virtual_machine\n+from perfkitbenchmarker import vm_util\n+\n+\n+EPEL6_RPM = ('http://dl.fedoraproject.org/pub/epel/'\n+             '6/x86_64/epel-release-6-8.noarch.rpm')\n+EPEL7_RPM = ('http://dl.fedoraproject.org/pub/epel/'\n+             '7/x86_64/e/epel-release-7-5.noarch.rpm')\n+\n+UPDATE_RETRIES = 5\n+SSH_RETRIES = 10\n+DEFAULT_SSH_PORT = 22\n+REMOTE_KEY_PATH = '.ssh/id_rsa'\n+\n+FLAGS = flags.FLAGS\n+\n+# This pair of scripts used for executing long-running commands, which will be\n+# resilient in the face of SSH connection errors.\n+# EXECUTE_COMMAND runs a command, streaming stdout / stderr to a file, then\n+# writing the return code to a file. An exclusive lock is acquired on the return\n+# code file, so that other processes may wait for completion.\n+EXECUTE_COMMAND = 'execute_command.py'\n+# WAIT_FOR_COMMAND waits on the file lock created by EXECUTE_COMMAND,\n+# then copies the stdout and stderr, exiting with the status of the command run\n+# by EXECUTE_COMMAND.\n+WAIT_FOR_COMMAND = 'wait_for_command.py'\n+\n+\n+class BaseLinuxMixin(virtual_machine.BaseOsMixin):\n+  \"\"\"Class that holds Linux related VM methods and attributes.\"\"\"\n+\n+  # If multiple ssh calls are made in parallel using -t it will mess\n+  # the stty settings up and the terminal will become very hard to use.\n+  # Serializing calls to ssh with the -t option fixes the problem.\n+  _pseudo_tty_lock = threading.Lock()\n+\n+  def __init__(self):\n+    super(BaseLinuxMixin, self).__init__()\n+    self.ssh_port = DEFAULT_SSH_PORT\n+    self.remote_access_ports = [self.ssh_port]\n+    self.has_private_key = False\n+\n+    self._remote_command_script_upload_lock = threading.Lock()\n+    self._has_remote_command_script = False\n+\n+  def __getstate__(self):\n+    \"\"\"Get state for pickling.\"\"\"\n+    d = self.__dict__.copy()\n+    # Locks cannot be pickled, so we just drop it and create a new one in\n+    # __setstate__.\n+    del d['_remote_command_script_upload_lock']\n+    return d\n+\n+  def __setstate__(self, state):\n+    \"\"\"Restores state after unpickling.\"\"\"\n+    self.__dict__ = state\n+    # Locks cannot be pickled, so we create a new one after deserialization.\n+    self._remote_command_script_upload_lock = threading.Lock()\n+\n+  def _PushRobustCommandScripts(self):\n+    \"\"\"Pushes the scripts required by RobustRemoteCommand to this VM.\n+\n+    If the scripts have already been placed on the VM, this is a noop.\n+    \"\"\"\n+    with self._remote_command_script_upload_lock:\n+      if not self._has_remote_command_script:\n+        for f in (EXECUTE_COMMAND, WAIT_FOR_COMMAND):\n+          self.PushDataFile(f, os.path.join(vm_util.VM_TMP_DIR,\n+                                            os.path.basename(f)))\n+        self._has_remote_command_script = True\n+\n+  def RobustRemoteCommand(self, command):\n+    \"\"\"Runs a command on the VM in a more robust way than RemoteCommand.\n+\n+    Executes a command via a pair of scripts on the VM:\n+\n+    * EXECUTE_COMMAND, which runs 'command' in a nohupped background process.\n+    * WAIT_FOR_COMMAND, which waits on a file lock held by EXECUTE_COMMAND until\n+      'command' completes, then returns with the stdout, stderr, and exit status\n+      of 'command'.\n+\n+    Temporary SSH failures (where ssh returns a 255) while waiting for the\n+    command to complete will be tolerated and safely retried.\n+    \"\"\"\n+    self._PushRobustCommandScripts()\n+\n+    execute_path = os.path.join(vm_util.VM_TMP_DIR,\n+                                os.path.basename(EXECUTE_COMMAND))\n+    wait_path = os.path.join(vm_util.VM_TMP_DIR,\n+                             os.path.basename(WAIT_FOR_COMMAND))\n+\n+    uid = uuid.uuid4()\n+    file_base = os.path.join(vm_util.VM_TMP_DIR, 'cmd%s' % uid)\n+    stdout_file = file_base + '.stdout'\n+    stderr_file = file_base + '.stderr'\n+    status_file = file_base + '.status'\n+\n+    if not isinstance(command, basestring):\n+      command = ' '.join(command)\n+\n+    start_command = ['nohup', 'python', execute_path,\n+                     '--stdout', stdout_file,\n+                     '--stderr', stderr_file,\n+                     '--status', status_file,\n+                     '--command', pipes.quote(command)]\n+\n+    start_command = '%s 1> /dev/null 2> /dev/null &' % ' '.join(start_command)\n+    self.RemoteCommand(start_command)\n+\n+    wait_command = ['python', wait_path, '--stdout', stdout_file,\n+                    '--stderr', stderr_file,\n+                    '--status', status_file,\n+                    '--delete']\n+    return self.RemoteCommand(' '.join(wait_command), should_log=False)\n+\n+  def OnStartup(self):\n+    if self.is_static and self.install_packages:\n+      self.SnapshotPackages()\n+    self.BurnCpu()\n+\n+  @vm_util.Retry(log_errors=False, poll_interval=1)\n+  def WaitForBootCompletion(self):\n+    \"\"\"Waits until VM is has booted.\"\"\"\n+    resp, _ = self.RemoteCommand('hostname', retries=1, suppress_warning=True)\n+    if self.bootable_time is None:\n+      self.bootable_time = time.time()\n+    if self.hostname is None:\n+      self.hostname = resp[:-1]\n+\n+  def SnapshotPackages(self):\n+    \"\"\"Grabs a snapshot of the currently installed packages.\"\"\"\n+    pass\n+\n+  def RestorePackages(self):\n+    \"\"\"Restores the currently installed packages to those snapshotted.\"\"\"\n+    pass\n+\n+  def PackageCleanup(self):\n+    \"\"\"Cleans up all installed packages.\n+\n+    Deletes the temp directory, restores packages, and uninstalls all\n+    PerfKit packages.\n+    \"\"\"\n+    for package_name in self._installed_packages:\n+      self.Uninstall(package_name)\n+    self.RestorePackages()\n+    self.RemoteCommand('rm -rf %s' % vm_util.VM_TMP_DIR)\n+\n+  def GetPathToConfig(self, package_name):\n+    \"\"\"Returns the path to the config file for PerfKit packages.\n+\n+    This function is mostly useful when config files locations\n+    don't match across distributions (such as mysql). Packages don't\n+    need to implement it if this is not the case.\n+    \"\"\"\n+    pass\n+\n+  def GetServiceName(self, package_name):\n+    \"\"\"Returns the service name of a PerfKit package.\n+\n+    This function is mostly useful when service names don't\n+    match across distributions (such as mongodb). Packages don't\n+    need to implement it if this is not the case.\n+    \"\"\"\n+    pass\n+\n+  @vm_util.Retry()\n+  def FormatDisk(self, device_path):\n+    \"\"\"Formats a disk attached to the VM.\"\"\"\n+    fmt_cmd = ('sudo mke2fs -F -E lazy_itable_init=0 -O '\n+               '^has_journal -t ext4 -b 4096 %s' % device_path)\n+    self.RemoteCommand(fmt_cmd)\n+\n+  def MountDisk(self, device_path, mount_path):\n+    \"\"\"Mounts a formatted disk in the VM.\"\"\"\n+    mnt_cmd = ('sudo mkdir -p {1};sudo mount {0} {1};'\n+               'sudo chown -R $USER:$USER {1};').format(device_path, mount_path)\n+    self.RemoteCommand(mnt_cmd)\n+\n+  def RemoteCopy(self, file_path, remote_path='', copy_to=True):\n+    \"\"\"Copies a file to or from the VM.\n+\n+    Args:\n+      file_path: Local path to file.\n+      remote_path: Optional path of where to copy file on remote host.\n+      copy_to: True to copy to vm, False to copy from vm.\n+\n+    Raises:\n+      RemoteCommandError: If there was a problem copying the file.\n+    \"\"\"\n+    if vm_util.RunningOnWindows():\n+      if ':' in file_path:\n+        # scp doesn't like colons in paths.\n+        file_path = file_path.split(':', 1)[1]\n+      # Replace the last instance of '\\' with '/' to make scp happy.\n+      file_path = '/'.join(file_path.rsplit('\\\\', 1))\n+\n+    remote_location = '%s@%s:%s' % (\n+        self.user_name, self.ip_address, remote_path)\n+    scp_cmd = ['scp', '-P', str(self.ssh_port), '-pr']\n+    scp_cmd.extend(vm_util.GetSshOptions(self.ssh_private_key))\n+    if copy_to:\n+      scp_cmd.extend([file_path, remote_location])\n+    else:\n+      scp_cmd.extend([remote_location, file_path])\n+\n+    stdout, stderr, retcode = vm_util.IssueCommand(scp_cmd, timeout=None)\n+\n+    if retcode:\n+      full_cmd = ' '.join(scp_cmd)\n+      error_text = ('Got non-zero return code (%s) executing %s\\n'","path":"perfkitbenchmarker/linux_virtual_machine.py","position":251,"original_position":251,"commit_id":"4ede2df13659b60bbc21e1d36ae3b3a320ccf582","original_commit_id":"4ede2df13659b60bbc21e1d36ae3b3a320ccf582","user":{"login":"ivansmf","id":6992417,"avatar_url":"https://avatars.githubusercontent.com/u/6992417?v=3","gravatar_id":"","url":"https://api.github.com/users/ivansmf","html_url":"https://github.com/ivansmf","followers_url":"https://api.github.com/users/ivansmf/followers","following_url":"https://api.github.com/users/ivansmf/following{/other_user}","gists_url":"https://api.github.com/users/ivansmf/gists{/gist_id}","starred_url":"https://api.github.com/users/ivansmf/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ivansmf/subscriptions","organizations_url":"https://api.github.com/users/ivansmf/orgs","repos_url":"https://api.github.com/users/ivansmf/repos","events_url":"https://api.github.com/users/ivansmf/events{/privacy}","received_events_url":"https://api.github.com/users/ivansmf/received_events","type":"User","site_admin":false},"body":"use os.linesep","created_at":"2015-06-19T20:38:47Z","updated_at":"2015-06-19T20:38:47Z","html_url":"https://github.com/GoogleCloudPlatform/PerfKitBenchmarker/pull/321#discussion_r32867231","pull_request_url":"https://api.github.com/repos/GoogleCloudPlatform/PerfKitBenchmarker/pulls/321","_links":{"self":{"href":"https://api.github.com/repos/GoogleCloudPlatform/PerfKitBenchmarker/pulls/comments/32867231"},"html":{"href":"https://github.com/GoogleCloudPlatform/PerfKitBenchmarker/pull/321#discussion_r32867231"},"pull_request":{"href":"https://api.github.com/repos/GoogleCloudPlatform/PerfKitBenchmarker/pulls/321"}}},"pull_request":{"url":"https://api.github.com/repos/GoogleCloudPlatform/PerfKitBenchmarker/pulls/321","id":38040573,"html_url":"https://github.com/GoogleCloudPlatform/PerfKitBenchmarker/pull/321","diff_url":"https://github.com/GoogleCloudPlatform/PerfKitBenchmarker/pull/321.diff","patch_url":"https://github.com/GoogleCloudPlatform/PerfKitBenchmarker/pull/321.patch","issue_url":"https://api.github.com/repos/GoogleCloudPlatform/PerfKitBenchmarker/issues/321","number":321,"state":"closed","locked":false,"title":"Refactor VM classes","user":{"login":"ehankland","id":8193699,"avatar_url":"https://avatars.githubusercontent.com/u/8193699?v=3","gravatar_id":"","url":"https://api.github.com/users/ehankland","html_url":"https://github.com/ehankland","followers_url":"https://api.github.com/users/ehankland/followers","following_url":"https://api.github.com/users/ehankland/following{/other_user}","gists_url":"https://api.github.com/users/ehankland/gists{/gist_id}","starred_url":"https://api.github.com/users/ehankland/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ehankland/subscriptions","organizations_url":"https://api.github.com/users/ehankland/orgs","repos_url":"https://api.github.com/users/ehankland/repos","events_url":"https://api.github.com/users/ehankland/events{/privacy}","received_events_url":"https://api.github.com/users/ehankland/received_events","type":"User","site_admin":false},"body":"Add a BaseOsMixin and a LinuxMixin subclass that holds linux specific methods and attributes","created_at":"2015-06-18T18:59:17Z","updated_at":"2015-06-19T20:38:47Z","closed_at":"2015-06-19T20:33:54Z","merged_at":"2015-06-19T20:33:54Z","merge_commit_sha":"9efbf3d907f99e8d1396dc0b826102d43a273e0b","assignee":{"login":"cmccoy","id":564884,"avatar_url":"https://avatars.githubusercontent.com/u/564884?v=3","gravatar_id":"","url":"https://api.github.com/users/cmccoy","html_url":"https://github.com/cmccoy","followers_url":"https://api.github.com/users/cmccoy/followers","following_url":"https://api.github.com/users/cmccoy/following{/other_user}","gists_url":"https://api.github.com/users/cmccoy/gists{/gist_id}","starred_url":"https://api.github.com/users/cmccoy/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/cmccoy/subscriptions","organizations_url":"https://api.github.com/users/cmccoy/orgs","repos_url":"https://api.github.com/users/cmccoy/repos","events_url":"https://api.github.com/users/cmccoy/events{/privacy}","received_events_url":"https://api.github.com/users/cmccoy/received_events","type":"User","site_admin":false},"milestone":null,"commits_url":"https://api.github.com/repos/GoogleCloudPlatform/PerfKitBenchmarker/pulls/321/commits","review_comments_url":"https://api.github.com/repos/GoogleCloudPlatform/PerfKitBenchmarker/pulls/321/comments","review_comment_url":"https://api.github.com/repos/GoogleCloudPlatform/PerfKitBenchmarker/pulls/comments{/number}","comments_url":"https://api.github.com/repos/GoogleCloudPlatform/PerfKitBenchmarker/issues/321/comments","statuses_url":"https://api.github.com/repos/GoogleCloudPlatform/PerfKitBenchmarker/statuses/4ede2df13659b60bbc21e1d36ae3b3a320ccf582","head":{"label":"GoogleCloudPlatform:linux","ref":"linux","sha":"4ede2df13659b60bbc21e1d36ae3b3a320ccf582","user":{"login":"GoogleCloudPlatform","id":2810941,"avatar_url":"https://avatars.githubusercontent.com/u/2810941?v=3","gravatar_id":"","url":"https://api.github.com/users/GoogleCloudPlatform","html_url":"https://github.com/GoogleCloudPlatform","followers_url":"https://api.github.com/users/GoogleCloudPlatform/followers","following_url":"https://api.github.com/users/GoogleCloudPlatform/following{/other_user}","gists_url":"https://api.github.com/users/GoogleCloudPlatform/gists{/gist_id}","starred_url":"https://api.github.com/users/GoogleCloudPlatform/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/GoogleCloudPlatform/subscriptions","organizations_url":"https://api.github.com/users/GoogleCloudPlatform/orgs","repos_url":"https://api.github.com/users/GoogleCloudPlatform/repos","events_url":"https://api.github.com/users/GoogleCloudPlatform/events{/privacy}","received_events_url":"https://api.github.com/users/GoogleCloudPlatform/received_events","type":"Organization","site_admin":false},"repo":{"id":21950910,"name":"PerfKitBenchmarker","full_name":"GoogleCloudPlatform/PerfKitBenchmarker","owner":{"login":"GoogleCloudPlatform","id":2810941,"avatar_url":"https://avatars.githubusercontent.com/u/2810941?v=3","gravatar_id":"","url":"https://api.github.com/users/GoogleCloudPlatform","html_url":"https://github.com/GoogleCloudPlatform","followers_url":"https://api.github.com/users/GoogleCloudPlatform/followers","following_url":"https://api.github.com/users/GoogleCloudPlatform/following{/other_user}","gists_url":"https://api.github.com/users/GoogleCloudPlatform/gists{/gist_id}","starred_url":"https://api.github.com/users/GoogleCloudPlatform/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/GoogleCloudPlatform/subscriptions","organizations_url":"https://api.github.com/users/GoogleCloudPlatform/orgs","repos_url":"https://api.github.com/users/GoogleCloudPlatform/repos","events_url":"https://api.github.com/users/GoogleCloudPlatform/events{/privacy}","received_events_url":"https://api.github.com/users/GoogleCloudPlatform/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/GoogleCloudPlatform/PerfKitBenchmarker","description":"Perfkit Benchmarker contains set of benchmarks to measure and compare cloud offerings. The benchmarks are not tuned (i.e. use defaults) to reflect what most users will see. PerfKit Benchmarker is licensed under the Apache 2 license terms. Please make sure to read, understand and agree to the terms of the LICENSE and CONTRIBUTING files before proceeding.","fork":false,"url":"https://api.github.com/repos/GoogleCloudPlatform/PerfKitBenchmarker","forks_url":"https://api.github.com/repos/GoogleCloudPlatform/PerfKitBenchmarker/forks","keys_url":"https://api.github.com/repos/GoogleCloudPlatform/PerfKitBenchmarker/keys{/key_id}","collaborators_url":"https://api.github.com/repos/GoogleCloudPlatform/PerfKitBenchmarker/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/GoogleCloudPlatform/PerfKitBenchmarker/teams","hooks_url":"https://api.github.com/repos/GoogleCloudPlatform/PerfKitBenchmarker/hooks","issue_events_url":"https://api.github.com/repos/GoogleCloudPlatform/PerfKitBenchmarker/issues/events{/number}","events_url":"https://api.github.com/repos/GoogleCloudPlatform/PerfKitBenchmarker/events","assignees_url":"https://api.github.com/repos/GoogleCloudPlatform/PerfKitBenchmarker/assignees{/user}","branches_url":"https://api.github.com/repos/GoogleCloudPlatform/PerfKitBenchmarker/branches{/branch}","tags_url":"https://api.github.com/repos/GoogleCloudPlatform/PerfKitBenchmarker/tags","blobs_url":"https://api.github.com/repos/GoogleCloudPlatform/PerfKitBenchmarker/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/GoogleCloudPlatform/PerfKitBenchmarker/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/GoogleCloudPlatform/PerfKitBenchmarker/git/refs{/sha}","trees_url":"https://api.github.com/repos/GoogleCloudPlatform/PerfKitBenchmarker/git/trees{/sha}","statuses_url":"https://api.github.com/repos/GoogleCloudPlatform/PerfKitBenchmarker/statuses/{sha}","languages_url":"https://api.github.com/repos/GoogleCloudPlatform/PerfKitBenchmarker/languages","stargazers_url":"https://api.github.com/repos/GoogleCloudPlatform/PerfKitBenchmarker/stargazers","contributors_url":"https://api.github.com/repos/GoogleCloudPlatform/PerfKitBenchmarker/contributors","subscribers_url":"https://api.github.com/repos/GoogleCloudPlatform/PerfKitBenchmarker/subscribers","subscription_url":"https://api.github.com/repos/GoogleCloudPlatform/PerfKitBenchmarker/subscription","commits_url":"https://api.github.com/repos/GoogleCloudPlatform/PerfKitBenchmarker/commits{/sha}","git_commits_url":"https://api.github.com/repos/GoogleCloudPlatform/PerfKitBenchmarker/git/commits{/sha}","comments_url":"https://api.github.com/repos/GoogleCloudPlatform/PerfKitBenchmarker/comments{/number}","issue_comment_url":"https://api.github.com/repos/GoogleCloudPlatform/PerfKitBenchmarker/issues/comments{/number}","contents_url":"https://api.github.com/repos/GoogleCloudPlatform/PerfKitBenchmarker/contents/{+path}","compare_url":"https://api.github.com/repos/GoogleCloudPlatform/PerfKitBenchmarker/compare/{base}...{head}","merges_url":"https://api.github.com/repos/GoogleCloudPlatform/PerfKitBenchmarker/merges","archive_url":"https://api.github.com/repos/GoogleCloudPlatform/PerfKitBenchmarker/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/GoogleCloudPlatform/PerfKitBenchmarker/downloads","issues_url":"https://api.github.com/repos/GoogleCloudPlatform/PerfKitBenchmarker/issues{/number}","pulls_url":"https://api.github.com/repos/GoogleCloudPlatform/PerfKitBenchmarker/pulls{/number}","milestones_url":"https://api.github.com/repos/GoogleCloudPlatform/PerfKitBenchmarker/milestones{/number}","notifications_url":"https://api.github.com/repos/GoogleCloudPlatform/PerfKitBenchmarker/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/GoogleCloudPlatform/PerfKitBenchmarker/labels{/name}","releases_url":"https://api.github.com/repos/GoogleCloudPlatform/PerfKitBenchmarker/releases{/id}","created_at":"2014-07-17T17:23:26Z","updated_at":"2015-06-18T16:35:21Z","pushed_at":"2015-06-19T20:33:56Z","git_url":"git://github.com/GoogleCloudPlatform/PerfKitBenchmarker.git","ssh_url":"git@github.com:GoogleCloudPlatform/PerfKitBenchmarker.git","clone_url":"https://github.com/GoogleCloudPlatform/PerfKitBenchmarker.git","svn_url":"https://github.com/GoogleCloudPlatform/PerfKitBenchmarker","homepage":"","size":150311,"stargazers_count":454,"watchers_count":454,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":53,"mirror_url":null,"open_issues_count":76,"forks":53,"open_issues":76,"watchers":454,"default_branch":"master"}},"base":{"label":"GoogleCloudPlatform:dev","ref":"dev","sha":"87a3c49e2d5c165fe0a6eade3c3bb49778395a03","user":{"login":"GoogleCloudPlatform","id":2810941,"avatar_url":"https://avatars.githubusercontent.com/u/2810941?v=3","gravatar_id":"","url":"https://api.github.com/users/GoogleCloudPlatform","html_url":"https://github.com/GoogleCloudPlatform","followers_url":"https://api.github.com/users/GoogleCloudPlatform/followers","following_url":"https://api.github.com/users/GoogleCloudPlatform/following{/other_user}","gists_url":"https://api.github.com/users/GoogleCloudPlatform/gists{/gist_id}","starred_url":"https://api.github.com/users/GoogleCloudPlatform/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/GoogleCloudPlatform/subscriptions","organizations_url":"https://api.github.com/users/GoogleCloudPlatform/orgs","repos_url":"https://api.github.com/users/GoogleCloudPlatform/repos","events_url":"https://api.github.com/users/GoogleCloudPlatform/events{/privacy}","received_events_url":"https://api.github.com/users/GoogleCloudPlatform/received_events","type":"Organization","site_admin":false},"repo":{"id":21950910,"name":"PerfKitBenchmarker","full_name":"GoogleCloudPlatform/PerfKitBenchmarker","owner":{"login":"GoogleCloudPlatform","id":2810941,"avatar_url":"https://avatars.githubusercontent.com/u/2810941?v=3","gravatar_id":"","url":"https://api.github.com/users/GoogleCloudPlatform","html_url":"https://github.com/GoogleCloudPlatform","followers_url":"https://api.github.com/users/GoogleCloudPlatform/followers","following_url":"https://api.github.com/users/GoogleCloudPlatform/following{/other_user}","gists_url":"https://api.github.com/users/GoogleCloudPlatform/gists{/gist_id}","starred_url":"https://api.github.com/users/GoogleCloudPlatform/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/GoogleCloudPlatform/subscriptions","organizations_url":"https://api.github.com/users/GoogleCloudPlatform/orgs","repos_url":"https://api.github.com/users/GoogleCloudPlatform/repos","events_url":"https://api.github.com/users/GoogleCloudPlatform/events{/privacy}","received_events_url":"https://api.github.com/users/GoogleCloudPlatform/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/GoogleCloudPlatform/PerfKitBenchmarker","description":"Perfkit Benchmarker contains set of benchmarks to measure and compare cloud offerings. The benchmarks are not tuned (i.e. use defaults) to reflect what most users will see. PerfKit Benchmarker is licensed under the Apache 2 license terms. Please make sure to read, understand and agree to the terms of the LICENSE and CONTRIBUTING files before proceeding.","fork":false,"url":"https://api.github.com/repos/GoogleCloudPlatform/PerfKitBenchmarker","forks_url":"https://api.github.com/repos/GoogleCloudPlatform/PerfKitBenchmarker/forks","keys_url":"https://api.github.com/repos/GoogleCloudPlatform/PerfKitBenchmarker/keys{/key_id}","collaborators_url":"https://api.github.com/repos/GoogleCloudPlatform/PerfKitBenchmarker/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/GoogleCloudPlatform/PerfKitBenchmarker/teams","hooks_url":"https://api.github.com/repos/GoogleCloudPlatform/PerfKitBenchmarker/hooks","issue_events_url":"https://api.github.com/repos/GoogleCloudPlatform/PerfKitBenchmarker/issues/events{/number}","events_url":"https://api.github.com/repos/GoogleCloudPlatform/PerfKitBenchmarker/events","assignees_url":"https://api.github.com/repos/GoogleCloudPlatform/PerfKitBenchmarker/assignees{/user}","branches_url":"https://api.github.com/repos/GoogleCloudPlatform/PerfKitBenchmarker/branches{/branch}","tags_url":"https://api.github.com/repos/GoogleCloudPlatform/PerfKitBenchmarker/tags","blobs_url":"https://api.github.com/repos/GoogleCloudPlatform/PerfKitBenchmarker/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/GoogleCloudPlatform/PerfKitBenchmarker/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/GoogleCloudPlatform/PerfKitBenchmarker/git/refs{/sha}","trees_url":"https://api.github.com/repos/GoogleCloudPlatform/PerfKitBenchmarker/git/trees{/sha}","statuses_url":"https://api.github.com/repos/GoogleCloudPlatform/PerfKitBenchmarker/statuses/{sha}","languages_url":"https://api.github.com/repos/GoogleCloudPlatform/PerfKitBenchmarker/languages","stargazers_url":"https://api.github.com/repos/GoogleCloudPlatform/PerfKitBenchmarker/stargazers","contributors_url":"https://api.github.com/repos/GoogleCloudPlatform/PerfKitBenchmarker/contributors","subscribers_url":"https://api.github.com/repos/GoogleCloudPlatform/PerfKitBenchmarker/subscribers","subscription_url":"https://api.github.com/repos/GoogleCloudPlatform/PerfKitBenchmarker/subscription","commits_url":"https://api.github.com/repos/GoogleCloudPlatform/PerfKitBenchmarker/commits{/sha}","git_commits_url":"https://api.github.com/repos/GoogleCloudPlatform/PerfKitBenchmarker/git/commits{/sha}","comments_url":"https://api.github.com/repos/GoogleCloudPlatform/PerfKitBenchmarker/comments{/number}","issue_comment_url":"https://api.github.com/repos/GoogleCloudPlatform/PerfKitBenchmarker/issues/comments{/number}","contents_url":"https://api.github.com/repos/GoogleCloudPlatform/PerfKitBenchmarker/contents/{+path}","compare_url":"https://api.github.com/repos/GoogleCloudPlatform/PerfKitBenchmarker/compare/{base}...{head}","merges_url":"https://api.github.com/repos/GoogleCloudPlatform/PerfKitBenchmarker/merges","archive_url":"https://api.github.com/repos/GoogleCloudPlatform/PerfKitBenchmarker/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/GoogleCloudPlatform/PerfKitBenchmarker/downloads","issues_url":"https://api.github.com/repos/GoogleCloudPlatform/PerfKitBenchmarker/issues{/number}","pulls_url":"https://api.github.com/repos/GoogleCloudPlatform/PerfKitBenchmarker/pulls{/number}","milestones_url":"https://api.github.com/repos/GoogleCloudPlatform/PerfKitBenchmarker/milestones{/number}","notifications_url":"https://api.github.com/repos/GoogleCloudPlatform/PerfKitBenchmarker/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/GoogleCloudPlatform/PerfKitBenchmarker/labels{/name}","releases_url":"https://api.github.com/repos/GoogleCloudPlatform/PerfKitBenchmarker/releases{/id}","created_at":"2014-07-17T17:23:26Z","updated_at":"2015-06-18T16:35:21Z","pushed_at":"2015-06-19T20:33:56Z","git_url":"git://github.com/GoogleCloudPlatform/PerfKitBenchmarker.git","ssh_url":"git@github.com:GoogleCloudPlatform/PerfKitBenchmarker.git","clone_url":"https://github.com/GoogleCloudPlatform/PerfKitBenchmarker.git","svn_url":"https://github.com/GoogleCloudPlatform/PerfKitBenchmarker","homepage":"","size":150311,"stargazers_count":454,"watchers_count":454,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":53,"mirror_url":null,"open_issues_count":76,"forks":53,"open_issues":76,"watchers":454,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/GoogleCloudPlatform/PerfKitBenchmarker/pulls/321"},"html":{"href":"https://github.com/GoogleCloudPlatform/PerfKitBenchmarker/pull/321"},"issue":{"href":"https://api.github.com/repos/GoogleCloudPlatform/PerfKitBenchmarker/issues/321"},"comments":{"href":"https://api.github.com/repos/GoogleCloudPlatform/PerfKitBenchmarker/issues/321/comments"},"review_comments":{"href":"https://api.github.com/repos/GoogleCloudPlatform/PerfKitBenchmarker/pulls/321/comments"},"review_comment":{"href":"https://api.github.com/repos/GoogleCloudPlatform/PerfKitBenchmarker/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/GoogleCloudPlatform/PerfKitBenchmarker/pulls/321/commits"},"statuses":{"href":"https://api.github.com/repos/GoogleCloudPlatform/PerfKitBenchmarker/statuses/4ede2df13659b60bbc21e1d36ae3b3a320ccf582"}}}}