cronicle 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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