diff --git a/application/opencraft/README.md b/application/opencraft/README.md new file mode 100644 index 0000000..0cbe9cb --- /dev/null +++ b/application/opencraft/README.md @@ -0,0 +1,29 @@ +# Building the Application +Notice that Opencraft is hosted in a private repository. +In order to be able to build Opencraft using Ansible, you need to have a ssh-key added to your key manager that has access to the repository. + +To do that, execute +``` +eval $(ssh-agent) +ssh-add path/to/private/key/with/access +``` + +## Publisher +For the publisher, simply execute the `docker.sh` script to build it. + +To be able to build the _linux/arm64_ architecture, you will need to install Docker Desktop. +Once installed and running, you can check with `docker buildx ls` if a driver is selected that supports the architecture. +This is indicated by the `*` behind the name. +If this is not the case and you see `desktop-linux` in the list, execute +``` +docker buildx create --use desktop-linux +``` +This will create a new driver based on Docker Desktop and select it as the default. +This change does not persist across reboots. + +## Subscriber +For the subscriber, execute +``` +ansible-playbook build_server.yml -v +``` +which will then run Ansible locally to build and push the server/subscriber. diff --git a/application/opencraft/launch_benchmark_kubeedge.yml b/application/opencraft/launch_benchmark_kubeedge.yml new file mode 100644 index 0000000..f3591b8 --- /dev/null +++ b/application/opencraft/launch_benchmark_kubeedge.yml @@ -0,0 +1,26 @@ +--- +- hosts: cloudcontroller + become: true + tasks: + - name: Create job file + template: + src: template_server.yml.j2 + dest: /home/{{ username }}/job-template.yaml + + - name: Create job directory + file: + path: /home/{{ username }}/jobs + state: directory + + - name: Create job multiple times + shell: | + for i in `seq 0 {{ replicas }}` + do + cat "/home/{{ username }}/job-template.yaml" | sed "s/\%ITEM/$i/" \ + > "/home/{{ username }}/jobs/job-$i.yaml" + done + + - name: Launch jobs + command: > + kubectl create --kubeconfig="/home/{{ username }}/.kube/config" + -f "/home/{{ username }}/jobs" diff --git a/application/opencraft/launch_benchmark_kubernetes.yml b/application/opencraft/launch_benchmark_kubernetes.yml new file mode 100644 index 0000000..f3591b8 --- /dev/null +++ b/application/opencraft/launch_benchmark_kubernetes.yml @@ -0,0 +1,26 @@ +--- +- hosts: cloudcontroller + become: true + tasks: + - name: Create job file + template: + src: template_server.yml.j2 + dest: /home/{{ username }}/job-template.yaml + + - name: Create job directory + file: + path: /home/{{ username }}/jobs + state: directory + + - name: Create job multiple times + shell: | + for i in `seq 0 {{ replicas }}` + do + cat "/home/{{ username }}/job-template.yaml" | sed "s/\%ITEM/$i/" \ + > "/home/{{ username }}/jobs/job-$i.yaml" + done + + - name: Launch jobs + command: > + kubectl create --kubeconfig="/home/{{ username }}/.kube/config" + -f "/home/{{ username }}/jobs" diff --git a/application/opencraft/publisher/Dockerfile b/application/opencraft/publisher/Dockerfile new file mode 100644 index 0000000..0b4c00a --- /dev/null +++ b/application/opencraft/publisher/Dockerfile @@ -0,0 +1,15 @@ +FROM node:14.21.1-alpine + +ENV HOST=127.0.0.1 +ENV PORT=25565 +ENV USERNAME=Steve +ENV BOX_WIDTH=500 +ENV NUMBER_STEPS=10000 + +# get dependencies +COPY src/package.json package.json +RUN npm install --loglevel verbose + +COPY src/worker_bot.js worker_bot.js + +CMD node worker_bot.js \ No newline at end of file diff --git a/application/opencraft/publisher/docker.sh b/application/opencraft/publisher/docker.sh new file mode 100755 index 0000000..48246dc --- /dev/null +++ b/application/opencraft/publisher/docker.sh @@ -0,0 +1,2 @@ +#!/bin/bash +docker buildx build --platform linux/amd64,linux/arm64 -t lwagner1/opencraft_benchmark:opencraft_bot --push . diff --git a/application/opencraft/publisher/src/package.json b/application/opencraft/publisher/src/package.json new file mode 100644 index 0000000..69545bf --- /dev/null +++ b/application/opencraft/publisher/src/package.json @@ -0,0 +1,7 @@ +{ + "dependencies": { + "mineflayer": "4.6.0", + "mineflayer-pathfinder": "2.4.2", + "vec3": "0.1.7" + } +} \ No newline at end of file diff --git a/application/opencraft/publisher/src/worker_bot.js b/application/opencraft/publisher/src/worker_bot.js new file mode 100644 index 0000000..2ac3b1c --- /dev/null +++ b/application/opencraft/publisher/src/worker_bot.js @@ -0,0 +1,77 @@ + +const mineflayer = require('mineflayer'); +const pathfinder = require('mineflayer-pathfinder').pathfinder +const Movements = require('mineflayer-pathfinder').Movements +const { GoalNear, GoalXZ } = require('mineflayer-pathfinder').goals +const v = require("vec3"); + +const host = process.env.HOST +const port = parseInt(process.env.PORT) +const username = process.env.USERNAME +const box_width = parseInt(process.env.BOX_WIDTH) +const number_steps = parseInt(process.env.NUMBER_STEPS) + +const upper_limit_random_position = 1000 +let initial_random_x = getRandomInt(upper_limit_random_position) +let initial_random_z = getRandomInt(upper_limit_random_position) +const box_center = v(5, -60, 2); + +function getRandomInt(max) { + return Math.floor(Math.random() * max); +} + +function nextGoal(bot) { + let x = box_center.x + getRandomInt(box_width) - (box_width / 2); + let z = box_center.z + getRandomInt(box_width) - (box_width / 2); + console.log(`${username} should go to ${x} and ${z}`) + //console.log(`bot ${bot.username} should walk from ${bot.entity.position} to ${v(x, bot.entity.position.y, z)}`) + return new GoalXZ(x, z); +} + +function sleep(ms) { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); +} + +console.log(`Creating bot with name ${username} connecting to ${host}:${port}`) +let worker_bot = mineflayer.createBot({ + host: host, // opencraft server ip + username: username, // opencraft username + port: port, // only set if you need a port that isn't 25565 +}); +worker_bot.on('kicked', console.log) +worker_bot.on('error', console.log) +worker_bot.loadPlugin(pathfinder) + + + +worker_bot.once("spawn", async () => { + box_center.x = worker_bot.entity.position.x + box_center.z = worker_bot.entity.position.z + let defaultMove = new Movements(worker_bot) + defaultMove.allowSprinting = false + defaultMove.canDig = false + worker_bot.pathfinder.setMovements(defaultMove) + // worker_bot.pathfinder.thinkTimeout = 60000 // max 60 seconds to find path from start to finish + let step = 0 + while (step < number_steps) { + console.log(step) + let goal = nextGoal(worker_bot); + try { + await worker_bot.pathfinder.goto(goal) + } catch (e) { + // if the bot cannot find a path, carry on and let it try to move somewhere else + if (e.name != "NoPath" && e.name != "Timeout") { + console.log(`${username} died :-(`) + throw e + } + } + step += 1 + } + worker_bot.chat(`${username} is done!`) + worker_bot.quit(`${username} is done!`) + + process.exit(0) +}); +// parentPort.postMessage({}); \ No newline at end of file diff --git a/application/opencraft/subscriber/build_server.yml b/application/opencraft/subscriber/build_server.yml new file mode 100644 index 0000000..f775cce --- /dev/null +++ b/application/opencraft/subscriber/build_server.yml @@ -0,0 +1,48 @@ +--- +- hosts: localhost + connection: local + tasks: + - name: Checkout Opencraft + git: + repo: 'git@github.com:atlarge-research/opencraft-dev.git' + version: 'dev' + dest: '/tmp/opencraft' + + - name: Copy configuration file to server directory + copy: + src: './opencraft.yml' + dest: '/tmp/opencraft/opencraft.yml' + remote_src: true + + - name: Copy start file to server directory + copy: + src: './start.sh' + dest: '/tmp/opencraft/start.sh' + remote_src: true + + - name: Change image to Alpine # Amazon Linux 2 does not have tools installed to kill processes + lineinfile: + path: '/tmp/opencraft/Dockerfile' + search_string: 'FROM amazoncorretto:8' + line: 'FROM amazoncorretto:8-alpine' + + - name: Add configuration file to dockerfile + blockinfile: + path: '/tmp/opencraft/Dockerfile' + insertbefore: 'CMD ["java", "-jar", "opencraft.jar"]' + block: | + COPY --from=builder /usr/src/opencraft/start.sh /usr/local/bin/start.sh + RUN chmod +x /usr/local/bin/start.sh + COPY ./opencraft.yml /config/opencraft.yml + + - name: Output server values # Amazon Linux 2 does not have tools installed to kill processes + lineinfile: + path: '/tmp/opencraft/Dockerfile' + search_string: 'CMD ["java", "-jar", "opencraft.jar"]' + line: 'CMD ["start.sh"]' + + + - name: Build and push image + shell: + cmd: 'docker buildx build --platform linux/amd64 -t lwagner1/opencraft_benchmark:opencraft_server --push .' + chdir: '/tmp/opencraft' diff --git a/application/opencraft/subscriber/opencraft.yml b/application/opencraft/subscriber/opencraft.yml new file mode 100644 index 0000000..d6fc094 --- /dev/null +++ b/application/opencraft/subscriber/opencraft.yml @@ -0,0 +1,149 @@ +# opencraft.yml is the main configuration file for a Opencraft server +# It contains everything from server.properties and bukkit.yml in a +# normal CraftBukkit installation. + +opencraft: + collector: false + logging: + events: true + overload-breaker: false + kludge: + cache-chunks: false + messaging: + type: dyconit + policy: chunk + merge: false + broker: + type: read-write + async: true + threads: 8 + capacity: 2147483647 + channel: unsafe + host: localhost + port: 0 + username: '' + password: '' + virtualHost: '' + chunk-population: + policy: default + filterBCM: 'true' + function: '' + provider: azure + endpoint: '' + storage: + provider: default + sastoken: '' + endpoint: '' + container: '' + cacheregionpolicy: distance + distance: 0 + player-operation: + provider: default + endpoint: '' + time-simulation: + provider: default + endpoint: '' + weather-simulation: + provider: default + endpoint: '' +server: + ip: '' + port: 25565 + name: Opencraft Server + log-file: logs/log-%D.txt + online-mode: false + max-players: 999 + whitelisted: false + motd: An Opencraft server + shutdown-message: Server shutting down. + allow-client-mods: true + dns: [] + log-level: INFO + autosave: true + snooper-enabled: false + prevent-proxy-connections: true +console: + use-jline: false + prompt: '> ' + date-format: HH:mm:ss + log-date-format: yyyy/MM/dd HH:mm:ss + log-level: INFO +game: + gamemode: CREATIVE + gamemode-force: true + difficulty: NORMAL + hardcore: false + pvp: true + max-build-height: 256 + announce-achievements: true + allow-flight: false + command-blocks: false + resource-pack: '' + resource-pack-hash: '' +creatures: + enable: + monsters: false + animals: false + npcs: false + limit: + monsters: 70 + animals: 15 + water: 5 + ambient: 15 + ticks: + monsters: 1 + animal: 400 +folders: + plugins: plugins + update: update + worlds: worlds + libraries: lib +files: + permissions: permissions.yml + commands: commands.yml + help: help.yml +advanced: + connection-throttle: 4000 + idle-timeout: 0 + warn-on-overload: true + exact-login-location: false + plugin-profiling: false + deprecated-verbose: 'false' + compression-threshold: 256 + proxy-support: false + player-sample-count: 12 + graphics-compute: + enable: false + use-any-device: false + region-file: + cache-size: 256 + compression: true + profile-lookup-timeout: 5 + suggest-player-name-when-null-tab-completions: true +extras: + query-enabled: false + query-port: 25614 + query-plugins: true + rcon-enabled: false + rcon-password: opencraft + rcon-port: 25575 + rcon-colors: true +world: + name: world + seed: '' + level-type: FLAT + spawn-radius: 16 + view-distance: 8 + gen-structures: true + allow-nether: true + allow-end: true + keep-spawn-loaded: true + populate-anchored-chunks: true + classic-style-water: false + disable-generation: false +libraries: + checksum-validation: true + repository-url: https://repo1.maven.org/maven2/ + download-attempts: 2 + compatibility-bundle: CRAFTBUKKIT + list: [] diff --git a/application/opencraft/subscriber/start.sh b/application/opencraft/subscriber/start.sh new file mode 100644 index 0000000..54ec4c3 --- /dev/null +++ b/application/opencraft/subscriber/start.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +java -jar opencraft.jar +cat /opencraft-events.log \ No newline at end of file diff --git a/application/opencraft/template_server.yml.j2 b/application/opencraft/template_server.yml.j2 new file mode 100644 index 0000000..a900c56 --- /dev/null +++ b/application/opencraft/template_server.yml.j2 @@ -0,0 +1,35 @@ +apiVersion: v1 +kind: Pod +metadata: + name: {{ app_name }}-%ITEM + labels: + app.kubernetes.io/name: {{ app_name }}-%ITEM + applicationRunning: 'opencraft-server' +spec: + restartPolicy: Never # important so that server can be stopped without making K8 recreate the pod + containers: + - name: {{ app_name }} + image: {{ image }} + ports: + - containerPort: 25565 + name: server-port + imagePullPolicy: Always + resources: + requests: + memory: "{{ memory_req }}Mi" + cpu: {{ cpu_req }} + +--- +apiVersion: v1 +kind: Service +metadata: + name: {{ app_name }}-service-%ITEM +spec: + type: NodePort + selector: + app.kubernetes.io/name: {{ app_name }}-%ITEM + ports: + - name: server-service-port + port: 25565 + nodePort: 3000%ITEM + targetPort: server-port \ No newline at end of file diff --git a/benchmark/output.py b/benchmark/output.py index c819964..99ca546 100644 --- a/benchmark/output.py +++ b/benchmark/output.py @@ -88,6 +88,8 @@ def get_worker_output(config, machines): machines[0].process(config, command, shell=True, ssh=config["cloud_ssh"][0]) command = ["kubectl", "get", "pod", container, "-o", "yaml"] + elif config["benchmark"]["application"] == "opencraft": + command = ["kubectl", "logs", container] commands.append(command) @@ -448,6 +450,57 @@ def gather_endpoint_metrics(config, endpoint_output, container_names): return endpoint_metrics +def gather_worker_metrics_opencraft(worker_output): + """Calculates the average tick rate and its standard deviation per server. + The server captures more than just the tick rate so this method can be adapted to get more metrics. + Args: + worker_output (list(list(str))): Output of each container that ran in cloud/edge. + Element in outer list is the node, element in inner list is a line in the output. + + Returns: + list(dict): List of parsed output for each endpoint + """ + worker_metrics = [] + if worker_output == []: + return worker_metrics + + worker_set = { + "worker_id": None, + "ticks_avg": None, + "ticks_stdev": None, + } + + for i, out in enumerate(worker_output): + logging.info("Parse output from worker node %i", i) + w_metrics = copy.deepcopy(worker_set) + w_metrics["worker_id"] = i + + # skip forward to header, which contains the labels of the columns (timestamp, key, value) + # the first rows are only the logs of the server console which we don't care about :O + idx = 0 + while "timestamp" not in out[idx]: + idx += 1 + + # filter data based on tick + filtered_data = [out[idx].split()] + for row_idx in range(idx + 1, len(out)): + # change the following line to get more metrics captured + row_split = out[row_idx].split() + if "tick" == row_split[1]: + filtered_data.append(row_split) + + # calculate metrics + df = pd.DataFrame(filtered_data[1:], columns=filtered_data[0]) + df["value"] = pd.to_numeric(df["value"]) + # filter before the following lines if you have more than one metric + w_metrics["ticks_avg"] = df["value"].mean() + w_metrics["ticks_stdev"] = df["value"].std() + + worker_metrics.append(w_metrics) + + return sorted(worker_metrics, key=lambda x: x["worker_id"]) + + def gather_metrics(machines, config, worker_output, endpoint_output, container_names, starttime): """Process the raw output to lists of dicts @@ -486,9 +539,15 @@ def gather_metrics(machines, config, worker_output, endpoint_output, container_n worker_metrics = gather_worker_metrics_image(worker_output) elif config["benchmark"]["application"] == "empty": worker_metrics = gather_worker_metrics_empty(config, machines, worker_output, starttime) + elif config["benchmark"]["application"] == "opencraft": + worker_metrics = gather_worker_metrics_opencraft(worker_output) endpoint_metrics = [] - if config["infrastructure"]["endpoint_nodes"]: + # endpoints do not deliver metrics for opencraft + if ( + config["infrastructure"]["endpoint_nodes"] + and config["benchmark"]["application"] != "opencraft" + ): endpoint_metrics = gather_endpoint_metrics(config, endpoint_output, container_names) return worker_metrics, endpoint_metrics @@ -593,15 +652,35 @@ def format_output_image(config, worker_metrics, endpoint_metrics): logging.debug("Output in csv format\n%s", repr(df2.to_csv())) +def format_output_opencraft(config, worker_metrics): + """Pretty-prints the metrics for opencraft into CSV. + + Args: + config (dict): Parsed configuration + worker_metrics (list(dict)): Metrics per worker node + """ + logging.info("------------------------------------") + logging.info("%s OUTPUT", config["mode"].upper()) + logging.info("------------------------------------") + df = pd.DataFrame(worker_metrics) + df_no_indices = df.to_string(index=False) + logging.info("\n%s", df_no_indices) + + # Print ouput in csv format + logging.debug("Output in csv format\n%s", repr(df.to_csv())) + + def format_output(config, worker_metrics, endpoint_metrics): """Format processed output to provide useful insights Args: config (dict): Parsed configuration - sub_metrics (list(dict)): Metrics per worker node + worker_metrics (list(dict)): Metrics per worker node endpoint_metrics (list(dict)): Metrics per endpoint """ if config["benchmark"]["application"] == "image_classification": format_output_image(config, worker_metrics, endpoint_metrics) elif config["benchmark"]["application"] == "empty": format_output_empty(config, worker_metrics) + elif config["benchmark"]["application"] == "opencraft": + format_output_opencraft(config, worker_metrics) diff --git a/benchmark/start.py b/benchmark/start.py index d78d9d5..0d086d6 100644 --- a/benchmark/start.py +++ b/benchmark/start.py @@ -204,6 +204,9 @@ def start_worker(config, machines): app_vars = { "sleep_time": config["benchmark"]["sleep_time"], } + # no extra variables are needed for the opencraft server + elif config["benchmark"]["application"] == "opencraft": + app_vars = {} # Merge the two var dicts all_vars = {**global_vars, **app_vars} @@ -247,6 +250,22 @@ def start_worker(config, machines): # Waiting for the applications to fully initialize (includes scheduling) time.sleep(10) + command = "kubectl wait pods -n default -l applicationRunning=opencraft-server --for condition=Ready --timeout=90s" + output, error = machines[0].process(config, command, shell=True, ssh=config["cloud_ssh"][0])[0] + machines[0].process( + config, + command, + shell=True, + ) + if output: + logging.info(output) + if error: + logging.error(error) + sys.exit() + + if config["benchmark"]["application"] == "opencraft": + busy_wait_opencraft_server(config, machines) + logging.info("Deployed %i %s applications", worker_apps, config["mode"]) logging.info("Wait for subscriber applications to be scheduled and running") @@ -298,6 +317,36 @@ def start_worker(config, machines): return starttime +def busy_wait_opencraft_server(config, machines): + """Scans the logs of all opencraft servers for "Ready for connections" using busy waiting. + There's no timeout, so the application might hang if the servers never become ready. + + Returns once all servers are running. + + Args: + config (dict): Parsed configuration + machines (list(Machine object)): List of machine objects representing physical machines + """ + # get pods + command = "kubectl get pods -l applicationRunning=opencraft-server --no-headers" + output, error = machines[0].process(config, command, shell=True, ssh=config["cloud_ssh"][0])[0] + + # check all servers if they contain + for line in output: + pod_name = line.split()[0] + while True: + command = f"kubectl logs {pod_name}" + output, error = machines[0].process( + config, command, shell=True, ssh=config["cloud_ssh"][0] + )[0] + if error: + logging.error(error) + exit() + + if any("Ready for connections" in o for o in output): + break + + def start_worker_mist(config, machines): """Start running the mist worker subscriber containers using Docker. Wait for them to finish, and get their output. @@ -452,7 +501,15 @@ def start_endpoint(config, machines): ): # Docker container name and variables depends on deployment mode cont_name = "endpoint%i" % (worker_i * end_per_work + endpoint_i) - env = ["FREQUENCY=%i" % (config["benchmark"]["frequency"])] + env = [] + if config["benchmark"]["application"] == "image_classification": + env.append("FREQUENCY=%i" % (config["benchmark"]["frequency"])) + elif config["benchmark"]["application"] == "opencraft": + env.append(f"HOST={worker_ip}") + env.append(f"PORT={30000 + worker_i}") + env.append(f"USERNAME=endpointX{worker_i}X{endpoint_i}") + env.append("BOX_WIDTH=20") + env.append(f"NUMBER_STEPS={config['benchmark']['steps_bot']}") if config["mode"] == "cloud" or config["mode"] == "edge": cont_name = "%s%i_" % (config["mode"], worker_i) + cont_name @@ -500,7 +557,9 @@ def start_endpoint(config, machines): for ssh, (output, error) in zip(sshs, results): logging.debug("Check output of endpoint start in ssh [%s]", ssh) - if error and "Your kernel does not support swap limit capabilities" not in error[0]: + if error and not any( + "Your kernel does not support swap limit capabilities" in line for line in error + ): logging.error("".join(error)) sys.exit() elif not output: @@ -654,6 +713,8 @@ def start(config, machines): # Wait for benchmark to finish if config["mode"] == "cloud" or config["mode"] == "edge": + if config["benchmark"]["application"] == "opencraft": + stop_opencraft(config, machines) if config["benchmark"]["resource_manager"] != "mist": wait_worker_completion(config, machines) else: @@ -678,3 +739,40 @@ def start(config, machines): machines, config, worker_output, endpoint_output, container_names, starttime ) out.format_output(config, worker_metrics, endpoint_metrics) + + +def stop_opencraft(config, machines): + """_summary_ + + Args: + config (_type_): _description_ + machines (_type_): _description_ + count_servers (_type_): _description_ + """ + num_clouds = ( + config["infrastructure"]["cloud_nodes"] - 1 + ) # there is always a cloud controller on which no server is deployed + num_edges = config["infrastructure"]["edge_nodes"] + if num_clouds > 0 and num_edges > 0: + logging.error("opencraft currently only handles setups with servers in cloud xor edge") + sys.exit() + + number_server = max(num_clouds, num_edges) + app_name = config["benchmark"]["application"].replace("_", "-") + for i in range(number_server): + command = ( + '"kubectl exec -it ' + + app_name + + "-" + + str(i) + + " -- /bin/sh -c 'pkill java' " + + '--kubeconfig=/home/cloud_controller/.kube/config"' + ) + output, error = machines[0].process( + config, (command), shell=True, ssh=config["cloud_ssh"][0] + )[0] + if any(output): + logging.info(output) + if any(["input is not a terminal or the right kind of file" not in e for e in error]): + logging.error(error) + sys.exit() diff --git a/configuration/bench_cloud.cfg b/configuration/bench_cloud.cfg index f7e8523..bfd064a 100644 --- a/configuration/bench_cloud.cfg +++ b/configuration/bench_cloud.cfg @@ -3,12 +3,12 @@ [infrastructure] provider = qemu -cloud_nodes = 2 +cloud_nodes = 4 cloud_cores = 4 cloud_memory = 4 cloud_quota = 1.0 -endpoint_nodes = 1 +endpoint_nodes = 6 endpoint_cores = 1 endpoint_memory = 1 endpoint_quota = 0.5 @@ -18,6 +18,7 @@ wireless_network_preset = 4g [benchmark] resource_manager = kubernetes - -application = image_classification -frequency = 5 \ No newline at end of file +docker_pull = True +application = minecraft +frequency = 5 +steps_bot = 10 \ No newline at end of file diff --git a/configuration/template.cfg b/configuration/template.cfg index 70dabe9..8046564 100644 --- a/configuration/template.cfg +++ b/configuration/template.cfg @@ -141,7 +141,7 @@ docker_pull = False # Options: True, False. Default: False # Application to use # Note 1: Empty currently on works with kubernetes-control (experimental) -application = image_classification # Options: image_classification, empty (mandatory) +application = image_classification # Options: image_classification, empty, opencraft (mandatory) # CPU (in cores) and memory (in GB) per application for the cloud/edge worker application_worker_cpu = 3.5 # Options: >= 0.1. Default: cloud_cores - 0.5 @@ -163,6 +163,9 @@ frequency = 5 # Options: >= 1 (mandatory if using this app) # For empty (experimental) sleep_time = 60 # Options: >= 1 (mandatory if using this app) +# For opencraft +steps_bot = 10 # Options: >= 1 (mandatory if using this app) + # Already run your application on the worker once beforehand (experimental) # This guarantees the appliation is cached for the run you want to measure afterward cache_worker = False # Option: True, False (default: False) diff --git a/configuration_parser/start.py b/configuration_parser/start.py index e84b3e6..b2ef3d1 100644 --- a/configuration_parser/start.py +++ b/configuration_parser/start.py @@ -759,7 +759,7 @@ def benchmark(parser, config, new): sec, "application", str, - lambda x: x in ["image_classification", "empty"], + lambda x: x in ["image_classification", "opencraft", "empty"], mandatory=True, ) @@ -850,6 +850,17 @@ def benchmark(parser, config, new): lambda x: x >= 1, mandatory=True, ) + elif new[sec]["application"] == "opencraft": + option_check( + parser, + config, + new, + sec, + "steps_bot", + int, + lambda x: x >= 1, + mandatory=True, + ) option_check( parser, diff --git a/infrastructure/ansible.py b/infrastructure/ansible.py index cdee10b..2baa3a9 100644 --- a/infrastructure/ansible.py +++ b/infrastructure/ansible.py @@ -335,6 +335,16 @@ def copy(config, machines): d = dest + "launch_benchmark.yml" out.append(machines[0].copy_files(config, path, d)) + # copy opencraft template file as well, it uses an extra template file + path = os.path.join( + config["base"], + "application", + config["benchmark"]["application"], + "template_server.yml.j2", + ) + d = dest + "template_server.yml.j2" + out.append(machines[0].copy_files(config, path, d)) + # Copy playbooks for installing resource managers and execution_models if not config["infrastructure"]["infra_only"]: if config["mode"] == "cloud" or config["mode"] == "edge": diff --git a/main.py b/main.py index b7ab093..e148666 100644 --- a/main.py +++ b/main.py @@ -98,6 +98,14 @@ def add_constants(config): } elif config["benchmark"]["application"] == "empty": config["images"] = {"worker": "redplanet00/kubeedge-applications:empty"} + elif config["benchmark"]["application"] == "opencraft": + config["images"] = { + "worker": "lwagner1/opencraft_benchmark:opencraft_server", + "endpoint": "lwagner1/opencraft_benchmark:opencraft_bot", + # this is a hack to avoid infrastructure/start.py/docker_pull to throw a KeyError + # for opencraft, no combined image exists + "combined": "lwagner1/opencraft_benchmark:opencraft_bot", + } # 100.100.100.100 # Prefix .Mid.Post