示例#1
0
def arena_landing(workout_id):
    workout = ds_client.get(ds_client.key('cybergym-workout', workout_id))
    unit = ds_client.get(ds_client.key('cybergym-unit', workout['unit_id']))

    student_instructions_url = None
    if 'student_instructions_url' in workout:
        student_instructions_url = workout['student_instructions_url']

    assessment = guac_user = guac_pass = flags_found = None

    if 'workout_user' in workout:
        guac_user = workout['workout_user']
    if 'workout_password' in workout:
        guac_pass = workout['workout_password']
    if 'assessment' in workout:
        try:
            assessment, assessment_type = get_assessment_questions(workout)
        except TypeError:
            print("type errors")

    if (request.method == "POST"):
        return process_assessment(workout, workout_id, request, assessment)

    return render_template('arena_landing.html',
                           description=unit['description'],
                           assessment=assessment,
                           running=workout['running'],
                           unit_id=workout['unit_id'],
                           dns_suffix=dns_suffix,
                           guac_user=guac_user,
                           guac_pass=guac_pass,
                           arena_id=workout_id,
                           student_instructions=student_instructions_url)
    def commit_to_cloud(self):
        """
        Commits the parsed workout specification for multiple student builds to the cloud datastore.
        This first stores the unit to the datastore and then all the individual builds
        @return: None
        """
        cloud_log(LogIDs.MAIN_APP, f"Creating unit {self.unit_id}",
                  LOG_LEVELS.INFO)
        new_unit = datastore.Entity(
            ds_client.key('cybergym-unit', self.unit_id))
        new_unit.update(self.new_unit)

        workout_ids = []
        for cloud_ready_spec in self.cloud_ready_specs:
            workout_id = ''.join(
                random.choice(string.ascii_lowercase) for i in range(10))
            workout_ids.append(workout_id)
            new_workout = datastore.Entity(
                ds_client.key('cybergym-workout', workout_id))
            new_workout.update(cloud_ready_spec)
            ds_client.put(new_workout)
            # Store the server specifications for compute workouts
            if self.build_type == BuildTypes.COMPUTE:
                self._commit_workout_servers(workout_id, new_workout)
        new_unit['workouts'] = workout_ids
        ds_client.put(new_unit)
        # If this is an arena, then store all server configurations at this time.
        if self.build_type == BuildTypes.ARENA:
            CompetitionServerSpecToCloud(
                unit=new_unit,
                workout_ids=workout_ids,
                workout_specs=self.cloud_ready_specs).commit_to_cloud()

        return {'unit_id': self.unit_id, 'build_type': self.build_type}
def pub_manage_server(server_name, action, topic_name="manage-server"):
    server = ds_client.get(ds_client.key('cybergym-server', server_name))
    workout_id = server.get('workout', None)
    workout = ds_client.get(ds_client.key('cybergym-workout', workout_id))
    build_project_location = workout.get('build_project_location', project)

    publisher = pubsub_v1.PublisherClient()
    topic_path = publisher.topic_path(build_project_location, topic_name)
    publisher.publish(topic_path,
                      data=b'Server Build',
                      action=action.encode('utf-8'),
                      server_name=server_name)
示例#4
0
def nuke_workout(workout_id):
    #Get workout information
    workout = ds_client.get(ds_client.key('cybergym-workout', workout_id))
    unit = ds_client.get(ds_client.key('cybergym-unit', workout['unit_id']))
    #Create new workout of same type
    workout_type = workout['type']
    unit_name = unit['unit_name']
    unit_id = workout['unit_id']

    submitted_answers = None
    if 'submitted_answers' in workout:
        submitted_answers = workout['submitted_answers']
    if 'expiration' in unit:
        expiration = unit['expiration']
    else:
        expiration = 0
    instructor_id = workout['user_email']
    yaml_string = parse_workout_yaml(workout_type)
    unit_id, build_type, new_id = process_workout_yaml(yaml_string,
                                                       workout_type, unit_name,
                                                       1, expiration,
                                                       instructor_id, unit_id)

    if submitted_answers:
        new_workout = ds_client.get(ds_client.key('cybergym-workout', new_id))
        new_workout['submitted_answers'] = submitted_answers

    unit_id = workout['unit_id']
    #Get new workout information
    response = {
        "unit_id": unit_id,
        "build_type": build_type,
        "workout_id": new_id
    }

    if build_type == 'compute':
        pub_build_single_workout(
            workout_id=new_id,
            topic_name=workout_globals.ps_build_workout_topic)

    if workout_id in unit['workouts']:
        unit['workouts'].remove(workout_id)
    unit['workouts'].append(new_id)
    ds_client.put(unit)

    workout['misfit'] = True
    ds_client.put(workout)

    return json.dumps(response)
示例#5
0
def complete_verification():
    if (request.method == 'POST'):
        workout_request = request.get_json(force=True)

        workout_id = workout_request['workout_id']
        token = workout_request['token']
        workout = ds_client.get(ds_client.key('cybergym-workout', workout_id))

        token_exists = next(item for item in workout['assessment']['questions']
                            if item['key'] == token)
        token_pos = next(
            (i for i, item in enumerate(workout['assessment']['questions'])
             if item['key'] == token), None)
        if token_exists:
            logger.info(
                "Completion token matches. Setting the workout question %d to complete."
                % token_pos)
            workout['assessment']['questions'][token_pos]['complete'] = True
            ds_client.put(workout)
            logger.info('%s workout question %d marked complete.' %
                        (workout_id, token_pos + 1))
            return 'OK', 200
        else:
            logger.info(
                "In complete_verification: Completion key %s does NOT exist in assessment dict! Aborting"
                % token)
def change_workout_state():
    if request.method == 'POST':
        request_data = request.get_json(force=True)
        response = {}
        response['workout_id'] = request_data['workout_id']
        response['new_state'] = request_data['new_state']

        workout = ds_client.get(
            ds_client.key('cybergym-workout', request_data['workout_id']))
        if 'state' in workout:
            previous_state = workout['state']
        workout['state'] = request_data['new_state']
        g_logger = log_client.logger('admin-app')
        g_logger.log_struct(
            {
                "message":
                "Workout {} state override: {} to {}".format(
                    request_data['workout_id'], previous_state,
                    request_data['new_state']),
                "previous_state":
                str(previous_state),
                "new_state":
                str(request_data['new_state']),
                "workout":
                str(request_data['workout_id'])
            },
            severity=LOG_LEVELS.INFO)
        ds_client.put(workout)
        return json.dumps(response)
示例#7
0
def arena_list(unit_id):
    unit = ds_client.get(ds_client.key('cybergym-unit', unit_id))
    build_type = unit['build_type']
    workout_url_path = unit['workout_url_path']
    workout_list = get_unit_workouts(unit_id)

    teacher_instructions_url = None
    if 'teacher_instructions_url' in unit:
        teacher_instructions_url = unit['teacher_instructions_url']

    student_instructions_url = None
    if 'student_instructions_url' in unit:
        student_instructions_url = unit['student_instructions_url']

    start_time = None
    if 'start_time' in unit:
        start_time = unit['start_time']
        # start_time = time.gmtime(start_time)
    unit_teams = None
    if 'teams' in unit:
        unit_teams = unit['teams']
    if (request.method == "POST"):
        return json.dumps(unit)

    if unit:
        return render_template('arena_list.html',
                               unit_teams=unit_teams,
                               teacher_instructions=teacher_instructions_url,
                               workout_list=workout_list,
                               student_instructions=student_instructions_url,
                               description=unit['description'],
                               unit_id=unit_id,
                               start_time=start_time)
示例#8
0
def workout_list(unit_id):
    unit = ds_client.get(ds_client.key('cybergym-unit', unit_id))
    build_type = unit['build_type']
    workout_url_path = unit['workout_url_path']
    workout_list = get_unit_workouts(unit_id)

    teacher_instructions_url = None
    if 'teacher_instructions_url' in unit:
        teacher_instructions_url = unit['teacher_instructions_url']

    #For updating individual workout ready state
    if (request.method == "POST"):
        if build_type == 'arena':
            return json.dumps(unit)
        return json.dumps(workout_list)

    if unit and len(str(workout_list)) > 0:
        return render_template('workout_list.html',
                               build_type=build_type,
                               workout_url_path=workout_url_path,
                               workout_list=workout_list,
                               unit_id=unit_id,
                               description=unit['description'],
                               teacher_instructions=teacher_instructions_url)
    else:
        return render_template('no_workout.html')
示例#9
0
def store_workout_info(workout_id, unit_id, user_mail, workout_duration,
                       workout_type, networks, servers, routes, firewall_rules,
                       assessment, student_instructions_url, student_entry):
    ts = str(calendar.timegm(time.gmtime()))
    new_workout = datastore.Entity(
        ds_client.key('cybergym-workout', workout_id))

    new_workout.update({
        'unit_id': unit_id,
        'user_email': user_mail,
        'student_instructions_url': student_instructions_url,
        'expiration': workout_duration,
        'type': workout_type,
        'start_time': ts,
        'run_hours': 0,
        'timestamp': ts,
        'resources_deleted': False,
        'running': False,
        'misfit': False,
        'networks': networks,
        'servers': servers,
        'routes': routes,
        'firewall_rules': firewall_rules,
        'assessment': assessment,
        'complete': False,
        'student_entry': student_entry
    })

    ds_client.put(new_workout)
示例#10
0
def unit_signup(unit_id):
    unit = ds_client.get(ds_client.key('cybergym-unit', unit_id))
    if request.method == 'POST':
        workout_query = ds_client.query(kind='cybergym-workout')
        workout_query.add_filter('unit_id', '=', unit_id)
        claimed_workout = None
        for workout in list(workout_query.fetch()):
            if 'student_name' in workout:
                if workout['student_name'] == None or workout[
                        'student_name'] == "":
                    with ds_client.transaction():
                        claimed_workout = workout
                        claimed_workout['student_name'] = request.form[
                            'student_name']
                        ds_client.put(claimed_workout)
                        if unit['build_type'] == 'arena':
                            return redirect('/student/arena_landing/%s' %
                                            claimed_workout.key.name)
                        else:
                            return redirect('/student/landing/%s' %
                                            claimed_workout.key.name)
            else:
                with ds_client.transaction():
                    claimed_workout = workout
                    claimed_workout['student_name'] = request.form[
                        'student_name']
                    ds_client.put(claimed_workout)
                    if unit['build_type'] == 'arena':
                        return redirect('/student/arena_landing/%s' %
                                        claimed_workout.key.name)
                    else:
                        return redirect('/student/landing/%s' %
                                        claimed_workout.key.name)
        return render_template('unit_signup.html', unit_full=True)
    return render_template('unit_signup.html')
def register_workout_update(project, dnszone, workout_id, old_ip, new_ip):
    service = googleapiclient.discovery.build('dns', 'v1')

    key = ds_client.key('cybergym-workout', workout_id)
    workout = ds_client.get(key)
    change_body = {
        "deletions": [{
            "kind": "dns#resourceRecordSet",
            "name": workout_id + dns_suffix + ".",
            "rrdatas": [old_ip],
            "type": "A",
            "ttl": 30
        }],
        "additions": [{
            "kind": "dns#resourceRecordSet",
            "name": workout_id + dns_suffix + ".",
            "rrdatas": [new_ip],
            "type": "A",
            "ttl": 30
        }]
    }

    request = service.changes().create(project=project,
                                       managedZone=dnszone,
                                       body=change_body)
    response = request.execute()

    workout["external_ip"] = new_ip
    ds_client.put(workout)
def get_arena_ip_addresses_for_workout(workout_id):
    """
    Returns the server to local IP address mapping for a given arena and student workout. Not all servers have a
    direct guacamole connection, and the IP addresses are displayed to the student for jumping to other hosts
    from their landing server.
    :param workout_id: The Workout ID associated with the given arena
    """
    workout = ds_client.get(ds_client.key('cybergym-workout', workout_id))
    unit_id = workout['unit_id']
    arena_servers = []
    for server_spec in workout['student_servers']:
        server = ds_client.get(
            ds_client.key('cybergym-server',
                          f"{workout_id}-{server_spec['name']}"))
        if server:
            server_to_ip = {'name': server_spec['name']}
            nics = []
            for interface in server['config']['networkInterfaces']:
                nic = {
                    'network': path.basename(interface['subnetwork']),
                    'ip': interface['networkIP']
                }
                nics.append(nic)
            server_to_ip['nics'] = nics
            arena_servers.append(server_to_ip)

    # Also include any additional shared servers in the arena
    unit = ds_client.get(ds_client.key('cybergym-unit', unit_id))
    if 'arena' in unit and 'servers' in unit['arena'] and unit['arena'][
            'servers']:
        for server_spec in unit['arena']['servers']:
            server = ds_client.get(
                ds_client.key('cybergym-server',
                              f"{unit_id}-{server_spec['name']}"))
            if server:
                server_to_ip = {'name': server['name']}
                nics = []
                for interface in server['config']['networkInterfaces']:
                    nic = {
                        'network': path.basename(interface['subnetwork']),
                        'ip': interface['networkIP']
                    }
                    nics.append(nic)
                server_to_ip['nics'] = nics
                arena_servers.append(server_to_ip)

    return arena_servers
def store_comment(comment_email, comment_subject, comment_text):
    new_comment = datastore.Entity(ds_client.key('cybergym-comments'))
    new_comment['comment_email'] = comment_email
    new_comment['subject'] = comment_subject
    new_comment['comment_text'] = comment_text
    new_comment['message_viewed'] = False
    new_comment['date'] = datetime.datetime.now()
    ds_client.put(new_comment)
def pub_stop_vm(workout_id, topic_name='stop-vm'):
    publisher = pubsub_v1.PublisherClient()
    workout = ds_client.get(ds_client.key('cybergym-workout', workout_id))
    build_project_location = workout.get('build_project_location', project)
    topic_path = publisher.topic_path(build_project_location, topic_name)
    data = 'Cyber Gym VM Stop Request'
    publisher.publish(topic_path,
                      data=data.encode('utf-8'),
                      workout_id=workout_id)
 def __init__(self, workout_id):
     self.workout_id = workout_id
     self.workout = ds_client.get(
         ds_client.key('cybergym-workout', self.workout_id))
     self.assessment_info = self.workout[
         'assessment'] if 'assessment' in self.workout else None
     self.submitted_answers = self.workout[
         'submitted_answers'] if 'submitted_answers' in self.workout else None
     self.uploaded_files = self.workout[
         'uploaded_files'] if 'uploaded_files' in self.workout else []
     """
         Get workout build type to determine how to process assessment submissions
             - Arena submissions add points to all workouts assigned to the same team
             - Regular workouts simply store the submitted answer / files in the datastore
     """
     unit = ds_client.get(
         ds_client.key('cybergym-unit', self.workout['unit_id']))
     self.workout_build_type = unit['build_type']
def change_workout_expiration():
    if request.method == "POST":
        request_data = request.get_json(force=True)
        if 'workout_id' in request_data:
            workout = ds_client.get(
                ds_client.key('cybergym-workout', request_data['workout_id']))
            workout['expiration'] = request_data['new_expiration']
            ds_client.put(workout)
        return json.dumps(str("Test"))
 def __init__(self, unit_id):
     self.allocation = {}
     self.unit_id = unit_id
     self.unit = ds_client.get(ds_client.key('cybergym-unit', unit_id))
     unit_workouts = ds_client.query(kind='cybergym-workout')
     unit_workouts.add_filter("unit_id", "=", unit_id)
     self.workouts = list(unit_workouts.fetch())
     self.workout_count = len(self.workouts)
     self.remaining_count = self.workout_count
def store_student_feedback(feedback, workout_id):
    student_feedback = datastore.Entity(
        ds_client.key('cybergym-student-feedback', workout_id))

    for key in feedback.keys():
        student_feedback[key] = feedback[key]
    ds_client.put(student_feedback)
    print(student_feedback)
    return student_feedback
示例#19
0
def admin_workout(workout_id):
    workout = ds_client.get(ds_client.key('cybergym-workout', workout_id))
    if workout:
        workout_server_query = ds_client.query(kind='cybergym-server')
        workout_server_query.add_filter('workout', '=', workout_id)
        server_list = []
        for server in list(workout_server_query.fetch()):
            server_list.append(server)
        return render_template('admin_workout.html', workout=workout, servers=server_list)
    else:
        abort(404)
def store_class_info(teacher_email, num_students, class_name, student_auth):
    new_class = datastore.Entity(ds_client.key('cybergym-class'))

    new_class['teacher_email'] = teacher_email
    class_roster = []
    for i in range(int(num_students)):
        class_roster.append("Student {}".format(i + 1))
    new_class['roster'] = class_roster
    new_class['class_name'] = class_name
    new_class['student_auth'] = student_auth
    ds_client.put(new_class)
def pub_nuke_workout(workout_id):
    workout = ds_client.get(ds_client.key('cybergym-workout', workout_id))
    build_project_location = workout.get('build_project_location', project)

    publisher = pubsub_v1.PublisherClient()
    topic_path = publisher.topic_path(build_project_location,
                                      PUBSUB_TOPICS.BUILD_WORKOUTS)
    data = "Workout nuke and rebuild request"
    publisher.publish(topic_path,
                      data=data.encode("utf-8"),
                      workout_id=workout_id,
                      action=WORKOUT_ACTIONS.NUKE)
示例#22
0
def arena_landing(workout_id):
    workout = ds_client.get(ds_client.key('cybergym-workout', workout_id))
    unit = ds_client.get(ds_client.key('cybergym-unit', workout['unit_id']))
    arena_server_info = get_arena_ip_addresses_for_workout(workout_id)
    assessment_manager = CyberArenaAssessment(workout_id)
    student_instructions_url = None
    if 'student_instructions_url' in workout:
        student_instructions_url = workout['student_instructions_url']
    formatted_instruction_url = student_instructions_url
    assessment = guac_user = guac_pass = flags_found = None

    if 'workout_user' in workout:
        guac_user = workout['workout_user']
    if 'workout_password' in workout:
        guac_pass = workout['workout_password']
    if 'assessment' in workout:
        try:
            assessment = assessment_manager.get_assessment_questions()
        except TypeError:
            g_logger = log_client.logger('cybergym-app-errors')
            g_logger.log_text(
                "TypeError encountered when submitting assessment for arena {}"
                .format(workout_id),
                severity=LOG_LEVELS.INFO)

    if (request.method == "POST"):
        attempt = assessment_manager.submit()
        return jsonify(attempt)

    return render_template('arena_landing.html',
                           description=unit['description'],
                           unit_id=unit.key.name,
                           assessment=assessment,
                           workout=workout,
                           dns_suffix=dns_suffix,
                           guac_user=guac_user,
                           guac_pass=guac_pass,
                           arena_id=workout_id,
                           student_instructions=formatted_instruction_url,
                           server_info=arena_server_info)
    def _get_build_allocation(self):
        """
        Identify the build allocation among the parent and all children based on available resources and identified
        quotas.
        @param workout_count: Number of workouts to build in this request
        @type workout_count: Integer
        @return: The parent/or children projects to use, which may split across multiple projects
        @rtype: Dict {'<parent>': 80, '<child1>': 300, '<child2>': 300}
        """
        # First, get all available projects.
        available = {project: self.MAX_BUILDS}
        admin_info = ds_client.get(
            ds_client.key(AdminInfoEntity.KIND, 'cybergym'))
        if AdminInfoEntity.Entities.CHILD_PROJECTS in admin_info:
            for child_project in admin_info[
                    AdminInfoEntity.Entities.CHILD_PROJECTS]:
                available[child_project] = self.MAX_BUILDS

        # Next find all active workouts for the application
        query_workouts = ds_client.query(kind='cybergym-workout')
        query_workouts.add_filter('active', '=', True)

        # Determine the available build left for each parent and children projects.
        for workout in list(query_workouts.fetch()):
            workout_project = workout.get('build_project_location', project)
            if workout_project not in available:
                cloud_log(
                    LogIDs.MAIN_APP,
                    f"Error in workout specification. The project {workout_project} is not "
                    f"a valid project for this application.", LOG_LEVELS.ERROR)
                return False
            available[workout_project] -= 1

        # Set the build allocation for this project based on availability.
        for _project in available:
            workouts_available = available[_project]
            if workouts_available > 0:
                _project_allocation = min(self.remaining_count,
                                          workouts_available)
                self.allocation[_project] = _project_allocation
                self.remaining_count -= _project_allocation

        if self.remaining_count > 0:
            cloud_log(
                LogIDs.MAIN_APP,
                "Error: Not enough available resources to complete the build!",
                LOG_LEVELS.ERROR)
            return False
        else:
            return True
示例#24
0
def stop_workout(workout_id):
    result = compute.instances().list(project=project, zone=zone,
                                      filter='name = {}*'.format(workout_id)).execute()
    workout = ds_client.get(ds_client.key('cybergym-workout', workout_id))
    workout['state'] == "READY"
    ds_client.put(workout)
    if 'items' in result:
        for vm_instance in result['items']:
            response = compute.instances().stop(project=project, zone=zone,
                                                instance=vm_instance["name"]).execute()

        print("Workouts stopped")
    else:
        print("No workouts to stop")
示例#25
0
def check_user_level():
    if (request.method == 'POST'):
        user_info = request.get_json(force=True)
        admin_info = ds_client.get(
            ds_client.key('cybergym-admin-info', 'cybergym'))
        response = {'authorized': False, 'admin': False}

        if user_info['user_email']:
            if user_info['user_email'] in admin_info['authorized_users']:
                response['authorized'] = True
                if user_info['user_email'] in admin_info['admins']:
                    response['admin'] = True
            else:
                if user_info['user_email'] not in admin_info['pending_users']:
                    admin_info['pending_users'].append(user_info['user_email'])
                    ds_client.put(admin_info)
        return json.dumps(response)
示例#26
0
def store_unit_info(id, email, unit_name, workout_name, build_type, ts,
                    workout_url_path, teacher_instructions_url,
                    workout_description):
    new_unit = datastore.Entity(ds_client.key('cybergym-unit', id))

    new_unit.update({
        "unit_name": unit_name,
        "build_type": build_type,
        "workout_name": workout_name,
        "instructor_id": email,
        "timestamp": ts,
        'workout_url_path': workout_url_path,
        "description": workout_description,
        "teacher_instructions_url": teacher_instructions_url,
        "workouts": []
    })

    ds_client.put(new_unit)
示例#27
0
def start_all():
    if (request.method == 'POST'):
        unit_id = request.form['unit_id']
        workout_list = get_unit_workouts(unit_id)
        t_list = []
        for workout_id in workout_list:
            workout = ds_client.get(
                ds_client.key('cybergym-workout', workout_id['name']))
            if 'time' not in request.form:
                workout['run_hours'] = 2
            else:
                workout['run_hours'] = min(int(request.form['time']),
                                           workout_globals.MAX_RUN_HOURS)
            ds_client.put(workout)

            pub_start_vm(workout_id['name'])

        return redirect("/workout_list/%s" % (unit_id))
示例#28
0
def start_arena():
    if request.method == 'POST':
        unit_id = request.form['unit_id']
        arena_unit = ds_client.get(ds_client.key('cybergym-unit', unit_id))
        if 'time' not in request.form:
            arena_unit['arena']['run_hours'] = 2
        else:
            arena_unit['arena']['run_hours'] = min(
                int(request.form['time']), workout_globals.MAX_RUN_HOURS)
        ds_client.put(arena_unit)
        start_time = time.gmtime(time.time())
        time_string = str(start_time[3]) + ":" + str(
            start_time[4]) + ":" + str(start_time[5])
        print(time_string)
        arena_unit['start_time'] = time_string
        ds_client.put(arena_unit)
        pub_start_vm(unit_id, 'start-arena')
    return redirect('/arena_list/%s' % (unit_id))
 def __init__(self):
     self.admin_info = ds_client.get(
         ds_client.key('cybergym-admin-info', 'cybergym'))
     if self.UserGroups.ADMINS not in self.admin_info:
         admin_email = myconfig.get_variable.config('admin_email')
         if not admin_email:
             cloud_log(LogIDs.MAIN_APP,
                       f"Error: Admin Email is not set for this project!",
                       LOG_LEVELS.ERROR)
         else:
             self.admin_info[self.UserGroups.ADMINS] = [admin_email]
     if self.UserGroups.AUTHORIZED not in self.admin_info:
         self.admin_info[self.UserGroups.AUTHORIZED] = []
     if self.UserGroups.STUDENTS not in self.admin_info:
         self.admin_info[self.UserGroups.STUDENTS] = []
     if self.UserGroups.PENDING not in self.admin_info:
         self.admin_info[self.UserGroups.PENDING] = []
     ds_client.put(self.admin_info)
示例#30
0
 def _update_build_spec(self):
     """
     Add credentials for the student entry to the workout, and add a default firewall rule to allow access
     to the student entry server.
     When the build type is an arena, each workout in the arena needs to have added the recently generated
     credentials.
     @param credentials: Credentials for users in a given build
     @type credentials: list of dict
     @param network_name: The name of the network the student entry server resides in
     @type: str
     @return: Status
     @rtype: bool
     """
     # Build the firewall rule to allow external access to the student entry.
     firewall_rule = {
         'name': 'allow-student-entry',
         'network': self.student_entry_network,
         'target_tags': ['student-entry'],
         'protocol': None,
         'ports': ['tcp/80,8080,443'],
         'source_ranges': ['0.0.0.0/0']
     }
     if self.type == BuildTypes.COMPUTE:
         if len(self.student_credentials) > 1:
             self.build['workout_credentials'] = self.student_credentials
         else:
             self.build['workout_user'] = self.student_credentials[0][
                 'workout_user']
             self.build['workout_password'] = self.student_credentials[0][
                 'workout_password']
         self.build['firewall_rules'].append(firewall_rule)
     elif self.type == BuildTypes.ARENA:
         for credential in self.student_credentials:
             workout_id = credential['workout_id']
             student_user = credential['workout_user']
             student_password = credential['workout_password']
             workout = ds_client.get(
                 ds_client.key('cybergym-workout', workout_id))
             workout['workout_user'] = student_user
             workout['workout_password'] = student_password
             ds_client.put(workout)
         self.build['arena']['firewall_rules'].append(firewall_rule)
     ds_client.put(self.build)
     return True