jenkins-factory 0.0.1
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.
- checksums.yaml +7 -0
- data/bin/jenkins_factory +19 -0
- data/lib/base_jenkins_ami.rb +20 -0
- data/lib/cfndsl/jenkins_cfndsl.rb +106 -0
- data/lib/jenkins_factory.rb +63 -0
- data/lib/job_seeder.rb +40 -0
- metadata +93 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: a11a17e3bdbd0d8632fefa847871616f6ad64a53
|
4
|
+
data.tar.gz: 4c89804b45d2267ceb3a258bd938853936bcb11b
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: aca24b4ab3305044f841b24a98164e0e3fc5c1a28180a226606ee465e80efbdc66c53803e880b9f0b7cca16c21160965f6c2456f84a81ba5a006f7318ce0ed2a
|
7
|
+
data.tar.gz: f0ed381302fc519c3ce53fe8ba531965754bf996ae3e47322ff77dbd1ab7ceb2f7184ac1ad9312071ed85a15e0b5b8627dcef1ca44fa9d01b194b1881e677920
|
data/bin/jenkins_factory
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'trollop'
|
3
|
+
require 'jenkins_factory'
|
4
|
+
require 'yaml'
|
5
|
+
|
6
|
+
opts = Trollop::options do
|
7
|
+
opt :jenkins_settings_yml_path, 'Show the YAML here', type: :string, required: true
|
8
|
+
end
|
9
|
+
|
10
|
+
jenkins_settings = YAML.load_file(opts[:jenkins_settings_yml_path])
|
11
|
+
|
12
|
+
jenkins_settings.keys.each do |k|
|
13
|
+
jenkins_settings[k.to_sym] = jenkins_settings[k]
|
14
|
+
jenkins_settings.delete k
|
15
|
+
end
|
16
|
+
|
17
|
+
jenkins_url = JenkinsFactory.new.create(jenkins_settings)
|
18
|
+
|
19
|
+
puts jenkins_url
|
@@ -0,0 +1,20 @@
|
|
1
|
+
class BaseJenkinsAmi
|
2
|
+
REGION_BASE_AMIS = {
|
3
|
+
'us-east-1' => 'ami-e2754888',
|
4
|
+
'us-west-2' => 'ami-677c9e07'
|
5
|
+
}
|
6
|
+
|
7
|
+
def discover_base_ami
|
8
|
+
if ENV['AWS_REGION'].nil?
|
9
|
+
raise 'AWS_REGION must be set in environment'
|
10
|
+
else
|
11
|
+
base_ami = REGION_BASE_AMIS[ENV['AWS_REGION']]
|
12
|
+
|
13
|
+
if base_ami.nil?
|
14
|
+
raise "#{ENV['AWS_REGION']} is illegitimate or unsupported region"
|
15
|
+
else
|
16
|
+
base_ami
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
CloudFormation {
|
2
|
+
|
3
|
+
IAM_Role('JenkinsInstanceRole') {
|
4
|
+
AssumeRolePolicyDocument JSON.load <<-END
|
5
|
+
{
|
6
|
+
"Statement":[
|
7
|
+
{
|
8
|
+
"Sid":"1",
|
9
|
+
"Effect":"Allow",
|
10
|
+
"Principal":{
|
11
|
+
"Service":[
|
12
|
+
"ec2.amazonaws.com"
|
13
|
+
]
|
14
|
+
},
|
15
|
+
"Action":"sts:AssumeRole"
|
16
|
+
}
|
17
|
+
]
|
18
|
+
}
|
19
|
+
END
|
20
|
+
|
21
|
+
Path '/'
|
22
|
+
|
23
|
+
Policies JSON.load <<-END
|
24
|
+
[
|
25
|
+
{
|
26
|
+
"PolicyName":"JenkinsGodlikeWreckYourAccountPolicy",
|
27
|
+
"PolicyDocument":{
|
28
|
+
"Version":"2012-10-17",
|
29
|
+
"Statement": [
|
30
|
+
{
|
31
|
+
"Action": [
|
32
|
+
"*"
|
33
|
+
],
|
34
|
+
"Effect": "Allow",
|
35
|
+
"Resource": "*"
|
36
|
+
}
|
37
|
+
]
|
38
|
+
}
|
39
|
+
}
|
40
|
+
]
|
41
|
+
END
|
42
|
+
}
|
43
|
+
|
44
|
+
IAM_InstanceProfile('JenkinsInstanceProfile') {
|
45
|
+
Path '/'
|
46
|
+
Roles [ Ref('JenkinsInstanceRole') ]
|
47
|
+
}
|
48
|
+
|
49
|
+
EC2_SecurityGroup('JenkinsSecurityGroup') {
|
50
|
+
VpcId vpc_id
|
51
|
+
GroupDescription 'Will mostly be phoning home to CP'
|
52
|
+
}
|
53
|
+
|
54
|
+
%w(22 8080).each do |ingress_port|
|
55
|
+
EC2_SecurityGroupIngress("SecurityGroupIngress#{ingress_port}") {
|
56
|
+
GroupId Ref('JenkinsSecurityGroup')
|
57
|
+
IpProtocol 'tcp'
|
58
|
+
FromPort ingress_port.to_s
|
59
|
+
ToPort ingress_port.to_s
|
60
|
+
CidrIp jenkins_ingress_ssh_cidr
|
61
|
+
}
|
62
|
+
end
|
63
|
+
|
64
|
+
EC2_Instance('JenkinsInstance') {
|
65
|
+
ImageId jenkins_base_ami_id
|
66
|
+
InstanceType 'm4.large'
|
67
|
+
KeyName jenkins_ec2_key_pair_name
|
68
|
+
|
69
|
+
IamInstanceProfile Ref('JenkinsInstanceProfile')
|
70
|
+
|
71
|
+
NetworkInterfaces [
|
72
|
+
NetworkInterface {
|
73
|
+
GroupSet Ref('JenkinsSecurityGroup')
|
74
|
+
AssociatePublicIpAddress associate_public_ip_address
|
75
|
+
DeviceIndex 0
|
76
|
+
DeleteOnTermination true
|
77
|
+
SubnetId subnet_id
|
78
|
+
}
|
79
|
+
]
|
80
|
+
|
81
|
+
start_jenkins_commands = [
|
82
|
+
"#!/bin/bash -xe\n",
|
83
|
+
"yum update -y aws-cfn-bootstrap\n",
|
84
|
+
"yum -y upgrade\n",
|
85
|
+
"service jenkins start\n"
|
86
|
+
]
|
87
|
+
|
88
|
+
cfn_signal_commands = [
|
89
|
+
'/opt/aws/bin/cfn-signal -e $? ',
|
90
|
+
' --stack ', Ref('AWS::StackName'),
|
91
|
+
' --resource JenkinsInstance ',
|
92
|
+
' --region ',Ref('AWS::Region'),"\n"
|
93
|
+
]
|
94
|
+
|
95
|
+
userdata_commands = start_jenkins_commands + extra_userdata + cfn_signal_commands
|
96
|
+
UserData FnBase64(FnJoin(
|
97
|
+
'',
|
98
|
+
userdata_commands
|
99
|
+
))
|
100
|
+
|
101
|
+
CreationPolicy('ResourceSignal', { 'Count' => 1, 'Timeout' => 'PT15M' })
|
102
|
+
}
|
103
|
+
|
104
|
+
Output(:JenkinsURL,
|
105
|
+
FnJoin('', [ 'http://', FnGetAtt('JenkinsInstance', 'PublicIp'), ':8080/']))
|
106
|
+
}
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'cfndsl_converger'
|
2
|
+
require_relative 'base_jenkins_ami'
|
3
|
+
require_relative 'job_seeder'
|
4
|
+
|
5
|
+
class JenkinsFactory
|
6
|
+
|
7
|
+
def create(controller_ip:,
|
8
|
+
ec2_keypair_name:,
|
9
|
+
vpc_id:,
|
10
|
+
subnet_id:,
|
11
|
+
|
12
|
+
job_repo:,
|
13
|
+
job_repo_branch: 'master',
|
14
|
+
job_definition_relative_path:,
|
15
|
+
|
16
|
+
# this is currently baked into the AMI
|
17
|
+
jenkins_admin_username:,
|
18
|
+
jenkins_admin_password:,
|
19
|
+
|
20
|
+
# crude bash commands, but maybe consider scp a tar of cookbooks?
|
21
|
+
extra_user_data_provisioning: [],
|
22
|
+
associate_public_ip_address: true)
|
23
|
+
|
24
|
+
customisations = {
|
25
|
+
'jenkins_base_ami_id' => BaseJenkinsAmi.new.discover_base_ami,
|
26
|
+
'jenkins_ingress_ssh_cidr' => controller_ip,
|
27
|
+
'jenkins_ec2_key_pair_name' => ec2_keypair_name,
|
28
|
+
'subnet_id' => subnet_id,
|
29
|
+
'vpc_id' => vpc_id,
|
30
|
+
'associate_public_ip_address' => associate_public_ip_address.to_s,
|
31
|
+
'extra_userdata' => extra_user_data_provisioning
|
32
|
+
}
|
33
|
+
|
34
|
+
stack_outputs = converge_jenkins_stack customisations: customisations
|
35
|
+
|
36
|
+
jenkins_connection_info = {
|
37
|
+
'jenkins_url' => stack_outputs['JenkinsURL'],
|
38
|
+
'jenkins_user' => jenkins_admin_username,
|
39
|
+
'jenkins_pass' => jenkins_admin_password
|
40
|
+
}
|
41
|
+
|
42
|
+
jobs_location = {
|
43
|
+
'job_repo' => job_repo,
|
44
|
+
'job_repo_branch' => job_repo_branch,
|
45
|
+
'job_definition_relative_path' => job_definition_relative_path
|
46
|
+
}
|
47
|
+
|
48
|
+
JobSeeder.new.seed_jobs jenkins_connection_info: jenkins_connection_info,
|
49
|
+
jobs_location: jobs_location
|
50
|
+
|
51
|
+
stack_outputs['JenkinsURL']
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
def converge_jenkins_stack(customisations:)
|
57
|
+
converger = CfndslConverger.new
|
58
|
+
outputs = converger.converge stack_name: "Jenkins-Factory-#{Time.now.to_i}",
|
59
|
+
path_to_stack: 'lib/cfndsl/jenkins_cfndsl.rb',
|
60
|
+
bindings: customisations
|
61
|
+
outputs
|
62
|
+
end
|
63
|
+
end
|
data/lib/job_seeder.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'jenkins_api_client'
|
2
|
+
|
3
|
+
# i guess also consider using local jenkins cli from user data?
|
4
|
+
class JobSeeder
|
5
|
+
def seed_jobs(jenkins_connection_info:,
|
6
|
+
jobs_location:)
|
7
|
+
|
8
|
+
client = jenkins_api_client jenkins_connection_info: jenkins_connection_info
|
9
|
+
|
10
|
+
job_name = 'job-seed'
|
11
|
+
if client.job.exists? job_name
|
12
|
+
client.job.delete job_name
|
13
|
+
end
|
14
|
+
|
15
|
+
seed_xml = patch_job_seed jobs_location: jobs_location
|
16
|
+
|
17
|
+
client.job.create job_name,
|
18
|
+
seed_xml
|
19
|
+
|
20
|
+
client.job.build job_name
|
21
|
+
end
|
22
|
+
|
23
|
+
# only exposed for testing, don't call me
|
24
|
+
# ok yea ERB more elegant but i'm feeling lazy
|
25
|
+
def patch_job_seed(jobs_location:)
|
26
|
+
seed_xml = IO.read(File.join('lib', 'xml', 'job-seed-config.xml.erb'))
|
27
|
+
seed_xml.gsub!(/<%= @job_definition_relative_path %>/, jobs_location['job_definition_relative_path'])
|
28
|
+
seed_xml.gsub!(/<%= @job_repo_branch %>/, jobs_location['job_repo_branch'])
|
29
|
+
seed_xml.gsub!(/<%= @job_repo %>/, jobs_location['job_repo'])
|
30
|
+
seed_xml
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def jenkins_api_client(jenkins_connection_info:)
|
36
|
+
JenkinsApi::Client.new server_url: jenkins_connection_info['jenkins_url'],
|
37
|
+
username: jenkins_connection_info['jenkins_user'],
|
38
|
+
password: jenkins_connection_info['jenkins_pass']
|
39
|
+
end
|
40
|
+
end
|
metadata
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: jenkins-factory
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- someguy
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-03-29 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: trollop
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 2.1.2
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 2.1.2
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: aws-sdk-utils
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 0.0.5
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 0.0.5
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: jenkins_api_client
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 1.4.2
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 1.4.2
|
55
|
+
description: Experimental single-click for cranking out a basic Jenkins instance in
|
56
|
+
EC2
|
57
|
+
email:
|
58
|
+
executables:
|
59
|
+
- jenkins_factory
|
60
|
+
extensions: []
|
61
|
+
extra_rdoc_files: []
|
62
|
+
files:
|
63
|
+
- bin/jenkins_factory
|
64
|
+
- lib/base_jenkins_ami.rb
|
65
|
+
- lib/cfndsl/jenkins_cfndsl.rb
|
66
|
+
- lib/jenkins_factory.rb
|
67
|
+
- lib/job_seeder.rb
|
68
|
+
homepage: https://github.com/stelligent/jenkins-factory
|
69
|
+
licenses:
|
70
|
+
- MIT
|
71
|
+
metadata: {}
|
72
|
+
post_install_message:
|
73
|
+
rdoc_options: []
|
74
|
+
require_paths:
|
75
|
+
- lib
|
76
|
+
- lib
|
77
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
78
|
+
requirements:
|
79
|
+
- - "~>"
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: '2.2'
|
82
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
83
|
+
requirements:
|
84
|
+
- - ">="
|
85
|
+
- !ruby/object:Gem::Version
|
86
|
+
version: '0'
|
87
|
+
requirements: []
|
88
|
+
rubyforge_project:
|
89
|
+
rubygems_version: 2.6.2
|
90
|
+
signing_key:
|
91
|
+
specification_version: 4
|
92
|
+
summary: jenkins_factory
|
93
|
+
test_files: []
|