cyclid 0.2.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.
Files changed (71) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +174 -0
  3. data/README.md +54 -0
  4. data/app/cyclid.rb +61 -0
  5. data/app/cyclid/config.rb +38 -0
  6. data/app/cyclid/controllers.rb +123 -0
  7. data/app/cyclid/controllers/auth.rb +34 -0
  8. data/app/cyclid/controllers/auth/token.rb +78 -0
  9. data/app/cyclid/controllers/health.rb +96 -0
  10. data/app/cyclid/controllers/organizations.rb +104 -0
  11. data/app/cyclid/controllers/organizations/collection.rb +134 -0
  12. data/app/cyclid/controllers/organizations/config.rb +128 -0
  13. data/app/cyclid/controllers/organizations/document.rb +135 -0
  14. data/app/cyclid/controllers/organizations/job.rb +266 -0
  15. data/app/cyclid/controllers/organizations/members.rb +145 -0
  16. data/app/cyclid/controllers/organizations/stages.rb +251 -0
  17. data/app/cyclid/controllers/users.rb +47 -0
  18. data/app/cyclid/controllers/users/collection.rb +131 -0
  19. data/app/cyclid/controllers/users/document.rb +133 -0
  20. data/app/cyclid/health_helpers.rb +40 -0
  21. data/app/cyclid/job.rb +3 -0
  22. data/app/cyclid/job/helpers.rb +67 -0
  23. data/app/cyclid/job/job.rb +164 -0
  24. data/app/cyclid/job/runner.rb +275 -0
  25. data/app/cyclid/job/stage.rb +67 -0
  26. data/app/cyclid/log_buffer.rb +104 -0
  27. data/app/cyclid/models.rb +3 -0
  28. data/app/cyclid/models/job_record.rb +25 -0
  29. data/app/cyclid/models/organization.rb +64 -0
  30. data/app/cyclid/models/plugin_config.rb +25 -0
  31. data/app/cyclid/models/stage.rb +42 -0
  32. data/app/cyclid/models/step.rb +29 -0
  33. data/app/cyclid/models/user.rb +60 -0
  34. data/app/cyclid/models/user_permissions.rb +28 -0
  35. data/app/cyclid/monkey_patches.rb +37 -0
  36. data/app/cyclid/plugin_registry.rb +75 -0
  37. data/app/cyclid/plugins.rb +125 -0
  38. data/app/cyclid/plugins/action.rb +48 -0
  39. data/app/cyclid/plugins/action/command.rb +89 -0
  40. data/app/cyclid/plugins/action/email.rb +207 -0
  41. data/app/cyclid/plugins/action/email/html.erb +58 -0
  42. data/app/cyclid/plugins/action/email/text.erb +13 -0
  43. data/app/cyclid/plugins/action/script.rb +90 -0
  44. data/app/cyclid/plugins/action/slack.rb +129 -0
  45. data/app/cyclid/plugins/action/slack/note.erb +5 -0
  46. data/app/cyclid/plugins/api.rb +195 -0
  47. data/app/cyclid/plugins/api/github.rb +111 -0
  48. data/app/cyclid/plugins/api/github/callback.rb +66 -0
  49. data/app/cyclid/plugins/api/github/methods.rb +201 -0
  50. data/app/cyclid/plugins/api/github/status.rb +67 -0
  51. data/app/cyclid/plugins/builder.rb +80 -0
  52. data/app/cyclid/plugins/builder/mist.rb +107 -0
  53. data/app/cyclid/plugins/dispatcher.rb +89 -0
  54. data/app/cyclid/plugins/dispatcher/local.rb +167 -0
  55. data/app/cyclid/plugins/provisioner.rb +40 -0
  56. data/app/cyclid/plugins/provisioner/debian.rb +90 -0
  57. data/app/cyclid/plugins/provisioner/ubuntu.rb +98 -0
  58. data/app/cyclid/plugins/source.rb +39 -0
  59. data/app/cyclid/plugins/source/git.rb +64 -0
  60. data/app/cyclid/plugins/transport.rb +63 -0
  61. data/app/cyclid/plugins/transport/ssh.rb +155 -0
  62. data/app/cyclid/sinatra/api_helpers.rb +66 -0
  63. data/app/cyclid/sinatra/auth_helpers.rb +127 -0
  64. data/app/cyclid/sinatra/warden/strategies/api_token.rb +62 -0
  65. data/app/cyclid/sinatra/warden/strategies/basic.rb +58 -0
  66. data/app/cyclid/sinatra/warden/strategies/hmac.rb +76 -0
  67. data/app/db.rb +51 -0
  68. data/bin/cyclid-db-init +107 -0
  69. data/db/schema.rb +92 -0
  70. data/lib/cyclid/app.rb +4 -0
  71. metadata +407 -0
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+ # Copyright 2016 Liqwyd Ltd.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ # Top level module for the core Cyclid code.
17
+ module Cyclid
18
+ # Module for the Cyclid API
19
+ module API
20
+ # Module for Cyclid Job related classes
21
+ module Job
22
+ # Non-AR model for Stages. Using a wrapper allows us to create an ad-hoc
23
+ # stage (I.e. one that is not stored in the database) or load a stage
24
+ # from the database and merge in over-rides without risking modifying
25
+ # the database object.
26
+ class StageView
27
+ attr_reader :name, :version, :steps
28
+ attr_accessor :on_success, :on_failure
29
+
30
+ def initialize(arg)
31
+ if arg.is_a? Cyclid::API::Stage
32
+ @name = arg.name
33
+ @version = arg.version
34
+ @steps = arg.steps.map(&:serializable_hash)
35
+ elsif arg.is_a? Hash
36
+ arg.symbolize_keys!
37
+
38
+ raise ArgumentError, 'name is required' unless arg.key? :name
39
+
40
+ @name = arg[:name]
41
+ @version = arg.fetch(:version, '1.0.0')
42
+
43
+ # Create & serialize Actions for each step
44
+ sequence = 1
45
+ @steps = arg[:steps].map do |step|
46
+ Cyclid.logger.debug "ad-hoc step=#{step}"
47
+
48
+ action_name = step['action']
49
+ plugin = Cyclid.plugins.find(action_name, Cyclid::API::Plugins::Action)
50
+
51
+ step_action = plugin.new(step)
52
+ raise ArgumentError if step_action.nil?
53
+
54
+ # Serialize the object into the Step and store it in the database.
55
+ action = Oj.dump(step_action)
56
+
57
+ step_definition = { sequence: sequence, action: action }
58
+ sequence += 1
59
+
60
+ step_definition
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,104 @@
1
+ # frozen_string_literal: true
2
+ # Copyright 2016 Liqwyd Ltd.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ # Top level module for the core Cyclid code.
17
+ module Cyclid
18
+ # Module for the Cyclid API
19
+ module API
20
+ # Simple in-memory FIFO; inspired by StringIO but reads & writes maintain
21
+ # their own position. It's unlike a file enough to not be derived from IO.
22
+ class StringFIFO
23
+ def initialize
24
+ @buffer = String.new
25
+ @write_pos = 0
26
+ @read_pos = 0
27
+ end
28
+
29
+ # Append data to the buffer & update the write position
30
+ def write(data)
31
+ @buffer += data
32
+ @write_pos += data.length
33
+ end
34
+
35
+ # Read data from the buffer. If length is given, read at most length
36
+ # characters from the buffer or whatever is available, whichever is
37
+ # smaller.
38
+ #
39
+ # Completely non-blocking; if no data is available, returns an empty
40
+ # string.
41
+ def read(length = nil)
42
+ len = if length
43
+ [length, @write_pos].min
44
+ else
45
+ @write_pos
46
+ end
47
+ start = @read_pos
48
+ @read_pos += len
49
+
50
+ @buffer[start, len]
51
+ end
52
+
53
+ # Return the entire contents of the buffer
54
+ def string
55
+ @buffer
56
+ end
57
+
58
+ alias to_s string
59
+
60
+ # Reset the buffer, read & write positions
61
+ def clear
62
+ @buffer = ''
63
+ @write_pos = 0
64
+ @read_pos = 0
65
+ end
66
+ end
67
+
68
+ # Intelligent buffer which can be passed to plugins which need to collate
69
+ # output data from different commands during a job
70
+ class LogBuffer
71
+ def initialize(job_record = nil, websocket = nil)
72
+ @job_record = job_record
73
+ @websocket = websocket
74
+ @buffer = StringFIFO.new
75
+ end
76
+
77
+ # Append data to the log and send it on to any configured consumers
78
+ def write(data)
79
+ # Append the new data to log
80
+ @buffer.write data
81
+
82
+ # Update the Job Record, if there is one
83
+ if @job_record
84
+ # XXX: This will destroy the database. Find a better method.
85
+ @job_record.log = @buffer.string
86
+ @job_record.save!
87
+ end
88
+
89
+ # Write to web socket
90
+ @websocket.write data if @websocket
91
+ end
92
+
93
+ # Non-destructively read any new data from the buffer
94
+ def read(length = nil)
95
+ @buffer.read(length)
96
+ end
97
+
98
+ # Return a complete copy of the data from the buffer
99
+ def log
100
+ @buffer.string
101
+ end
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+ # Load the models
3
+ require_rel 'models/*.rb'
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+ # Copyright 2016 Liqwyd Ltd.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ # Top level module for the core Cyclid code.
17
+ module Cyclid
18
+ # Module for the Cyclid API
19
+ module API
20
+ # Model for Users
21
+ class JobRecord < ActiveRecord::Base
22
+ Cyclid.logger.debug('In the JobRecod model')
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+ # Copyright 2016 Liqwyd Ltd.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ # Top level module for the core Cyclid code.
17
+ module Cyclid
18
+ # Module for the Cyclid API
19
+ module API
20
+ # Model for Organizations
21
+ class Organization < ActiveRecord::Base
22
+ Cyclid.logger.debug('In the Organization model')
23
+
24
+ class << self
25
+ # Return the collection of Organizations as an array of Hashes (instead
26
+ # of Organization objects)
27
+ def all_as_hash
28
+ all.to_a.map(&:serializable_hash)
29
+ end
30
+ end
31
+
32
+ validates :name, presence: true
33
+ validates :owner_email, presence: true
34
+
35
+ validates :rsa_private_key, presence: true
36
+ validates :rsa_public_key, presence: true
37
+ validates :salt, presence: true
38
+
39
+ validates_uniqueness_of :name
40
+
41
+ has_and_belongs_to_many :users,
42
+ after_add: :add_user_org_perm,
43
+ after_remove: :remove_user_org_perm
44
+
45
+ has_many :userpermissions
46
+ has_many :stages
47
+ has_many :job_records
48
+ has_many :plugin_configs
49
+
50
+ # Ensure that a set of Userpermissions exist when a User is added to
51
+ # this Organization
52
+ def add_user_org_perm(user)
53
+ Cyclid.logger.debug "Creating org. perm. for #{user.username}"
54
+ user.userpermissions << Userpermission.new(organization: self)
55
+ end
56
+
57
+ # Remove Userpermissions when a User is removed from this Organization
58
+ def remove_user_org_perm(user)
59
+ Cyclid.logger.debug "Destroying org. perm. for #{user.username}"
60
+ user.userpermissions.delete(Userpermission.find_by(organization: self))
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+ # Copyright 2016 Liqwyd Ltd.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ # Top level module for the core Cyclid code.
17
+ module Cyclid
18
+ # Module for the Cyclid API
19
+ module API
20
+ # Model for PluginConfigs
21
+ class PluginConfig < ActiveRecord::Base
22
+ belongs_to :organization
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+ # Copyright 2016 Liqwyd Ltd.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ # Top level module for the core Cyclid code.
17
+ module Cyclid
18
+ # Module for the Cyclid API
19
+ module API
20
+ # Model for Stages
21
+ class Stage < ActiveRecord::Base
22
+ Cyclid.logger.debug('In the Stage model')
23
+
24
+ class << self
25
+ # Return the collection of Stages as an array of Hashes (instead
26
+ # of Stage objects)
27
+ def all_as_hash
28
+ all.to_a.map(&:serializable_hash)
29
+ end
30
+ end
31
+
32
+ validates :name, presence: true
33
+ validates :version, presence: true
34
+
35
+ validates_uniqueness_of :name, scope: :version
36
+ validates_format_of :version, with: /\A\d+.\d+.\d+.?\d*\z/
37
+
38
+ belongs_to :organization
39
+ has_many :steps
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+ # Copyright 2016 Liqwyd Ltd.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ # Top level module for the core Cyclid code.
17
+ module Cyclid
18
+ # Module for the Cyclid API
19
+ module API
20
+ # Model for Steps
21
+ class Step < ActiveRecord::Base
22
+ Cyclid.logger.debug('In the Step model')
23
+
24
+ validates :sequence, presence: true
25
+
26
+ belongs_to :stage
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+ # Copyright 2016 Liqwyd Ltd.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ require 'bcrypt'
17
+
18
+ # Top level module for the core Cyclid code.
19
+ module Cyclid
20
+ # Module for the Cyclid API
21
+ module API
22
+ # Model for Users
23
+ class User < ActiveRecord::Base
24
+ Cyclid.logger.debug('In the User model')
25
+
26
+ class << self
27
+ # Return the collection of Users as an array of Hashes (instead
28
+ # of User objects)
29
+ def all_as_hash
30
+ all.to_a.map(&:serializable_hash)
31
+ end
32
+ end
33
+
34
+ validates :username, presence: true
35
+ validates :email, presence: true
36
+
37
+ validates_uniqueness_of :username
38
+
39
+ has_and_belongs_to_many :organizations
40
+ has_many :userpermissions
41
+ has_many :job_records
42
+
43
+ # Allow an unencryped password to be passed in via. new_password and
44
+ # ensure it is encrypted into password when the record is saved
45
+ attr_accessor :new_password
46
+
47
+ before_save :hash_new_password, if: :password_changed?
48
+
49
+ # Check if the new_password attribute has changed
50
+ def password_changed?
51
+ !@new_password.blank?
52
+ end
53
+
54
+ # Generate a BCrypt2 password from the plaintext
55
+ def hash_new_password
56
+ self.password = BCrypt::Password.create(@new_password)
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+ # Copyright 2016 Liqwyd Ltd.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ # Top level module for the core Cyclid code.
17
+ module Cyclid
18
+ # Module for the Cyclid API
19
+ module API
20
+ # Model for UserPermissions
21
+ class Userpermission < ActiveRecord::Base
22
+ Cyclid.logger.debug('In the Userpermission model')
23
+
24
+ belongs_to :user
25
+ belongs_to :organization
26
+ end
27
+ end
28
+ end