├── .gitignore ├── .travis.yml ├── README.org ├── Scenario-101 ├── README.md ├── config │ ├── node.json │ └── solo.rb ├── cookbooks │ └── example │ │ └── recipes │ │ └── default.rb └── docker-compose.yml ├── Scenario-102 ├── README.md ├── Vagrantfile ├── config │ ├── node.json │ └── solo.rb └── cookbooks │ └── example │ ├── .rubocop.yml │ ├── .travis.yml │ ├── Berksfile │ ├── Gemfile │ ├── README.md │ ├── metadata.rb │ └── recipes │ └── default.rb ├── Scenario-103 ├── README.md ├── config │ ├── node.json │ └── solo.rb ├── cookbooks │ └── example │ │ ├── .rubocop.yml │ │ ├── .travis.yml │ │ ├── Berksfile │ │ ├── Gemfile │ │ ├── README.md │ │ ├── metadata.rb │ │ └── recipes │ │ └── default.rb └── docker-compose.yml ├── Scenario-201 ├── README.md └── cookbooks │ └── example │ ├── .kitchen.yml │ ├── .rubocop.yml │ ├── .travis.yml │ ├── Berksfile │ ├── Gemfile │ ├── README.md │ ├── attributes │ └── default.rb │ ├── metadata.rb │ ├── recipes │ └── default.rb │ ├── templates │ └── default │ │ └── version.txt.erb │ └── test │ └── integration │ └── default │ └── serverspec │ └── server_spec.rb ├── Scenario-202 ├── README.md └── cookbooks │ └── example │ ├── .kitchen.yml │ ├── .kitchen_digitalocean.yml │ ├── .kitchen_ec2.yml │ ├── .kitchen_vagrant.yml │ ├── .rubocop.yml │ ├── .travis.yml │ ├── Berksfile │ ├── Gemfile │ ├── README.md │ ├── attributes │ └── default.rb │ ├── chefignore │ ├── metadata.rb │ ├── recipes │ └── default.rb │ ├── templates │ └── default │ │ └── version.txt.erb │ └── test │ └── integration │ └── default │ └── serverspec │ └── server_spec.rb ├── Scenario-301 ├── README.md └── cookbooks │ └── jenkins-demo │ ├── .kitchen.yml │ ├── .kitchen_digitalocean.yml │ ├── .kitchen_ec2.yml │ ├── .kitchen_vagrant.yml │ ├── .rubocop.yml │ ├── Berksfile │ ├── Gemfile │ ├── README.md │ ├── attributes │ ├── conf_job.rb │ └── default.rb │ ├── files │ └── default │ │ └── serverspec_check.sh │ ├── metadata.rb │ ├── recipes │ ├── conf_job.rb │ ├── default.rb │ └── master.rb │ ├── templates │ └── default │ │ └── CommonServerCheckRepo │ │ └── config.xml │ └── test │ ├── integration │ └── default │ │ └── serverspec │ │ └── server_spec.rb │ └── shared │ └── verify_job_config.rb ├── Scenario-302 ├── README.md └── cookbooks │ └── jenkins-demo │ ├── .kitchen.yml │ ├── .kitchen_digitalocean.yml │ ├── .kitchen_ec2.yml │ ├── .kitchen_vagrant.yml │ ├── .rubocop.yml │ ├── Berksfile │ ├── Gemfile │ ├── README.md │ ├── attributes │ ├── conf_job.rb │ └── default.rb │ ├── files │ └── default │ │ └── serverspec_check.sh │ ├── metadata.rb │ ├── recipes │ ├── backup.rb │ ├── conf_job.rb │ ├── default.rb │ ├── master.rb │ └── security.rb │ ├── templates │ └── default │ │ └── CommonServerCheckRepo │ │ └── config.xml │ └── test │ ├── integration │ └── default │ │ └── serverspec │ │ └── server_spec.rb │ └── shared │ └── verify_job_config.rb ├── Scenario-303 ├── README.md └── cookbooks │ └── jenkins-demo │ ├── .kitchen.yml │ ├── .kitchen_digitalocean.yml │ ├── .kitchen_ec2.yml │ ├── .kitchen_vagrant.yml │ ├── .rubocop.yml │ ├── Berksfile │ ├── Gemfile │ ├── README.md │ ├── attributes │ ├── conf_test_job.rb │ └── default.rb │ ├── files │ └── default │ │ └── serverspec_check.sh │ ├── metadata.rb │ ├── recipes │ ├── backup.rb │ ├── conf_test_job.rb │ ├── default.rb │ ├── master.rb │ ├── security.rb │ └── test_pipeline.rb │ ├── templates │ └── default │ │ ├── CommonServerCheckRepo │ │ └── config.xml │ │ ├── JenkinsFileExample1 │ │ ├── Jenkinsfile.groovy │ │ └── config.xml │ │ └── JenkinsFileExample2 │ │ ├── Jenkinsfile.groovy │ │ └── config.xml │ └── test │ ├── integration │ └── default │ │ └── serverspec │ │ └── server_spec.rb │ └── shared │ └── verify_job_config.rb ├── Scenario-401 ├── README.md └── cookbooks │ └── jenkins-demo │ ├── .kitchen.yml │ ├── .rubocop.yml │ ├── Berksfile │ ├── Gemfile │ ├── README.md │ ├── attributes │ └── default.rb │ ├── metadata.rb │ ├── recipes │ ├── conf_job.rb │ ├── default.rb │ └── master.rb │ ├── templates │ └── default │ │ └── CollectFiles.xml.erb │ └── test │ └── integration │ └── default │ └── serverspec │ └── server_spec.rb └── images ├── chef-study.graffle ├── chef_icon.png ├── scenario-101-screenshot.jpg ├── scenario-102-screenshot.jpg ├── scenario-103-design.png ├── scenario-201-design.png ├── scenario-202-design.png └── scenario-401-design.png /.gitignore: -------------------------------------------------------------------------------- 1 | local-mode-cache 2 | .vagrant 3 | *.deb 4 | Berksfile.lock 5 | .kitchen 6 | Gemfile.lock 7 | Dockerfile-kitchen* 8 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: ruby 2 | rvm: 3 | - 2.2 4 | # command to install dependencies 5 | install: 6 | - gem install rubocop -v "0.48.1" 7 | # command to run tests 8 | script: 9 | - find . -name cookbooks | xargs rubocop 10 | -------------------------------------------------------------------------------- /Scenario-101/README.md: -------------------------------------------------------------------------------- 1 | [![LinkedIn](https://raw.githubusercontent.com/USDevOps/mywechat-slack-group/master/images/linkedin.png)](https://www.linkedin.com/in/dennyzhang001) slack [![Github](https://raw.githubusercontent.com/USDevOps/mywechat-slack-group/master/images/github.png)](https://github.com/DennyZhang) 2 | 3 | File me [tickets](https://github.com/DennyZhang/challenges-chef/issues) or star [the repo](https://github.com/DennyZhang/challenges-chef). 4 | 5 | 6 | 7 | Table of Contents 8 | ================= 9 | 10 | * [Requirements](#requirements) 11 | * [Procedure](#procedure) 12 | 13 | 14 | 15 | 16 | # Requirements 17 | ``` 18 | 1. Use docker container to start a env with chef pre-installed 19 | 2. Create a dummy cookbook and apply it 20 | ``` 21 | 22 | # Procedure 23 | 24 | - Start docker-compose env 25 | 26 | docker-compose up -d 27 | 28 | - Login to the container, and run procedure 29 | ``` 30 | docker exec -it my_chef sh 31 | apt-get -y update 32 | 33 | cd /tmp 34 | 35 | - Before chef apply, jq package is missing 36 | which jq 37 | 38 | - From config/node.json, we specify to apply example cookbook 39 | chef-solo -c config/solo.rb -j config/node.json 40 | 41 | - After chef apply, jq package is installed 42 | which jq 43 | ``` 44 | 45 | - Destroy docker-compose env after testing 46 | 47 | ``` 48 | docker-compose down -v 49 | ``` 50 | 51 | -------------------------------------------------------------------------------- /Scenario-101/config/node.json: -------------------------------------------------------------------------------- 1 | { 2 | "run_list": [ "recipe[example]" ] 3 | } 4 | -------------------------------------------------------------------------------- /Scenario-101/config/solo.rb: -------------------------------------------------------------------------------- 1 | cookbook_path File.expand_path(File.join(File.dirname(__FILE__), '..', "cookbooks")) -------------------------------------------------------------------------------- /Scenario-101/cookbooks/example/recipes/default.rb: -------------------------------------------------------------------------------- 1 | package 'jq' 2 | -------------------------------------------------------------------------------- /Scenario-101/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '2' 2 | services: 3 | my_chef: 4 | container_name: my_chef 5 | hostname: my_chef 6 | # https://hub.docker.com/r/chef/chefdk/ 7 | image: chef/chefdk 8 | entrypoint: ["tail", "-f", "/dev/null"] 9 | volumes: 10 | - ./config:/tmp/config 11 | - ./cookbooks:/tmp/cookbooks 12 | -------------------------------------------------------------------------------- /Scenario-102/README.md: -------------------------------------------------------------------------------- 1 | [![LinkedIn](https://raw.githubusercontent.com/USDevOps/mywechat-slack-group/master/images/linkedin.png)](https://www.linkedin.com/in/dennyzhang001) slack [![Github](https://raw.githubusercontent.com/USDevOps/mywechat-slack-group/master/images/github.png)](https://github.com/DennyZhang) 2 | 3 | File me [tickets](https://github.com/DennyZhang/challenges-chef/issues) or star [the repo](https://github.com/DennyZhang/challenges-chef). 4 | 5 | 6 | 7 | Table of Contents 8 | ================= 9 | 10 | * [Requirements](#requirements) 11 | * [Procedure](#procedure) 12 | * [Test in public cloud?](#test-in-public-cloud) 13 | 14 | 15 | 16 | 17 | # Requirements 18 | 1. Start a VM, install chef facility 19 | 2. Create a dummy cookbook to install jq package 20 | 3. Before install jq, run "apt-get update" by chef. So you need berkshelf. 21 | 4. Enforce rubocop and foodcritic for code static check 22 | 23 | # Procedure 24 | - Start VM via vagrant 25 | ``` 26 | vagrant up 27 | ``` 28 | More about virtualbox: https://www.virtualbox.org/wiki/Downloads 29 | 30 | More about vagrant: https://www.vagrantup.com/docs/providers/basic_usage.html 31 | 32 | - Login and install chef-dk 33 | ``` 34 | ssh vagrant@192.168.50.10 35 | # password: vagrant 36 | 37 | # https://downloads.chef.io/chefdk 38 | wget -O /tmp/chefdk.deb \ 39 | https://packages.chef.io/files/stable/chefdk/2.3.4/ubuntu/16.04/chefdk_2.3.4-1_amd64.deb 40 | 41 | sudo dpkg -i /tmp/chefdk*.deb 42 | 43 | # chef-solo version: 13.4.19 44 | chef-solo -verison 45 | ``` 46 | 47 | - Upload chef cookbook code 48 | ``` 49 | scp -r Scenario-102 vagrant@192.168.50.10:/tmp/ 50 | ``` 51 | 52 | - Get cookbooks dependency 53 | ``` 54 | ssh vagrant@192.168.50.10 55 | mkdir -p /tmp/berks_cookbooks 56 | cd /tmp/Scenario-102/cookbooks/example/ 57 | berks vendor /tmp/berks_cookbooks 58 | ls -lth /tmp/berks_cookbooks 59 | 60 | cd /tmp/Scenario-102/ 61 | ``` 62 | 63 | - Apply Chef update 64 | ``` 65 | ssh vagrant@192.168.50.10 66 | cd /tmp/Scenario-102 67 | 68 | # Before chef deployment, our VM doesn't have jq package 69 | which jq 70 | sudo chef-solo -c config/solo.rb -j config/node.json 71 | 72 | # After deployment, we should see jq package installed 73 | which jq 74 | ``` 75 | 76 | - Run code static check 77 | rubocop: 78 | ``` 79 | gem install rubocop -v "0.44.1" 80 | cd cookbooks/example 81 | rubocop . 82 | ``` 83 | Check more about rubocop: https://www.dennyzhang.com/rubocop_errors 84 | 85 | foodcritic: 86 | ``` 87 | gem install foodcritic -v "4.0.0" 88 | cd cookbooks/ 89 | foodcritic example 90 | ``` 91 | 92 | TODO: how to install foodcritic in mac OSX 93 | 94 | - Destroy local vm 95 | ``` 96 | vagrant destroy -f 97 | ``` 98 | 99 | # Test in public cloud? 100 | 101 | Now you have finished local VM deployment. Congratulations! 102 | 103 | Why not move to public cloud? AWS, AZure, or whatever. Should be easy for you, right? 104 | 105 | -------------------------------------------------------------------------------- /Scenario-102/Vagrantfile: -------------------------------------------------------------------------------- 1 | # -*- mode: ruby -*- 2 | Vagrant.configure("2") do |config| 3 | config.vm.box = "ubuntu/trusty64" 4 | config.vm.provider "virtualbox" do |vb| 5 | vb.name = "chef-sandbox" 6 | vb.customize ["modifyvm", :id, "--memory", 512, "--cpus", 2] 7 | end 8 | # host-only network 9 | config.vm.network :private_network, ip: "192.168.50.10" 10 | end 11 | -------------------------------------------------------------------------------- /Scenario-102/config/node.json: -------------------------------------------------------------------------------- 1 | { 2 | "run_list": [ "recipe[example]" ] 3 | } 4 | -------------------------------------------------------------------------------- /Scenario-102/config/solo.rb: -------------------------------------------------------------------------------- 1 | cookbook_path [File.expand_path(File.join(File.dirname(__FILE__), '..', "cookbooks")), '/tmp/berks_cookbooks/'] -------------------------------------------------------------------------------- /Scenario-102/cookbooks/example/.rubocop.yml: -------------------------------------------------------------------------------- 1 | AllCops: 2 | Excludes: 3 | 4 | Metrics/LineLength: 5 | Max: 100 6 | 7 | Style/Next: 8 | Enabled: false 9 | 10 | BlockLength: 11 | Max: 90 12 | -------------------------------------------------------------------------------- /Scenario-102/cookbooks/example/.travis.yml: -------------------------------------------------------------------------------- 1 | language: ruby 2 | 3 | rvm: 4 | - 2.1.1 5 | 6 | script: 7 | - bundle exec rspec --color --format progress 8 | - bundle exec foodcritic -f any . 9 | -------------------------------------------------------------------------------- /Scenario-102/cookbooks/example/Berksfile: -------------------------------------------------------------------------------- 1 | # -*- ruby -*- 2 | source 'https://supermarket.getchef.com' 3 | 4 | metadata 5 | -------------------------------------------------------------------------------- /Scenario-102/cookbooks/example/Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | # source 'https://ruby.taobao.org/' 3 | 4 | gem 'foodcritic', '~> 4.0.0' 5 | gem 'rubocop', '~> 0.48.1' 6 | -------------------------------------------------------------------------------- /Scenario-102/cookbooks/example/README.md: -------------------------------------------------------------------------------- 1 | A chef cookbook template: 2 | - Run apt-get update 3 | - Install jq package 4 | - Enforce rubocop and foodcritic code static check 5 | -------------------------------------------------------------------------------- /Scenario-102/cookbooks/example/metadata.rb: -------------------------------------------------------------------------------- 1 | name 'example' 2 | maintainer 'DennyZhang.com' 3 | maintainer_email 'contact@dennyzhang.com' 4 | license 'All rights reserved' 5 | description 'Dummy chef cookbook' 6 | long_description IO.read(File.join(File.dirname(__FILE__), 'README.md')) 7 | version '0.0.1' 8 | issues_url 'https://www.dennyzhang.com' 9 | source_url 'https://www.dennyzhang.com' 10 | 11 | supports 'ubuntu' 12 | 13 | depends 'apt' 14 | -------------------------------------------------------------------------------- /Scenario-102/cookbooks/example/recipes/default.rb: -------------------------------------------------------------------------------- 1 | # Run apt-get update first 2 | include_recipe 'apt::default' 3 | 4 | package 'jq' 5 | -------------------------------------------------------------------------------- /Scenario-103/README.md: -------------------------------------------------------------------------------- 1 | [![LinkedIn](https://raw.githubusercontent.com/USDevOps/mywechat-slack-group/master/images/linkedin.png)](https://www.linkedin.com/in/dennyzhang001) slack [![Github](https://raw.githubusercontent.com/USDevOps/mywechat-slack-group/master/images/github.png)](https://github.com/DennyZhang) 2 | 3 | File me [tickets](https://github.com/DennyZhang/challenges-chef/issues) or star [the repo](https://github.com/DennyZhang/challenges-chef). 4 | 5 | 6 | 7 | Table of Contents 8 | ================= 9 | 10 | * [Requirements](#requirements) 11 | * [Procedures](#procedures) 12 | 13 | 14 | 15 | 16 | 17 | # Requirements 18 | 1. Start 3 containers to run chef server, knife workstation and chef client 19 | 2. Install and configure knife 20 | 3. From knife node run chef deployment in chef client node 21 | 22 | # Procedures 23 | - Start docker-compose env 24 | ``` 25 | docker-compose up -d 26 | docker-compose ps 27 | ``` 28 | 29 | - Setup chef server in docker container 30 | 31 | In docker-compose.yml, chef_server is using a dedicated chef server image. 32 | 33 | ``` 34 | # https://hub.docker.com/r/base/chef-server/~/dockerfile/ 35 | 36 | # Verify chef server 37 | curl -k -I https://localhost/users/login 38 | ``` 39 | 40 | - Use chef_client as both client and knife workstation 41 | 42 | - Get certificate from chef server to chef knife 43 | 44 | To configure knife, we need admin.pem and chef-validator.pem from chef server node 45 | 46 | ``` 47 | docker cp chef_server:/etc/chef-server/admin.pem /tmp/admin.pem 48 | docker cp chef_server:/etc/chef-server/chef-validator.pem /tmp/chef-validator.pem 49 | 50 | docker cp /tmp/admin.pem chef_knife:/tmp/ 51 | docker cp /tmp/chef-validator.pem chef_knife:/tmp/ 52 | 53 | rm -rf /tmp/admin.pem /tmp/chef-validator.pem 54 | ``` 55 | 56 | - Configure knife workstation 57 | ``` 58 | docker exec -it chef_knife bash 59 | 60 | mkdir -p /root/chef-server/.chef 61 | mv /tmp/*.pem /root/chef-server/ 62 | chmod 600 -R /root/chef-server/*.pem 63 | ls -lth /root/chef-server/ 64 | 65 | which knife 66 | 67 | curl -k -I https://chef_server/organizations/digitalocean 68 | 69 | knife configure --initial 70 | 71 | # Please enter the chef server URL: 72 | # https://chef_server/organizations/myorg 73 | # 74 | # Please enter a name for the new user: 75 | # dennykitchen 76 | # 77 | # Please enter a password for the new user: 78 | # password1 79 | # 80 | 81 | cat > ~/.ssh/knife.rb < 111 | -------------------------------------------------------------------------------- /Scenario-103/config/node.json: -------------------------------------------------------------------------------- 1 | { 2 | "run_list": [ "recipe[example]" ] 3 | } 4 | -------------------------------------------------------------------------------- /Scenario-103/config/solo.rb: -------------------------------------------------------------------------------- 1 | cookbook_path [File.expand_path(File.join(File.dirname(__FILE__), '..', "cookbooks")), '/tmp/cookbooks/'] -------------------------------------------------------------------------------- /Scenario-103/cookbooks/example/.rubocop.yml: -------------------------------------------------------------------------------- 1 | AllCops: 2 | Excludes: 3 | 4 | Metrics/LineLength: 5 | Max: 100 6 | 7 | Style/Next: 8 | Enabled: false 9 | 10 | BlockLength: 11 | Max: 90 12 | -------------------------------------------------------------------------------- /Scenario-103/cookbooks/example/.travis.yml: -------------------------------------------------------------------------------- 1 | language: ruby 2 | 3 | rvm: 4 | - 2.1.1 5 | 6 | script: 7 | - bundle exec rspec --color --format progress 8 | - bundle exec foodcritic -f any . 9 | -------------------------------------------------------------------------------- /Scenario-103/cookbooks/example/Berksfile: -------------------------------------------------------------------------------- 1 | # -*- ruby -*- 2 | source 'https://supermarket.getchef.com' 3 | 4 | metadata 5 | -------------------------------------------------------------------------------- /Scenario-103/cookbooks/example/Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | # source 'https://ruby.taobao.org/' 3 | 4 | gem 'foodcritic', '~> 4.0.0' 5 | gem 'rubocop', '~> 0.48.1' 6 | -------------------------------------------------------------------------------- /Scenario-103/cookbooks/example/README.md: -------------------------------------------------------------------------------- 1 | A chef cookbook template: 2 | - Run apt-get update 3 | - Install jq package 4 | - Enforce rubocop and foodcritic code static check 5 | -------------------------------------------------------------------------------- /Scenario-103/cookbooks/example/metadata.rb: -------------------------------------------------------------------------------- 1 | name 'example' 2 | maintainer 'DennyZhang.com' 3 | maintainer_email 'contact@dennyzhang.com' 4 | license 'All rights reserved' 5 | description 'Dummy chef cookbook' 6 | long_description IO.read(File.join(File.dirname(__FILE__), 'README.md')) 7 | version '0.0.1' 8 | issues_url 'https://www.dennyzhang.com' 9 | source_url 'https://www.dennyzhang.com' 10 | 11 | supports 'ubuntu' 12 | 13 | depends 'apt' 14 | -------------------------------------------------------------------------------- /Scenario-103/cookbooks/example/recipes/default.rb: -------------------------------------------------------------------------------- 1 | # Run apt-get update first 2 | include_recipe 'apt::default' 3 | 4 | package 'jq' 5 | -------------------------------------------------------------------------------- /Scenario-103/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '2' 2 | services: 3 | chef_server: 4 | container_name: chef_server 5 | hostname: chef_server 6 | # https://hub.docker.com/r/base/chef-server/~/dockerfile/ 7 | image: base/chef-server 8 | # entrypoint: ["tail", "-f", "/dev/null"] 9 | privileged: true 10 | ports: 11 | - "443:443" 12 | chef_knife: 13 | container_name: chef_knife 14 | hostname: chef_knife 15 | # https://hub.docker.com/r/chef/chefdk/ 16 | image: chef/chefdk 17 | entrypoint: ["tail", "-f", "/dev/null"] 18 | chef_client: 19 | container_name: chef_client 20 | hostname: chef_client 21 | # https://hub.docker.com/r/chef/chefdk/ 22 | image: chef/chefdk 23 | entrypoint: ["tail", "-f", "/dev/null"] 24 | volumes: 25 | - ./config:/tmp/config 26 | - ./cookbooks:/tmp/cookbooks 27 | -------------------------------------------------------------------------------- /Scenario-201/README.md: -------------------------------------------------------------------------------- 1 | [![LinkedIn](https://raw.githubusercontent.com/USDevOps/mywechat-slack-group/master/images/linkedin.png)](https://www.linkedin.com/in/dennyzhang001) slack [![Github](https://raw.githubusercontent.com/USDevOps/mywechat-slack-group/master/images/github.png)](https://github.com/DennyZhang) 2 | 3 | File me [tickets](https://github.com/DennyZhang/challenges-chef/issues) or star [the repo](https://github.com/DennyZhang/challenges-chef). 4 | 5 | 6 | 7 | Table of Contents 8 | ================= 9 | 10 | * [Requirements](#requirements) 11 | * [Procedure](#procedure) 12 | 13 | 14 | 15 | 16 | 17 | # Requirements 18 | Run kitchen docker in your laptop. 19 | 1. Use kitchen to test your cookbook: start a container and test the logic 20 | 2. Enforce kitchen verify logic via serverspec 21 | 22 | # Procedure 23 | - Install bundle 24 | ``` 25 | apt-get install ruby-dev 26 | 27 | ruby --version 28 | # https://github.com/bundler/bundler/issues/4065 29 | sudo gem install bundler -n /usr/local/bin 30 | 31 | bundle --version 32 | ``` 33 | 34 | - Install gem depenencies 35 | ``` 36 | cd cookbooks/example 37 | bundle install 38 | ``` 39 | 40 | - Run kitchen test 41 | ``` 42 | # https://github.com/test-kitchen/kitchen-docker 43 | kitchen converge 44 | kitchen list 45 | kitchen verify 46 | kitchen destroy 47 | ``` 48 | 49 | 50 | -------------------------------------------------------------------------------- /Scenario-201/cookbooks/example/.kitchen.yml: -------------------------------------------------------------------------------- 1 | --- 2 | driver: 3 | name: docker 4 | 5 | driver_config: 6 | instance_name: <%= ENV.fetch('INSTANCE_NAME', "example") %> 7 | hostname: <%= ENV.fetch('INSTANCE_NAME', "example") %> 8 | use_sudo: false 9 | privileged: true 10 | remove_images: false 11 | image: <%= ENV.fetch('IMAGE_NAME', "chef/chefdk") %> 12 | # tls_verify: true 13 | # tls_cacert: <%= ENV.fetch('TLS_FOLDER', "tls") %>/ca.pem 14 | # tls_cert: <%= ENV.fetch('TLS_FOLDER', "tls") %>/cert.pem 15 | # tls_key: <%= ENV.fetch('TLS_FOLDER', "tls") %>/key.pem 16 | # socket: tcp://172.17.0.1:4243 17 | transport: 18 | username: kitchen 19 | 20 | provisioner: 21 | name: chef_zero 22 | require_chef_omnibus: 12.17.44 23 | data_path: test/shared 24 | client_rb: 25 | file_cache_path: "/var/chef/cache" 26 | 27 | platforms: 28 | - name: ubuntu-14.04 29 | 30 | suites: 31 | - name: default 32 | run_list: 33 | - recipe[apt::default] 34 | - recipe[example::default] 35 | attributes: 36 | {example: 37 | {update_version: '1.1' 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Scenario-201/cookbooks/example/.rubocop.yml: -------------------------------------------------------------------------------- 1 | AllCops: 2 | Excludes: 3 | 4 | Metrics/LineLength: 5 | Max: 100 6 | 7 | Style/Next: 8 | Enabled: false 9 | 10 | BlockLength: 11 | Max: 90 12 | -------------------------------------------------------------------------------- /Scenario-201/cookbooks/example/.travis.yml: -------------------------------------------------------------------------------- 1 | language: ruby 2 | 3 | rvm: 4 | - 2.1.1 5 | 6 | script: 7 | - bundle exec rspec --color --format progress 8 | - bundle exec foodcritic -f any . 9 | -------------------------------------------------------------------------------- /Scenario-201/cookbooks/example/Berksfile: -------------------------------------------------------------------------------- 1 | # -*- ruby -*- 2 | source 'https://supermarket.getchef.com' 3 | 4 | metadata 5 | -------------------------------------------------------------------------------- /Scenario-201/cookbooks/example/Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | # source 'https://ruby.taobao.org/' 3 | 4 | gem 'kitchen-docker', '>= 2.5.0' 5 | gem 'test-kitchen', '>= 1.4.1' 6 | 7 | gem 'berkshelf', '>= 5.2.0' 8 | 9 | gem 'foodcritic', '~> 4.0.0' 10 | gem 'rubocop', '~> 0.48.1' 11 | -------------------------------------------------------------------------------- /Scenario-201/cookbooks/example/README.md: -------------------------------------------------------------------------------- 1 | A chef cookbook template: 2 | -------------------------------------------------------------------------------- /Scenario-201/cookbooks/example/attributes/default.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | default['example']['update_version'] = '1.0' 4 | -------------------------------------------------------------------------------- /Scenario-201/cookbooks/example/metadata.rb: -------------------------------------------------------------------------------- 1 | name 'example' 2 | maintainer 'DennyZhang.com' 3 | maintainer_email 'contact@dennyzhang.com' 4 | license 'All rights reserved' 5 | description 'Dummy chef cookbook' 6 | long_description IO.read(File.join(File.dirname(__FILE__), 'README.md')) 7 | version '0.0.1' 8 | issues_url 'https://www.dennyzhang.com' 9 | source_url 'https://www.dennyzhang.com' 10 | 11 | supports 'ubuntu' 12 | 13 | depends 'apt' 14 | -------------------------------------------------------------------------------- /Scenario-201/cookbooks/example/recipes/default.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | # 4 | # Cookbook Name:: example 5 | # Recipe:: default 6 | # 7 | # Copyright 2017, DennyZhang.com 8 | # 9 | # All rights reserved - Do Not Redistribute 10 | # 11 | 12 | %w[jq].each do |x| 13 | package 'jq' do 14 | action :install 15 | not_if "dpkg -l #{x} | grep -E '^ii'" 16 | end 17 | end 18 | 19 | directory '/etc/ec2-user/' do 20 | owner 'root' 21 | group 'root' 22 | mode 0o755 23 | action :create 24 | end 25 | 26 | template '/etc/ec2-user/version.txt' do 27 | source 'version.txt.erb' 28 | mode 0o700 29 | end 30 | -------------------------------------------------------------------------------- /Scenario-201/cookbooks/example/templates/default/version.txt.erb: -------------------------------------------------------------------------------- 1 | Update version: <%= node['example']['update_version'] %> -------------------------------------------------------------------------------- /Scenario-201/cookbooks/example/test/integration/default/serverspec/server_spec.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | require 'serverspec' 4 | require 'socket' 5 | require 'json' 6 | 7 | # Required by serverspec 8 | set :backend, :exec 9 | 10 | chef_data = JSON.parse(IO.read('/tmp/kitchen/dna.json')) 11 | 12 | update_version = \ 13 | chef_data.fetch('example').fetch('update_version') 14 | 15 | # TODO: verify the specific version '1.5-1-a5b5cbe' 16 | describe package('jq') do 17 | it { should be_installed } 18 | end 19 | 20 | describe command('cat /etc/ec2-user/version.txt') do 21 | its(:stdout) { should contain update_version } 22 | end 23 | -------------------------------------------------------------------------------- /Scenario-202/README.md: -------------------------------------------------------------------------------- 1 | [![LinkedIn](https://raw.githubusercontent.com/USDevOps/mywechat-slack-group/master/images/linkedin.png)](https://www.linkedin.com/in/dennyzhang001) slack [![Github](https://raw.githubusercontent.com/USDevOps/mywechat-slack-group/master/images/github.png)](https://github.com/DennyZhang) 2 | 3 | File me [tickets](https://github.com/DennyZhang/challenges-chef/issues) or star [the repo](https://github.com/DennyZhang/challenges-chef). 4 | 5 | 6 | 7 | Table of Contents 8 | ================= 9 | 10 | * [Requirements](#requirements) 11 | * [Procedure](#procedure) 12 | * [Common Setup](#common-setup) 13 | * [kitchen docker deployment](#kitchen-docker-deployment) 14 | * [kitchen digitalocean deployment](#kitchen-digitalocean-deployment) 15 | * [kitchen ec2 deployment](#kitchen-ec2-deployment) 16 | * [kitchen vagrant deployment](#kitchen-vagrant-deployment) 17 | 18 | 19 | 20 | 21 | 22 | # Requirements 23 | 1. Use Kitchen to test local vm deployment 24 | 2. Use Kitchen to test docker deployment 25 | 3. Use Kitchen to test cloud VM deployment 26 | 27 | # Procedure 28 | ## Common Setup 29 | - Install bundle 30 | ``` 31 | apt-get install ruby-dev 32 | 33 | ruby --version 34 | # https://github.com/bundler/bundler/issues/4065 35 | sudo gem install bundler -n /usr/local/bin 36 | 37 | bundle --version 38 | ``` 39 | 40 | - Install gem depenencies 41 | ``` 42 | cd cookbooks/example 43 | bundle install 44 | ``` 45 | 46 | ## kitchen docker deployment 47 | - Run kitchen test 48 | ``` 49 | # https://github.com/test-kitchen/kitchen-docker 50 | kitchen converge 51 | kitchen list 52 | kitchen verify 53 | kitchen destroy 54 | ``` 55 | 56 | ## kitchen digitalocean deployment 57 | ``` 58 | # https://github.com/test-kitchen/kitchen-digitalocean 59 | cd cookbooks/example 60 | export KITCHEN_YAML=".kitchen_digitalocean.yml" 61 | 62 | # Customize this with your credential 63 | export DIGITALOCEAN_ACCESS_TOKEN="1234" 64 | export DIGITALOCEAN_SSH_KEY_IDS="1234, 5678" 65 | 66 | kitchen converge 67 | kitchen list 68 | kitchen verify 69 | kitchen destroy 70 | 71 | - TODO: how does the ssh key work? With which OS user, and where the key is? 72 | ``` 73 | 74 | ## kitchen ec2 deployment 75 | - Install AWS cli and configure aws credential 76 | ``` 77 | # http://docs.aws.amazon.com/cli/latest/userguide/installing.html 78 | pip install awscli 79 | aws configure 80 | 81 | # Customize this 82 | export KEY_USER="denny-kitchen-test" 83 | aws ec2 create-key-pair --key-name $KEY_USER | ruby -e "require 'json'; puts JSON.parse(STDIN.read)['KeyMaterial']" > ~/.ssh/$KEY_USER 84 | 85 | chmod 600 ~/.ssh/$KEY_USER 86 | 87 | export AWS_SSH_KEY_ID="$KEY_USER" 88 | 89 | ``` 90 | 91 | - Install and run kitchen-ec2 92 | ``` 93 | # https://github.com/test-kitchen/kitchen-ec2 94 | # https://github.com/test-kitchen/kitchen-ec2/blob/master/lib/kitchen/driver/ec2.rb 95 | # http://kg4giy.com/2015/12/11/test-kitchen-to-support-amazon-web-service-aws-amis/ 96 | 97 | cd cookbooks/example 98 | export KITCHEN_YAML=".kitchen_ec2.yml" 99 | # TODO: customize this 100 | export AWS_SSH_KEY_ID="$KEY_USER" 101 | 102 | # Update bundle: https://github.com/chef/chef-provisioning/issues/151 103 | bundle update 104 | 105 | kitchen converge 106 | kitchen list 107 | kitchen verify 108 | kitchen destroy 109 | ``` 110 | 111 | ## kitchen vagrant deployment 112 | ``` 113 | # https://github.com/test-kitchen/kitchen-vagrant 114 | cd cookbooks/example 115 | export KITCHEN_YAML=".kitchen_vagrant.yml" 116 | 117 | bundle install 118 | 119 | kitchen converge 120 | kitchen list 121 | kitchen verify 122 | kitchen destroy 123 | ``` 124 | 125 | -------------------------------------------------------------------------------- /Scenario-202/cookbooks/example/.kitchen.yml: -------------------------------------------------------------------------------- 1 | --- 2 | driver: 3 | name: docker 4 | 5 | driver_config: 6 | instance_name: <%= ENV.fetch('INSTANCE_NAME', "example") %> 7 | hostname: <%= ENV.fetch('INSTANCE_NAME', "example") %> 8 | use_sudo: false 9 | privileged: true 10 | remove_images: false 11 | image: <%= ENV.fetch('IMAGE_NAME', "chef/chefdk") %> 12 | # tls_verify: true 13 | # tls_cacert: <%= ENV.fetch('TLS_FOLDER', "tls") %>/ca.pem 14 | # tls_cert: <%= ENV.fetch('TLS_FOLDER', "tls") %>/cert.pem 15 | # tls_key: <%= ENV.fetch('TLS_FOLDER', "tls") %>/key.pem 16 | # socket: tcp://172.17.0.1:4243 17 | transport: 18 | username: kitchen 19 | 20 | provisioner: 21 | name: chef_zero 22 | require_chef_omnibus: 13.6.4 23 | data_path: test/shared 24 | client_rb: 25 | file_cache_path: "/var/chef/cache" 26 | 27 | platforms: 28 | - name: ubuntu-14.04 29 | 30 | suites: 31 | - name: default 32 | run_list: 33 | - recipe[apt::default] 34 | - recipe[example::default] 35 | attributes: 36 | {example: 37 | {update_version: '1.1' 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Scenario-202/cookbooks/example/.kitchen_digitalocean.yml: -------------------------------------------------------------------------------- 1 | --- 2 | driver: 3 | name: digitalocean 4 | 5 | provisioner: 6 | name: chef_zero 7 | require_chef_omnibus: 13.6.4 8 | data_path: test/shared 9 | 10 | platforms: 11 | - name: example 12 | driver_config: 13 | region: sfo2 14 | size: <%= ENV.fetch('DIGITALOCEAN_FLAVOR', "1gb") %> 15 | private_networking: false 16 | image: ubuntu-14-04-x64 17 | server_name: <%= ENV.fetch('INSTANCE_NAME', "example") %> 18 | 19 | suites: 20 | - name: default 21 | run_list: 22 | - recipe[apt::default] 23 | - recipe[example::default] 24 | attributes: 25 | {example: 26 | {update_version: '1.1' 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Scenario-202/cookbooks/example/.kitchen_ec2.yml: -------------------------------------------------------------------------------- 1 | --- 2 | driver: 3 | name: ec2 4 | region: us-east-1 5 | 6 | transport: 7 | ssh_key: ~/.ssh/<%= ENV.fetch('KEY_USER', "") %> 8 | username: ["ec2-user"] 9 | 10 | provisioner: 11 | name: chef_zero 12 | require_chef_omnibus: 13.6.4 13 | data_path: test/shared 14 | 15 | platforms: 16 | - name: ubuntu-14.04 17 | driver: 18 | image_id: <%= ENV.fetch('EC2_IMAGE_ID', "ami-6869aa05") %> 19 | instance_type: <%= ENV.fetch('EC2_INSTANCE_TYPE', "t2.micro") %> 20 | 21 | suites: 22 | - name: default 23 | run_list: 24 | - recipe[apt::default] 25 | - recipe[example::default] 26 | attributes: 27 | {example: 28 | {update_version: '1.1' 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Scenario-202/cookbooks/example/.kitchen_vagrant.yml: -------------------------------------------------------------------------------- 1 | --- 2 | driver: 3 | name: vagrant 4 | 5 | driver_config: 6 | instance_name: <%= ENV.fetch('INSTANCE_NAME', "example") %> 7 | hostname: <%= ENV.fetch('INSTANCE_NAME', "example") %> 8 | transport: 9 | username: kitchen 10 | 11 | provisioner: 12 | name: chef_zero 13 | require_chef_omnibus: 13.6.4 14 | data_path: test/shared 15 | client_rb: 16 | file_cache_path: "/var/chef/cache" 17 | 18 | platforms: 19 | - name: ubuntu-14.04 20 | 21 | suites: 22 | - name: default 23 | run_list: 24 | - recipe[apt::default] 25 | - recipe[example::default] 26 | attributes: 27 | {example: 28 | {update_version: '1.1' 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Scenario-202/cookbooks/example/.rubocop.yml: -------------------------------------------------------------------------------- 1 | AllCops: 2 | Excludes: 3 | 4 | Metrics/LineLength: 5 | Max: 100 6 | 7 | Style/Next: 8 | Enabled: false 9 | 10 | BlockLength: 11 | Max: 90 12 | -------------------------------------------------------------------------------- /Scenario-202/cookbooks/example/.travis.yml: -------------------------------------------------------------------------------- 1 | language: ruby 2 | 3 | rvm: 4 | - 2.1.1 5 | 6 | script: 7 | - bundle exec rspec --color --format progress 8 | - bundle exec foodcritic -f any . 9 | -------------------------------------------------------------------------------- /Scenario-202/cookbooks/example/Berksfile: -------------------------------------------------------------------------------- 1 | # -*- ruby -*- 2 | source 'https://supermarket.getchef.com' 3 | 4 | metadata 5 | -------------------------------------------------------------------------------- /Scenario-202/cookbooks/example/Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | # source 'https://ruby.taobao.org/' 3 | 4 | gem 'kitchen-digitalocean', '= 0.9.8' 5 | gem 'kitchen-docker', '= 2.6.0' 6 | gem 'kitchen-ec2', '= 1.3.2' 7 | gem 'kitchen-vagrant', '= 1.2.1' 8 | 9 | gem 'test-kitchen', '= 1.19.1' 10 | 11 | gem 'berkshelf', '= 6.3.1' 12 | 13 | gem 'foodcritic', '~> 4.0.0' 14 | gem 'rubocop', '~> 0.48.1' 15 | -------------------------------------------------------------------------------- /Scenario-202/cookbooks/example/README.md: -------------------------------------------------------------------------------- 1 | A chef cookbook template: 2 | -------------------------------------------------------------------------------- /Scenario-202/cookbooks/example/attributes/default.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | default['example']['update_version'] = '1.0' 4 | -------------------------------------------------------------------------------- /Scenario-202/cookbooks/example/chefignore: -------------------------------------------------------------------------------- 1 | .kitchen -------------------------------------------------------------------------------- /Scenario-202/cookbooks/example/metadata.rb: -------------------------------------------------------------------------------- 1 | name 'example' 2 | maintainer 'DennyZhang.com' 3 | maintainer_email 'contact@dennyzhang.com' 4 | license 'All rights reserved' 5 | description 'Dummy chef cookbook' 6 | long_description IO.read(File.join(File.dirname(__FILE__), 'README.md')) 7 | version '0.0.1' 8 | issues_url 'https://www.dennyzhang.com' 9 | source_url 'https://www.dennyzhang.com' 10 | 11 | supports 'ubuntu' 12 | 13 | depends 'apt' 14 | -------------------------------------------------------------------------------- /Scenario-202/cookbooks/example/recipes/default.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | # 4 | # Cookbook Name:: example 5 | # Recipe:: default 6 | # 7 | # Copyright 2017, DennyZhang.com 8 | # 9 | # All rights reserved - Do Not Redistribute 10 | # 11 | 12 | %w[jq].each do |x| 13 | package x do 14 | action :install 15 | not_if "dpkg -l #{x} | grep -E '^ii'" 16 | end 17 | end 18 | 19 | directory '/etc/ec2-user/' do 20 | owner 'root' 21 | group 'root' 22 | mode 0o755 23 | action :create 24 | end 25 | 26 | template '/etc/ec2-user/version.txt' do 27 | source 'version.txt.erb' 28 | mode 0o700 29 | end 30 | -------------------------------------------------------------------------------- /Scenario-202/cookbooks/example/templates/default/version.txt.erb: -------------------------------------------------------------------------------- 1 | Update version: <%= node['example']['update_version'] %> -------------------------------------------------------------------------------- /Scenario-202/cookbooks/example/test/integration/default/serverspec/server_spec.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | require 'serverspec' 4 | require 'socket' 5 | require 'json' 6 | 7 | # Required by serverspec 8 | set :backend, :exec 9 | 10 | chef_data = JSON.parse(IO.read('/tmp/kitchen/dna.json')) 11 | 12 | update_version = \ 13 | chef_data.fetch('example').fetch('update_version') 14 | 15 | # TODO: verify the specific version '1.5-1-a5b5cbe' 16 | describe package('jq') do 17 | it { should be_installed } 18 | end 19 | 20 | describe command('cat /etc/ec2-user/version.txt') do 21 | its(:stdout) { should contain update_version } 22 | end 23 | -------------------------------------------------------------------------------- /Scenario-301/README.md: -------------------------------------------------------------------------------- 1 | [![LinkedIn](https://raw.githubusercontent.com/USDevOps/mywechat-slack-group/master/images/linkedin.png)](https://www.linkedin.com/in/dennyzhang001) slack [![Github](https://raw.githubusercontent.com/USDevOps/mywechat-slack-group/master/images/github.png)](https://github.com/DennyZhang) 2 | 3 | File me [tickets](https://github.com/DennyZhang/challenges-chef/issues) or star [the repo](https://github.com/DennyZhang/challenges-chef). 4 | 5 | 6 | 7 | Table of Contents 8 | ================= 9 | 10 | * [Requirement](#requirement) 11 | * [Procedure](#procedure) 12 | * [More Resources](#more-resources) 13 | 14 | 15 | 16 | # Requirement 17 | 18 | 1. Deploy a standalone jenkins by chef 19 | 2. Chef shall add one jenkins user 20 | 3. Chef shall add a dummy job with slack notification enabled 21 | 4. Run deployment in docker, vagrant and EC2 22 | 5. Test both Ubuntu 14.04 and Centos 7 23 | 24 | # Procedure 25 | ## Common Setup 26 | - Install bundle 27 | ``` 28 | apt-get install ruby-dev 29 | 30 | ruby --version 31 | # https://github.com/bundler/bundler/issues/4065 32 | sudo gem install bundler -n /usr/local/bin 33 | 34 | bundle --version 35 | ``` 36 | 37 | - Install gem depenencies 38 | ``` 39 | cd cookbooks/jenkins-demo 40 | bundle install 41 | ``` 42 | 43 | ## kitchen docker deployment 44 | - Run kitchen test 45 | ``` 46 | # https://github.com/test-kitchen/kitchen-docker 47 | 48 | # Customize this, if you need to enable jenkins slack notification 49 | export SLACK_TOKEN="XXXX" 50 | kitchen list 51 | kitchen test 52 | ``` 53 | 54 | ## kitchen digitalocean deployment 55 | ``` 56 | # https://github.com/test-kitchen/kitchen-digitalocean 57 | cd cookbooks/jenkins-demo 58 | export KITCHEN_YAML=".kitchen_digitalocean.yml" 59 | 60 | # Customize this with your credential 61 | export DIGITALOCEAN_ACCESS_TOKEN="1234" 62 | export DIGITALOCEAN_SSH_KEY_IDS="1234, 5678" 63 | 64 | # Customize this, if you need to enable jenkins slack notification 65 | export SLACK_TOKEN="XXXX" 66 | kitchen list 67 | kitchen test 68 | 69 | - TODO: how does the ssh key work? With which OS user, and where the key is? 70 | ``` 71 | 72 | ## kitchen ec2 deployment 73 | - Install AWS cli and configure aws credential 74 | ``` 75 | # http://docs.aws.amazon.com/cli/latest/userguide/installing.html 76 | pip install awscli 77 | aws configure 78 | 79 | # Customize this 80 | export KEY_USER="denny-kitchen-test" 81 | aws ec2 create-key-pair --key-name $KEY_USER | ruby -e "require 'json'; puts JSON.parse(STDIN.read)['KeyMaterial']" > ~/.ssh/$KEY_USER 82 | 83 | chmod 600 ~/.ssh/$KEY_USER 84 | 85 | export AWS_SSH_KEY_ID="$KEY_USER" 86 | ``` 87 | 88 | - Install and run kitchen-ec2 89 | ``` 90 | # https://github.com/test-kitchen/kitchen-ec2 91 | # https://github.com/test-kitchen/kitchen-ec2/blob/master/lib/kitchen/driver/ec2.rb 92 | # http://kg4giy.com/2015/12/11/test-kitchen-to-support-amazon-web-service-aws-amis/ 93 | 94 | cd cookbooks/jenkins-demo 95 | export KITCHEN_YAML=".kitchen_ec2.yml" 96 | # TODO: customize this 97 | export AWS_SSH_KEY_ID="$KEY_USER" 98 | 99 | # Update bundle: https://github.com/chef/chef-provisioning/issues/151 100 | bundle update 101 | 102 | # Customize this, if you need to enable jenkins slack notification 103 | export SLACK_TOKEN="XXXX" 104 | kitchen list 105 | kitchen test 106 | ``` 107 | 108 | ## kitchen vagrant deployment 109 | ``` 110 | # https://github.com/test-kitchen/kitchen-vagrant 111 | cd cookbooks/jenkins-demo 112 | export KITCHEN_YAML=".kitchen_vagrant.yml" 113 | 114 | bundle install 115 | 116 | # Customize this, if you need to enable jenkins slack notification 117 | export SLACK_TOKEN="XXXX" 118 | kitchen list 119 | kitchen test 120 | ``` 121 | 122 | # More Resources 123 | - jenkins cookbook: https://github.com/chef-cookbooks/jenkins 124 | 125 | -------------------------------------------------------------------------------- /Scenario-301/cookbooks/jenkins-demo/.kitchen.yml: -------------------------------------------------------------------------------- 1 | --- 2 | driver: 3 | name: docker 4 | 5 | driver_config: 6 | use_sudo: false 7 | # because Docker and SystemD/Upstart 8 | privileged: true 9 | remove_images: false 10 | hostname: <%= ENV.fetch('INSTANCE_NAME', "jenkins-demo") %> 11 | # tls_verify: true 12 | # tls_cacert: <%= ENV.fetch('TLS_FOLDER', "tls") %>/ca.pem 13 | # tls_cert: <%= ENV.fetch('TLS_FOLDER', "tls") %>/cert.pem 14 | # tls_key: <%= ENV.fetch('TLS_FOLDER', "tls") %>/key.pem 15 | # socket: tcp://172.17.0.1:4243 16 | transport: 17 | username: kitchen 18 | 19 | provisioner: 20 | name: chef_zero 21 | require_chef_omnibus: 13.6.4 22 | data_path: test/shared 23 | client_rb: 24 | file_cache_path: "/var/chef/cache" 25 | 26 | platforms: 27 | - name: centos-7 28 | driver_config: 29 | # https://hub.docker.com/r/dokken/centos-7/ 30 | instance_name: <%= ENV.fetch('INSTANCE_NAME', "jenkins-demo-centos7") %> 31 | image: <%= ENV.fetch('IMAGE_NAME', "dokken/centos-7") %> 32 | pid_one_command: /usr/lib/systemd/systemd 33 | forward: 34 | - <%= ENV.fetch('DOCKER_PORT_FORWARD_PREFIX', "180") %>80:8080 35 | - name: ubuntu-14.04 36 | driver_config: 37 | instance_name: <%= ENV.fetch('INSTANCE_NAME', "jenkins-demo-ubuntu1404") %> 38 | image: <%= ENV.fetch('IMAGE_NAME', "ubuntu:14.04") %> 39 | forward: 40 | - <%= ENV.fetch('DOCKER_PORT_FORWARD_PREFIX', "280") %>80:8080 41 | 42 | suites: 43 | - name: default 44 | run_list: 45 | - recipe[apt::default] 46 | - recipe[jenkins-demo::default] 47 | - recipe[jenkins-demo::conf_job] 48 | attributes: 49 | {jenkins_demo: 50 | {jenkins_jobs: 'CommonServerCheckRepo', 51 | slack_teamdomain: 'mywechat', 52 | slack_authtoken: '<%= ENV.fetch('SLACK_TOKEN', "") %>', 53 | # TODO different env use different port 54 | # TODO use server ip 55 | slack_buildserverurl: 'http://localhost:<%= ENV.fetch('DOCKER_PORT_FORWARD_PREFIX', "180") %>80/', 56 | slack_room: '#denny-alerts', 57 | default_username: '<%= ENV.fetch('JENKINS_DEFAULT_USERNAME', "usertest123") %>', 58 | default_password: '<%= ENV.fetch('JENKINS_DEFAULT_PASSWORD', "password123") %>' 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /Scenario-301/cookbooks/jenkins-demo/.kitchen_digitalocean.yml: -------------------------------------------------------------------------------- 1 | --- 2 | driver: 3 | name: digitalocean 4 | 5 | provisioner: 6 | name: chef_zero 7 | require_chef_omnibus: 13.6.4 8 | data_path: test/shared 9 | 10 | platforms: 11 | - name: jenkins-demo-centos7 12 | driver_config: 13 | region: sfo2 14 | size: <%= ENV.fetch('DIGITALOCEAN_FLAVOR', "1gb") %> 15 | private_networking: false 16 | # https://github.com/test-kitchen/kitchen-digitalocean 17 | image: centos-7-x64 18 | server_name: <%= ENV.fetch('INSTANCE_NAME', "jenkins-demo-centos7") %> 19 | - name: jenkins-demo-ubuntu1404 20 | driver_config: 21 | region: sfo2 22 | size: <%= ENV.fetch('DIGITALOCEAN_FLAVOR', "1gb") %> 23 | private_networking: false 24 | image: ubuntu-14-04-x64 25 | server_name: <%= ENV.fetch('INSTANCE_NAME', "jenkins-demo-ubuntu1404") %> 26 | 27 | suites: 28 | - name: default 29 | run_list: 30 | - recipe[apt::default] 31 | - recipe[jenkins-demo::default] 32 | - recipe[jenkins-demo::conf_job] 33 | attributes: 34 | {jenkins_demo: 35 | {jenkins_jobs: 'CommonServerCheckRepo', 36 | slack_teamdomain: 'mywechat', 37 | slack_authtoken: '<%= ENV.fetch('SLACK_TOKEN', "") %>', 38 | # TODO different env use different port 39 | # TODO use server ip 40 | slack_buildserverurl: 'http://localhost:<%= ENV.fetch('DOCKER_PORT_FORWARD_PREFIX', "180") %>80/', 41 | slack_room: '#denny-alerts', 42 | default_username: '<%= ENV.fetch('JENKINS_DEFAULT_USERNAME', "usertest123") %>', 43 | default_password: '<%= ENV.fetch('JENKINS_DEFAULT_PASSWORD', "password123") %>' 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Scenario-301/cookbooks/jenkins-demo/.kitchen_ec2.yml: -------------------------------------------------------------------------------- 1 | --- 2 | driver: 3 | name: ec2 4 | region: us-east-1 5 | 6 | transport: 7 | ssh_key: ~/.ssh/<%= ENV.fetch('KEY_USER', "") %> 8 | username: ec2-user 9 | 10 | provisioner: 11 | name: chef_zero 12 | require_chef_omnibus: 13.6.4 13 | data_path: test/shared 14 | 15 | platforms: 16 | - name: ubuntu-1404 17 | driver: 18 | # https://cloud-images.ubuntu.com/releases/14.04/release-20150506/ 19 | image_id: <%= ENV.fetch('EC2_IMAGE_ID', "ami-8d9e1cf7") %> 20 | instance_type: <%= ENV.fetch('EC2_INSTANCE_TYPE', "t2.micro") %> 21 | transport: 22 | username: ubuntu 23 | - name: centos-7 24 | driver: 25 | # https://wiki.centos.org/Cloud/AWS 26 | # https://stackoverflow.com/questions/40835953/how-to-find-ami-id-of-centos-7-image-in-aws-marketplace 27 | image_id: <%= ENV.fetch('EC2_IMAGE_ID', "ami-ae7bfdb8") %> 28 | instance_type: <%= ENV.fetch('EC2_INSTANCE_TYPE', "t2.micro") %> 29 | transport: 30 | username: centos 31 | - name: centos-ami 32 | driver: 33 | image_id: <%= ENV.fetch('EC2_IMAGE_ID', "ami-6869aa05") %> 34 | instance_type: <%= ENV.fetch('EC2_INSTANCE_TYPE', "t2.micro") %> 35 | 36 | suites: 37 | - name: default 38 | run_list: 39 | - recipe[apt::default] 40 | - recipe[jenkins-demo::default] 41 | - recipe[jenkins-demo::conf_job] 42 | attributes: 43 | {jenkins_demo: 44 | {jenkins_jobs: 'CommonServerCheckRepo', 45 | slack_teamdomain: 'mywechat', 46 | slack_authtoken: '<%= ENV.fetch('SLACK_TOKEN', "") %>', 47 | # TODO different env use different port 48 | # TODO use server ip 49 | slack_buildserverurl: 'http://localhost:<%= ENV.fetch('DOCKER_PORT_FORWARD_PREFIX', "180") %>80/', 50 | slack_room: '#denny-alerts', 51 | default_username: '<%= ENV.fetch('JENKINS_DEFAULT_USERNAME', "usertest123") %>', 52 | default_password: '<%= ENV.fetch('JENKINS_DEFAULT_PASSWORD', "password123") %>' 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /Scenario-301/cookbooks/jenkins-demo/.kitchen_vagrant.yml: -------------------------------------------------------------------------------- 1 | --- 2 | driver: 3 | name: vagrant 4 | 5 | driver_config: 6 | hostname: <%= ENV.fetch('INSTANCE_NAME', "jenkins-demo") %> 7 | # https://github.com/test-kitchen/kitchen-vagrant 8 | memory: 1024 9 | transport: 10 | username: kitchen 11 | 12 | provisioner: 13 | name: chef_zero 14 | require_chef_omnibus: 13.6.4 15 | data_path: test/shared 16 | client_rb: 17 | file_cache_path: "/var/chef/cache" 18 | 19 | platforms: 20 | - name: centos-7 21 | driver_config: 22 | instance_name: <%= ENV.fetch('INSTANCE_NAME', "jenkins-demo-centos7") %> 23 | network: 24 | - ["forwarded_port", {guest: 8080, host: 18080}] 25 | - name: ubuntu-14.04 26 | # https://stackoverflow.com/questions/38677059/port-forwarding-not-working-with-test-kitchen-and-vagrant 27 | driver_config: 28 | instance_name: <%= ENV.fetch('INSTANCE_NAME', "jenkins-demo-ubuntu1404") %> 29 | network: 30 | - ["forwarded_port", {guest: 8080, host: 28080}] 31 | 32 | suites: 33 | - name: default 34 | run_list: 35 | - recipe[apt::default] 36 | - recipe[jenkins-demo::default] 37 | - recipe[jenkins-demo::conf_job] 38 | attributes: 39 | {jenkins_demo: 40 | {jenkins_jobs: 'CommonServerCheckRepo', 41 | slack_teamdomain: 'mywechat', 42 | slack_authtoken: '<%= ENV.fetch('SLACK_TOKEN', "") %>', 43 | # TODO different env use different port 44 | # TODO use server ip 45 | slack_buildserverurl: 'http://localhost:<%= ENV.fetch('DOCKER_PORT_FORWARD_PREFIX', "180") %>80/', 46 | slack_room: '#denny-alerts', 47 | default_username: '<%= ENV.fetch('JENKINS_DEFAULT_USERNAME', "usertest123") %>', 48 | default_password: '<%= ENV.fetch('JENKINS_DEFAULT_PASSWORD', "password123") %>' 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Scenario-301/cookbooks/jenkins-demo/.rubocop.yml: -------------------------------------------------------------------------------- 1 | AllCops: 2 | Exclude: 3 | - Berksfile 4 | 5 | Style/Next: 6 | Enabled: false 7 | 8 | Metrics/LineLength: 9 | Max: 90 10 | 11 | MethodLength: 12 | Max: 20 13 | 14 | Metrics/AbcSize: 15 | Enabled: false 16 | -------------------------------------------------------------------------------- /Scenario-301/cookbooks/jenkins-demo/Berksfile: -------------------------------------------------------------------------------- 1 | # -*- ruby -*- 2 | source 'https://supermarket.getchef.com' 3 | 4 | metadata 5 | -------------------------------------------------------------------------------- /Scenario-301/cookbooks/jenkins-demo/Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | # source 'https://ruby.taobao.org/' 3 | 4 | gem 'kitchen-digitalocean', '= 0.9.8' 5 | gem 'kitchen-docker', '= 2.6.0' 6 | gem 'kitchen-ec2', '= 1.3.2' 7 | gem 'kitchen-vagrant', '= 1.2.1' 8 | 9 | gem 'test-kitchen', '= 1.19.1' 10 | 11 | gem 'berkshelf', '= 6.3.1' 12 | 13 | gem 'foodcritic', '~> 4.0.0' 14 | gem 'rubocop', '~> 0.48.1' 15 | -------------------------------------------------------------------------------- /Scenario-301/cookbooks/jenkins-demo/README.md: -------------------------------------------------------------------------------- 1 | jenkins-demo Cookbook 2 | ================ 3 | Setup and configure demo jenkins 4 | -------------------------------------------------------------------------------- /Scenario-301/cookbooks/jenkins-demo/attributes/conf_job.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | # 4 | # Copyright 2017, DennyZhang.com 5 | # 6 | # All rights reserved - Do Not Redistribute 7 | # 8 | 9 | default['jenkins_demo']['jenkins_jobs'] = '' 10 | # slack notification 11 | default['jenkins_demo']['slack_teamdomain'] = '' 12 | default['jenkins_demo']['slack_authtoken'] = '' 13 | default['jenkins_demo']['slack_buildserverurl'] = '' 14 | default['jenkins_demo']['slack_room'] = '' 15 | -------------------------------------------------------------------------------- /Scenario-301/cookbooks/jenkins-demo/attributes/default.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | # 4 | # Copyright 2017, DennyZhang.com 5 | # 6 | # All rights reserved - Do Not Redistribute 7 | # 8 | 9 | default['jenkins_demo']['jenkins_plugins'] = { 10 | 'thinBackup' => '1.9', 11 | # 'command-launcher' => '1.0', 12 | 'bouncycastle-api' => '2.16.2', 13 | 'credentials' => '2.1.16', 14 | 'plain-credentials' => '1.4', 15 | 'slack' => '2.3', 16 | 'script-security' => '1.35' 17 | } 18 | 19 | ######################################## 20 | default['jenkins_demo']['default_username'] = '' 21 | default['jenkins_demo']['default_password'] = '' 22 | -------------------------------------------------------------------------------- /Scenario-301/cookbooks/jenkins-demo/files/default/serverspec_check.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | function setup_serverspec() { 3 | working_dir=${1?} 4 | cd "$working_dir" 5 | if [ ! -f spec/spec_helper.rb ]; then 6 | echo "Setup Serverspec Test case" 7 | cat > spec/spec_helper.rb < Rakefile < 'spec:all' 18 | task :default => :spec 19 | 20 | namespace :spec do 21 | targets = [] 22 | Dir.glob('./spec/*').each do |dir| 23 | next unless File.directory?(dir) 24 | target = File.basename(dir) 25 | target = "_#{target}" if target == "default" 26 | targets << target 27 | end 28 | 29 | task :all => targets 30 | task :default => :all 31 | 32 | targets.each do |target| 33 | original_target = target == "_default" ? target[1..-1] : target 34 | desc "Run serverspec tests to #{original_target}" 35 | RSpec::Core::RakeTask.new(target.to_sym) do |t| 36 | ENV['TARGET_HOST'] = original_target 37 | t.pattern = "spec/#{original_target}/*_spec.rb" 38 | end 39 | end 40 | end 41 | EOF 42 | fi 43 | } 44 | 45 | ######################################################### 46 | [ -n "$working_dir" ] || working_dir="$WORKSPACE" 47 | 48 | mkdir -p "$working_dir/spec/localhost" 49 | cd "$working_dir" 50 | 51 | setup_serverspec "$working_dir" 52 | 53 | cat > spec/localhost/sample_spec.rb <= 14.04' 14 | depends 'apt', '=2.6.1' 15 | depends 'java' 16 | depends 'jenkins', '=5.0.4' 17 | -------------------------------------------------------------------------------- /Scenario-301/cookbooks/jenkins-demo/recipes/conf_job.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | # 4 | # Cookbook Name:: jenkins-demo 5 | # Recipe:: conf_job 6 | # 7 | # Copyright 2017, DennyZhang.com 8 | # 9 | # All rights reserved - Do Not Redistribute 10 | # 11 | 12 | jenkins_jobs = node['jenkins_demo']['jenkins_jobs'] 13 | 14 | # Install Jenkins jobs 15 | jenkins_jobs.split(',').each do |job_name| 16 | config = File.join(Chef::Config[:file_cache_path], "#{job_name}.xml") 17 | 18 | template config do 19 | source "#{job_name}/config.xml" 20 | end 21 | 22 | # Create a jenkins job (default action is `:create`) 23 | jenkins_job job_name do 24 | config config 25 | end 26 | end 27 | 28 | # Install required facilities 29 | if jenkins_jobs.index('CommonServerCheckRepo') 30 | if platform_family?('debian') 31 | 32 | # https://www.brightbox.com/blog/2017/01/13/ruby-2-4-ubuntu-packages/ 33 | apt_repository 'ruby-repo' do 34 | uri 'ppa:brightbox/ruby-ng' 35 | distribution node['lsb']['codename'] 36 | key 'C3173AA6' 37 | keyserver 'keyserver.ubuntu.com' 38 | retries 3 39 | retry_delay 3 40 | not_if { ::File.exist?('/etc/apt/sources.list.d/ruby-repo.list') } 41 | end 42 | 43 | %w[ruby2.4 ruby2.4-dev netcat gem rake].each do |x| 44 | package x do 45 | action :install 46 | not_if "dpkg -l #{x} | grep -E '^ii'" 47 | end 48 | end 49 | else 50 | %w[nc gem rake].each do |x| 51 | package x do 52 | action :install 53 | # TODO: change this 54 | # not_if "dpkg -l #{x} | grep -E '^ii'" 55 | end 56 | end 57 | end 58 | 59 | # keep the gem installation minimal: --no-ri --no-rdoc 60 | # https://coderwall.com/p/spo6bq/default-no-ri-no-rdoc-on-ruby-gem-installation 61 | file '/root/.gemrc' do 62 | content 'gem: --no-ri --no-rdoc' 63 | mode 0o755 64 | owner 'root' 65 | group 'root' 66 | end 67 | 68 | gem_package 'serverspec' do 69 | action :install 70 | version '2.41.3' 71 | end 72 | 73 | cookbook_file '/var/lib/jenkins/script/serverspec_check.sh' do 74 | source 'serverspec_check.sh' 75 | mode 0o755 76 | user 'jenkins' 77 | group 'jenkins' 78 | end 79 | end 80 | -------------------------------------------------------------------------------- /Scenario-301/cookbooks/jenkins-demo/recipes/default.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | # 4 | # Cookbook Name:: jenkins-demo 5 | # Recipe:: default 6 | # 7 | # Copyright 2017, DennyZhang.com 8 | # 9 | # All rights reserved - Do Not Redistribute 10 | # 11 | 12 | include_recipe 'jenkins-demo::master' 13 | 14 | if platform_family?('debian') 15 | # Install iproute2 for ss package 16 | %w[lsof iproute2].each do |x| 17 | package x do 18 | action :install 19 | not_if "dpkg -l #{x} | grep -E '^ii'" 20 | end 21 | end 22 | else 23 | %w[lsof].each do |x| 24 | package x do 25 | action :install 26 | # TODO: change this 27 | # not_if "dpkg -l #{x} | grep -E '^ii'" 28 | end 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /Scenario-301/cookbooks/jenkins-demo/recipes/master.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | # 4 | # Cookbook Name:: jenkins-demo 5 | # Recipe:: master 6 | # 7 | # Copyright 2017, DennyZhang.com 8 | # 9 | # All rights reserved - Do Not Redistribute 10 | # 11 | 12 | apt_update 'update' if platform_family?('debian') 13 | 14 | node.default['java']['install_flavor'] = 'oracle' 15 | node.default['java']['jdk_version'] = '8' 16 | node.default['java']['set_etc_environment'] = true 17 | node.default['java']['oracle']['accept_oracle_download_terms'] = true 18 | 19 | if %w[debian ubuntu].include?(node['platform_family']) 20 | node.default['jenkins']['master']['repository'] = \ 21 | 'http://pkg.jenkins-ci.org/debian' 22 | node.default['jenkins']['master']['repository_key'] = \ 23 | 'http://pkg.jenkins-ci.org/debian/jenkins-ci.org.key' 24 | end 25 | 26 | node.default['jenkins']['executor']['timeout'] = 360 27 | 28 | include_recipe 'java::default' 29 | include_recipe 'jenkins::master' 30 | 31 | # Install some plugins needed, but not installed on jenkins2 by default 32 | node['jenkins_demo']['jenkins_plugins'].each do |plugin| 33 | jenkins_plugin plugin[0] do 34 | version plugin[1] 35 | notifies :execute, 'jenkins_command[safe-restart]', :immediately 36 | end 37 | end 38 | 39 | jenkins_command 'safe-restart' do 40 | action :nothing 41 | end 42 | 43 | %w[/var/lib/jenkins/script].each do |x| 44 | directory x do 45 | owner 'jenkins' 46 | group 'jenkins' 47 | mode 0o755 48 | action :create 49 | end 50 | end 51 | 52 | # Create password credentials 53 | username = node['jenkins_demo']['default_username'] 54 | password = node['jenkins_demo']['default_password'] 55 | if username != '' 56 | # https://gist.github.com/hayderimran7/50cb1244cc1e856873a4 57 | jenkins_script "add_user #{username}" do 58 | command <<-EOH.gsub(/^ {4}/, '') 59 | import jenkins.model.* 60 | import hudson.security.* 61 | 62 | def instance = Jenkins.getInstance() 63 | 64 | def hudsonRealm = new HudsonPrivateSecurityRealm(false) 65 | hudsonRealm.createAccount("#{username}", "#{password}") 66 | instance.setSecurityRealm(hudsonRealm) 67 | instance.save() 68 | EOH 69 | not_if "test -d /var/lib/jenkins/users/#{username}" 70 | end 71 | end 72 | -------------------------------------------------------------------------------- /Scenario-301/cookbooks/jenkins-demo/templates/default/CommonServerCheckRepo/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | false 5 | 6 | 7 | 8 | -1 9 | 50 10 | -1 11 | -1 12 | 13 | 14 | 15 | false 16 | 17 | 18 | 19 | 20 | test_spec 21 | 22 | # ping check 23 | ["www.github.com"].each do |item| 24 | describe command("ping -c3 #{item}") do 25 | its(:exit_status) { should eq 0 } 26 | end 27 | end 28 | 29 | # Check anonymous http links 30 | ["http://www.dennyzhang.com/", 31 | "https://www.dennyzhang.com/", 32 | "https://code.dennyzhang.com/", 33 | "http://slack.dennyzhang.com/", 34 | ].each do |url| 35 | describe command('curl -I --connect-timeout 10 -k %s 2>&1' %[url]) do 36 | its(:stdout) { should match /HTTP\/1.1 200 OK/ } 37 | end 38 | end 39 | 40 | describe service('jenkins') do 41 | it { should be_running } 42 | end 43 | 44 | # Check at least 2 GB free disk 45 | describe command("[ $(df -h / | tail -n1 |awk -F' ' '{print $4}' | awk -F'G' '{print $1}' | awk -F'.' '{print $1}') -gt 2 ]") do 46 | its(:exit_status) { should eq 0 } 47 | end 48 | 49 | # TODO: enable this 50 | # # Check at least 2 GB free memory 51 | # describe command("[ $(free -ml | grep 'buffers/cache' | awk -F' ' '{print $4}') -gt 2048 ]") do 52 | # its(:exit_status) { should eq 0 } 53 | # end 54 | 55 | # TODO: enable this 56 | # # Check remote tcp port 57 | # ["vpn.dennyzhang.com:6188", # vpn 58 | # "www.dennyzhang.com:443", # ssl 59 | # ].each do |ip_port| 60 | # (ip, port) = ip_port.split(':') 61 | # describe command("nc -z -v -w5 #{ip} #{port} 2>&1") do 62 | # its(:stdout) { should match /open/ } 63 | # end 64 | # end 65 | 66 | # # check cpu loadavg in latest one min 67 | # ["172.17.0.1:2702:10"].each do |item| 68 | # (ip, port, cpu_load) = item.split(':') 69 | # command_str = "[ `ssh -o stricthostkeychecking=no -i /var/jenkins_home/.ssh/docker_host_id_rsa -p %s root@%s cat /proc/loadavg | awk '{print int($1+0.99)}'` -lt %s ]" \ 70 | # % [port, ip, cpu_load] 71 | # describe command(command_str) do 72 | # its(:exit_status) { should eq 0 } 73 | # end 74 | # end 75 | 76 | # # check docker container number 77 | # ["172.17.0.1:2702:15"].each do |item| 78 | # (ip, port, container_count) = item.split(':') 79 | # command_str = "[ `ssh -o stricthostkeychecking=no -i /var/jenkins_home/.ssh/docker_host_id_rsa -p %s root@%s docker ps | sed 1d | wc -l` -lt %s ]" \ 80 | # % [port, ip, container_count] 81 | # describe command(command_str) do 82 | # its(:exit_status) { should eq 0 } 83 | # end 84 | # end 85 | 86 | 87 | 88 | 89 | 90 | 91 | true 92 | false 93 | false 94 | false 95 | 96 | 97 | H H/5 * * * 98 | 99 | 100 | false 101 | 102 | 103 | #!/bin/bash -ex 104 | bash -e /var/lib/jenkins/script/serverspec_check.sh 105 | 106 | 107 | 108 | 109 | 110 | false 111 | false 112 | false 113 | TestParent 114 | 115 | 3 116 | 117 | 1 118 | 119 | 120 | <%= node['jenkins_demo']['slack_teamdomain'] %> 121 | <%= node['jenkins_demo']['slack_authtoken'] %> 122 | <%= node['jenkins_demo']['slack_buildserverurl'] %> 123 | <%= node['jenkins_demo']['slack_room'] %> 124 | false 125 | false 126 | false 127 | false 128 | false 129 | true 130 | true 131 | true 132 | false 133 | NONE 134 | false 135 | 136 | 137 | 138 | 139 | 140 | -------------------------------------------------------------------------------- /Scenario-301/cookbooks/jenkins-demo/test/integration/default/serverspec/server_spec.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | require 'serverspec' 4 | 5 | # Required by serverspec 6 | set :backend, :exec 7 | 8 | ############################################################################# 9 | require 'json' 10 | 11 | describe command('java -version') do 12 | its(:stderr) { should contain '1.8' } 13 | end 14 | 15 | describe command('chef-solo --version') do 16 | its(:stdout) { should contain '13.6.4' } 17 | end 18 | 19 | if %w[redhat centos].include?(os[:family]) 20 | describe command('yum info jenkins') do 21 | its(:stdout) { should contain '2.73.3' } 22 | end 23 | elsif %w[debian ubuntu].include?(os[:family]) 24 | # debian related environment spec 25 | describe command('dpkg -l | grep jenkins') do 26 | its(:stdout) { should contain '2.90' } 27 | end 28 | end 29 | 30 | ############################################################################# 31 | # If extra jenkins jobs have been triggered, verify the logic 32 | require_relative '../../../kitchen/data/verify_job_config' 33 | 34 | ############################################################################# 35 | port = 8080 36 | # Wait for service slow start/restart 37 | describe port(port), wait: { timeout: 60 } do 38 | it { should be_listening } 39 | end 40 | -------------------------------------------------------------------------------- /Scenario-301/cookbooks/jenkins-demo/test/shared/verify_job_config.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | require 'serverspec' 4 | 5 | # Required by serverspec 6 | set :backend, :exec 7 | 8 | ############################################################################# 9 | require 'json' 10 | 11 | chef_data = JSON.parse(IO.read('/tmp/kitchen/dna.json')) 12 | jenkins_jobs = \ 13 | chef_data.fetch('jenkins_demo').fetch('jenkins_jobs') 14 | 15 | if jenkins_jobs.index('CommonServerCheckRepo') 16 | 17 | describe file('/var/lib/jenkins/script/serverspec_check.sh') do 18 | it { should be_file } 19 | end 20 | 21 | describe command('which nc') do 22 | its(:exit_status) { should eq 0 } 23 | end 24 | 25 | describe command('gem list | grep serverspec') do 26 | its(:stdout) { should contain '2.41.3' } 27 | end 28 | 29 | if %w[redhat centos].include?(os[:family]) 30 | describe command('gem --version') do 31 | its(:stdout) { should contain '2.0.14' } 32 | end 33 | 34 | describe command('rake --version') do 35 | its(:stdout) { should contain '0.9.6' } 36 | end 37 | elsif %w[debian ubuntu].include?(os[:family]) 38 | # debian related environment spec 39 | describe command('gem --version') do 40 | its(:stdout) { should contain '2.6.13' } 41 | end 42 | 43 | describe command('rake --version') do 44 | its(:stdout) { should contain '10.0.4' } 45 | end 46 | end 47 | 48 | end 49 | -------------------------------------------------------------------------------- /Scenario-302/README.md: -------------------------------------------------------------------------------- 1 | [![LinkedIn](https://raw.githubusercontent.com/USDevOps/mywechat-slack-group/master/images/linkedin.png)](https://www.linkedin.com/in/dennyzhang001) slack [![Github](https://raw.githubusercontent.com/USDevOps/mywechat-slack-group/master/images/github.png)](https://github.com/DennyZhang) 2 | 3 | File me [tickets](https://github.com/DennyZhang/challenges-chef/issues) or star [the repo](https://github.com/DennyZhang/challenges-chef). 4 | 5 | 6 | 7 | Table of Contents 8 | ================= 9 | 10 | * [Requirement](#requirement) 11 | * [Procedure](#procedure) 12 | * [More Resources](#more-resources) 13 | 14 | 15 | 16 | # Requirement 17 | 18 | 1. For better security, only registered user can login 19 | 2. For better security, Jenkins listen on port 18080, instead of 8080 20 | 3. When Jenkins is down, get alerts 21 | 22 | Quiz: 23 | - Once I have enabled Jenkins security, how my chef update will work? 24 | 25 | # Procedure 26 | ## Common Setup 27 | - Install bundle 28 | ``` 29 | apt-get install ruby-dev 30 | 31 | ruby --version 32 | # https://github.com/bundler/bundler/issues/4065 33 | sudo gem install bundler -n /usr/local/bin 34 | 35 | bundle --version 36 | ``` 37 | 38 | - Install gem depenencies 39 | ``` 40 | cd cookbooks/jenkins-demo 41 | bundle install 42 | ``` 43 | 44 | ## kitchen docker deployment 45 | - Run kitchen test 46 | ``` 47 | # https://github.com/test-kitchen/kitchen-docker 48 | kitchen converge 49 | kitchen list 50 | kitchen verify 51 | kitchen destroy 52 | ``` 53 | 54 | ## kitchen digitalocean deployment 55 | ``` 56 | # https://github.com/test-kitchen/kitchen-digitalocean 57 | cd cookbooks/jenkins-demo 58 | export KITCHEN_YAML=".kitchen_digitalocean.yml" 59 | 60 | # Customize this with your credential 61 | export DIGITALOCEAN_ACCESS_TOKEN="1234" 62 | export DIGITALOCEAN_SSH_KEY_IDS="1234, 5678" 63 | 64 | kitchen converge 65 | kitchen list 66 | kitchen verify 67 | kitchen destroy 68 | 69 | - TODO: how does the ssh key work? With which OS user, and where the key is? 70 | ``` 71 | 72 | ## kitchen ec2 deployment 73 | - Install AWS cli and configure aws credential 74 | ``` 75 | # http://docs.aws.amazon.com/cli/latest/userguide/installing.html 76 | pip install awscli 77 | aws configure 78 | 79 | # Customize this 80 | export KEY_USER="denny-kitchen-test" 81 | aws ec2 create-key-pair --key-name $KEY_USER | ruby -e "require 'json'; puts JSON.parse(STDIN.read)['KeyMaterial']" > ~/.ssh/$KEY_USER 82 | 83 | chmod 600 ~/.ssh/$KEY_USER 84 | 85 | export AWS_SSH_KEY_ID="$KEY_USER" 86 | 87 | ``` 88 | 89 | - Install and run kitchen-ec2 90 | ``` 91 | # https://github.com/test-kitchen/kitchen-ec2 92 | # https://github.com/test-kitchen/kitchen-ec2/blob/master/lib/kitchen/driver/ec2.rb 93 | # http://kg4giy.com/2015/12/11/test-kitchen-to-support-amazon-web-service-aws-amis/ 94 | 95 | cd cookbooks/jenkins-demo 96 | export KITCHEN_YAML=".kitchen_ec2.yml" 97 | # TODO: customize this 98 | export AWS_SSH_KEY_ID="$KEY_USER" 99 | 100 | # Update bundle: https://github.com/chef/chef-provisioning/issues/151 101 | bundle update 102 | 103 | kitchen converge 104 | kitchen list 105 | kitchen verify 106 | kitchen destroy 107 | ``` 108 | 109 | ## kitchen vagrant deployment 110 | ``` 111 | # https://github.com/test-kitchen/kitchen-vagrant 112 | cd cookbooks/jenkins-demo 113 | export KITCHEN_YAML=".kitchen_vagrant.yml" 114 | 115 | bundle install 116 | 117 | kitchen converge 118 | kitchen list 119 | kitchen verify 120 | kitchen destroy 121 | ``` 122 | 123 | # More Resources 124 | - TODO: security improvement for the built-in chef user: attributes/default.rb 125 | 126 | - Critical Info 127 | ``` 128 | CentOS Jenkins conf: /etc/sysconfig/jenkins 129 | ``` 130 | 131 | 132 | -------------------------------------------------------------------------------- /Scenario-302/cookbooks/jenkins-demo/.kitchen.yml: -------------------------------------------------------------------------------- 1 | --- 2 | driver: 3 | name: docker 4 | 5 | driver_config: 6 | use_sudo: false 7 | # because Docker and SystemD/Upstart 8 | privileged: true 9 | remove_images: false 10 | hostname: <%= ENV.fetch('INSTANCE_NAME', "jenkins-demo") %> 11 | # tls_verify: true 12 | # tls_cacert: <%= ENV.fetch('TLS_FOLDER', "tls") %>/ca.pem 13 | # tls_cert: <%= ENV.fetch('TLS_FOLDER', "tls") %>/cert.pem 14 | # tls_key: <%= ENV.fetch('TLS_FOLDER', "tls") %>/key.pem 15 | # socket: tcp://172.17.0.1:4243 16 | transport: 17 | username: kitchen 18 | 19 | provisioner: 20 | name: chef_zero 21 | require_chef_omnibus: 13.6.4 22 | data_path: test/shared 23 | client_rb: 24 | file_cache_path: "/var/chef/cache" 25 | 26 | platforms: 27 | - name: centos-7 28 | driver_config: 29 | # https://hub.docker.com/r/dokken/centos-7/ 30 | instance_name: <%= ENV.fetch('INSTANCE_NAME', "jenkins-demo-centos7") %> 31 | image: <%= ENV.fetch('IMAGE_NAME', "dokken/centos-7") %> 32 | pid_one_command: /usr/lib/systemd/systemd 33 | forward: 34 | - <%= ENV.fetch('DOCKER_PORT_FORWARD_PREFIX', "180") %>83:8081 35 | - name: ubuntu-14.04 36 | driver_config: 37 | instance_name: <%= ENV.fetch('INSTANCE_NAME', "jenkins-demo-ubuntu1404") %> 38 | image: <%= ENV.fetch('IMAGE_NAME', "ubuntu:14.04") %> 39 | forward: 40 | - <%= ENV.fetch('DOCKER_PORT_FORWARD_PREFIX', "280") %>83:8081 41 | 42 | suites: 43 | - name: default 44 | run_list: 45 | - recipe[apt::default] 46 | - recipe[jenkins-demo::default] 47 | - recipe[jenkins-demo::conf_job] 48 | attributes: 49 | {jenkins_demo: 50 | {jenkins_port: '8081', 51 | jenkins_jobs: 'CommonServerCheckRepo', 52 | slack_teamdomain: 'mywechat', 53 | slack_authtoken: '<%= ENV.fetch('SLACK_TOKEN', "") %>', 54 | # TODO different env use different port 55 | # TODO use server ip 56 | slack_buildserverurl: 'http://localhost:<%= ENV.fetch('DOCKER_PORT_FORWARD_PREFIX', "180") %>80/', 57 | slack_room: '#denny-alerts', 58 | default_username: '<%= ENV.fetch('JENKINS_DEFAULT_USERNAME', "usertest123") %>', 59 | default_password: '<%= ENV.fetch('JENKINS_DEFAULT_PASSWORD', "password123") %>' 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /Scenario-302/cookbooks/jenkins-demo/.kitchen_digitalocean.yml: -------------------------------------------------------------------------------- 1 | --- 2 | driver: 3 | name: digitalocean 4 | 5 | provisioner: 6 | name: chef_zero 7 | require_chef_omnibus: 13.6.4 8 | data_path: test/shared 9 | 10 | platforms: 11 | - name: jenkins-demo-centos7 12 | driver_config: 13 | region: sfo2 14 | size: <%= ENV.fetch('DIGITALOCEAN_FLAVOR', "1gb") %> 15 | private_networking: false 16 | # https://github.com/test-kitchen/kitchen-digitalocean 17 | image: centos-7-x64 18 | server_name: <%= ENV.fetch('INSTANCE_NAME', "jenkins-demo-centos7") %> 19 | - name: jenkins-demo-ubuntu1404 20 | driver_config: 21 | region: sfo2 22 | size: <%= ENV.fetch('DIGITALOCEAN_FLAVOR', "1gb") %> 23 | private_networking: false 24 | image: ubuntu-14-04-x64 25 | server_name: <%= ENV.fetch('INSTANCE_NAME', "jenkins-demo-ubuntu1404") %> 26 | 27 | suites: 28 | - name: default 29 | run_list: 30 | - recipe[apt::default] 31 | - recipe[jenkins-demo::default] 32 | - recipe[jenkins-demo::conf_job] 33 | attributes: 34 | {jenkins_demo: 35 | {jenkins_port: '8081', 36 | jenkins_jobs: 'CommonServerCheckRepo', 37 | slack_teamdomain: 'mywechat', 38 | slack_authtoken: '<%= ENV.fetch('SLACK_TOKEN', "") %>', 39 | # TODO different env use different port 40 | # TODO use server ip 41 | slack_buildserverurl: 'http://localhost:<%= ENV.fetch('DOCKER_PORT_FORWARD_PREFIX', "180") %>81/', 42 | slack_room: '#denny-alerts', 43 | default_username: '<%= ENV.fetch('JENKINS_DEFAULT_USERNAME', "usertest123") %>', 44 | default_password: '<%= ENV.fetch('JENKINS_DEFAULT_PASSWORD', "password123") %>' 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Scenario-302/cookbooks/jenkins-demo/.kitchen_ec2.yml: -------------------------------------------------------------------------------- 1 | --- 2 | driver: 3 | name: ec2 4 | region: us-east-1 5 | 6 | transport: 7 | ssh_key: ~/.ssh/<%= ENV.fetch('KEY_USER', "") %> 8 | username: ec2-user 9 | 10 | provisioner: 11 | name: chef_zero 12 | require_chef_omnibus: 13.6.4 13 | data_path: test/shared 14 | 15 | platforms: 16 | - name: ubuntu-1404 17 | driver: 18 | # https://cloud-images.ubuntu.com/releases/14.04/release-20150506/ 19 | image_id: <%= ENV.fetch('EC2_IMAGE_ID', "ami-8d9e1cf7") %> 20 | instance_type: <%= ENV.fetch('EC2_INSTANCE_TYPE', "t2.micro") %> 21 | transport: 22 | username: ubuntu 23 | - name: centos-7 24 | driver: 25 | # https://wiki.centos.org/Cloud/AWS 26 | # https://stackoverflow.com/questions/40835953/how-to-find-ami-id-of-centos-7-image-in-aws-marketplace 27 | image_id: <%= ENV.fetch('EC2_IMAGE_ID', "ami-ae7bfdb8") %> 28 | instance_type: <%= ENV.fetch('EC2_INSTANCE_TYPE', "t2.micro") %> 29 | transport: 30 | username: centos 31 | - name: centos-ami 32 | driver: 33 | image_id: <%= ENV.fetch('EC2_IMAGE_ID', "ami-6869aa05") %> 34 | instance_type: <%= ENV.fetch('EC2_INSTANCE_TYPE', "t2.micro") %> 35 | 36 | suites: 37 | - name: default 38 | run_list: 39 | - recipe[apt::default] 40 | - recipe[jenkins-demo::default] 41 | - recipe[jenkins-demo::conf_job] 42 | attributes: 43 | {jenkins_demo: 44 | {jenkins_port: '8081', 45 | jenkins_jobs: 'CommonServerCheckRepo', 46 | slack_teamdomain: 'mywechat', 47 | slack_authtoken: '<%= ENV.fetch('SLACK_TOKEN', "") %>', 48 | # TODO different env use different port 49 | # TODO use server ip 50 | slack_buildserverurl: 'http://localhost:<%= ENV.fetch('DOCKER_PORT_FORWARD_PREFIX', "180") %>81/', 51 | slack_room: '#denny-alerts', 52 | default_username: '<%= ENV.fetch('JENKINS_DEFAULT_USERNAME', "usertest123") %>', 53 | default_password: '<%= ENV.fetch('JENKINS_DEFAULT_PASSWORD', "password123") %>' 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Scenario-302/cookbooks/jenkins-demo/.kitchen_vagrant.yml: -------------------------------------------------------------------------------- 1 | --- 2 | driver: 3 | name: vagrant 4 | 5 | driver_config: 6 | hostname: <%= ENV.fetch('INSTANCE_NAME', "jenkins-demo") %> 7 | # https://github.com/test-kitchen/kitchen-vagrant 8 | memory: 1024 9 | transport: 10 | username: kitchen 11 | 12 | provisioner: 13 | name: chef_zero 14 | require_chef_omnibus: 13.6.4 15 | data_path: test/shared 16 | client_rb: 17 | file_cache_path: "/var/chef/cache" 18 | 19 | platforms: 20 | - name: centos-7 21 | driver_config: 22 | instance_name: <%= ENV.fetch('INSTANCE_NAME', "jenkins-demo-centos7") %> 23 | network: 24 | - ["forwarded_port", {guest: 8080, host: 18080}] 25 | - name: ubuntu-14.04 26 | # https://stackoverflow.com/questions/38677059/port-forwarding-not-working-with-test-kitchen-and-vagrant 27 | driver_config: 28 | instance_name: <%= ENV.fetch('INSTANCE_NAME', "jenkins-demo-ubuntu1404") %> 29 | network: 30 | - ["forwarded_port", {guest: 8080, host: 28080}] 31 | 32 | suites: 33 | - name: default 34 | run_list: 35 | - recipe[apt::default] 36 | - recipe[jenkins-demo::default] 37 | - recipe[jenkins-demo::conf_job] 38 | attributes: 39 | {jenkins_demo: 40 | {jenkins_port: '8081', 41 | jenkins_jobs: 'CommonServerCheckRepo', 42 | slack_teamdomain: 'mywechat', 43 | slack_authtoken: '<%= ENV.fetch('SLACK_TOKEN', "") %>', 44 | # TODO different env use different port 45 | # TODO use server ip 46 | slack_buildserverurl: 'http://localhost:<%= ENV.fetch('DOCKER_PORT_FORWARD_PREFIX', "180") %>81/', 47 | slack_room: '#denny-alerts', 48 | default_username: '<%= ENV.fetch('JENKINS_DEFAULT_USERNAME', "usertest123") %>', 49 | default_password: '<%= ENV.fetch('JENKINS_DEFAULT_PASSWORD', "password123") %>' 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Scenario-302/cookbooks/jenkins-demo/.rubocop.yml: -------------------------------------------------------------------------------- 1 | AllCops: 2 | Exclude: 3 | - Berksfile 4 | 5 | Style/Next: 6 | Enabled: false 7 | 8 | Metrics/LineLength: 9 | Max: 90 10 | 11 | MethodLength: 12 | Max: 20 13 | 14 | Metrics/AbcSize: 15 | Enabled: false 16 | -------------------------------------------------------------------------------- /Scenario-302/cookbooks/jenkins-demo/Berksfile: -------------------------------------------------------------------------------- 1 | # -*- ruby -*- 2 | source 'https://supermarket.getchef.com' 3 | 4 | metadata 5 | -------------------------------------------------------------------------------- /Scenario-302/cookbooks/jenkins-demo/Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | # source 'https://ruby.taobao.org/' 3 | 4 | gem 'kitchen-digitalocean', '= 0.9.8' 5 | gem 'kitchen-docker', '= 2.6.0' 6 | gem 'kitchen-ec2', '= 1.3.2' 7 | gem 'kitchen-vagrant', '= 1.2.1' 8 | 9 | gem 'test-kitchen', '= 1.19.1' 10 | 11 | gem 'berkshelf', '= 6.3.1' 12 | 13 | gem 'foodcritic', '~> 4.0.0' 14 | gem 'rubocop', '~> 0.48.1' 15 | -------------------------------------------------------------------------------- /Scenario-302/cookbooks/jenkins-demo/README.md: -------------------------------------------------------------------------------- 1 | jenkins-demo Cookbook 2 | ================ 3 | Setup and configure demo jenkins 4 | -------------------------------------------------------------------------------- /Scenario-302/cookbooks/jenkins-demo/attributes/conf_job.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | # 4 | # Copyright 2017, DennyZhang.com 5 | # 6 | # All rights reserved - Do Not Redistribute 7 | # 8 | 9 | default['jenkins_demo']['jenkins_jobs'] = '' 10 | # slack notification 11 | default['jenkins_demo']['slack_teamdomain'] = '' 12 | default['jenkins_demo']['slack_authtoken'] = '' 13 | default['jenkins_demo']['slack_buildserverurl'] = '' 14 | default['jenkins_demo']['slack_room'] = '' 15 | -------------------------------------------------------------------------------- /Scenario-302/cookbooks/jenkins-demo/attributes/default.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | # 4 | # Copyright 2017, DennyZhang.com 5 | # 6 | # All rights reserved - Do Not Redistribute 7 | # 8 | default['jenkins_demo']['jenkins_port'] = 8080 9 | 10 | default['jenkins_demo']['jenkins_plugins'] = { 11 | 'thinBackup' => '1.9', 12 | # TODO 13 | # 'command-launcher' => '1.0', 14 | 'bouncycastle-api' => '2.16.2', 15 | 'credentials' => '2.1.16', 16 | 'plain-credentials' => '1.4', 17 | 'slack' => '2.3', 18 | 'script-security' => '1.35', 19 | 'matrix-auth' => '2.2' 20 | } 21 | 22 | ######################################## 23 | default['jenkins_demo']['default_username'] = '' 24 | default['jenkins_demo']['default_password'] = '' 25 | 26 | # TODO: improve the security 27 | default['jenkins_demo']['chef_private_key'] = \ 28 | '-----BEGIN RSA PRIVATE KEY----- 29 | MIIEpgIBAAKCAQEA6fIwUKxZXgKqEE6HCM94eEEeQ+n9mGpKn+CiKExI97mQtio4 30 | uzB/4A7qVXfBYaa2jbPZzD6bDvGco88vgeDuRB5tNh/sRBD3T7L9CxNIGp9gMMsu 31 | tRprwI5MEUsDDFXMKo5ZinpRe9fud5UBOmEHK0vjRVSgLVCGYdv/iXaBKY3feH8a 32 | 4gUuTzkdbUtoUMAUTfNyevhUfLRKSWjr5+f7krYYTqJpM7KUAL9e2dYMjkj3He7g 33 | iM4uiPtAQnMYcsyevNgpM0uKnp6+pPzTMSkSNp3uIK6aQ4lR80lEfq8fRwqzsIuJ 34 | dRT/+iJpd6XF8+GSyOt/tEh1RPiEKiGHLpmZGQIDAQABAoIBAQDFsipuIhcrQKki 35 | OpoWMe0mAjFnRtdM85W4YYXm9AA9h4zow+lJFoUZfME+FINQ2CcwvClzVfyGtlqe 36 | ezk0UjZHTkcQFA3+vy+fJCx+LX8jMEeDNFB2Lqub/yP9ARzEUcTEuaKlSRSOyTz1 37 | xO9SvCfoyKp4Ljll0cSd8eGR8pjX2TSfJ85aFAcP1CHGa/qGdxhSrbL2PMXaNFIT 38 | 27ZEUo4FVqcwRFN6JuO4sAlnyg8axXlXNLpwPzW1Zi7auS9nAO9bDEIhP4YfFwWs 39 | /iV7KBs/bryez94XS68b3MUXoZWS+1nP8ivBSOCH0mWy5/PhR4esih2EhXk/hi3P 40 | dp6aX4p5AoGBAPrmS+4lrvnvk2EOj3vqSergd31XBTM6NRKSsIYCtlaXsVjMym/i 41 | UdqcLqha4IEW3mucmpD3MBsTqshHGTI+67+tU/G23kThV/3U3a+jSR10FjgACPRd 42 | 8VhxrhTBvKjcw0uKeMl9uE0eb/2q8uVtX/8InOCvEfNGFCcszLsYFBr3AoGBAO6z 43 | qhWt8y/HkqWgBcbDJKx+T050nM9fkkBk1ILZn/GMEU828aEvKSwa8wzcx1gPo8Uu 44 | TP2SS0K0vnQv75UfyafgxFMVlELQrRTLHJqFQrCGikgBLNwHjRdvHfNujoBXbv+9 45 | g4LVFqHv0/kVRc1kXhdEwBCZm29rCDVusKK0C1hvAoGBAOAY4qkLL4Y93j1KbA4Z 46 | 7XvEkfV5zEM9Mjosm06XDZW6V8Ug5Y+ZbdL8vQ/SW8PxUSh87/GbV3RX1KqeFnsy 47 | iA7kGZ5D37NWMumdP4SpK50LGu1Z2qWpYu/EWeBgSsnopObL/6a4i+0VyqGgFuOl 48 | FaENaFGnDTlk1otHEHXrw8lxAoGBAITL11fwSlbOhLs3537ImeKM8roHDiYgWVER 49 | x1h0khLjhc24F31Aq3sqEwWY3h4TtVzBgXugo9Ycj8g70uH3qUyIMzC11KHHTkM/ 50 | LE6azJtAfjXI0Zgna0saOmNvoj+sZMhKOpvSyKCWuCrettKpf98aFHAnxN2bghmX 51 | 1xTtbVJpAoGBAKnqvADsNFaI1Ak7tdfJJ+chxnxXd1k6Mly44Jsp6oako4Nl2Uiw 52 | 3xL4JGed+QBmjFh+n4hR9T7J65fUFvBixBEAhDSXcRHWL84xTQWLtdHK4+zDWGJt 53 | n2DMrFzhp1H6neUFMBeNOw+fQuhPj6OcLrs4dRdyQhVRp0ZOJyLMS39e 54 | -----END RSA PRIVATE KEY-----' 55 | 56 | default['jenkins_demo']['chef_public_key'] = \ 57 | 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDp8jBQrFleAqoQTocIz3h4QR5'\ 58 | 'D6f2Yakqf4KIoTEj3uZC2Kji7MH/gDupVd8FhpraNs9nMPpsO8Zyjzy+B4O5EHm'\ 59 | '02H+xEEPdPsv0LE0gan2Awyy61GmvAjkwRSwMMVcwqjlmKelF71+53lQE6YQcrS'\ 60 | '+NFVKAtUIZh2/+JdoEpjd94fxriBS5POR1tS2hQwBRN83J6+FR8tEpJaOvn5/uS'\ 61 | 'thhOomkzspQAv17Z1gyOSPcd7uCIzi6I+0BCcxhyzJ682CkzS4qenr6k/NMxKRI'\ 62 | '2ne4grppDiVHzSUR+rx9HCrOwi4l1FP/6Iml3pcXz4ZLI63+0SHVE+IQqIYcumZ'\ 63 | 'kZ chef@mytest.com' 64 | -------------------------------------------------------------------------------- /Scenario-302/cookbooks/jenkins-demo/files/default/serverspec_check.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | function setup_serverspec() { 3 | working_dir=${1?} 4 | cd "$working_dir" 5 | if [ ! -f spec/spec_helper.rb ]; then 6 | echo "Setup Serverspec Test case" 7 | cat > spec/spec_helper.rb < Rakefile < 'spec:all' 18 | task :default => :spec 19 | 20 | namespace :spec do 21 | targets = [] 22 | Dir.glob('./spec/*').each do |dir| 23 | next unless File.directory?(dir) 24 | target = File.basename(dir) 25 | target = "_#{target}" if target == "default" 26 | targets << target 27 | end 28 | 29 | task :all => targets 30 | task :default => :all 31 | 32 | targets.each do |target| 33 | original_target = target == "_default" ? target[1..-1] : target 34 | desc "Run serverspec tests to #{original_target}" 35 | RSpec::Core::RakeTask.new(target.to_sym) do |t| 36 | ENV['TARGET_HOST'] = original_target 37 | t.pattern = "spec/#{original_target}/*_spec.rb" 38 | end 39 | end 40 | end 41 | EOF 42 | fi 43 | } 44 | 45 | ######################################################### 46 | [ -n "$working_dir" ] || working_dir="$WORKSPACE" 47 | 48 | mkdir -p "$working_dir/spec/localhost" 49 | cd "$working_dir" 50 | 51 | setup_serverspec "$working_dir" 52 | 53 | cat > spec/localhost/sample_spec.rb <= 14.04' 14 | depends 'apt', '=2.6.1' 15 | depends 'java' 16 | depends 'jenkins', '=5.0.4' 17 | -------------------------------------------------------------------------------- /Scenario-302/cookbooks/jenkins-demo/recipes/backup.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | # 4 | # Cookbook Name:: jenkins-demo 5 | # Recipe:: backup 6 | # 7 | # Copyright 2017, DennyZhang.com 8 | # 9 | # All rights reserved - Do Not Redistribute 10 | # 11 | -------------------------------------------------------------------------------- /Scenario-302/cookbooks/jenkins-demo/recipes/conf_job.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | # 4 | # Cookbook Name:: jenkins-demo 5 | # Recipe:: conf_job 6 | # 7 | # Copyright 2017, DennyZhang.com 8 | # 9 | # All rights reserved - Do Not Redistribute 10 | # 11 | 12 | jenkins_jobs = node['jenkins_demo']['jenkins_jobs'] 13 | 14 | # Install Jenkins jobs 15 | jenkins_jobs.split(',').each do |job_name| 16 | config = File.join(Chef::Config[:file_cache_path], "#{job_name}.xml") 17 | 18 | template config do 19 | source "#{job_name}/config.xml" 20 | end 21 | 22 | # Create a jenkins job (default action is `:create`) 23 | jenkins_job job_name do 24 | config config 25 | end 26 | end 27 | 28 | # Install required facilities 29 | if jenkins_jobs.index('CommonServerCheckRepo') 30 | # keep the gem installation minimal: --no-ri --no-rdoc 31 | # https://coderwall.com/p/spo6bq/default-no-ri-no-rdoc-on-ruby-gem-installation 32 | file '/root/.gemrc' do 33 | content 'gem: --no-ri --no-rdoc' 34 | mode 0o755 35 | owner 'root' 36 | group 'root' 37 | end 38 | 39 | if platform_family?('debian') 40 | 41 | # https://www.brightbox.com/blog/2017/01/13/ruby-2-4-ubuntu-packages/ 42 | apt_repository 'ruby-repo' do 43 | uri 'ppa:brightbox/ruby-ng' 44 | distribution node['lsb']['codename'] 45 | key 'C3173AA6' 46 | keyserver 'keyserver.ubuntu.com' 47 | retries 3 48 | retry_delay 3 49 | not_if { ::File.exist?('/etc/apt/sources.list.d/ruby-repo.list') } 50 | end 51 | 52 | %w[ruby2.4 ruby2.4-dev netcat gem rake].each do |x| 53 | package x do 54 | action :install 55 | not_if "dpkg -l #{x} | grep -E '^ii'" 56 | end 57 | end 58 | else 59 | %w[nc gem yum zlib-devel gcc gcc-c++ ruby-devel rubygems].each do |x| 60 | package x do 61 | action :install 62 | # TODO: change this 63 | # not_if "dpkg -l #{x} | grep -E '^ii'" 64 | end 65 | end 66 | 67 | gem_package 'rake' do 68 | action :install 69 | version '12.3.0' 70 | end 71 | 72 | # gem_package 'io-console' do 73 | # action :install 74 | # version '0.4.6' 75 | # end 76 | execute 'Install io-console' do 77 | command 'gem install io-console' 78 | action :run 79 | not_if 'gem list | grep io-console' 80 | end 81 | end 82 | 83 | gem_package 'serverspec' do 84 | action :install 85 | version '2.41.3' 86 | end 87 | 88 | cookbook_file '/var/lib/jenkins/script/serverspec_check.sh' do 89 | source 'serverspec_check.sh' 90 | mode 0o755 91 | user 'jenkins' 92 | group 'jenkins' 93 | end 94 | end 95 | -------------------------------------------------------------------------------- /Scenario-302/cookbooks/jenkins-demo/recipes/default.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | # 4 | # Cookbook Name:: jenkins-demo 5 | # Recipe:: default 6 | # 7 | # Copyright 2017, DennyZhang.com 8 | # 9 | # All rights reserved - Do Not Redistribute 10 | # 11 | 12 | include_recipe 'jenkins-demo::master' 13 | 14 | if platform_family?('debian') 15 | # Install iproute2 for ss package 16 | %w[lsof iproute2].each do |x| 17 | package x do 18 | action :install 19 | not_if "dpkg -l #{x} | grep -E '^ii'" 20 | end 21 | end 22 | else 23 | %w[lsof].each do |x| 24 | package x do 25 | action :install 26 | # TODO: change this 27 | # not_if "dpkg -l #{x} | grep -E '^ii'" 28 | end 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /Scenario-302/cookbooks/jenkins-demo/recipes/master.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | # 4 | # Cookbook Name:: jenkins-demo 5 | # Recipe:: master 6 | # 7 | # Copyright 2017, DennyZhang.com 8 | # 9 | # All rights reserved - Do Not Redistribute 10 | # 11 | 12 | apt_update 'update' if platform_family?('debian') 13 | 14 | node.default['java']['install_flavor'] = 'oracle' 15 | node.default['java']['jdk_version'] = '8' 16 | node.default['java']['set_etc_environment'] = true 17 | node.default['java']['oracle']['accept_oracle_download_terms'] = true 18 | 19 | if %w[debian ubuntu].include?(node['platform_family']) 20 | node.default['jenkins']['master']['repository'] = \ 21 | 'http://pkg.jenkins-ci.org/debian' 22 | node.default['jenkins']['master']['repository_key'] = \ 23 | 'http://pkg.jenkins-ci.org/debian/jenkins-ci.org.key' 24 | end 25 | 26 | node.default['jenkins']['executor']['timeout'] = 360 27 | 28 | node.default['jenkins']['master']['port'] = node['jenkins_demo']['jenkins_port'] 29 | node.default['jenkins']['master']['endpoint'] = \ 30 | "http://#{node['jenkins']['master']['host']}:#{node['jenkins']['master']['port']}" 31 | 32 | include_recipe 'java::default' 33 | include_recipe 'jenkins::master' 34 | 35 | # Install some plugins needed, but not installed on jenkins2 by default 36 | node['jenkins_demo']['jenkins_plugins'].each do |plugin| 37 | jenkins_plugin plugin[0] do 38 | version plugin[1] 39 | notifies :execute, 'jenkins_command[safe-restart]', :immediately 40 | end 41 | end 42 | 43 | jenkins_command 'safe-restart' do 44 | action :nothing 45 | end 46 | 47 | %w[/var/lib/jenkins/script].each do |x| 48 | directory x do 49 | owner 'jenkins' 50 | group 'jenkins' 51 | mode 0o755 52 | action :create 53 | end 54 | end 55 | 56 | include_recipe 'jenkins-demo::security' 57 | include_recipe 'jenkins-demo::backup' 58 | -------------------------------------------------------------------------------- /Scenario-302/cookbooks/jenkins-demo/recipes/security.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | # 4 | # Cookbook Name:: jenkins-demo 5 | # Recipe:: security 6 | # 7 | # Copyright 2017, DennyZhang.com 8 | # 9 | # All rights reserved - Do Not Redistribute 10 | # 11 | 12 | require 'openssl' 13 | require 'net/ssh' 14 | # key = OpenSSL::PKey::RSA.new(jenkins['private_key']) 15 | # private_key = key.to_pem 16 | # public_key = "#{key.ssh_type} #{[key.to_blob].pack('m0')}" 17 | 18 | # https://goo.gl/jvn5TN 19 | # Jenkins itself login the server 20 | 21 | private_key = node['jenkins_demo']['chef_private_key'] 22 | public_key = node['jenkins_demo']['chef_public_key'] 23 | 24 | # Set the private key on the executor 25 | node.run_state[:jenkins_private_key] = private_key 26 | 27 | # Create a default Chef user with the public key 28 | jenkins_user 'chef' do 29 | full_name 'Chef Client' 30 | public_keys [public_key] 31 | end 32 | 33 | # Turn on basic authentication 34 | jenkins_script 'setup authentication' do 35 | command <<-EOH.gsub(/^ {4}/, '') 36 | import jenkins.model.* 37 | def instance = Jenkins.getInstance() 38 | 39 | import hudson.security.* 40 | def realm = new HudsonPrivateSecurityRealm(false) 41 | instance.setSecurityRealm(realm) 42 | 43 | def strategy = new hudson.security.FullControlOnceLoggedInAuthorizationStrategy() 44 | instance.setAuthorizationStrategy(strategy) 45 | 46 | instance.save() 47 | EOH 48 | # TODO: add not_if 49 | end 50 | 51 | ################################################################################ 52 | username = node['jenkins_demo']['default_username'] 53 | password = node['jenkins_demo']['default_password'] 54 | if username != '' 55 | # Create a dummy user 56 | # https://gist.github.com/hayderimran7/50cb1244cc1e856873a4 57 | jenkins_script "add_user #{username}" do 58 | command <<-EOH.gsub(/^ {4}/, '') 59 | import jenkins.model.* 60 | import hudson.security.* 61 | 62 | def instance = Jenkins.getInstance() 63 | 64 | def hudsonRealm = new HudsonPrivateSecurityRealm(false) 65 | hudsonRealm.createAccount("#{username}", "#{password}") 66 | instance.setSecurityRealm(hudsonRealm) 67 | instance.save() 68 | EOH 69 | not_if "test -d /var/lib/jenkins/users/#{username}" 70 | end 71 | end 72 | 73 | # Use matrix authorization model 74 | # Gives all authenticated users admin access 75 | # https://github.com/glenjamin/jenkins-groovy-examples/blob/master/README.md 76 | jenkins_script 'all authenticated users admin access' do 77 | command <<-EOH.gsub(/^ {4}/, '') 78 | import jenkins.model.* 79 | def instance = Jenkins.getInstance() 80 | 81 | import hudson.security.* 82 | def realm = new HudsonPrivateSecurityRealm(false) 83 | instance.setSecurityRealm(realm) 84 | 85 | def strategy = new hudson.security.GlobalMatrixAuthorizationStrategy() 86 | strategy.add(Jenkins.ADMINISTER, 'authenticated') 87 | instance.setAuthorizationStrategy(strategy) 88 | 89 | instance.save() 90 | EOH 91 | # TODO: add not_if 92 | end 93 | -------------------------------------------------------------------------------- /Scenario-302/cookbooks/jenkins-demo/templates/default/CommonServerCheckRepo/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | false 5 | 6 | 7 | 8 | -1 9 | 50 10 | -1 11 | -1 12 | 13 | 14 | 15 | false 16 | 17 | 18 | 19 | 20 | test_spec 21 | 22 | # ping check 23 | ["www.github.com"].each do |item| 24 | describe command("ping -c3 #{item}") do 25 | its(:exit_status) { should eq 0 } 26 | end 27 | end 28 | 29 | # Check anonymous http links 30 | ["http://www.dennyzhang.com/", 31 | "https://www.dennyzhang.com/", 32 | "https://code.dennyzhang.com/", 33 | "http://slack.dennyzhang.com/", 34 | ].each do |url| 35 | describe command('curl -I --connect-timeout 10 -k %s 2>&1' %[url]) do 36 | its(:stdout) { should match /HTTP\/1.1 200 OK/ } 37 | end 38 | end 39 | 40 | describe service('jenkins') do 41 | it { should be_running } 42 | end 43 | 44 | # Check at least 2 GB free disk 45 | describe command("[ $(df -h / | tail -n1 |awk -F' ' '{print $4}' | awk -F'G' '{print $1}' | awk -F'.' '{print $1}') -gt 2 ]") do 46 | its(:exit_status) { should eq 0 } 47 | end 48 | 49 | # TODO: enable this 50 | # # Check at least 2 GB free memory 51 | # describe command("[ $(free -ml | grep 'buffers/cache' | awk -F' ' '{print $4}') -gt 2048 ]") do 52 | # its(:exit_status) { should eq 0 } 53 | # end 54 | 55 | # TODO: support for both CentOS and Ubuntu OS 56 | # # Check remote tcp port 57 | # ["vpn.dennyzhang.com:6188", # vpn 58 | # "www.dennyzhang.com:443", # ssl 59 | # ].each do |ip_port| 60 | # (ip, port) = ip_port.split(':') 61 | # describe command("nc -z -v -w5 #{ip} #{port} 2>&1") do 62 | # its(:stdout) { should match /open/ } 63 | # end 64 | # end 65 | 66 | # # check cpu loadavg in latest one min 67 | # ["172.17.0.1:2702:10"].each do |item| 68 | # (ip, port, cpu_load) = item.split(':') 69 | # command_str = "[ `ssh -o stricthostkeychecking=no -i /var/jenkins_home/.ssh/docker_host_id_rsa -p %s root@%s cat /proc/loadavg | awk '{print int($1+0.99)}'` -lt %s ]" \ 70 | # % [port, ip, cpu_load] 71 | # describe command(command_str) do 72 | # its(:exit_status) { should eq 0 } 73 | # end 74 | # end 75 | 76 | # # check docker container number 77 | # ["172.17.0.1:2702:15"].each do |item| 78 | # (ip, port, container_count) = item.split(':') 79 | # command_str = "[ `ssh -o stricthostkeychecking=no -i /var/jenkins_home/.ssh/docker_host_id_rsa -p %s root@%s docker ps | sed 1d | wc -l` -lt %s ]" \ 80 | # % [port, ip, container_count] 81 | # describe command(command_str) do 82 | # its(:exit_status) { should eq 0 } 83 | # end 84 | # end 85 | 86 | 87 | 88 | 89 | 90 | 91 | true 92 | false 93 | false 94 | false 95 | 96 | 97 | H H/5 * * * 98 | 99 | 100 | false 101 | 102 | 103 | #!/bin/bash -ex 104 | export PATH=$PATH:/usr/local/bin/ 105 | bash -e /var/lib/jenkins/script/serverspec_check.sh 106 | 107 | 108 | 109 | 110 | 111 | false 112 | false 113 | false 114 | TestParent 115 | 116 | 3 117 | 118 | 1 119 | 120 | 121 | <%= node['jenkins_demo']['slack_teamdomain'] %> 122 | <%= node['jenkins_demo']['slack_authtoken'] %> 123 | <%= node['jenkins_demo']['slack_buildserverurl'] %> 124 | <%= node['jenkins_demo']['slack_room'] %> 125 | false 126 | false 127 | false 128 | false 129 | false 130 | true 131 | true 132 | true 133 | false 134 | NONE 135 | false 136 | 137 | 138 | 139 | 140 | 141 | -------------------------------------------------------------------------------- /Scenario-302/cookbooks/jenkins-demo/test/integration/default/serverspec/server_spec.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | require 'serverspec' 4 | 5 | # Required by serverspec 6 | set :backend, :exec 7 | 8 | ############################################################################# 9 | require 'json' 10 | 11 | describe command('java -version') do 12 | its(:stderr) { should contain '1.8' } 13 | end 14 | 15 | describe command('chef-solo --version') do 16 | its(:stdout) { should contain '13.6.4' } 17 | end 18 | 19 | if %w[redhat centos].include?(os[:family]) 20 | describe command('yum info jenkins') do 21 | its(:stdout) { should contain '2.73.3' } 22 | end 23 | elsif %w[debian ubuntu].include?(os[:family]) 24 | # debian related environment spec 25 | describe command('dpkg -l | grep jenkins') do 26 | its(:stdout) { should contain '2.91' } 27 | end 28 | end 29 | 30 | ############################################################################# 31 | # If extra jenkins jobs have been triggered, verify the logic 32 | require_relative '../../../kitchen/data/verify_job_config' 33 | 34 | ############################################################################# 35 | require 'json' 36 | chef_data = JSON.parse(IO.read('/tmp/kitchen/dna.json')) 37 | 38 | jenkins_port = chef_data.fetch('jenkins_demo').fetch('jenkins_port') 39 | # Wait for service slow start/restart 40 | describe port(jenkins_port), wait: { timeout: 60 } do 41 | it { should be_listening } 42 | end 43 | 44 | ############################################################################# 45 | username = chef_data.fetch('jenkins_demo').fetch('default_username') 46 | 47 | if username != '' 48 | describe file("/var/lib/jenkins/users/#{username}") do 49 | it { should be_directory } 50 | end 51 | end 52 | -------------------------------------------------------------------------------- /Scenario-302/cookbooks/jenkins-demo/test/shared/verify_job_config.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | require 'serverspec' 4 | 5 | # Required by serverspec 6 | set :backend, :exec 7 | # https://github.com/test-kitchen/test-kitchen/issues/469 8 | set :path, '/sbin:/usr/local/sbin:/usr/local/bin:$PATH' 9 | 10 | ############################################################################# 11 | require 'json' 12 | 13 | chef_data = JSON.parse(IO.read('/tmp/kitchen/dna.json')) 14 | jenkins_jobs = \ 15 | chef_data.fetch('jenkins_demo').fetch('jenkins_jobs') 16 | 17 | if jenkins_jobs.index('CommonServerCheckRepo') 18 | 19 | describe file('/var/lib/jenkins/script/serverspec_check.sh') do 20 | it { should be_file } 21 | end 22 | 23 | describe command('which nc') do 24 | its(:exit_status) { should eq 0 } 25 | end 26 | 27 | describe command('gem list | grep serverspec') do 28 | its(:stdout) { should contain '2.41.3' } 29 | end 30 | 31 | if %w[redhat centos].include?(os[:family]) 32 | describe command('gem --version') do 33 | its(:stdout) { should contain '2.0.14' } 34 | end 35 | 36 | describe command('rake --version') do 37 | its(:stdout) { should contain '12.3.0' } 38 | end 39 | elsif %w[debian ubuntu].include?(os[:family]) 40 | # debian related environment spec 41 | describe command('gem --version') do 42 | its(:stdout) { should contain '2.6.13' } 43 | end 44 | 45 | describe command('rake --version') do 46 | its(:stdout) { should contain '10.0.4' } 47 | end 48 | end 49 | 50 | end 51 | -------------------------------------------------------------------------------- /Scenario-303/README.md: -------------------------------------------------------------------------------- 1 | [![LinkedIn](https://raw.githubusercontent.com/USDevOps/mywechat-slack-group/master/images/linkedin.png)](https://www.linkedin.com/in/dennyzhang001) slack [![Github](https://raw.githubusercontent.com/USDevOps/mywechat-slack-group/master/images/github.png)](https://github.com/DennyZhang) 2 | 3 | File me [tickets](https://github.com/DennyZhang/challenges-chef/issues) or star [the repo](https://github.com/DennyZhang/challenges-chef). 4 | 5 | 6 | 7 | Table of Contents 8 | ================= 9 | 10 | * [Requirement](#requirement) 11 | * [Procedure](#procedure) 12 | * [More Resources](#more-resources) 13 | 14 | 15 | 16 | # Requirement 17 | 18 | 1. Use Jenkinsfile to create a Jenkins pipeline 19 | 2. Enable and configure ThinBackup 20 | 21 | Quiz: 22 | - Once I have enabled Jenkins security, how my chef update will work? 23 | 24 | # Procedure 25 | ## Common Setup 26 | - Install bundle 27 | ``` 28 | apt-get install ruby-dev 29 | 30 | ruby --version 31 | # https://github.com/bundler/bundler/issues/4065 32 | sudo gem install bundler -n /usr/local/bin 33 | 34 | bundle --version 35 | ``` 36 | 37 | - Install gem depenencies 38 | ``` 39 | cd cookbooks/jenkins-demo 40 | bundle install 41 | ``` 42 | 43 | ## kitchen docker deployment 44 | - Run kitchen test 45 | ``` 46 | # https://github.com/test-kitchen/kitchen-docker 47 | kitchen converge 48 | kitchen list 49 | kitchen verify 50 | kitchen destroy 51 | ``` 52 | 53 | ## kitchen digitalocean deployment 54 | ``` 55 | # https://github.com/test-kitchen/kitchen-digitalocean 56 | cd cookbooks/jenkins-demo 57 | export KITCHEN_YAML=".kitchen_digitalocean.yml" 58 | 59 | # Customize this with your credential 60 | export DIGITALOCEAN_ACCESS_TOKEN="1234" 61 | export DIGITALOCEAN_SSH_KEY_IDS="1234, 5678" 62 | 63 | kitchen converge 64 | kitchen list 65 | kitchen verify 66 | kitchen destroy 67 | 68 | - TODO: how does the ssh key work? With which OS user, and where the key is? 69 | ``` 70 | 71 | ## kitchen ec2 deployment 72 | - Install AWS cli and configure aws credential 73 | ``` 74 | # http://docs.aws.amazon.com/cli/latest/userguide/installing.html 75 | pip install awscli 76 | aws configure 77 | 78 | # Customize this 79 | export KEY_USER="denny-kitchen-test" 80 | aws ec2 create-key-pair --key-name $KEY_USER | ruby -e "require 'json'; puts JSON.parse(STDIN.read)['KeyMaterial']" > ~/.ssh/$KEY_USER 81 | 82 | chmod 600 ~/.ssh/$KEY_USER 83 | 84 | export AWS_SSH_KEY_ID="$KEY_USER" 85 | 86 | ``` 87 | 88 | - Install and run kitchen-ec2 89 | ``` 90 | # https://github.com/test-kitchen/kitchen-ec2 91 | # https://github.com/test-kitchen/kitchen-ec2/blob/master/lib/kitchen/driver/ec2.rb 92 | # http://kg4giy.com/2015/12/11/test-kitchen-to-support-amazon-web-service-aws-amis/ 93 | 94 | cd cookbooks/jenkins-demo 95 | export KITCHEN_YAML=".kitchen_ec2.yml" 96 | # TODO: customize this 97 | export AWS_SSH_KEY_ID="$KEY_USER" 98 | 99 | # Update bundle: https://github.com/chef/chef-provisioning/issues/151 100 | bundle update 101 | 102 | kitchen converge 103 | kitchen list 104 | kitchen verify 105 | kitchen destroy 106 | ``` 107 | 108 | ## kitchen vagrant deployment 109 | ``` 110 | # https://github.com/test-kitchen/kitchen-vagrant 111 | cd cookbooks/jenkins-demo 112 | export KITCHEN_YAML=".kitchen_vagrant.yml" 113 | 114 | bundle install 115 | 116 | kitchen converge 117 | kitchen list 118 | kitchen verify 119 | kitchen destroy 120 | ``` 121 | 122 | # More Resources 123 | - TODO: security improvement for the built-in chef user: attributes/default.rb 124 | 125 | - Critical Info 126 | ``` 127 | CentOS Jenkins conf: /etc/sysconfig/jenkins 128 | ``` 129 | 130 | 131 | -------------------------------------------------------------------------------- /Scenario-303/cookbooks/jenkins-demo/.kitchen.yml: -------------------------------------------------------------------------------- 1 | --- 2 | driver: 3 | name: docker 4 | 5 | driver_config: 6 | use_sudo: false 7 | # because Docker and SystemD/Upstart 8 | privileged: true 9 | remove_images: false 10 | hostname: <%= ENV.fetch('INSTANCE_NAME', "jenkins-demo") %> 11 | # tls_verify: true 12 | # tls_cacert: <%= ENV.fetch('TLS_FOLDER', "tls") %>/ca.pem 13 | # tls_cert: <%= ENV.fetch('TLS_FOLDER', "tls") %>/cert.pem 14 | # tls_key: <%= ENV.fetch('TLS_FOLDER', "tls") %>/key.pem 15 | # socket: tcp://172.17.0.1:4243 16 | transport: 17 | username: kitchen 18 | 19 | provisioner: 20 | name: chef_zero 21 | require_chef_omnibus: 13.6.4 22 | data_path: test/shared 23 | client_rb: 24 | file_cache_path: "/var/chef/cache" 25 | 26 | platforms: 27 | - name: centos-7 28 | driver_config: 29 | # https://hub.docker.com/r/dokken/centos-7/ 30 | instance_name: <%= ENV.fetch('INSTANCE_NAME', "jenkins-demo-centos7") %> 31 | image: <%= ENV.fetch('IMAGE_NAME', "dokken/centos-7") %> 32 | pid_one_command: /usr/lib/systemd/systemd 33 | forward: 34 | - <%= ENV.fetch('DOCKER_PORT_FORWARD_PREFIX', "180") %>83:8081 35 | - name: ubuntu-14.04 36 | driver_config: 37 | instance_name: <%= ENV.fetch('INSTANCE_NAME', "jenkins-demo-ubuntu1404") %> 38 | image: <%= ENV.fetch('IMAGE_NAME', "ubuntu:14.04") %> 39 | forward: 40 | - <%= ENV.fetch('DOCKER_PORT_FORWARD_PREFIX', "280") %>83:8081 41 | 42 | suites: 43 | - name: default 44 | run_list: 45 | - recipe[apt::default] 46 | - recipe[jenkins-demo::default] 47 | - recipe[jenkins-demo::conf_test_job] 48 | attributes: 49 | {jenkins_demo: 50 | {jenkins_port: '8081', 51 | slack_teamdomain: 'mywechat', 52 | slack_authtoken: '<%= ENV.fetch('SLACK_TOKEN', "") %>', 53 | # TODO different env use different port 54 | # TODO use server ip 55 | slack_buildserverurl: 'http://localhost:<%= ENV.fetch('DOCKER_PORT_FORWARD_PREFIX', "180") %>80/', 56 | slack_room: '#denny-alerts', 57 | default_username: '<%= ENV.fetch('JENKINS_DEFAULT_USERNAME', "usertest123") %>', 58 | default_password: '<%= ENV.fetch('JENKINS_DEFAULT_PASSWORD', "password123") %>' 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /Scenario-303/cookbooks/jenkins-demo/.kitchen_digitalocean.yml: -------------------------------------------------------------------------------- 1 | --- 2 | driver: 3 | name: digitalocean 4 | 5 | provisioner: 6 | name: chef_zero 7 | require_chef_omnibus: 13.6.4 8 | data_path: test/shared 9 | 10 | platforms: 11 | - name: jenkins-demo-centos7 12 | driver_config: 13 | region: sfo2 14 | size: <%= ENV.fetch('DIGITALOCEAN_FLAVOR', "1gb") %> 15 | private_networking: false 16 | # https://github.com/test-kitchen/kitchen-digitalocean 17 | image: centos-7-x64 18 | server_name: <%= ENV.fetch('INSTANCE_NAME', "jenkins-demo-centos7") %> 19 | - name: jenkins-demo-ubuntu1404 20 | driver_config: 21 | region: sfo2 22 | size: <%= ENV.fetch('DIGITALOCEAN_FLAVOR', "1gb") %> 23 | private_networking: false 24 | image: ubuntu-14-04-x64 25 | server_name: <%= ENV.fetch('INSTANCE_NAME', "jenkins-demo-ubuntu1404") %> 26 | 27 | suites: 28 | - name: default 29 | run_list: 30 | - recipe[apt::default] 31 | - recipe[jenkins-demo::default] 32 | - recipe[jenkins-demo::conf_test_job] 33 | attributes: 34 | {jenkins_demo: 35 | {jenkins_port: '8081', 36 | slack_teamdomain: 'mywechat', 37 | slack_authtoken: '<%= ENV.fetch('SLACK_TOKEN', "") %>', 38 | # TODO different env use different port 39 | # TODO use server ip 40 | slack_buildserverurl: 'http://localhost:<%= ENV.fetch('DOCKER_PORT_FORWARD_PREFIX', "180") %>81/', 41 | slack_room: '#denny-alerts', 42 | default_username: '<%= ENV.fetch('JENKINS_DEFAULT_USERNAME', "usertest123") %>', 43 | default_password: '<%= ENV.fetch('JENKINS_DEFAULT_PASSWORD', "password123") %>' 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Scenario-303/cookbooks/jenkins-demo/.kitchen_ec2.yml: -------------------------------------------------------------------------------- 1 | --- 2 | driver: 3 | name: ec2 4 | region: us-east-1 5 | 6 | transport: 7 | ssh_key: ~/.ssh/<%= ENV.fetch('KEY_USER', "") %> 8 | username: ec2-user 9 | 10 | provisioner: 11 | name: chef_zero 12 | require_chef_omnibus: 13.6.4 13 | data_path: test/shared 14 | 15 | platforms: 16 | - name: ubuntu-1404 17 | driver: 18 | # https://cloud-images.ubuntu.com/releases/14.04/release-20150506/ 19 | image_id: <%= ENV.fetch('EC2_IMAGE_ID', "ami-8d9e1cf7") %> 20 | instance_type: <%= ENV.fetch('EC2_INSTANCE_TYPE', "t2.micro") %> 21 | transport: 22 | username: ubuntu 23 | - name: centos-7 24 | driver: 25 | # https://wiki.centos.org/Cloud/AWS 26 | # https://stackoverflow.com/questions/40835953/how-to-find-ami-id-of-centos-7-image-in-aws-marketplace 27 | image_id: <%= ENV.fetch('EC2_IMAGE_ID', "ami-ae7bfdb8") %> 28 | instance_type: <%= ENV.fetch('EC2_INSTANCE_TYPE', "t2.micro") %> 29 | transport: 30 | username: centos 31 | - name: centos-ami 32 | driver: 33 | image_id: <%= ENV.fetch('EC2_IMAGE_ID', "ami-6869aa05") %> 34 | instance_type: <%= ENV.fetch('EC2_INSTANCE_TYPE', "t2.micro") %> 35 | 36 | suites: 37 | - name: default 38 | run_list: 39 | - recipe[apt::default] 40 | - recipe[jenkins-demo::default] 41 | - recipe[jenkins-demo::conf_test_job] 42 | attributes: 43 | {jenkins_demo: 44 | {jenkins_port: '8081', 45 | slack_teamdomain: 'mywechat', 46 | slack_authtoken: '<%= ENV.fetch('SLACK_TOKEN', "") %>', 47 | # TODO different env use different port 48 | # TODO use server ip 49 | slack_buildserverurl: 'http://localhost:<%= ENV.fetch('DOCKER_PORT_FORWARD_PREFIX', "180") %>81/', 50 | slack_room: '#denny-alerts', 51 | default_username: '<%= ENV.fetch('JENKINS_DEFAULT_USERNAME', "usertest123") %>', 52 | default_password: '<%= ENV.fetch('JENKINS_DEFAULT_PASSWORD', "password123") %>' 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /Scenario-303/cookbooks/jenkins-demo/.kitchen_vagrant.yml: -------------------------------------------------------------------------------- 1 | --- 2 | driver: 3 | name: vagrant 4 | 5 | driver_config: 6 | hostname: <%= ENV.fetch('INSTANCE_NAME', "jenkins-demo") %> 7 | # https://github.com/test-kitchen/kitchen-vagrant 8 | memory: 1024 9 | transport: 10 | username: kitchen 11 | 12 | provisioner: 13 | name: chef_zero 14 | require_chef_omnibus: 13.6.4 15 | data_path: test/shared 16 | client_rb: 17 | file_cache_path: "/var/chef/cache" 18 | 19 | platforms: 20 | - name: centos-7 21 | driver_config: 22 | instance_name: <%= ENV.fetch('INSTANCE_NAME', "jenkins-demo-centos7") %> 23 | network: 24 | - ["forwarded_port", {guest: 8080, host: 18080}] 25 | - name: ubuntu-14.04 26 | # https://stackoverflow.com/questions/38677059/port-forwarding-not-working-with-test-kitchen-and-vagrant 27 | driver_config: 28 | instance_name: <%= ENV.fetch('INSTANCE_NAME', "jenkins-demo-ubuntu1404") %> 29 | network: 30 | - ["forwarded_port", {guest: 8080, host: 28080}] 31 | 32 | suites: 33 | - name: default 34 | run_list: 35 | - recipe[apt::default] 36 | - recipe[jenkins-demo::default] 37 | - recipe[jenkins-demo::conf_test_job] 38 | attributes: 39 | {jenkins_demo: 40 | {jenkins_port: '8081', 41 | slack_teamdomain: 'mywechat', 42 | slack_authtoken: '<%= ENV.fetch('SLACK_TOKEN', "") %>', 43 | # TODO different env use different port 44 | # TODO use server ip 45 | slack_buildserverurl: 'http://localhost:<%= ENV.fetch('DOCKER_PORT_FORWARD_PREFIX', "180") %>81/', 46 | slack_room: '#denny-alerts', 47 | default_username: '<%= ENV.fetch('JENKINS_DEFAULT_USERNAME', "usertest123") %>', 48 | default_password: '<%= ENV.fetch('JENKINS_DEFAULT_PASSWORD', "password123") %>' 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Scenario-303/cookbooks/jenkins-demo/.rubocop.yml: -------------------------------------------------------------------------------- 1 | AllCops: 2 | Exclude: 3 | - Berksfile 4 | 5 | Style/Next: 6 | Enabled: false 7 | 8 | Metrics/LineLength: 9 | Max: 90 10 | 11 | MethodLength: 12 | Max: 20 13 | 14 | Metrics/AbcSize: 15 | Enabled: false 16 | -------------------------------------------------------------------------------- /Scenario-303/cookbooks/jenkins-demo/Berksfile: -------------------------------------------------------------------------------- 1 | # -*- ruby -*- 2 | source 'https://supermarket.getchef.com' 3 | 4 | metadata 5 | -------------------------------------------------------------------------------- /Scenario-303/cookbooks/jenkins-demo/Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | # source 'https://ruby.taobao.org/' 3 | 4 | gem 'kitchen-digitalocean', '= 0.9.8' 5 | gem 'kitchen-docker', '= 2.6.0' 6 | gem 'kitchen-ec2', '= 1.3.2' 7 | gem 'kitchen-vagrant', '= 1.2.1' 8 | 9 | gem 'test-kitchen', '= 1.19.1' 10 | 11 | gem 'berkshelf', '= 6.3.1' 12 | 13 | gem 'foodcritic', '~> 4.0.0' 14 | gem 'rubocop', '~> 0.48.1' 15 | -------------------------------------------------------------------------------- /Scenario-303/cookbooks/jenkins-demo/README.md: -------------------------------------------------------------------------------- 1 | jenkins-demo Cookbook 2 | ================ 3 | Setup and configure demo jenkins 4 | -------------------------------------------------------------------------------- /Scenario-303/cookbooks/jenkins-demo/attributes/conf_test_job.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | # 4 | # Copyright 2017, DennyZhang.com 5 | # 6 | # All rights reserved - Do Not Redistribute 7 | # 8 | 9 | # slack notification 10 | default['jenkins_demo']['slack_teamdomain'] = '' 11 | default['jenkins_demo']['slack_authtoken'] = '' 12 | default['jenkins_demo']['slack_buildserverurl'] = '' 13 | default['jenkins_demo']['slack_room'] = '' 14 | -------------------------------------------------------------------------------- /Scenario-303/cookbooks/jenkins-demo/attributes/default.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | # 4 | # Copyright 2017, DennyZhang.com 5 | # 6 | # All rights reserved - Do Not Redistribute 7 | # 8 | default['jenkins_demo']['jenkins_port'] = 8080 9 | 10 | # TODO: speed up the deployment process 11 | default['jenkins_demo']['jenkins_plugins'] = { 12 | 'icon-shim' => '2.0.3', 13 | 'credentials' => '2.1.16', 14 | 'thinBackup' => '1.9', 15 | # 'command-launcher' => '1.0', 16 | 'bouncycastle-api' => '2.16.2', 17 | 'plain-credentials' => '1.4', 18 | 'slack' => '2.3', 19 | 'script-security' => '1.35', 20 | 'matrix-auth' => '2.2', 21 | 'ssh-credentials' => '1.13' 22 | } 23 | 24 | ######################################## 25 | default['jenkins_demo']['default_username'] = '' 26 | default['jenkins_demo']['default_password'] = '' 27 | 28 | # TODO: improve the security 29 | default['jenkins_demo']['chef_private_key'] = \ 30 | '-----BEGIN RSA PRIVATE KEY----- 31 | MIIEpgIBAAKCAQEA6fIwUKxZXgKqEE6HCM94eEEeQ+n9mGpKn+CiKExI97mQtio4 32 | uzB/4A7qVXfBYaa2jbPZzD6bDvGco88vgeDuRB5tNh/sRBD3T7L9CxNIGp9gMMsu 33 | tRprwI5MEUsDDFXMKo5ZinpRe9fud5UBOmEHK0vjRVSgLVCGYdv/iXaBKY3feH8a 34 | 4gUuTzkdbUtoUMAUTfNyevhUfLRKSWjr5+f7krYYTqJpM7KUAL9e2dYMjkj3He7g 35 | iM4uiPtAQnMYcsyevNgpM0uKnp6+pPzTMSkSNp3uIK6aQ4lR80lEfq8fRwqzsIuJ 36 | dRT/+iJpd6XF8+GSyOt/tEh1RPiEKiGHLpmZGQIDAQABAoIBAQDFsipuIhcrQKki 37 | OpoWMe0mAjFnRtdM85W4YYXm9AA9h4zow+lJFoUZfME+FINQ2CcwvClzVfyGtlqe 38 | ezk0UjZHTkcQFA3+vy+fJCx+LX8jMEeDNFB2Lqub/yP9ARzEUcTEuaKlSRSOyTz1 39 | xO9SvCfoyKp4Ljll0cSd8eGR8pjX2TSfJ85aFAcP1CHGa/qGdxhSrbL2PMXaNFIT 40 | 27ZEUo4FVqcwRFN6JuO4sAlnyg8axXlXNLpwPzW1Zi7auS9nAO9bDEIhP4YfFwWs 41 | /iV7KBs/bryez94XS68b3MUXoZWS+1nP8ivBSOCH0mWy5/PhR4esih2EhXk/hi3P 42 | dp6aX4p5AoGBAPrmS+4lrvnvk2EOj3vqSergd31XBTM6NRKSsIYCtlaXsVjMym/i 43 | UdqcLqha4IEW3mucmpD3MBsTqshHGTI+67+tU/G23kThV/3U3a+jSR10FjgACPRd 44 | 8VhxrhTBvKjcw0uKeMl9uE0eb/2q8uVtX/8InOCvEfNGFCcszLsYFBr3AoGBAO6z 45 | qhWt8y/HkqWgBcbDJKx+T050nM9fkkBk1ILZn/GMEU828aEvKSwa8wzcx1gPo8Uu 46 | TP2SS0K0vnQv75UfyafgxFMVlELQrRTLHJqFQrCGikgBLNwHjRdvHfNujoBXbv+9 47 | g4LVFqHv0/kVRc1kXhdEwBCZm29rCDVusKK0C1hvAoGBAOAY4qkLL4Y93j1KbA4Z 48 | 7XvEkfV5zEM9Mjosm06XDZW6V8Ug5Y+ZbdL8vQ/SW8PxUSh87/GbV3RX1KqeFnsy 49 | iA7kGZ5D37NWMumdP4SpK50LGu1Z2qWpYu/EWeBgSsnopObL/6a4i+0VyqGgFuOl 50 | FaENaFGnDTlk1otHEHXrw8lxAoGBAITL11fwSlbOhLs3537ImeKM8roHDiYgWVER 51 | x1h0khLjhc24F31Aq3sqEwWY3h4TtVzBgXugo9Ycj8g70uH3qUyIMzC11KHHTkM/ 52 | LE6azJtAfjXI0Zgna0saOmNvoj+sZMhKOpvSyKCWuCrettKpf98aFHAnxN2bghmX 53 | 1xTtbVJpAoGBAKnqvADsNFaI1Ak7tdfJJ+chxnxXd1k6Mly44Jsp6oako4Nl2Uiw 54 | 3xL4JGed+QBmjFh+n4hR9T7J65fUFvBixBEAhDSXcRHWL84xTQWLtdHK4+zDWGJt 55 | n2DMrFzhp1H6neUFMBeNOw+fQuhPj6OcLrs4dRdyQhVRp0ZOJyLMS39e 56 | -----END RSA PRIVATE KEY-----' 57 | 58 | default['jenkins_demo']['chef_public_key'] = \ 59 | 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDp8jBQrFleAqoQTocIz3h4QR5'\ 60 | 'D6f2Yakqf4KIoTEj3uZC2Kji7MH/gDupVd8FhpraNs9nMPpsO8Zyjzy+B4O5EHm'\ 61 | '02H+xEEPdPsv0LE0gan2Awyy61GmvAjkwRSwMMVcwqjlmKelF71+53lQE6YQcrS'\ 62 | '+NFVKAtUIZh2/+JdoEpjd94fxriBS5POR1tS2hQwBRN83J6+FR8tEpJaOvn5/uS'\ 63 | 'thhOomkzspQAv17Z1gyOSPcd7uCIzi6I+0BCcxhyzJ682CkzS4qenr6k/NMxKRI'\ 64 | '2ne4grppDiVHzSUR+rx9HCrOwi4l1FP/6Iml3pcXz4ZLI63+0SHVE+IQqIYcumZ'\ 65 | 'kZ chef@mytest.com' 66 | -------------------------------------------------------------------------------- /Scenario-303/cookbooks/jenkins-demo/files/default/serverspec_check.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | function setup_serverspec() { 3 | working_dir=${1?} 4 | cd "$working_dir" 5 | if [ ! -f spec/spec_helper.rb ]; then 6 | echo "Setup Serverspec Test case" 7 | cat > spec/spec_helper.rb < Rakefile < 'spec:all' 18 | task :default => :spec 19 | 20 | namespace :spec do 21 | targets = [] 22 | Dir.glob('./spec/*').each do |dir| 23 | next unless File.directory?(dir) 24 | target = File.basename(dir) 25 | target = "_#{target}" if target == "default" 26 | targets << target 27 | end 28 | 29 | task :all => targets 30 | task :default => :all 31 | 32 | targets.each do |target| 33 | original_target = target == "_default" ? target[1..-1] : target 34 | desc "Run serverspec tests to #{original_target}" 35 | RSpec::Core::RakeTask.new(target.to_sym) do |t| 36 | ENV['TARGET_HOST'] = original_target 37 | t.pattern = "spec/#{original_target}/*_spec.rb" 38 | end 39 | end 40 | end 41 | EOF 42 | fi 43 | } 44 | 45 | ######################################################### 46 | [ -n "$working_dir" ] || working_dir="$WORKSPACE" 47 | 48 | mkdir -p "$working_dir/spec/localhost" 49 | cd "$working_dir" 50 | 51 | setup_serverspec "$working_dir" 52 | 53 | cat > spec/localhost/sample_spec.rb <= 14.04' 14 | depends 'apt', '=2.6.1' 15 | depends 'java' 16 | depends 'jenkins', '=5.0.4' 17 | -------------------------------------------------------------------------------- /Scenario-303/cookbooks/jenkins-demo/recipes/backup.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | # 4 | # Cookbook Name:: jenkins-demo 5 | # Recipe:: backup 6 | # 7 | # Copyright 2017, DennyZhang.com 8 | # 9 | # All rights reserved - Do Not Redistribute 10 | # 11 | -------------------------------------------------------------------------------- /Scenario-303/cookbooks/jenkins-demo/recipes/conf_test_job.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | # 4 | # Cookbook Name:: jenkins-demo 5 | # Recipe:: conf_test_job 6 | # 7 | # Copyright 2017, DennyZhang.com 8 | # 9 | # All rights reserved - Do Not Redistribute 10 | # 11 | 12 | ################################################################################ 13 | # Install simple jobs 14 | %w[CommonServerCheckRepo].each do |job_name| 15 | config = File.join(Chef::Config[:file_cache_path], "#{job_name}.xml") 16 | template config do 17 | source "#{job_name}/config.xml" 18 | end 19 | 20 | jenkins_job job_name do 21 | config config 22 | end 23 | end 24 | 25 | # Install facilities related to the jobs 26 | 27 | # keep the gem installation minimal: --no-ri --no-rdoc 28 | # https://coderwall.com/p/spo6bq/default-no-ri-no-rdoc-on-ruby-gem-installation 29 | file '/root/.gemrc' do 30 | content 'gem: --no-ri --no-rdoc' 31 | mode 0o755 32 | owner 'root' 33 | group 'root' 34 | end 35 | 36 | if platform_family?('debian') 37 | 38 | # https://www.brightbox.com/blog/2017/01/13/ruby-2-4-ubuntu-packages/ 39 | apt_repository 'ruby-repo' do 40 | uri 'ppa:brightbox/ruby-ng' 41 | distribution node['lsb']['codename'] 42 | key 'C3173AA6' 43 | keyserver 'keyserver.ubuntu.com' 44 | retries 3 45 | retry_delay 3 46 | not_if { ::File.exist?('/etc/apt/sources.list.d/ruby-repo.list') } 47 | end 48 | 49 | %w[ruby2.4 ruby2.4-dev netcat gem rake].each do |x| 50 | package x do 51 | action :install 52 | not_if "dpkg -l #{x} | grep -E '^ii'" 53 | end 54 | end 55 | else 56 | %w[nc gem yum zlib-devel gcc gcc-c++ ruby-devel rubygems].each do |x| 57 | package x do 58 | action :install 59 | # TODO: change this 60 | # not_if "dpkg -l #{x} | grep -E '^ii'" 61 | end 62 | end 63 | 64 | gem_package 'rake' do 65 | action :install 66 | version '12.3.0' 67 | end 68 | 69 | # TODO: better way to install io-console gem 70 | execute 'Install io-console' do 71 | command 'gem install io-console' 72 | action :run 73 | not_if 'gem list | grep io-console' 74 | end 75 | end 76 | 77 | gem_package 'serverspec' do 78 | action :install 79 | version '2.41.3' 80 | end 81 | 82 | cookbook_file '/var/lib/jenkins/script/serverspec_check.sh' do 83 | source 'serverspec_check.sh' 84 | mode 0o755 85 | user 'jenkins' 86 | group 'jenkins' 87 | end 88 | ################################################################################ 89 | include_recipe 'jenkins-demo::test_pipeline' 90 | -------------------------------------------------------------------------------- /Scenario-303/cookbooks/jenkins-demo/recipes/default.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | # 4 | # Cookbook Name:: jenkins-demo 5 | # Recipe:: default 6 | # 7 | # Copyright 2017, DennyZhang.com 8 | # 9 | # All rights reserved - Do Not Redistribute 10 | # 11 | 12 | include_recipe 'jenkins-demo::master' 13 | 14 | if platform_family?('debian') 15 | # Install iproute2 for ss package 16 | %w[lsof iproute2].each do |x| 17 | package x do 18 | action :install 19 | not_if "dpkg -l #{x} | grep -E '^ii'" 20 | end 21 | end 22 | else 23 | %w[lsof].each do |x| 24 | package x do 25 | action :install 26 | # TODO: change this 27 | # not_if "dpkg -l #{x} | grep -E '^ii'" 28 | end 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /Scenario-303/cookbooks/jenkins-demo/recipes/master.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | # 4 | # Cookbook Name:: jenkins-demo 5 | # Recipe:: master 6 | # 7 | # Copyright 2017, DennyZhang.com 8 | # 9 | # All rights reserved - Do Not Redistribute 10 | # 11 | 12 | apt_update 'update' if platform_family?('debian') 13 | 14 | node.default['java']['install_flavor'] = 'oracle' 15 | node.default['java']['jdk_version'] = '8' 16 | node.default['java']['set_etc_environment'] = true 17 | node.default['java']['oracle']['accept_oracle_download_terms'] = true 18 | # Avoid unecessary change to /etc/sysconfig/jenkins in CentOS 19 | node.default['jenkins']['java'] = 'java' 20 | 21 | if %w[debian ubuntu].include?(node['platform_family']) 22 | node.default['jenkins']['master']['repository'] = \ 23 | 'http://pkg.jenkins-ci.org/debian' 24 | node.default['jenkins']['master']['repository_key'] = \ 25 | 'http://pkg.jenkins-ci.org/debian/jenkins-ci.org.key' 26 | end 27 | 28 | node.default['jenkins']['executor']['timeout'] = 480 29 | 30 | node.default['jenkins']['master']['port'] = node['jenkins_demo']['jenkins_port'] 31 | node.default['jenkins']['master']['endpoint'] = \ 32 | "http://#{node['jenkins']['master']['host']}:#{node['jenkins']['master']['port']}" 33 | 34 | include_recipe 'java::default' 35 | include_recipe 'jenkins::master' 36 | 37 | # Install some plugins needed, but not installed on jenkins2 by default 38 | node['jenkins_demo']['jenkins_plugins'].each do |plugin| 39 | jenkins_plugin plugin[0] do 40 | version plugin[1] 41 | notifies :execute, 'jenkins_command[safe-restart]', :delayed 42 | end 43 | end 44 | 45 | # force restart, since critical jenkins plugin installed 46 | # TODO: When re-run chef update, avoid this extra blind jenkins restart 47 | jenkins_command 'safe-restart' do 48 | action :execute 49 | end 50 | 51 | %w[/var/lib/jenkins/script].each do |x| 52 | directory x do 53 | owner 'jenkins' 54 | group 'jenkins' 55 | mode 0o755 56 | action :create 57 | end 58 | end 59 | 60 | include_recipe 'jenkins-demo::security' 61 | include_recipe 'jenkins-demo::backup' 62 | -------------------------------------------------------------------------------- /Scenario-303/cookbooks/jenkins-demo/recipes/security.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | # 4 | # Cookbook Name:: jenkins-demo 5 | # Recipe:: security 6 | # 7 | # Copyright 2017, DennyZhang.com 8 | # 9 | # All rights reserved - Do Not Redistribute 10 | # 11 | 12 | require 'openssl' 13 | require 'net/ssh' 14 | # key = OpenSSL::PKey::RSA.new(jenkins['private_key']) 15 | # private_key = key.to_pem 16 | # public_key = "#{key.ssh_type} #{[key.to_blob].pack('m0')}" 17 | 18 | # https://goo.gl/jvn5TN 19 | # Jenkins itself login the server 20 | 21 | private_key = node['jenkins_demo']['chef_private_key'] 22 | public_key = node['jenkins_demo']['chef_public_key'] 23 | 24 | # Set the private key on the executor 25 | node.run_state[:jenkins_private_key] = private_key 26 | 27 | # Create a default Chef user with the public key 28 | jenkins_user 'chef' do 29 | full_name 'Chef Client' 30 | public_keys [public_key] 31 | end 32 | 33 | # Turn on basic authentication 34 | jenkins_script 'setup authentication' do 35 | command <<-EOH.gsub(/^ {4}/, '') 36 | import jenkins.model.* 37 | def instance = Jenkins.getInstance() 38 | 39 | import hudson.security.* 40 | def realm = new HudsonPrivateSecurityRealm(false) 41 | instance.setSecurityRealm(realm) 42 | 43 | def strategy = new hudson.security.FullControlOnceLoggedInAuthorizationStrategy() 44 | instance.setAuthorizationStrategy(strategy) 45 | 46 | instance.save() 47 | EOH 48 | # TODO: add not_if 49 | end 50 | 51 | ################################################################################ 52 | username = node['jenkins_demo']['default_username'] 53 | password = node['jenkins_demo']['default_password'] 54 | if username != '' 55 | # Create a dummy user 56 | # https://gist.github.com/hayderimran7/50cb1244cc1e856873a4 57 | jenkins_script "add_user #{username}" do 58 | command <<-EOH.gsub(/^ {4}/, '') 59 | import jenkins.model.* 60 | import hudson.security.* 61 | 62 | def instance = Jenkins.getInstance() 63 | 64 | def hudsonRealm = new HudsonPrivateSecurityRealm(false) 65 | hudsonRealm.createAccount("#{username}", "#{password}") 66 | instance.setSecurityRealm(hudsonRealm) 67 | instance.save() 68 | EOH 69 | not_if "test -d /var/lib/jenkins/users/#{username}" 70 | end 71 | end 72 | 73 | # Use matrix authorization model 74 | # Gives all authenticated users admin access 75 | # https://github.com/glenjamin/jenkins-groovy-examples/blob/master/README.md 76 | jenkins_script 'all authenticated users admin access' do 77 | command <<-EOH.gsub(/^ {4}/, '') 78 | import jenkins.model.* 79 | def instance = Jenkins.getInstance() 80 | 81 | import hudson.security.* 82 | def realm = new HudsonPrivateSecurityRealm(false) 83 | instance.setSecurityRealm(realm) 84 | 85 | def strategy = new hudson.security.GlobalMatrixAuthorizationStrategy() 86 | strategy.add(Jenkins.ADMINISTER, 'authenticated') 87 | instance.setAuthorizationStrategy(strategy) 88 | 89 | instance.save() 90 | EOH 91 | # TODO: add not_if 92 | end 93 | -------------------------------------------------------------------------------- /Scenario-303/cookbooks/jenkins-demo/recipes/test_pipeline.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | # 4 | # Cookbook Name:: jenkins-demo 5 | # Recipe:: test_pipeline 6 | # 7 | # Copyright 2017, DennyZhang.com 8 | # 9 | # All rights reserved - Do Not Redistribute 10 | # 11 | ################################################################################ 12 | # Install Jenkins pipeline plugins 13 | 14 | package 'git' do 15 | action :install 16 | end 17 | 18 | jenkins_pipeline_plugins = { 19 | ############################################ 20 | # Install git plugin 21 | 'git' => '3.6.4', 22 | # upgrade or downgrade plugins 23 | 'structs' => '1.10', 24 | 'scm-api' => '2.2.5', 25 | ############################################ 26 | # Install pipeline plugin 27 | 'workflow-aggregator' => '2.5', 28 | # upgrade or downgrade plugins 29 | 'workflow-step-api' => '2.14', 30 | 'branch-api' => '2.0.15', 31 | # Need to install branch-api, then cloudbees-folder 32 | # If not, branch-api:v2.0.15 will downgrade cloudbees-folder to v6.1.0 33 | 'cloudbees-folder' => '6.2.1', 34 | 'workflow-cps' => '2.41', 35 | 'workflow-support' => '2.16', 36 | 'credentials' => '2.1.16', 37 | 'plain-credentials' => '1.4', 38 | 'git-client' => '2.6.0' 39 | } 40 | 41 | jenkins_pipeline_plugins.each do |plugin| 42 | jenkins_plugin plugin[0] do 43 | version plugin[1] 44 | notifies :execute, 'jenkins_command[safe-restart]', :delayed 45 | end 46 | end 47 | 48 | # force restart, since critical jenkins plugin installed 49 | jenkins_command 'safe-restart' do 50 | action :execute 51 | end 52 | 53 | %w[JenkinsFileExample1 JenkinsFileExample2].each do |job_name| 54 | config = File.join(Chef::Config[:file_cache_path], "#{job_name}.xml") 55 | template config do 56 | source "#{job_name}/config.xml" 57 | end 58 | 59 | jenkins_job job_name do 60 | config config 61 | end 62 | end 63 | ################################################################################ 64 | -------------------------------------------------------------------------------- /Scenario-303/cookbooks/jenkins-demo/templates/default/CommonServerCheckRepo/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | false 5 | 6 | 7 | 8 | -1 9 | 50 10 | -1 11 | -1 12 | 13 | 14 | 15 | false 16 | 17 | 18 | 19 | 20 | test_spec 21 | 22 | # ping check 23 | ["www.github.com"].each do |item| 24 | describe command("ping -c3 #{item}") do 25 | its(:exit_status) { should eq 0 } 26 | end 27 | end 28 | 29 | # Check anonymous http links 30 | ["http://www.dennyzhang.com/", 31 | "https://www.dennyzhang.com/", 32 | "https://code.dennyzhang.com/", 33 | "http://slack.dennyzhang.com/", 34 | ].each do |url| 35 | describe command('curl -I --connect-timeout 10 -k %s 2>&1' %[url]) do 36 | its(:stdout) { should match /HTTP\/1.1 200 OK/ } 37 | end 38 | end 39 | 40 | describe service('jenkins') do 41 | it { should be_running } 42 | end 43 | 44 | # Check at least 2 GB free disk 45 | describe command("[ $(df -h / | tail -n1 |awk -F' ' '{print $4}' | awk -F'G' '{print $1}' | awk -F'.' '{print $1}') -gt 2 ]") do 46 | its(:exit_status) { should eq 0 } 47 | end 48 | 49 | # TODO: enable this 50 | # # Check at least 2 GB free memory 51 | # describe command("[ $(free -ml | grep 'buffers/cache' | awk -F' ' '{print $4}') -gt 2048 ]") do 52 | # its(:exit_status) { should eq 0 } 53 | # end 54 | 55 | # TODO: support for both CentOS and Ubuntu OS 56 | # # Check remote tcp port 57 | # ["vpn.dennyzhang.com:6188", # vpn 58 | # "www.dennyzhang.com:443", # ssl 59 | # ].each do |ip_port| 60 | # (ip, port) = ip_port.split(':') 61 | # describe command("nc -z -v -w5 #{ip} #{port} 2>&1") do 62 | # its(:stdout) { should match /open/ } 63 | # end 64 | # end 65 | 66 | # # check cpu loadavg in latest one min 67 | # ["172.17.0.1:2702:10"].each do |item| 68 | # (ip, port, cpu_load) = item.split(':') 69 | # command_str = "[ `ssh -o stricthostkeychecking=no -i /var/jenkins_home/.ssh/docker_host_id_rsa -p %s root@%s cat /proc/loadavg | awk '{print int($1+0.99)}'` -lt %s ]" \ 70 | # % [port, ip, cpu_load] 71 | # describe command(command_str) do 72 | # its(:exit_status) { should eq 0 } 73 | # end 74 | # end 75 | 76 | # # check docker container number 77 | # ["172.17.0.1:2702:15"].each do |item| 78 | # (ip, port, container_count) = item.split(':') 79 | # command_str = "[ `ssh -o stricthostkeychecking=no -i /var/jenkins_home/.ssh/docker_host_id_rsa -p %s root@%s docker ps | sed 1d | wc -l` -lt %s ]" \ 80 | # % [port, ip, container_count] 81 | # describe command(command_str) do 82 | # its(:exit_status) { should eq 0 } 83 | # end 84 | # end 85 | 86 | 87 | 88 | 89 | 90 | 91 | true 92 | false 93 | false 94 | false 95 | 96 | 97 | H H/5 * * * 98 | 99 | 100 | false 101 | 102 | 103 | #!/bin/bash -ex 104 | export PATH=$PATH:/usr/local/bin/ 105 | bash -e /var/lib/jenkins/script/serverspec_check.sh 106 | 107 | 108 | 109 | 110 | 111 | false 112 | false 113 | false 114 | TestParent 115 | 116 | 3 117 | 118 | 1 119 | 120 | 121 | <%= node['jenkins_demo']['slack_teamdomain'] %> 122 | <%= node['jenkins_demo']['slack_authtoken'] %> 123 | <%= node['jenkins_demo']['slack_buildserverurl'] %> 124 | <%= node['jenkins_demo']['slack_room'] %> 125 | false 126 | false 127 | false 128 | false 129 | false 130 | true 131 | true 132 | true 133 | false 134 | NONE 135 | false 136 | 137 | 138 | 139 | 140 | 141 | -------------------------------------------------------------------------------- /Scenario-303/cookbooks/jenkins-demo/templates/default/JenkinsFileExample1/Jenkinsfile.groovy: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env groovy 2 | 3 | node('master') { 4 | try { 5 | stage('build') { 6 | sh "echo dummy build action" 7 | } 8 | 9 | stage('test') { 10 | sh "echo dummy test action" 11 | } 12 | 13 | stage('deploy') { 14 | sh "echo dummy deploy action" 15 | } 16 | } catch(error) { 17 | throw error 18 | } finally { 19 | // Any cleanup operations needed, whether we hit an error or not 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Scenario-303/cookbooks/jenkins-demo/templates/default/JenkinsFileExample1/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | false 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 2 14 | 15 | 16 | https://github.com/DennyZhang/challenges-jenkins-groovy.git 17 | 18 | 19 | 20 | 21 | */master 22 | 23 | 24 | false 25 | 26 | 27 | 28 | Scenario-301/cookbooks/jenkins-demo/templates/default/JenkinsFileExample1/Jenkinsfile.groovy 29 | true 30 | 31 | 32 | false 33 | 34 | -------------------------------------------------------------------------------- /Scenario-303/cookbooks/jenkins-demo/templates/default/JenkinsFileExample2/Jenkinsfile.groovy: -------------------------------------------------------------------------------- 1 | node { 2 | // // http://www.commandlinefu.com/commands/view/3584/remove-color-codes-special-characters-with-sed 3 | // // parameters: slack_channel, slack_domain, slack_token 4 | // // get who has triggered the pipeline job 5 | // def sh_command = "head -n 1 $HUDSON_HOME/jobs/$JOB_BASE_NAME/builds/$BUILD_NUMBER/log | awk -F'=' '{print \$2}' | sed -r \"s/\\x1B\\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]//g\"" 6 | // def username = sh(script: sh_command, returnStdout: true) 7 | // username = username.trim() 8 | // def job_name = sh(script: "echo $JOB_BASE_NAME", returnStdout: true) 9 | // job_name = job_name.trim() 10 | // slackSend channel: slack_channel, message: 'Job(' + job_name + ') has been triggered by ' + username, teamDomain: slack_domain, tokenCredentialId: slack_token 11 | 12 | try { 13 | stage('Build') { 14 | echo 'Building..' 15 | } 16 | stage('Test') { 17 | build job: "CommonServerCheckRepo" 18 | } 19 | if (whether_skip_deploy == "false") { 20 | stage('Deploy') { 21 | echo 'Deploying....' 22 | } 23 | } 24 | } 25 | finally { 26 | echo "Finally Actions" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Scenario-303/cookbooks/jenkins-demo/templates/default/JenkinsFileExample2/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | false 6 | 7 | 8 | 9 | 10 | whether_skip_deploy 11 | If checked, deploy stage will be skipped 12 | false 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 2 23 | 24 | 25 | https://github.com/DennyZhang/challenges-jenkins-groovy.git 26 | 27 | 28 | 29 | 30 | */master 31 | 32 | 33 | false 34 | 35 | 36 | 37 | Scenario-301/cookbooks/jenkins-demo/templates/default/JenkinsFileExample2/Jenkinsfile.groovy 38 | true 39 | 40 | 41 | false 42 | 43 | -------------------------------------------------------------------------------- /Scenario-303/cookbooks/jenkins-demo/test/integration/default/serverspec/server_spec.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | require 'serverspec' 4 | 5 | # Required by serverspec 6 | set :backend, :exec 7 | 8 | ############################################################################# 9 | require 'json' 10 | 11 | describe command('java -version') do 12 | its(:stderr) { should contain '1.8' } 13 | end 14 | 15 | describe command('chef-solo --version') do 16 | its(:stdout) { should contain '13.6.4' } 17 | end 18 | 19 | if %w[redhat centos].include?(os[:family]) 20 | describe command('yum info jenkins') do 21 | its(:stdout) { should contain '2.73.3' } 22 | end 23 | elsif %w[debian ubuntu].include?(os[:family]) 24 | # debian related environment spec 25 | describe command('dpkg -l | grep jenkins') do 26 | its(:stdout) { should contain '2.91' } 27 | end 28 | end 29 | 30 | ############################################################################# 31 | # If extra jenkins jobs have been triggered, verify the logic 32 | require_relative '../../../kitchen/data/verify_job_config' 33 | 34 | ############################################################################# 35 | require 'json' 36 | chef_data = JSON.parse(IO.read('/tmp/kitchen/dna.json')) 37 | 38 | jenkins_port = chef_data.fetch('jenkins_demo').fetch('jenkins_port') 39 | # Wait for service slow start/restart 40 | describe port(jenkins_port), wait: { timeout: 60 } do 41 | it { should be_listening } 42 | end 43 | 44 | ############################################################################# 45 | username = chef_data.fetch('jenkins_demo').fetch('default_username') 46 | 47 | if username != '' 48 | describe file("/var/lib/jenkins/users/#{username}") do 49 | it { should be_directory } 50 | end 51 | end 52 | -------------------------------------------------------------------------------- /Scenario-303/cookbooks/jenkins-demo/test/shared/verify_job_config.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | require 'serverspec' 4 | 5 | # Required by serverspec 6 | set :backend, :exec 7 | # https://github.com/test-kitchen/test-kitchen/issues/469 8 | set :path, '/sbin:/usr/local/sbin:/usr/local/bin:$PATH' 9 | 10 | ############################################################################# 11 | describe file('/var/lib/jenkins/script/serverspec_check.sh') do 12 | it { should be_file } 13 | end 14 | 15 | describe command('which nc') do 16 | its(:exit_status) { should eq 0 } 17 | end 18 | 19 | describe command('gem list | grep serverspec') do 20 | its(:stdout) { should contain '2.41.3' } 21 | end 22 | 23 | if %w[redhat centos].include?(os[:family]) 24 | describe command('gem --version') do 25 | its(:stdout) { should contain '2.0.14' } 26 | end 27 | 28 | describe command('rake --version') do 29 | its(:stdout) { should contain '12.3.0' } 30 | end 31 | elsif %w[debian ubuntu].include?(os[:family]) 32 | # debian related environment spec 33 | describe command('gem --version') do 34 | its(:stdout) { should contain '2.6.13' } 35 | end 36 | 37 | describe command('rake --version') do 38 | its(:stdout) { should contain '10.0.4' } 39 | end 40 | end 41 | 42 | jenkins_plugins_versions = { 43 | 'workflow-cps' => '2.41', 44 | 'git' => '3.6.4', 45 | 'workflow-job' => '2.9', 46 | 'workflow-support' => '2.16', 47 | 'cloudbees-folder' => '6.2.1', 48 | 'credentials' => '2.1.16', 49 | 'plain-credentials' => '1.4', 50 | 'git-client' => '2.6.0' 51 | } 52 | # verify plugin version 53 | jenkins_plugins_versions.each do |plugin| 54 | describe file("/var/lib/jenkins/plugins/#{plugin[0]}/META-INF/MANIFEST.MF") do 55 | its(:content) { should contain "Plugin-Version: #{plugin[1]}" } 56 | end 57 | end 58 | -------------------------------------------------------------------------------- /Scenario-401/README.md: -------------------------------------------------------------------------------- 1 | [![LinkedIn](https://raw.githubusercontent.com/USDevOps/mywechat-slack-group/master/images/linkedin.png)](https://www.linkedin.com/in/dennyzhang001) slack [![Github](https://raw.githubusercontent.com/USDevOps/mywechat-slack-group/master/images/github.png)](https://github.com/DennyZhang) 2 | 3 | File me [tickets](https://github.com/DennyZhang/challenges-chef/issues) or star [the repo](https://github.com/DennyZhang/challenges-chef). 4 | 5 | 6 | 7 | Table of Contents 8 | ================= 9 | 10 | * [Requirement](#requirement) 11 | * [Procedure](#procedure) 12 | * [More Resources](#more-resources) 13 | 14 | 15 | 16 | 17 | # Requirement 18 | 19 | 1. Test 2 nodes jenkins cluster deployment in docker 20 | 2. Use Jenkinsfile to configure Jenkins 21 | 3. Define Jenkins pipeline 22 | 23 | # Procedure 24 | - Start docker-compose env 25 | docker-compose up -d 26 | 27 | - Login to the container, and run procedure 28 | ``` 29 | docker exec -it my_chef sh 30 | 31 | mkdir -p /tmp/berks_cookbooks 32 | 33 | cd /tmp/cookbooks/jenkins-demo/ 34 | berks vendor /tmp/berks_cookbooks 35 | ls -lth /tmp/berks_cookbooks 36 | ``` 37 | 38 | - Apply Chef update 39 | ``` 40 | cd /tmp 41 | # From config/node.json, we specify to apply example cookbook 42 | chef-solo -L chef_solo.log -c config/solo.rb -j config/node.json 43 | 44 | - After deployment, jenkins is up and running 45 | ``` 46 | 47 | - Verify Jenkins 48 | curl -I http://localhost:8080 49 | 50 | - Destroy docker-compose env after testing 51 | 52 | ``` 53 | docker-compose down -v 54 | ``` 55 | 56 | # More Resources 57 | - jenkins cookbook: https://github.com/chef-cookbooks/jenkins 58 | 59 | -------------------------------------------------------------------------------- /Scenario-401/cookbooks/jenkins-demo/.kitchen.yml: -------------------------------------------------------------------------------- 1 | --- 2 | driver: 3 | name: docker 4 | 5 | driver_config: 6 | instance_name: <%= ENV.fetch('INSTANCE_NAME', "jenkins-demo") %> 7 | hostname: <%= ENV.fetch('INSTANCE_NAME', "jenkins-demo") %> 8 | use_sudo: false 9 | privileged: true 10 | remove_images: false 11 | image: <%= ENV.fetch('IMAGE_NAME', "chef/chefdk") %> 12 | forward: 13 | - <%= ENV.fetch('DOCKER_PORT_FORWARD_PREFIX', "80") %>80:8080 14 | # tls_verify: true 15 | # tls_cacert: <%= ENV.fetch('TLS_FOLDER', "tls") %>/ca.pem 16 | # tls_cert: <%= ENV.fetch('TLS_FOLDER', "tls") %>/cert.pem 17 | # tls_key: <%= ENV.fetch('TLS_FOLDER', "tls") %>/key.pem 18 | # socket: tcp://172.17.0.1:4243 19 | transport: 20 | username: kitchen 21 | 22 | provisioner: 23 | name: chef_zero 24 | require_chef_omnibus: 13.6.4 25 | data_path: test/shared 26 | client_rb: 27 | file_cache_path: "/var/chef/cache" 28 | 29 | platforms: 30 | - name: ubuntu-14.04 31 | 32 | suites: 33 | - name: default 34 | run_list: 35 | - recipe[apt::default] 36 | - recipe[jenkins-demo::default] 37 | attributes: 38 | {jenkins-demo: 39 | {update_version: '1.1' 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Scenario-401/cookbooks/jenkins-demo/.rubocop.yml: -------------------------------------------------------------------------------- 1 | AllCops: 2 | Exclude: 3 | - Berksfile 4 | 5 | Style/Next: 6 | Enabled: false 7 | 8 | Metrics/LineLength: 9 | Max: 90 10 | 11 | MethodLength: 12 | Max: 20 13 | 14 | Metrics/AbcSize: 15 | Enabled: false 16 | -------------------------------------------------------------------------------- /Scenario-401/cookbooks/jenkins-demo/Berksfile: -------------------------------------------------------------------------------- 1 | # -*- ruby -*- 2 | source 'https://supermarket.getchef.com' 3 | 4 | metadata 5 | -------------------------------------------------------------------------------- /Scenario-401/cookbooks/jenkins-demo/Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | # source 'https://ruby.taobao.org/' 3 | 4 | gem 'kitchen-digitalocean', '= 0.9.8' 5 | gem 'kitchen-docker', '= 2.6.0' 6 | gem 'kitchen-ec2', '= 1.3.2' 7 | gem 'kitchen-vagrant', '= 1.2.1' 8 | 9 | gem 'test-kitchen', '= 1.19.1' 10 | 11 | gem 'berkshelf', '= 6.3.1' 12 | 13 | gem 'foodcritic', '~> 4.0.0' 14 | gem 'rubocop', '~> 0.48.1' 15 | -------------------------------------------------------------------------------- /Scenario-401/cookbooks/jenkins-demo/README.md: -------------------------------------------------------------------------------- 1 | jenkins-demo Cookbook 2 | ================ 3 | Setup and configure jenkins for mdm project 4 | 5 | KITCHEN_YAML=.kitchen.docker.yml kitchen test 6 | KITCHEN_YAML=.kitchen.vagrant.yml kitchen test 7 | -------------------------------------------------------------------------------- /Scenario-401/cookbooks/jenkins-demo/attributes/default.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | default['jenkins_plugins'] = { 4 | 'thinBackup' => '1.9', 5 | 'slack' => '2.3' 6 | } 7 | 8 | default['jenkins_mdm']['buildrepo_dir'] = '/var/lib/jenkins/code' 9 | default['jenkins_mdm']['avoid_external_network'] = '1' 10 | default['jenkins_mdm']['data_rentention_days'] = '7' 11 | 12 | default['jenkins_mdm']['docker_daemon_ip'] = '172.17.0.1' 13 | default['jenkins_mdm']['install_devkit'] = '0' 14 | 15 | default['jenkins_mdm']['jenkins_jobs'] = 'TailLogfile' 16 | -------------------------------------------------------------------------------- /Scenario-401/cookbooks/jenkins-demo/metadata.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | name 'jenkins-demo' 4 | maintainer 'DennyZhang' 5 | maintainer_email 'contact@dennyzhang.com' 6 | license 'All rights reserved' 7 | description 'Setup and configure jenkins' 8 | long_description IO.read(File.join(File.dirname(__FILE__), 'README.md')) 9 | version '0.0.1' 10 | source_url 'https://www.dennyzhang.com' 11 | issues_url 'https://www.dennyzhang.com' 12 | 13 | supports 'ubuntu', '>= 14.04' 14 | depends 'apt', '=2.6.1' 15 | depends 'java' 16 | depends 'jenkins', '=5.0.4' 17 | -------------------------------------------------------------------------------- /Scenario-401/cookbooks/jenkins-demo/recipes/conf_job.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | # 4 | # Cookbook Name:: jenkins-demo 5 | # Recipe:: conf_job 6 | # 7 | # Copyright 2017, DennyZhang.com 8 | # 9 | # All rights reserved - Do Not Redistribute 10 | # 11 | 12 | node['jenkins_mdm']['jenkins_jobs'].split(',').each do |job_name| 13 | config = File.join(Chef::Config[:file_cache_path], "#{job_name}.xml") 14 | 15 | template config do 16 | source "#{job_name}.xml.erb" 17 | end 18 | 19 | # Create a jenkins job (default action is `:create`) 20 | jenkins_job job_name do 21 | config config 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /Scenario-401/cookbooks/jenkins-demo/recipes/default.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | # 4 | # Cookbook Name:: jenkins-demo 5 | # Recipe:: default 6 | # 7 | # Copyright 2017, DennyZhang.com 8 | # 9 | # All rights reserved - Do Not Redistribute 10 | # 11 | 12 | # TODO 13 | include_recipe 'jenkins-demo::master' 14 | -------------------------------------------------------------------------------- /Scenario-401/cookbooks/jenkins-demo/recipes/master.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | # 4 | # Cookbook Name:: jenkins-demo 5 | # Recipe:: master 6 | # 7 | # Copyright 2017, DennyZhang.com 8 | # 9 | # All rights reserved - Do Not Redistribute 10 | # 11 | 12 | apt_update 'update' if platform_family?('debian') 13 | 14 | node.default['java']['install_flavor'] = 'oracle' 15 | node.default['java']['jdk_version'] = '8' 16 | node.default['java']['set_etc_environment'] = true 17 | node.default['java']['oracle']['accept_oracle_download_terms'] = true 18 | 19 | include_recipe 'java::default' 20 | include_recipe 'jenkins::master' 21 | 22 | # Install some plugins needed, but not installed on jenkins2 by default 23 | node['jenkins_plugins'].each do |plugin| 24 | jenkins_plugin plugin[0] do 25 | version plugin[1] 26 | notifies :execute, 'jenkins_command[safe-restart]', :immediately 27 | end 28 | end 29 | 30 | jenkins_command 'safe-restart' do 31 | action :nothing 32 | end 33 | -------------------------------------------------------------------------------- /Scenario-401/cookbooks/jenkins-demo/templates/default/CollectFiles.xml.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -1 7 | 50 8 | -1 9 | -1 10 | 11 | false 12 | 13 | 14 | 15 | 16 | server_list 17 | 18 | <%= node['jenkins_mdm']['docker_daemon_ip'] %>:6022 19 | 20 | 21 | file_list 22 | 23 | /etc/hosts 24 | /opt/couchbase/etc/couchbase/static_config 25 | /opt/mdm/config/mdm.yml 26 | /opt/mdm/logs/mdm-initscript.log 27 | /opt/mdm/logs/mdm-app.log 28 | /opt/mdm/logs/mdm-app-audit.log 29 | /opt/mdm/logs/mdm-app-error.log 30 | /opt/mdm/logs/mdmbackup-initscript.log 31 | /etc/elasticsearch/elasticsearch.yml 32 | /var/log/elasticsearch/mdm.log 33 | /var/log/elasticsearch/mdm_index_indexing_slowlog.log 34 | /var/log/elasticsearch/mdm_deprecation.log 35 | /var/log/elasticsearch/mdm_index_search_slowlog.log 36 | 37 | 38 | env_parameters 39 | 40 | export jenkins_baseurl="http://192.168.50.10:18080" 41 | 42 | 43 | 44 | 45 | 46 | 47 | true 48 | false 49 | false 50 | false 51 | 52 | false 53 | 54 | 55 | #!/bin/bash -e 56 | export ssh_key_file="/var/lib/jenkins/ssh_id_rsa" 57 | bash -e /var/lib/jenkins/code/scripts/collect_files.sh 58 | 59 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /Scenario-401/cookbooks/jenkins-demo/test/integration/default/serverspec/server_spec.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | require 'serverspec' 4 | 5 | # Required by serverspec 6 | set :backend, :exec 7 | 8 | ############################################################################# 9 | # TODO: make the code more general 10 | require 'json' 11 | # chef_data = JSON.parse(IO.read('/tmp/kitchen/dna.json')) 12 | # buildrepo_dir = chef_data.fetch('jenkins_mdm').fetch('buildrepo_dir') 13 | 14 | describe command('java -version') do 15 | its(:stderr) { should contain 'java version \"1.8' } 16 | end 17 | 18 | %w[8080].each do |port| 19 | describe port(port) do 20 | it { should be_listening } 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /images/chef_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dennyzhang/challenges-chef/5e58a8153e7b98a3b9b7ad574591ac25b004267c/images/chef_icon.png -------------------------------------------------------------------------------- /images/scenario-101-screenshot.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dennyzhang/challenges-chef/5e58a8153e7b98a3b9b7ad574591ac25b004267c/images/scenario-101-screenshot.jpg -------------------------------------------------------------------------------- /images/scenario-102-screenshot.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dennyzhang/challenges-chef/5e58a8153e7b98a3b9b7ad574591ac25b004267c/images/scenario-102-screenshot.jpg -------------------------------------------------------------------------------- /images/scenario-103-design.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dennyzhang/challenges-chef/5e58a8153e7b98a3b9b7ad574591ac25b004267c/images/scenario-103-design.png -------------------------------------------------------------------------------- /images/scenario-201-design.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dennyzhang/challenges-chef/5e58a8153e7b98a3b9b7ad574591ac25b004267c/images/scenario-201-design.png -------------------------------------------------------------------------------- /images/scenario-202-design.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dennyzhang/challenges-chef/5e58a8153e7b98a3b9b7ad574591ac25b004267c/images/scenario-202-design.png -------------------------------------------------------------------------------- /images/scenario-401-design.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dennyzhang/challenges-chef/5e58a8153e7b98a3b9b7ad574591ac25b004267c/images/scenario-401-design.png --------------------------------------------------------------------------------