Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/master' into brand_old_game_page
Browse files Browse the repository at this point in the history
  • Loading branch information
mrniket committed May 15, 2018
2 parents fac692c + 9f2d6c4 commit c071b86
Show file tree
Hide file tree
Showing 7 changed files with 110 additions and 36 deletions.
90 changes: 75 additions & 15 deletions aimmo_runner/minikube.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -40,40 +50,80 @@ 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())
return content


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()))
return content


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')
else:
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)
Expand All @@ -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()
Expand All @@ -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()
Expand Down
3 changes: 2 additions & 1 deletion aimmo_runner/runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()

Expand Down
14 changes: 9 additions & 5 deletions docs/usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,20 +29,24 @@


## Running with Kubernetes with containers
**64bit environment is required for this mode!**
* Follow the instructions at [game frontend documentation](https://github.com/ocadotechnology/aimmo/blob/master/game_frontend/README.md) in order to install all the frontend requirements.
* By default, the local environment runs each worker in a Python thread. However, for some testing, it is useful to run as a Kubernetes cluster. Note that this is not for most testing, the default is more convenient as the Kubernetes cluster is slow and runs into resource limits with ~10 avatars.
* Linux, Windows (minikube is experimental though), and OSX (untested) are supported.
* By default, the local environment runs each worker in a Python thread. This is the closest mode that reflects the environment in production. However, this will require much more resources.
* Linux, Windows, and OSX.
* Prerequisites:
* All platforms: VT-x/AMD-v virtualization.
* Linux: [Virtualbox](https://www.virtualbox.org/wiki/Downloads).
* OSX: either [Virtualbox](https://www.virtualbox.org/wiki/Downloads) or [VMWare Fusion](http://www.vmware.com/products/fusion.html).
* Download Docker, Minikube, and Kubectl before running the script.
* On Mac ([download homebrew](https://brew.sh/)) and run `brew update && brew install kubectl && brew cask install docker minikube virtualbox`.
* To download Docker, Minikube, and Kubectl before running the script.
* On Mac ([download homebrew](https://brew.sh/)) and run `brew update && brew cask install docker virtualbox`.
* Install a fixed minikube version (at the time of this article this is 0.25.2 but you can confirm that [here](https://github.com/ocadotechnology/aimmo/blob/b0fd1bf852b1b2630a8546d173798ec9a670c480/.travis.yml#L23)). To do this write
`curl -Lo minikube https://storage.googleapis.com/minikube/releases/v0.25.2/minikube-darwin-amd64 && chmod +x minikube && sudo mv minikube /usr/local/bin/
` and replace the version with the desired one.
* On Ubuntu ([download snap](https://snapcraft.io/)) and run `sudo snap install kubectl --classic` then follow the ([docker installation instructions](https://docs.docker.com/install/linux/docker-ce/ubuntu/)).
* On Windows ([download chocolatey](https://chocolatey.org/)) and run `choco install kubernetes-cli` followed by the ([docker installation instructions for Windows](https://docs.docker.com/docker-for-windows/)).
* Alter your `/etc/hosts` file by adding the following to the end of the file: `192.168.99.100 local.aimmo.codeforlife.education`. You may be required to run this with `sudo` as the file is protected.
* Usage: `python run.py -k`. This will:
* Run `minikube start` (if the cluster is not already running).
* Run `minikube start --memory=2048 -cpus=2`. Feel free to change these values appropriately to your specifiation.
* Images are built and a aimmo-game-creator is created in your cluster. You can preview this in your kubernetes dashboard. Run `minikube dashboard` to open this.
* Perform the same setup that run.py normally performs.
* Start the Django project (which is not kubernetes controlled) on localhost:8000.
Expand Down
7 changes: 6 additions & 1 deletion players/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,9 @@
class AddGameForm(ModelForm):
class Meta:
model = Game
exclude = ['Main', 'owner', 'auth_token', 'completed', 'main_user', 'static_data', 'can_play']
exclude = ['Main', 'owner', 'auth_token', 'completed', 'main_user', 'static_data', 'can_play',
'public', 'generator', 'target_num_cells_per_avatar',
'target_num_score_locations_per_avatar', 'score_despawn_chance',
'target_num_pickups_per_avatar', 'pickup_spawn_chance', 'obstacle_ratio',
'start_height', 'start_width'
]
3 changes: 1 addition & 2 deletions players/management/commands/generate_players.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,8 @@ def _get_available_code_files(base_directory):

_AVATAR_CODES = list(_get_available_code_files(_AVATAR_CODES_DIRECTORY))

# Code file loading


# Code file loading
def _load_code_file(filename):
if not filename.endswith('.py'):
filename = filename + '.py'
Expand Down
10 changes: 5 additions & 5 deletions players/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,12 @@ class Game(models.Model):
generator = models.CharField(max_length=20, choices=GAME_GENERATORS, default=GAME_GENERATORS[0][0])
target_num_cells_per_avatar = models.FloatField(default=16)
target_num_score_locations_per_avatar = models.FloatField(default=0.5)
score_despawn_chance = models.FloatField(default=0.02)
target_num_pickups_per_avatar = models.FloatField(default=0.5)
pickup_spawn_chance = models.FloatField(default=0.02)
score_despawn_chance = models.FloatField(default=0.05)
target_num_pickups_per_avatar = models.FloatField(default=1.2)
pickup_spawn_chance = models.FloatField(default=0.1)
obstacle_ratio = models.FloatField(default=0.1)
start_height = models.IntegerField(default=11)
start_width = models.IntegerField(default=11)
start_height = models.IntegerField(default=31)
start_width = models.IntegerField(default=31)

@property
def is_active(self):
Expand Down
19 changes: 12 additions & 7 deletions players/templates/players/add_game.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,17 @@
{% load bootstrap_tags %}

{% block content %}
<h1>Add a new game</h1>
<form action="" method="post">
{% csrf_token %}
<div class="form-actions">
{{ form|as_bootstrap }}
<input type="submit" value="Submit" class="btn btn-primary">
<div class="row">
<div class="col-md-6 col-md-offset-3">
<h1>Add a new game</h1>
<form action="" method="post">
{% csrf_token %}
<div class="form-actions">
{{ form|as_bootstrap }}
<input type="submit" value="Submit" class="btn btn-primary">
</div>
</form>
</div>
</form>
</div>

{% endblock %}

0 comments on commit c071b86

Please sign in to comment.