cronicle 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: ce9c4a8eff04541e0649bf02eb6e096774d2d42b
4
+ data.tar.gz: 0833f3ca301c909805d70910e08491de147f4507
5
+ SHA512:
6
+ metadata.gz: 2237ab42e1da6822a540b0a806a67da32155288aeb9a6fdb345ec85baf6b66e137b9b95745898166e9446405e07dbb4dcad3604929ad00e4042978e68282f180
7
+ data.tar.gz: c48de4d137fcb1030b8fede56e6189b439d58cd788c12a4ad70be84e31594dd7bb2c8dce361e1985245fcc778701894ae4562fbe18e0e3641a72dbfeb146062a
data/.gitignore ADDED
@@ -0,0 +1,19 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
15
+ test.rb
16
+ Jobfile
17
+ /.vagrant
18
+ *.pem
19
+ *.bak
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --colour
2
+ --require spec_helper
data/.travis.yml ADDED
@@ -0,0 +1,22 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.0.0
4
+ before_install:
5
+ - openssl aes-256-cbc -K $encrypted_3e901e83a832_key -iv $encrypted_3e901e83a832_iv
6
+ -in cronicle.us-east-1.pem.enc -out cronicle.us-east-1.pem -d
7
+ install:
8
+ - wget https://dl.bintray.com/mitchellh/vagrant/vagrant_1.7.2_x86_64.deb
9
+ - sudo dpkg -i vagrant_1.7.2_x86_64.deb
10
+ before_script:
11
+ - vagrant plugin install vagrant-aws
12
+ - vagrant up --provider=aws
13
+ script:
14
+ - bundle install
15
+ - bundle exec rake
16
+ after_script:
17
+ - vagrant destroy -f
18
+ env:
19
+ global:
20
+ - secure: CdUw5RJ8GXVCD5Orr+hP7tscfE1rNFyz2bnIqWj8jLCnxcLY7TqcV9v1z130uuU+keAyzAFIOPu1GHrr83Sgyo2MIwQkYfA52K1gB5ThzZXZQDSvGKJk3mtfvRkxJVmUxeCEZVC9QXKqR5WW15Cj7wBG4Y6dClty3zwyH7MtPI8=
21
+ - secure: gR/fjFSW81OtcnI8lQREfwj/EeW0YOsXOTUpZCPRdWaaIKGYmjB+6H+KgPcw1nGy+kknb5HXyOTLTSKOngC6WW1EaeKYzKqKGn8xlFGpFMmLCVXyDJG85ABr8jC768AltbYPYuUYb0JgX2PEMH1NNbCVaQqh8oUlBOjMrMqCbzk=
22
+ - EC2_KEYPAIR_NAME=cronicle.us-east-1
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in cronicle.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 Genki Sugawara
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,127 @@
1
+ # Cronicle
2
+
3
+ It is a tool for execute script, and define cron on remote hosts.
4
+
5
+ [![Gem Version](https://badge.fury.io/rb/cronicle.svg)](http://badge.fury.io/rb/cronicle)
6
+ [![Build Status](https://travis-ci.org/winebarrel/cronicle.svg?branch=master)](https://travis-ci.org/winebarrel/cronicle)
7
+
8
+ ## Installation
9
+
10
+ Add this line to your application's Gemfile:
11
+
12
+ ```ruby
13
+ gem 'cronicle'
14
+ ```
15
+
16
+ And then execute:
17
+
18
+ $ bundle
19
+
20
+ Or install it yourself as:
21
+
22
+ $ gem install cronicle
23
+
24
+ ## Usage
25
+
26
+ ```
27
+ Commands:
28
+ cronicle apply # Apply cron jobs to remote hosts
29
+ cronicle exec JOB_NAME # Execute a job on remote hosts
30
+ cronicle help [COMMAND] # Describe available commands or one specific command
31
+
32
+ Options:
33
+ -f, [--file=FILE] # Job definition file
34
+ # Default: Jobfile
35
+ -h, [--hosts=HOSTS] # Hosts definition file
36
+ -r, [--target-roles=one two three] # Target host role list
37
+ -p, [--sudo-password=SUDO-PASSWORD] # Sudo password
38
+ [--dry-run], [--no-dry-run] # Do not actually change
39
+ -c, [--ssh-config=SSH-CONFIG] # OpenSSH configuration file
40
+ [--connection-timeout=N] # SSH connection timeout
41
+ [--concurrency=N] # SSH concurrency
42
+ # Default: 10
43
+ [--libexec=LIBEXEC] # Cronicle libexec path
44
+ # Default: /var/lib/cronicle/libexec
45
+ -v, [--verbose], [--no-verbose] # Verbose mode
46
+ [--debug], [--no-debug] # Debug mode
47
+ [--color], [--no-color] # Colorize log
48
+ # Default: true
49
+ ```
50
+
51
+ ## Quick Start
52
+
53
+ ```sh
54
+ $ cat Jobfile
55
+ on servers: :your_hostname do
56
+ job :my_job, user: "ec2-user", schedule: "* * * * *" do
57
+ puts "hello"
58
+ end
59
+ end
60
+
61
+ $ cronicle exec my_job
62
+ my_job on your_hostname/ec2-user> Execute job
63
+ my_job on your_hostname/ec2-user> hello
64
+
65
+ $ cronicle apply --dry-run
66
+ my_job on your_hostname/ec2-user> Create job: schedule="* * * * *" (dry-run)
67
+
68
+ $ cronicle apply
69
+ my_job on your_hostname/ec2-user> Create job: schedule="* * * * *"
70
+
71
+ $ ssh your_hostname 'crontab -l'
72
+ * * * * * /var/lib/cronicle/libexec/ec2-user/my_job 2>&1 | logger -t cronicle/ec2-user/my_job
73
+
74
+ $ ssh your_hostname 'cat /var/lib/cronicle/libexec/ec2-user/my_job'
75
+ #!/usr/bin/env ruby
76
+ puts "hello"
77
+ ```
78
+
79
+ ## Hosts definition file
80
+
81
+ Any of the following formats:
82
+
83
+ ```
84
+ server1,server2,...
85
+ ```
86
+ ```
87
+ server1
88
+ server2
89
+ ...
90
+ ```
91
+ ```javascript
92
+ {
93
+ "servers": {
94
+ "server1": ["web", "app"]
95
+ "server2": ["db"]
96
+ }
97
+ }
98
+ ```
99
+ ```javascript
100
+ {
101
+ "roles": {
102
+ "web": ["server1"],
103
+ "app": ["server1"],
104
+ "db": ["server2"]
105
+ }
106
+ }
107
+ ```
108
+
109
+ Hosts definition file is not required.
110
+
111
+ If you pass `--hosts` options, can be defined as follows in Jobfile:
112
+
113
+ ```ruby
114
+ on servers: /any_host/ do # use regexp
115
+ job :foo, user: "ec2-user", schedule: "* * * * *" do
116
+ 3.times do
117
+ puts "hello"
118
+ end
119
+ end
120
+ end
121
+
122
+ on roles: "web" do # use role
123
+ job :my_job, user: "ec2-user", schedule: "* * * * *" do
124
+ puts "hello"
125
+ end
126
+ end
127
+ ```
data/Rakefile ADDED
@@ -0,0 +1,5 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new('spec')
5
+ task :default => :spec
data/Vagrantfile ADDED
@@ -0,0 +1,56 @@
1
+ # -*- mode: ruby -*-
2
+ # vi: set ft=ruby :
3
+ VAGRANTFILE_API_VERSION = "2"
4
+
5
+ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
6
+ config.vm.box = "dummy"
7
+ config.vm.box_url = "https://github.com/mitchellh/vagrant-aws/raw/master/dummy.box"
8
+
9
+ config.vm.synced_folder ".", "/vagrant", disabled: true
10
+
11
+ config.vm.define :amazon_linux do |machine|
12
+ machine.vm.provider :aws do |aws, override|
13
+ aws.access_key_id = ENV["AWS_ACCESS_KEY_ID"]
14
+ aws.secret_access_key = ENV["AWS_SECRET_ACCESS_KEY"]
15
+ aws.keypair_name = ENV["EC2_KEYPAIR_NAME"]
16
+ aws.instance_type = "m1.large"
17
+ aws.region = ENV["AWS_REGION"] || 'us-east-1'
18
+ aws.terminate_on_shutdown = true
19
+ aws.ami = ENV["AMAZON_LINUX_AMI"] || "ami-8e682ce6"
20
+
21
+ override.ssh.username = "ec2-user"
22
+ override.ssh.private_key_path = ENV["EC2_PRIVATE_KEY_PATH"] || ENV["EC2_KEYPAIR_NAME"] + ".pem"
23
+ override.ssh.pty = true
24
+
25
+ override.vm.provision "shell", inline: <<-SH
26
+ echo cronicle | passwd --stdin ec2-user
27
+ echo 'ec2-user ALL=(ALL) ALL' > /etc/sudoers.d/cloud-init
28
+ SH
29
+
30
+ override.vm.boot_timeout = 180
31
+ end
32
+ end
33
+
34
+ config.vm.define :ubuntu do |machine|
35
+ machine.vm.provider :aws do |aws, override|
36
+ aws.access_key_id = ENV["AWS_ACCESS_KEY_ID"]
37
+ aws.secret_access_key = ENV["AWS_SECRET_ACCESS_KEY"]
38
+ aws.keypair_name = ENV["EC2_KEYPAIR_NAME"]
39
+ aws.instance_type = "m1.large"
40
+ aws.region = ENV["AWS_REGION"] || 'us-east-1'
41
+ aws.terminate_on_shutdown = true
42
+ aws.ami = ENV['UBUNTU_AMI'] || "ami-84562dec"
43
+
44
+ override.ssh.username = "ubuntu"
45
+ override.ssh.private_key_path = ENV["EC2_PRIVATE_KEY_PATH"] || ENV["EC2_KEYPAIR_NAME"] + ".pem"
46
+ override.ssh.pty = true
47
+
48
+ override.vm.provision "shell", inline: <<-SH
49
+ echo ubuntu:cronicle | chpasswd
50
+ echo 'ubuntu ALL=(ALL) ALL' > /etc/sudoers.d/90-cloud-init-users
51
+ SH
52
+
53
+ override.vm.boot_timeout = 180
54
+ end
55
+ end
56
+ end
data/bin/cronicle ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ $: << File.expand_path("#{File.dirname __FILE__}/../lib")
3
+ require 'rubygems'
4
+ require 'cronicle'
5
+
6
+ Cronicle::CLI.start(ARGV)
data/cronicle.gemspec ADDED
@@ -0,0 +1,31 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'cronicle/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'cronicle'
8
+ spec.version = Cronicle::VERSION
9
+ spec.authors = ['Genki Sugawara']
10
+ spec.email = ['sgwr_dts@yahoo.co.jp']
11
+ spec.summary = %q{It is a tool for execute script, and define cron on remote hosts.}
12
+ spec.description = %q{It is a tool for execute script, and define cron on remote hosts.}
13
+ spec.homepage = 'https://github.com/winebarrel/cronicle'
14
+ spec.license = 'MIT'
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ['lib']
20
+
21
+ spec.add_dependency 'sourcify', '~> 0.6.0.rc4'
22
+ spec.add_dependency 'sshkit', '~> 1.6.1'
23
+ spec.add_dependency 'thor'
24
+ spec.add_dependency 'colorize'
25
+ spec.add_dependency 'parallel'
26
+ spec.add_dependency 'diffy'
27
+ spec.add_development_dependency 'bundler'
28
+ spec.add_development_dependency 'rake'
29
+ spec.add_development_dependency 'rspec', '>= 3.0.0'
30
+ spec.add_development_dependency 'serverspec'
31
+ end
Binary file
data/lib/cronicle.rb ADDED
@@ -0,0 +1,28 @@
1
+ require 'colorize'
2
+ require 'diffy'
3
+ require 'json'
4
+ require 'parallel'
5
+ require 'set'
6
+ require 'shellwords'
7
+ require 'singleton'
8
+ require 'sourcify'
9
+ require 'sshkit'
10
+ require 'sshkit/dsl'
11
+ require 'tempfile'
12
+ require 'thor'
13
+
14
+ module Cronicle; end
15
+ require 'cronicle/ext/hash_ext'
16
+ require 'cronicle/ext/string_ext'
17
+ require 'cronicle/ext/sshkit_ext'
18
+ require 'cronicle/logger'
19
+ require 'cronicle/utils'
20
+ require 'cronicle/client'
21
+ require 'cronicle/cli'
22
+ require 'cronicle/driver'
23
+ require 'cronicle/dsl'
24
+ require 'cronicle/dsl/context'
25
+ require 'cronicle/dsl/context/job'
26
+ require 'cronicle/exporter'
27
+ require 'cronicle/host_list'
28
+ require 'cronicle/version'
@@ -0,0 +1,105 @@
1
+ class Cronicle::CLI < Thor
2
+ include Cronicle::Logger::Helper
3
+
4
+ class_option 'file', :aliases => '-f', :desc => 'Job definition file', :default => 'Jobfile'
5
+ class_option 'hosts', :aliases => '-h', :desc => 'Hosts definition file'
6
+ class_option 'target-roles', :aliases => '-r', :desc => 'Target host role list', :type => :array
7
+ class_option 'sudo-password', :aliases => '-p', :desc => 'Sudo password'
8
+ class_option 'dry-run', :desc => 'Do not actually change', :type => :boolean, :default => false
9
+ class_option 'ssh-config', :aliases => '-c', :desc => 'OpenSSH configuration file', :default => nil
10
+ class_option 'connection-timeout', :desc => 'SSH connection timeout', :type => :numeric, :default => nil
11
+ class_option 'concurrency', :desc => 'SSH concurrency', :type => :numeric, :default => Cronicle::Client::DEFAULTS[:concurrency]
12
+ class_option 'libexec', :desc => 'Cronicle libexec path', :default => Cronicle::Client::DEFAULTS[:libexec]
13
+ class_option 'verbose', :aliases => '-v', :desc => 'Verbose mode', :type => :boolean, :default => false
14
+ class_option 'debug', :desc => 'Debug mode', :type => :boolean, :default => false
15
+ class_option 'color', :desc => 'Colorize log', :type => :boolean, :default => true
16
+
17
+ def initialize(*args)
18
+ super
19
+
20
+ if options['debug']
21
+ Cronicle::Logger.instance.set_debug(true)
22
+ end
23
+
24
+ if not $stdin.tty? or not options['color']
25
+ String.disable_colorization = true
26
+ end
27
+ end
28
+
29
+ desc 'exec JOB_NAME', 'Execute a job on remote hosts'
30
+ def exec(job_name)
31
+ with_logging do
32
+ set_ssh_options
33
+ client.exec(jobfile, job_name)
34
+ end
35
+ end
36
+
37
+ desc 'apply', 'Apply cron jobs to remote hosts'
38
+ def apply
39
+ with_logging do
40
+ set_ssh_options
41
+ client.apply(jobfile)
42
+ end
43
+ end
44
+
45
+ private
46
+
47
+ def with_logging
48
+ begin
49
+ yield
50
+ rescue => e
51
+ if options['debug']
52
+ raise e
53
+ else
54
+ log(:error, e.message, :color => :red)
55
+ end
56
+ end
57
+ end
58
+
59
+ def client
60
+ Cronicle::Client.new(host_list, client_options)
61
+ end
62
+
63
+ def jobfile
64
+ file = options['file']
65
+
66
+ unless File.exist?(file)
67
+ raise Thor::Error, "No Jobfile found (looking for: #{file})"
68
+ end
69
+
70
+ file
71
+ end
72
+
73
+ def host_list
74
+ Cronicle::HostList.new(
75
+ options.fetch('hosts', ''),
76
+ host_list_options
77
+ )
78
+ end
79
+
80
+ def client_options
81
+ {
82
+ :sudo_password => options['sudo-password'],
83
+ :concurrency => options['concurrency'],
84
+ :libexec => options['libexec'],
85
+ :dry_run => options['dry-run'],
86
+ :verbose => options['verbose']
87
+ }
88
+ end
89
+
90
+ def host_list_options
91
+ {
92
+ :roles => options['target-roles']
93
+ }
94
+ end
95
+
96
+ def set_ssh_options
97
+ conn_timeout = options['connection-timeout']
98
+ ssh_config = options['ssh-config']
99
+
100
+ SSHKit::Backend::Netssh.configure do |ssh|
101
+ ssh.connection_timeout = conn_timeout if conn_timeout
102
+ ssh.ssh_options = {:config => ssh_config} if ssh_config
103
+ end
104
+ end
105
+ end