consul_kv_backup 0.0.1

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
+ SHA256:
3
+ metadata.gz: 13b187d68d4ff6d1592949f06a38ff5cbb996005799ffb522759f66a4539d26e
4
+ data.tar.gz: aa9d14e725256b181d6d70c59718c4dda0c578f3e15faf1b17322ae395b7a89d
5
+ SHA512:
6
+ metadata.gz: 239168aeaf537e277db14aa982bc4caf18fb07b95014c0001fd0fdec6ba725fc4951f3a48e1945fea3bffc9cba4e176f10160dafa50b2b9a208a1153aed3411c
7
+ data.tar.gz: 64d05b93d3d0fc99eb52f0c87f0d6b2c11179fe900f40bf4a995bf2b1d1c0e5fd1c479c32787d7376e91ae521ca8ef0aca5479ca7df1a5f410662eb2d7bb990d
data/.gitignore ADDED
@@ -0,0 +1,10 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ .vscode
data/Dockerfile ADDED
@@ -0,0 +1,13 @@
1
+ FROM consul:1.4.0
2
+
3
+ ARG gem_file
4
+
5
+ RUN apk add --no-cache jq build-base libc-dev linux-headers postgresql-dev libxml2-dev libxslt-dev ruby ruby-dev ruby-rdoc ruby-irb git openssh-client
6
+
7
+ COPY ./docker-entrypoint.sh /
8
+ COPY pkg/$gem_file /consul_kv_backup/
9
+
10
+ RUN cd /consul_kv_backup ; \
11
+ gem install $gem_file
12
+
13
+ ENTRYPOINT ["/docker-entrypoint.sh"]
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ source "https://rubygems.org"
2
+
3
+ repo_name = '/fortman/consul_kv_backup'
4
+
5
+ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
6
+
7
+ # Specify your gem's dependencies in consul_kv_backup.gemspec
8
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2019 Ryan Fortman
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,2 @@
1
+ # consul_kv_backup
2
+ Backup changes in consul kv storge to a git repository. Relies on the https://github.com/fortman/consul_watcher project.
data/Rakefile ADDED
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'open3'
5
+ require 'flazm_ruby_helpers/os'
6
+ require 'flazm_ruby_helpers/http'
7
+ require 'flazm_ruby_helpers/project'
8
+
9
+ spec_file = Gem::Specification.load('consul_kv_backup.gemspec')
10
+
11
+ task default: :docker_build
12
+
13
+ task :docker_tag, [:version, :docker_image_id] do |_task, args|
14
+ puts "Docker id #{args['docker_image_id']} => tag rfortman/consul_kv_backup:#{args['version']}"
15
+ tag_cmd = "docker tag #{args['docker_image_id']} rfortman/consul_kv_backup:#{args['version']}"
16
+ Open3.popen3(tag_cmd) do |_stdin, _stdout, stderr, wait_thr|
17
+ error = stderr.read
18
+ puts error unless wait_thr.value.success?
19
+ end
20
+ end
21
+
22
+ task docker_build: [:build] do
23
+ docker_image_id = nil
24
+ build_cmd = "docker build --build-arg gem_file=consul_kv_backup-#{spec_file.version}.gem ."
25
+ threads = []
26
+ Open3.popen3(build_cmd) do |_stdin, stdout, stderr, wait_thr|
27
+ { out: stdout, err: stderr }.each do |key, stream|
28
+ threads << Thread.new do
29
+ until (raw_line = stream.gets).nil?
30
+ match = raw_line.match(/Successfully built (.*)$/i)
31
+ docker_image_id = match.captures[0] if match
32
+ puts raw_line.to_s
33
+ end
34
+ end
35
+ end
36
+ threads.each(&:join)
37
+ if wait_thr.value.success?
38
+ Rake::Task['docker_tag'].invoke(spec_file.version, docker_image_id)
39
+ Rake::Task['docker_tag'].reenable
40
+ Rake::Task['docker_tag'].invoke('latest', docker_image_id)
41
+ end
42
+ end
43
+ end
44
+
45
+ task :start_deps do
46
+ cmd = 'docker-compose --file test/docker-compose.yml up -d consul rabbitmq'
47
+ FlazmRubyHelpers::Os.exec(cmd)
48
+ urls = [
49
+ 'http://localhost:8500/v1/status/leader',
50
+ 'http://localhost:15672'
51
+ ]
52
+ FlazmRubyHelpers::Http.wait_for_urls(urls)
53
+ cmd = 'docker-compose --file test/docker-compose.yml up -d consul-kv-watcher'
54
+ FlazmRubyHelpers::Os.exec(cmd)
55
+ end
56
+
57
+ task up: [:start_deps] do
58
+ cmd = 'docker-compose --file test/docker-compose.yml up consul-kv-backup'
59
+ _output, _status = FlazmRubyHelpers::Os.exec(cmd)
60
+ end
61
+
62
+ task :down do
63
+ cmd = 'docker-compose --file test/docker-compose.yml down'
64
+ _output, _status = FlazmRubyHelpers::Os.exec(cmd)
65
+ end
66
+
67
+ task publish: [:build, :docker_build] do
68
+ #FlazmRubyHelpers::Project::Git.publish(spec_file.version.to_s, 'origin', 'master')
69
+ FlazmRubyHelpers::Project::Docker.publish(spec_file.metadata['docker_image_name'], spec_file.version.to_s)
70
+ FlazmRubyHelpers::Project::Docker.publish(spec_file.metadata['docker_image_name'], 'latest')
71
+ FlazmRubyHelpers::Project::Gem.publish(spec_file.name.to_s, spec_file.version.to_s)
72
+ end
73
+
74
+ task :unpublish do
75
+ _output, _success = FlazmRubyHelpers::Os.exec("git tag --delete #{spec_file.version.to_s}")
76
+ _output, _success = FlazmRubyHelpers::Os.exec("gem yank #{spec_file.name.to_s} -v #{spec_file.version.to_s}")
77
+ puts "Please delete the tag from dockerhub at https://cloud.docker.com/repository/registry-1.docker.io/#{spec_file.metadata['docker_image_name']}/tags"
78
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.1
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path('lib', '..')
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'consul_kv_backup'
8
+ spec.version = IO.read('VERSION').chomp
9
+ spec.authors = ['Ryan Fortman']
10
+ spec.email = ['r.fortman.dev@gmail.com']
11
+
12
+ spec.summary = 'Send consul watch events to an amqp.'
13
+ spec.homepage = 'https://github.com/fortman/consul_kv_backup'
14
+ spec.metadata = {
15
+ 'docker_image_name' => 'rfortman/consul_kv_backup'
16
+ }
17
+
18
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
19
+ f.match(%r{^(test|spec|features)/})
20
+ end
21
+ spec.bindir = 'exe'
22
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
23
+ spec.require_paths = ['lib']
24
+
25
+ spec.add_development_dependency 'bundler', '~> 2.0'
26
+ spec.add_development_dependency 'rake', '~> 10.0'
27
+ # spec.add_runtime_dependency 'bundler', '~> 2.0'
28
+ spec.add_runtime_dependency 'diplomat', '~> 2.2.4'
29
+ spec.add_dependency 'bunny', '~> 1.7.0'
30
+ spec.add_dependency 'slop', '~> 4.6'
31
+ spec.add_dependency 'flazm_ruby_helpers', '~> 0.0.3'
32
+ end
@@ -0,0 +1,10 @@
1
+ #!/bin/sh
2
+
3
+ echo
4
+ echo "CLI_ARGS: \"${@}\""
5
+ if [[ ${#} != 0 ]]; then
6
+ exec $@
7
+ else
8
+ mkdir -p /repo ; cd /repo ; /usr/bin/consul_kv_backup --config-file /etc/consul_kv_backup/config.json
9
+ echo
10
+ fi
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # frozen_string_literal: true
4
+
5
+ require 'slop'
6
+ require 'logger'
7
+ require 'json'
8
+ require 'consul_kv_backup'
9
+
10
+ logger = Logger.new(STDOUT)
11
+
12
+ opts = Slop.parse do |o|
13
+ o.string '--config-file', required: true
14
+ o.on '-h', '--help', 'print help' do
15
+ logger.warn("\n#{o}")
16
+ exit(false)
17
+ end
18
+ end
19
+
20
+ config = JSON.parse(File.read(opts['config-file']))
21
+
22
+ ConsulKvBackup.start(config)
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'consul_kv_backup/consul'
4
+ require 'consul_kv_backup/amqp'
5
+ require 'consul_kv_backup/git'
6
+
7
+ module ConsulKvBackup
8
+ def self.start(config)
9
+ assemble(config)
10
+ @amqp.consul = @consul
11
+ @amqp.git = @git
12
+ @amqp.consume
13
+ end
14
+
15
+ def self.assemble(config)
16
+ @consul = ConsulKvBackup::Consul.new(config['consul'])
17
+ @amqp = ConsulKvBackup::Amqp.new(config['amqp'])
18
+ @git = ConsulKvBackup::Git.new(config['git'])
19
+ end
20
+ end
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bunny'
4
+ require 'flazm_ruby_helpers/class'
5
+ require 'json'
6
+
7
+ module ConsulKvBackup
8
+ # Send diff output to jq command line
9
+ class Amqp
10
+ include FlazmRubyHelpers::Class
11
+
12
+ attr_accessor :consul, :git
13
+ def initialize(amqp_config)
14
+ initialize_variables(amqp_config)
15
+ setup_connection
16
+ end
17
+
18
+ def setup_connection
19
+ @conn = Bunny.new(amqp_opts)
20
+ @conn.start
21
+ @ch = @conn.create_channel
22
+ @ex = Bunny::Exchange.new(@ch,
23
+ :topic,
24
+ @amqp_exchange,
25
+ durable: true)
26
+ @queue = @ch.queue(@amqp_queue, durable: true).bind(@ex, routing_key: @amqp_routing_key)
27
+ end
28
+
29
+ def consume
30
+ @consumer ||= @queue.subscribe(block: true, &itself.method(:process_message))
31
+ nil
32
+ end
33
+
34
+ private
35
+
36
+ def process_message(delivery_info, properties, body)
37
+ data = JSON.parse(body)
38
+ data['value'] = @consul.consul_key(data['key_path']) if data['new_value']
39
+
40
+ @git.process_data(data)
41
+ end
42
+
43
+ def amqp_opts
44
+ opts = {}
45
+ opts[:vhost] = @amqp_vhost
46
+ opts[:username] = @amqp_username
47
+ opts[:password] = @amqp_password
48
+ if @amqp_addresses
49
+ opts[:addresses] = @amqp_addresses
50
+ elsif @amqp_hosts
51
+ opts[:hosts] = @amqp_hosts
52
+ opts[:port] = @amqp_port if @rabbitmq_port
53
+ elsif @amqp_host
54
+ opts[:host] = @amqp_host
55
+ opts[:port] = @amqp_port if @rabbitmq_port
56
+ end
57
+ opts
58
+ end
59
+
60
+ def defaults
61
+ logger = Logger.new(STDOUT)
62
+ logger.level = Logger::DEBUG
63
+ {
64
+ logger: logger,
65
+ amqp_host: 'localhost',
66
+ amqp_hosts: nil,
67
+ amqp_addresses: nil,
68
+ amqp_port: nil,
69
+ amqp_vhost: '/',
70
+ amqp_username: 'guest',
71
+ amqp_password: 'guest',
72
+ amqp_queue: nil,
73
+ amqp_exchange: "amq.topic",
74
+ amqp_routing_key: 'consul_watcher.key.#'
75
+ }
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'flazm_ruby_helpers/class'
4
+ require 'diplomat'
5
+
6
+ module ConsulKvBackup
7
+ # Consul storage for previous watch data
8
+ class Consul
9
+ include FlazmRubyHelpers::Class
10
+
11
+ def initialize(consul_config)
12
+ initialize_variables(consul_config)
13
+ setup_connection
14
+ end
15
+
16
+ def consul_key(key_path)
17
+ Diplomat::Kv.get(key_path)
18
+ end
19
+
20
+ private
21
+
22
+ def setup_connection
23
+ Diplomat.configure do |config|
24
+ # Set up a custom Consul URL
25
+ config.url = @consul_http_addr
26
+ # Set extra Faraday configuration options and custom access token (ACL)
27
+ config.options = {headers: {"X-Consul-Token" => @consul_token}}
28
+ end
29
+ end
30
+
31
+ def defaults
32
+ logger = Logger.new(STDOUT)
33
+ logger.level = Logger::WARN
34
+ {
35
+ logger: logger,
36
+ consul_http_addr: 'http://localhost:8500',
37
+ consul_token: nil,
38
+ }
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,97 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'flazm_ruby_helpers/class'
4
+ require 'flazm_ruby_helpers/os'
5
+ require 'fileutils'
6
+
7
+ module ConsulKvBackup
8
+ # Consul storage for previous watch data
9
+ class Git
10
+ include FlazmRubyHelpers::Class
11
+
12
+ def initialize(git_config)
13
+ initialize_variables(git_config)
14
+ git_setup
15
+ end
16
+
17
+ def process_data(data)
18
+ path = data['key_path']
19
+ value = data['value']
20
+ dc = data['consul_dc']
21
+
22
+ git_set_branch(dc)
23
+
24
+ if data['old_value'] and !data['new_value']
25
+ git_rm(path)
26
+ else
27
+ git_add(path, value)
28
+ end
29
+
30
+ # git_push if @git['push']
31
+ end
32
+
33
+ private
34
+
35
+ def git_setup
36
+ FileUtils.mkdir_p(@git_root_dir) unless File.directory?(@git_root_dir)
37
+ FlazmRubyHelpers::Os.exec("git config --global core.sshCommand '#{@git_config['core.sshCommand']}'")
38
+ unless File.directory?("#{@git_root_dir}/.git")
39
+ FlazmRubyHelpers::Os.exec("git clone #{@git_config['remote.origin.url']} .")
40
+ end
41
+ @git_config.each_pair do |key, value|
42
+ FlazmRubyHelpers::Os.exec("git config --local #{key} '#{value}'")
43
+ end
44
+ if FlazmRubyHelpers::Os.exec("git count-objects")[0][0].match(/0 objects, 0 kilobytes/)
45
+ FlazmRubyHelpers::Os.exec("git commit --allow-empty -m 'Initial commit'")
46
+ end
47
+ end
48
+
49
+ def git_set_branch(branch = 'master')
50
+ exist = git_branch_exists?(branch)
51
+ if exist
52
+ FlazmRubyHelpers::Os.exec("git reset --hard HEAD")
53
+ FlazmRubyHelpers::Os.exec("git checkout #{branch}")
54
+ else
55
+ FlazmRubyHelpers::Os.exec("git fetch")
56
+ FlazmRubyHelpers::Os.exec("git branch #{branch} master")
57
+ FlazmRubyHelpers::Os.exec("git checkout #{branch}")
58
+ end
59
+ end
60
+
61
+ def git_branch_exists?(branch)
62
+ FlazmRubyHelpers::Os.exec("git branch --list")[0].each do |line|
63
+ return true if line.match(/#{branch}/)
64
+ end
65
+ false
66
+ end
67
+
68
+ def git_add(path, value)
69
+ file = File.open(path, 'w')
70
+ file.write(value)
71
+ file.close
72
+ FlazmRubyHelpers::Os.exec('git add --all')
73
+ FlazmRubyHelpers::Os.exec('git commit -m "automated backup: updating"')
74
+ end
75
+
76
+ def git_rm(path)
77
+ FlazmRubyHelpers::Os.exec("git rm #{path}")
78
+ FlazmRubyHelpers::Os.exec('git commit -m "automated backup: deleting"')
79
+ end
80
+
81
+ def git_rebase
82
+ FlazmRubyHelpers::Os.exec('git fetch')
83
+ FlazmRubyHelpers::Os.exec('git reset origin/master')
84
+ end
85
+
86
+ def git_push
87
+ FlazmRubyHelpers::Os.exec('git push')
88
+ end
89
+
90
+ def defaults
91
+ {
92
+ git_root_dir: '/tmp/consul_backup',
93
+ git_config: {}
94
+ }
95
+ end
96
+ end
97
+ end
metadata ADDED
@@ -0,0 +1,143 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: consul_kv_backup
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Ryan Fortman
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2019-06-14 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: diplomat
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 2.2.4
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 2.2.4
55
+ - !ruby/object:Gem::Dependency
56
+ name: bunny
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 1.7.0
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 1.7.0
69
+ - !ruby/object:Gem::Dependency
70
+ name: slop
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '4.6'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '4.6'
83
+ - !ruby/object:Gem::Dependency
84
+ name: flazm_ruby_helpers
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: 0.0.3
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: 0.0.3
97
+ description:
98
+ email:
99
+ - r.fortman.dev@gmail.com
100
+ executables:
101
+ - consul_kv_backup
102
+ extensions: []
103
+ extra_rdoc_files: []
104
+ files:
105
+ - ".gitignore"
106
+ - Dockerfile
107
+ - Gemfile
108
+ - LICENSE
109
+ - README.md
110
+ - Rakefile
111
+ - VERSION
112
+ - consul_kv_backup.gemspec
113
+ - docker-entrypoint.sh
114
+ - exe/consul_kv_backup
115
+ - lib/consul_kv_backup.rb
116
+ - lib/consul_kv_backup/amqp.rb
117
+ - lib/consul_kv_backup/consul.rb
118
+ - lib/consul_kv_backup/git.rb
119
+ homepage: https://github.com/fortman/consul_kv_backup
120
+ licenses: []
121
+ metadata:
122
+ docker_image_name: rfortman/consul_kv_backup
123
+ post_install_message:
124
+ rdoc_options: []
125
+ require_paths:
126
+ - lib
127
+ required_ruby_version: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ required_rubygems_version: !ruby/object:Gem::Requirement
133
+ requirements:
134
+ - - ">="
135
+ - !ruby/object:Gem::Version
136
+ version: '0'
137
+ requirements: []
138
+ rubyforge_project:
139
+ rubygems_version: 2.7.8
140
+ signing_key:
141
+ specification_version: 4
142
+ summary: Send consul watch events to an amqp.
143
+ test_files: []