cronicle 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +19 -0
- data/.rspec +2 -0
- data/.travis.yml +22 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +127 -0
- data/Rakefile +5 -0
- data/Vagrantfile +56 -0
- data/bin/cronicle +6 -0
- data/cronicle.gemspec +31 -0
- data/cronicle.us-east-1.pem.enc +0 -0
- data/lib/cronicle.rb +28 -0
- data/lib/cronicle/cli.rb +105 -0
- data/lib/cronicle/client.rb +161 -0
- data/lib/cronicle/driver.rb +157 -0
- data/lib/cronicle/dsl.rb +7 -0
- data/lib/cronicle/dsl/context.rb +48 -0
- data/lib/cronicle/dsl/context/job.rb +58 -0
- data/lib/cronicle/exporter.rb +56 -0
- data/lib/cronicle/ext/hash_ext.rb +8 -0
- data/lib/cronicle/ext/sshkit_ext.rb +147 -0
- data/lib/cronicle/ext/string_ext.rb +11 -0
- data/lib/cronicle/host_list.rb +89 -0
- data/lib/cronicle/logger.rb +92 -0
- data/lib/cronicle/utils.rb +43 -0
- data/lib/cronicle/version.rb +3 -0
- data/spec/cronicle_create_spec.rb +295 -0
- data/spec/cronicle_delete_spec.rb +334 -0
- data/spec/cronicle_exec_spec.rb +159 -0
- data/spec/cronicle_update_spec.rb +365 -0
- data/spec/host_list_spec.rb +162 -0
- data/spec/spec_helper.rb +150 -0
- metadata +223 -0
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
data/.rspec
ADDED
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
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
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
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'
|
data/lib/cronicle/cli.rb
ADDED
@@ -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
|