Class: CoursemologyDockerContainer

Inherits:
Docker::Container
  • Object
show all
Defined in:
lib/autoload/coursemology_docker_container.rb

Defined Under Namespace

Classes: DockerAttachBlock

Constant Summary collapse

HOME_PATH =

The path to the Coursemology user home directory.

'/home/coursemology'
PACKAGE_PATH =

The path to where the package will be extracted.

File.join(HOME_PATH, 'package')
REPORT_PATH =

With the old Makefile, the path to where the test report will be at.

File.join(PACKAGE_PATH, 'report.xml')
PUBLIC_REPORT_PATH =

With new Makefile targets, paths to the test group report files.

File.join(PACKAGE_PATH, 'report-public.xml')
PRIVATE_REPORT_PATH =
File.join(PACKAGE_PATH, 'report-private.xml')
EVALUATION_REPORT_PATH =
File.join(PACKAGE_PATH, 'report-evaluation.xml')
REPORT_PATHS =
{ 'report': REPORT_PATH,
'public': PUBLIC_REPORT_PATH,
'private': PRIVATE_REPORT_PATH,
'evaluation': EVALUATION_REPORT_PATH }.freeze
CONTAINER_MEMORY_LIMIT =

Maximum amount of memory the docker container can use. Enforced by Docker. https://docs.docker.com/engine/admin/resource_constraints/

128.megabytes
LOG_CONFIG =

Docker logs capture stdout, which can take up a lot of disk space on the host if student code has print statements in infinite loops. Set a maximum size for the stdout log which is retained by Docker. https://docs.docker.com/engine/admin/logging/json-file/

{ 'Type' => 'json-file',
'Config' => { 'max-size' => '10m', 'max-file' => '2' } }.freeze

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.create(image, argv: nil) ⇒ Object


36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/autoload/coursemology_docker_container.rb', line 36

def create(image, argv: nil)
  pull_image(image) unless Docker::Image.exist?(image)

  ActiveSupport::Notifications.instrument('create.docker.evaluator.coursemology',
                                          image: image) do |payload|
    options = { 'Image' => image }
    options['Cmd'] = argv if argv.present?
    options['HostConfig'] = { 'memory' => CONTAINER_MEMORY_LIMIT, 'LogConfig' => LOG_CONFIG }

    payload[:container] = super(options)
  end
end

Instance Method Details

#copy_package(package) ⇒ Object

Copies the contents of the package to the container.

Parameters:

  • package (String)

    The path to the package.


99
100
101
102
103
104
# File 'lib/autoload/coursemology_docker_container.rb', line 99

def copy_package(package)
  tar = tar_package(package)
  archive_in_stream(HOME_PATH) do
    tar.read(Excon.defaults[:chunk_size]).to_s
  end
end

#deleteObject


89
90
91
92
93
94
# File 'lib/autoload/coursemology_docker_container.rb', line 89

def delete
  ActiveSupport::Notifications.instrument('destroy.docker.evaluator.coursemology',
                                          container: id) do
    super
  end
end

#evaluation_resultArray<(String, String, Hash, Integer)>

Gets the output that Coursemology is interested in.

Returns:

  • (Array<(String, String, Hash, Integer)>)

    The stdout, stderr, hash of test reports and exit code.


115
116
117
118
119
# File 'lib/autoload/coursemology_docker_container.rb', line 115

def evaluation_result
  _, stdout, stderr = container_streams

  [stdout, stderr, extract_test_reports, exit_code]
end

#execute_packageObject


106
107
108
109
# File 'lib/autoload/coursemology_docker_container.rb', line 106

def execute_package
  start!
  wait
end

#exit_codeInteger?

Gets the exit code of the container.

Returns:

  • (Integer)

    The exit code of the container, if +wait+ was called before.

  • (nil)

    If the container is still running, or +wait+ was not called.


85
86
87
# File 'lib/autoload/coursemology_docker_container.rb', line 85

def exit_code
  info.fetch('State', {})['ExitCode']
end

#wait(time = nil) ⇒ Integer

Waits for the container to exit the Running state.

This will time out for long running operations, so keep retrying until we return.

Parameters:

  • time (Integer|nil) (defaults to: nil)

    The amount of time to wait.

Returns:

  • (Integer)

    The exit code of the container.


68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/autoload/coursemology_docker_container.rb', line 68

def wait(time = nil)
  container_state = info
  while container_state.fetch('State', {}).fetch('Running', true)
    super
    refresh!
    container_state = info
  end

  container_state['State']['ExitCode']
rescue Docker::Error::TimeoutError
  retry
end