jenkins-factory 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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: []
|