jenkins-factory 0.0.1

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