Repository: ocadotechnology/aimmo

Issue:
Minikube both locally and on Travis failing to build docker images
We had `capture_output` set to False and the traceback was ignored previously. Here it is now:
```
Traceback (most recent call last):
  File "/home/travis/build/ocadotechnology/aimmo/integration-tests/tests/test_kubernetes.py", line 21, in setUp
    self.processes = runner.run(use_minikube=True, server_wait=False, capture_output=True)
  File "/home/travis/build/ocadotechnology/aimmo/aimmo_runner/runner.py", line 56, in run
    minikube.start()
  File "/home/travis/build/ocadotechnology/aimmo/aimmo_runner/minikube.py", line 125, in start
    build_docker_images(MINIKUBE_EXECUTABLE)
  File "/home/travis/build/ocadotechnology/aimmo/aimmo_runner/minikube.py", line 67, in build_docker_images
    matches = re.finditer(r'^export (.+)="(.+)"$', raw_env_settings, re.MULTILINE)
  File "/home/travis/virtualenv/python2.7.14/lib/python2.7/re.py", line 190, in finditer
    return _compile(pattern, flags).finditer(string)
TypeError: expected string or buffer
```

I also found traces of Travis not being able to run `minikube docker-env` beforehand.

`raw_env_settings` turns out to be equal to None, because the following line:
`raw_env_settings = run_command([minikube, 'docker-env', '--shell="bash"'], False)` isn't running.

~~This started when we changed our driver to `none` few weeks back probably. This is intended behaviour and we can safely remove the code [probs](https://github.com/kubernetes/minikube/issues/2443).~~

`test_travis` branch first push contains more traceback


Discussion:

Resolving patch:
diff --git a/aimmo_runner/minikube.py b/aimmo_runner/minikube.py
--- a/aimmo_runner/minikube.py
+++ b/aimmo_runner/minikube.py
@@ -14,24 +14,34 @@
 
 
 def get_ip():
-    # http://stackoverflow.com/a/28950776/671626
+    """
+    Get a single primary IP address. This will not return all IPs in the
+    interface. See http://stackoverflow.com/a/28950776/671626
+    :return: Integer with the IP of the user.
+    """
     os_name = platform.system()
     if os_name == "Darwin":
         return socket.gethostbyname(socket.gethostname())
 
-    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+    client_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+
+    # noinspection PyBroadException
     try:
         # doesn't even have to be reachable
-        s.connect(('10.255.255.255', 0))
-        IP = s.getsockname()[0]
+        client_socket.connect(('10.255.255.255', 0))
+        IP = client_socket.getsockname()[0]
     except:
         IP = '127.0.0.1'
     finally:
-        s.close()
+        client_socket.close()
     return IP
 
 
 def restart_ingress_addon(minikube):
+    """
+    Ingress needs to be restarted for old paths to be removed at startup.
+    :param minikube: Executable minikube installed beforehand.
+    """
     try:
         run_command([minikube, 'addons', 'disable', 'ingress'])
     except:
@@ -40,6 +50,9 @@ def restart_ingress_addon(minikube):
 
 
 def create_ingress_yaml():
+    """
+    Loads a ingress yaml file into a python object.
+    """
     path = os.path.join(BASE_DIR, 'ingress.yaml')
     with open(path) as yaml_file:
         content = yaml.safe_load(yaml_file.read())
@@ -47,6 +60,9 @@ def create_ingress_yaml():
 
 
 def create_creator_yaml():
+    """
+    Loads a replication controller yaml file into a python object.
+    """
     orig_path = os.path.join(BASE_DIR, 'aimmo-game-creator', 'rc-aimmo-game-creator.yaml')
     with open(orig_path) as orig_file:
         content = yaml.safe_load(orig_file.read().replace('latest', 'test').replace('REPLACE_ME', 'http://%s:8000/players/api/games/' % get_ip()))
@@ -54,6 +70,10 @@ def create_creator_yaml():
 
 
 def start_cluster(minikube):
+    """
+    Starts the cluster unless it has been already started by the user.
+    :param minikube: Executable minikube installed beforehand.
+    """
     status = run_command([minikube, 'status'], True)
     if 'minikube: Running' in status:
         print('Cluster already running')
@@ -61,19 +81,49 @@ def start_cluster(minikube):
         run_command([minikube, 'start', '--memory=2048', '--cpus=2'])
 
 
+def create_docker_client(raw_env_settings):
+    """
+    Creates a docker client using the python SDK.
+    :param raw_env_settings: String that is returned by the 'minikube docker-env' command.
+    :return:
+    """
+    if vm_none_enabled(raw_env_settings):
+        matches = re.finditer(r'^export (.+)="(.+)"$', raw_env_settings, re.MULTILINE)
+        env_variables = dict([(m.group(1), m.group(2)) for m in matches])
+
+        return docker.from_env(
+            environment=env_variables,
+            version='auto',
+        )
+    else:
+        # VM driver is set
+        return docker.from_env(
+            version='auto'
+        )
+
+
+def vm_none_enabled(raw_env_settings):
+    """
+    Check if the VM driver is enabled or not. This is important to see where
+    the environment variables live.
+    :param raw_env_settings: String that is returned by the 'minikube docker-env' command.
+    :return: Boolean value indicating if enabled or not.
+    """
+    return False if 'driver does not support' in raw_env_settings else True
+
+
 def build_docker_images(minikube):
+    """
+    Finds environment settings and builds docker images for each directory.
+    :param minikube: Executable command to run in terminal.
+    """
     print('Building docker images')
     raw_env_settings = run_command([minikube, 'docker-env', '--shell="bash"'], True)
-    matches = re.finditer(r'^export (.+)="(.+)"$', raw_env_settings, re.MULTILINE)
-    env = dict([(m.group(1), m.group(2)) for m in matches])
 
-    client = docker.from_env(
-        environment=env,
-        version='auto',
-    )
+    client = create_docker_client(raw_env_settings)
 
-    dirs = ('aimmo-game', 'aimmo-game-creator', 'aimmo-game-worker')
-    for dir in dirs:
+    directories = ('aimmo-game', 'aimmo-game-creator', 'aimmo-game-worker')
+    for dir in directories:
         path = os.path.join(BASE_DIR, dir)
         tag = 'ocadotechnology/%s:test' % dir
         print("Building %s..." % tag)
@@ -84,7 +134,13 @@ def build_docker_images(minikube):
         )
 
 
-def restart_pods(game_creator, ingress_yaml):
+def restart_pods(game_creator_yaml, ingress_yaml):
+    """
+    Disables all the components running in the cluster and starts them again
+    with fresh updated state.
+    :param game_creator_yaml: Replication controller yaml settings file.
+    :param ingress_yaml: Ingress yaml settings file.
+    """
     print('Restarting pods')
     kubernetes.config.load_kube_config(context='minikube')
     api_instance = kubernetes.client.CoreV1Api()
@@ -111,12 +167,16 @@ def restart_pods(game_creator, ingress_yaml):
 
     extensions_api_instance.create_namespaced_ingress("default", ingress_yaml)
     api_instance.create_namespaced_replication_controller(
-        body=game_creator,
+        body=game_creator_yaml,
         namespace='default',
     )
 
 
 def start():
+    """
+    The entry point to the minikube class. Sends calls appropriately to set
+    up minikube.
+    """
     if platform.machine().lower() not in ('amd64', 'x86_64'):
         raise ValueError('Requires 64-bit')
     create_test_bin()
diff --git a/aimmo_runner/runner.py b/aimmo_runner/runner.py
--- a/aimmo_runner/runner.py
+++ b/aimmo_runner/runner.py
@@ -45,13 +45,14 @@ def run(use_minikube, server_wait=True, capture_output=False):
 
     server_args = []
     if use_minikube:
-        # Import minikube here, so we can install the deps first
         parent_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
         sys.path.append(os.path.join(parent_dir, 'aimmo_runner'))
 
         os.chdir(ROOT_DIR_LOCATION)
         run_command(['pip', 'install', '-r', os.path.join(ROOT_DIR_LOCATION, 'minikube_requirements.txt')],
                     capture_output=capture_output)
+
+        # Import minikube here, so we can install the deps first
         from aimmo_runner import minikube
         minikube.start()
 


Test patch: