manband 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/bin/jobhandler.rb CHANGED
@@ -7,6 +7,13 @@ require 'mb-minion'
7
7
 
8
8
  include Minion
9
9
 
10
+ # The program manages job commands. Master nodes (workflow handler) sends
11
+ # messages to jobhandler instances. Each instance manages one and
12
+ # only one message at a time. Jobhnadlers are also in charge of storage to S3.
13
+ # Author: Olivier Sallou <olivier.sallou@irisa.fr>
14
+ # Copyright: 2012, IRISA
15
+
16
+
10
17
  if ENV["MYSQL_URL"]==nil
11
18
  puts "MYSQL_URL environment variable is not set exiting..."
12
19
  exit 1
data/bin/manband.rb CHANGED
@@ -14,6 +14,10 @@ require 'manband/flowconfig.rb'
14
14
  require 'manband/job.rb'
15
15
  require 'manband/bandmanager.rb'
16
16
 
17
+ # The program sends a workflow execution request to manband orchestrator.
18
+ # Author: Olivier Sallou <olivier.sallou@irisa.fr>
19
+ # Copyright: 2012, IRISA
20
+
17
21
  log = Logger.new(STDOUT)
18
22
  log.level = Logger::INFO
19
23
 
data/bin/remoteband.rb CHANGED
@@ -7,6 +7,11 @@ require 'mb-minion'
7
7
 
8
8
  include Minion
9
9
 
10
+ # The program sends a workflow execution request to manband orchestrator.
11
+ # This program does not need database credentials but does not get workflow id in return
12
+ # Author: Olivier Sallou <olivier.sallou@irisa.fr>
13
+ # Copyright: 2012, IRISA
14
+
10
15
 
11
16
  log = Logger.new(STDOUT)
12
17
  log.level = Logger::INFO
data/bin/userband.rb CHANGED
@@ -8,6 +8,12 @@ $:.push File.expand_path("../lib")
8
8
 
9
9
  require 'manband/flowconfig.rb'
10
10
 
11
+ # The program is used to manage users (add, update) in the database.
12
+ # Users are used for web interface authentification and S3 credentials.
13
+ # Author: Olivier Sallou <olivier.sallou@irisa.fr>
14
+ # Copyright: 2012, IRISA
15
+
16
+
11
17
  log = Logger.new(STDOUT)
12
18
  log.level = Logger::INFO
13
19
 
@@ -7,6 +7,15 @@ require 'mb-minion'
7
7
 
8
8
  include Minion
9
9
 
10
+ # The program s the main orchestrator of the workflow.
11
+ # It starts with a workflow execution request and sends messages to job
12
+ # handlers according to the input workflow.
13
+ # It is possible to have multipe workflow handler, sharing messages for
14
+ # the same workflow, or to handler a high number of workflow requests.
15
+ # Author: Olivier Sallou <olivier.sallou@irisa.fr>
16
+ # Copyright: 2012, IRISA
17
+
18
+
10
19
  if ENV["MYSQL_URL"]==nil
11
20
  puts "MYSQL_URL environment variable is not set exiting..."
12
21
  exit 1
@@ -52,7 +61,7 @@ optparse.parse!
52
61
 
53
62
  userconf = File.expand_path("~")+"/.manband"
54
63
  if @@options[:conf]==nil && File.exists?(userconf)
55
- options[:conf]=userconf
64
+ @@options[:conf]=userconf
56
65
  end
57
66
 
58
67
  if @@options[:conf]!=nil
@@ -11,14 +11,14 @@ include Minion
11
11
  require 'manband/workflow.rb'
12
12
  require 'manband/flowconfig.rb'
13
13
 
14
- # Library to launch new workflows
14
+ # This class is used to launch new workflows
15
15
  class BandManager
16
16
 
17
17
  @@log = Logger.new(STDOUT)
18
18
  @@log.level = Logger::DEBUG
19
19
 
20
20
 
21
- # Load workflow file
21
+ # Loads a workflow file
22
22
  def self.load(wfile)
23
23
  if !File.exists?(wfile)
24
24
  @@log.error "Workflow file "+wfile+" does not exist!"
@@ -143,7 +143,7 @@ class BandManager
143
143
  end
144
144
  end
145
145
 
146
- # Execute a workflow from an other one
146
+ # Execute a workflow from an other one (clone it)
147
147
  def self.launchclone(id)
148
148
  workflow = WorkFlow.get(id)
149
149
  newworkflow = WorkFlow.new(:uid => workflow.uid , :name => workflow.name, :description => workflow.description, :created_at => Time.now, :file => workflow.file, :terminals => workflow.terminals, :status => STATUS_NEW, :workdir => FlowConfig.getjobdir(), :vars => workflow.vars, :bucket => workflow.bucket)
@@ -2,6 +2,9 @@ require 'uuid'
2
2
  require 'data_mapper'
3
3
  require 'dm-migrations'
4
4
 
5
+ # Configuration library
6
+
7
+ # Determines the workflow and node status
5
8
  STATUS_SKIP = -2
6
9
  STATUS_FAKE = -1
7
10
  STATUS_NEW = 0
@@ -10,12 +13,14 @@ STATUS_OVER = 2
10
13
  STATUS_SUSPEND = 3 # SUSPEND mode for a job means a job is over and paused
11
14
  STATUS_ERROR = 4
12
15
 
16
+ # Determines if a job must be stored to S3, and its current status
13
17
  STORE_NO = -1
14
18
  STORE_DO = 0
15
19
  STORE_RUN = 1
16
20
  STORE_OVER = 2
17
21
  STORE_ERROR = 4
18
22
 
23
+ # List of message operations
19
24
  OP_NEW = "new"
20
25
  OP_START = "start"
21
26
  OP_FINISH = "finish"
@@ -30,10 +35,10 @@ OP_CLEAN = "clean" # Delete work dirs of workflow
30
35
  OP_DESTROY = "destroy" # Delete workflow and its work dirs
31
36
  OP_STORE = "store" # Store result to S3
32
37
 
33
- # Base config
38
+ # This class holds the base config
34
39
  class FlowConfig
35
40
  @@workdir='/tmp'
36
- @@s3host = 'genokvm4.genouest.org'
41
+ @@s3host = 'localhost'
37
42
  @@s3port = '8773'
38
43
  @@s3path = '/services/Walrus'
39
44
 
@@ -47,6 +52,7 @@ class FlowConfig
47
52
  return @@s3host
48
53
  end
49
54
 
55
+ # Sets S3 storage parameters
50
56
  def self.sets3(host,port= '8773',path='/services/Walrus')
51
57
  @@s3host = host
52
58
  @@s3port = port
@@ -65,14 +71,21 @@ class FlowConfig
65
71
  return @@workdir
66
72
  end
67
73
 
74
+ # defines upload directory for webband
75
+ # It must be accessible by the handlers
68
76
  def self.setuploaddir(directory)
69
77
  @@uploaddir = directory
70
78
  end
71
79
 
80
+ # Defines the work directory. It must be shared between job
81
+ # and workflow handlers.
72
82
  def self.setworkdir(directory)
73
83
  @@workdir=directory
74
84
  end
75
85
 
86
+
87
+ # Returns a work directory for a job. Directory
88
+ # is based on a unique identifier.
76
89
  def self.getjobdir(workflowdir = nil)
77
90
  uuid = UUID.new
78
91
  if workflowdir == nil
data/lib/manband/job.rb CHANGED
@@ -11,10 +11,7 @@ include Minion
11
11
  #DataMapper.setup(:default, 'sqlite:///home/osallou/Desktop/genflow/project.db')
12
12
  DataMapper.setup(:default, ENV['MYSQL_URL'])
13
13
 
14
- #TODO manage IF operation and resutl.
15
- # Exit code = 0 selects first node, other code select second node
16
- # Should inform with a finish "code: exitcode" and manage it in workflowhandler to RUN selected node and SKIP other node
17
-
14
+ # This class defines the link between the nodes in the workflow
18
15
  class JobLink
19
16
  include DataMapper::Resource
20
17
 
@@ -25,11 +22,14 @@ class JobLink
25
22
 
26
23
  end
27
24
 
25
+ # This class manages the job execution and its status on a job handler.
28
26
  class Job
29
27
  include DataMapper::Resource
30
28
 
31
29
  @@debug = false
32
30
 
31
+ # Sets debug mode
32
+ # mode: boolean
33
33
  def self.debug(mode)
34
34
  @@debug = mode
35
35
  end
@@ -50,7 +50,10 @@ class Job
50
50
  property :error, Text, :default => "[]" # JSON Array of error, per instance
51
51
  property :store, Integer, :default => STORE_NO # Storage status
52
52
 
53
- # Update job status and launch the command
53
+ # Update job status and launch the command locally
54
+ # Sends a finish message or an error message according to the job status.
55
+ # if storage is needed, job will send a finish AND a store message. Storage
56
+ # will occur in parallel of the rest of the workflow.
54
57
  def run(curhandler,instance=0)
55
58
  # Send run command, possibly multiple ones according to pattern
56
59
  # Command would send a message when over
@@ -81,7 +84,7 @@ class Job
81
84
  end
82
85
  end
83
86
 
84
- # Skip treatment, just answer
87
+ # Skip treatment, just answer, for debug
85
88
  def skip(curhandler)
86
89
  curjob = Job.get(@id)
87
90
  curjob.update(:handler => curhandler.to_s)
@@ -89,7 +92,10 @@ class Job
89
92
  sendmessage(OP_FINISH,jobmsg)
90
93
  end
91
94
 
92
- # Execute locally the command
95
+ # Execute locally the command, creating directories and setting environment
96
+ # variables to empty string for security.
97
+ # wordir: job working directory
98
+ # instance: instance number in the list of commands
93
99
  def runcommand(workdir,instance)
94
100
  initcmd = "AMQP_URL="" && MYSQL_URL="" && mkdir -p "+workdir+" && cd "+workdir+" && WORKDIR="+workdir+" && "
95
101
  curjob = Job.get(@id)
@@ -102,7 +108,8 @@ class Job
102
108
  end
103
109
 
104
110
  # Change instance counter
105
- # If workflow is in suspend status, suspend the job at the end of its treatment
111
+ # If workflow is in suspend status, suspend the job at
112
+ # the end of its treatment
106
113
  def finish
107
114
  if @status == STATUS_SKIP
108
115
  return
@@ -133,7 +140,7 @@ class Job
133
140
  end
134
141
  end
135
142
 
136
- # Compare sintance counter to max instances
143
+ # Compares intance counter to max instances to determine if job is over.
137
144
  def isover?
138
145
  if @status == STATUS_OVER
139
146
  return true
@@ -179,7 +186,9 @@ class Job
179
186
  end
180
187
  end
181
188
  end
182
-
189
+
190
+ # Sets a job in ERROR status.
191
+ # instance: job instance number in fault
183
192
  def error!(instance = 0)
184
193
  @status= STATUS_ERROR
185
194
  curjob = Job.get(@id)
@@ -258,7 +267,12 @@ class Job
258
267
  end
259
268
  end
260
269
  end
261
-
270
+
271
+ # Sends a message. According to the operation, message will be
272
+ # sent to master or node queues.
273
+ # operation: kind of message
274
+ # msg: message to send
275
+ # jobqueue: optional specific queue
262
276
  def sendmessage(operation,msg,jobqueue='')
263
277
  queue = "manband.master"
264
278
  if operation == OP_RUN || operation == OP_SKIP || operation == OP_DESTROY || operation == OP_CLEAN|| operation == OP_STORE
data/lib/manband/store.rb CHANGED
@@ -7,7 +7,7 @@ require 'fileutils'
7
7
  require 'manband/flowconfig.rb'
8
8
  require 'manband/user.rb'
9
9
 
10
-
10
+ # this class manage the storage of a job directory to S3
11
11
  class Storeband
12
12
 
13
13
  @@log = Logger.new(STDOUT)
@@ -29,6 +29,11 @@ class Storeband
29
29
  end
30
30
 
31
31
  # Store a job workdir to S3
32
+ #
33
+ # job: current job
34
+ # uid: user identifier
35
+ # bucket: bucket name to store the zip file
36
+ # @return false in case of failure
32
37
  def store(job,uid,bucket="manband")
33
38
  user = User.get(uid)
34
39
  if user == nil
@@ -50,16 +55,21 @@ class Storeband
50
55
  compress(job.workdir, FlowConfig.workdir+"/"+zipfile)
51
56
  # Send file
52
57
  sends3(FlowConfig.workdir+"/"+zipfile,bucket,user.s3_access,user.s3_secret)
53
- rescue
54
- @@log.error "An error occured during S3 operation: "+job.id.to_s
58
+ rescue Exception => e
59
+ @@log.error "An error occured during S3 operation: "+job.id.to_s+" "+e.message
55
60
  job.update(:store => STORE_ERROR)
56
61
  return false
57
62
  end
58
63
  job.update(:store => STORE_OVER)
59
64
  end
60
65
 
66
+ # Sends the file to the S3 bucket
67
+ # name: file name
68
+ # bucket: destination bucket name
69
+ # access: user credential access
70
+ # secret: user credential secret
61
71
  def sends3(name,bucket,access,secret)
62
- @@log.debug "connect to s3"
72
+ @@log.debug "connect to s3: "+FlowConfig.s3host+":"+FlowConfig.s3port.to_s+FlowConfig.s3path
63
73
  AWS::S3::Base.establish_connection!(
64
74
  :access_key_id => access,
65
75
  :secret_access_key => secret,
data/lib/manband/user.rb CHANGED
@@ -7,6 +7,7 @@ require 'manband/flowconfig.rb'
7
7
  #DataMapper.setup(:default, 'sqlite:///tmp/project.db')
8
8
  DataMapper.setup(:default, ENV['MYSQL_URL'])
9
9
 
10
+ # This class manages users in the database
10
11
  class User
11
12
  include DataMapper::Resource
12
13
 
@@ -17,6 +18,8 @@ class User
17
18
  property :s3_access, String # User id key
18
19
  property :s3_secret, String # Secret key
19
20
 
21
+ # Creates a default admin account if it does not exists.
22
+ # Default password is <b>admin</b>
20
23
  def self.init
21
24
  admin = User.get(@@admin)
22
25
  if admin == nil
@@ -26,6 +29,9 @@ class User
26
29
  end
27
30
  end
28
31
 
32
+ # Check passwords
33
+ # password: user password
34
+ # @return: true if authentication is correct
29
35
  def authenticate(password)
30
36
  shapwd = Digest::SHA1.hexdigest(password)
31
37
  if self.password == shapwd
@@ -12,7 +12,9 @@ require 'manband/job.rb'
12
12
  DataMapper.setup(:default, ENV['MYSQL_URL'])
13
13
 
14
14
 
15
-
15
+ # This class orchestrator the workflow status and the workflow file
16
+ # analysis. It determines if workflow is over, what are the next jobs
17
+ # to execute, ...
16
18
  class WorkFlow
17
19
  include DataMapper::Resource
18
20
 
@@ -34,6 +36,8 @@ class WorkFlow
34
36
  property :parent, Integer, :default => 0 # Parent workflow id, none by default
35
37
  property :instances, Integer, :default => 0 # Number of sub workflows, if any
36
38
 
39
+ # Checks if a workflow is over, e.g. we have reached all the
40
+ # terminal nodes (leafs).
37
41
  def isover?
38
42
  # decrement terminals
39
43
  @terminals = @terminals - 1
@@ -54,7 +58,8 @@ class WorkFlow
54
58
  return false
55
59
  end
56
60
 
57
- # Return an array of node names
61
+ # Get the list of jobs to be run after current node
62
+ # @return an array of node names
58
63
  def getnextjobs(curnode)
59
64
  #fworkflow = YAML.load_file(@file)
60
65
  fworkflow = BandManager.load(@file)
@@ -75,6 +80,9 @@ class WorkFlow
75
80
  return nexts
76
81
  end
77
82
 
83
+ # Parse workflow file and create jobs and links in the database
84
+ # curnode: current node
85
+ # id: id of the node as link originator
78
86
  def parse(curnode, id = nil)
79
87
  #fworkflow = YAML.load_file(@file)
80
88
  fworkflow = BandManager.load(@file)
@@ -140,7 +148,9 @@ class WorkFlow
140
148
  return newcommand
141
149
  end
142
150
 
143
- # Return command for the node in the workflow
151
+ # Return a list of commands for the node in the workflow
152
+ # There is one command per input file matching regular expresssions,
153
+ # if any. Default is 1 command.
144
154
  def getnodecommand(curnode)
145
155
  #fworkflow = YAML.load_file(@file)
146
156
  fworkflow = BandManager.load(@file)
@@ -247,6 +257,7 @@ class WorkFlow
247
257
  return commands
248
258
  end
249
259
 
260
+ # Clean a workflow directory
250
261
  def clean
251
262
  workflow = WorkFlow.get(@id)
252
263
  if workflow.workdir == nil
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: manband
3
3
  version: !ruby/object:Gem::Version
4
- hash: 15
4
+ hash: 11
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
- - 4
8
+ - 5
9
9
  - 0
10
- version: 0.4.0
10
+ version: 0.5.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Olivier Sallou