fluent-plugin-cloudstack 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
+ SHA1:
3
+ metadata.gz: 2c162238913dc3df257fced1b4511542da70bcc8
4
+ data.tar.gz: ff71b4d47e21628a944fc89626ff2c2d069a7467
5
+ SHA512:
6
+ metadata.gz: 5e73c124caa441d3453bf58143d466bae661dcc906c721d0ab8b4ad1b0547300db7c57e72a654876532b2a3e86ced2c2b0979c0094ca2f35d58456376fb2614a
7
+ data.tar.gz: c31c87c1f4d276742f9de37d67df857f6a9642188f8079f1b9622cf516227c77e4a50baacbcd6af8dd7eec5acb9c88394184ffc261e1a82ad6bb14a61ee641c0
data/.gitignore ADDED
@@ -0,0 +1,20 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ coverage
6
+ InstalledFiles
7
+ lib/bundler/man
8
+ pkg
9
+ rdoc
10
+ spec/reports
11
+ test/tmp
12
+ test/version_tmp
13
+ tmp
14
+
15
+ # YARD artifacts
16
+ .yardoc
17
+ _yardoc
18
+ doc/
19
+ vendor/*
20
+ *.swp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
data/Gemfile.lock ADDED
@@ -0,0 +1,57 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ fluent-plugin-cloudstack (0.0.1)
5
+ eventmachine
6
+ fluentd (>= 0.10.7)
7
+ fog
8
+
9
+ GEM
10
+ remote: https://rubygems.org/
11
+ specs:
12
+ builder (3.2.2)
13
+ cool.io (1.1.1)
14
+ iobuffer (>= 1.0.0)
15
+ eventmachine (1.0.3)
16
+ excon (0.27.6)
17
+ fluentd (0.10.39)
18
+ cool.io (~> 1.1.1)
19
+ http_parser.rb (~> 0.5.1)
20
+ json (>= 1.4.3)
21
+ msgpack (>= 0.4.4, < 0.6.0, != 0.5.3, != 0.5.2, != 0.5.1, != 0.5.0)
22
+ yajl-ruby (~> 1.0)
23
+ fog (1.16.0)
24
+ builder
25
+ excon (~> 0.27.0)
26
+ formatador (~> 0.2.0)
27
+ mime-types
28
+ multi_json (~> 1.0)
29
+ net-scp (~> 1.1)
30
+ net-ssh (>= 2.1.3)
31
+ nokogiri (~> 1.5)
32
+ ruby-hmac
33
+ unicode (~> 0.4.4)
34
+ formatador (0.2.4)
35
+ http_parser.rb (0.5.3)
36
+ iobuffer (1.1.2)
37
+ json (1.8.1)
38
+ mime-types (1.25)
39
+ mini_portile (0.5.2)
40
+ msgpack (0.5.6)
41
+ multi_json (1.8.2)
42
+ net-scp (1.1.2)
43
+ net-ssh (>= 2.6.5)
44
+ net-ssh (2.7.0)
45
+ nokogiri (1.6.0)
46
+ mini_portile (~> 0.5.0)
47
+ rake (10.1.0)
48
+ ruby-hmac (0.4.0)
49
+ unicode (0.4.4)
50
+ yajl-ruby (1.1.0)
51
+
52
+ PLATFORMS
53
+ ruby
54
+
55
+ DEPENDENCIES
56
+ fluent-plugin-cloudstack!
57
+ rake
data/README.textile ADDED
@@ -0,0 +1,83 @@
1
+ h1. Fluent::Plugin::CloudStack
2
+
3
+ Fluentd input plugin to get usages and events from CloudStack API.
4
+
5
+ * usages
6
+ ** instance_usage
7
+ ** memory_usage
8
+ ** root_volume_usage
9
+ ** data_volume_usage
10
+ ** usages_per_service_offering
11
+ ** usages_per_disk_offering
12
+ * event
13
+
14
+
15
+ h2. Installation
16
+
17
+ Add this line to your application's Gemfile:
18
+
19
+ <pre>
20
+ gem 'fluent-plugin-cloudstack'
21
+ </pre>
22
+
23
+ Or install it yourself as:
24
+
25
+ <pre>
26
+ $ gem install fluent-plugin-cloudstack
27
+ </pre>
28
+
29
+ Or use td-agent : (on Ubuntu12.04)
30
+
31
+ <pre>
32
+ $ sudo /usr/lib/fluent/ruby/bin/fluent-gem install fluent-plugin-cloudstack
33
+ </pre>
34
+
35
+
36
+
37
+ h2. Configuration
38
+
39
+ <pre>
40
+ <source>
41
+ type cloudstack
42
+ host $cloudtack_host
43
+ apikey $cloudstack_apikey
44
+ secretkey $cloustack_secretkey
45
+
46
+ # optional
47
+ protocol $cloudstack_protocol_scheme # https or http, default https
48
+ path $cloudstack_path # default /client/api
49
+ port $cloudstack_port # default 443
50
+ interval $get_interval_sec # min 300, default 300
51
+ ssl $cloudtack_api_ssl # true or false, default true
52
+ domain_id $cloudstack_domain_id
53
+
54
+ tag $fluentd_tag # default cloudstack
55
+ </source>
56
+ </pre>
57
+
58
+
59
+
60
+ h2. Data Example
61
+
62
+ <pre>
63
+ 20131027T193928+0000 cloudstack.usages {"instances_usage":1,
64
+ "memory_usage":512,
65
+ "cpu_usage":1,
66
+ "root_volume_usage":16106127360,
67
+ "data_volume_usage":42949672960,
68
+ "usages_per_service_offering":{"t1.micro":1},
69
+ "usages_per_disk_offering":{"Datadisk 40GB":1}}
70
+
71
+ 20130507T041336+0000 cloudstack.event {"id":"xxxxxxx-4e64-4fa5-8045-5ecffb7e2417",
72
+ "username":"clnxxxxxxxxx",
73
+ "type":"USER.LOGIN",
74
+ "level":"INFO",
75
+ "description":"user has logged in from IP Address xxx.xxx.xxx.xxx",
76
+ "account":"clnxxxxxxx",
77
+ "domainid":"xxxxxxxx-dcc3-486b-90e8-02c514c93d1f",
78
+ "domain":"cln10000004",
79
+ "created":"2013-05-07T13:13:36+0900",
80
+ "state":"Completed",
81
+ "parentid":"0"}
82
+ </pre>
83
+
data/Rakefile ADDED
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
3
+
4
+ require 'rake/testtask'
5
+ Rake::TestTask.new(:test) do |test|
6
+ test.libs << 'lib' << 'test'
7
+ test.pattern = 'test/**/test_*.rb'
8
+ test.test_files = Dir['test/plugin/*.rb']
9
+ test.ruby_opts = ['-rubygems'] if defined? Gem
10
+ test.ruby_opts << '-I.'
11
+ test.verbose = true
12
+ end
13
+
14
+ task :default => :test
15
+
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.1
@@ -0,0 +1,24 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.name = "fluent-plugin-cloudstack"
6
+ gem.version = File.read("VERSION").strip
7
+ gem.authors = ["Yuichi UEMURA"]
8
+ gem.email = ["yuichi.u@gmail.com"]
9
+ gem.homepage = "https://github.com/u-ichi/fluent-plugin-cloudstack"
10
+ gem.summary = %q{cloudstack plugin for fluentd, a log collector}
11
+ gem.description = %q{cloudstack plugin for fluentd, a log collector}
12
+
13
+ gem.files = `git ls-files`.split("\n")
14
+ gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
15
+ gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
16
+ gem.require_paths = ["lib"]
17
+
18
+ gem.add_dependency "fluentd", ">= 0.10.7"
19
+ gem.add_dependency "fog"
20
+ gem.add_dependency "eventmachine"
21
+
22
+ gem.add_development_dependency "rake"
23
+ end
24
+
@@ -0,0 +1,175 @@
1
+ module Fluent
2
+ class CloudStackInput < Input
3
+ Fluent::Plugin.register_input("cloudstack", self)
4
+
5
+ INTERVAL_MIN = 300
6
+
7
+ config_param :host
8
+ config_param :path, :default =>'/client/api'
9
+ config_param :protocol, :default =>'https'
10
+ config_param :port, :default =>443
11
+ config_param :apikey
12
+ config_param :secretkey
13
+ config_param :domain_id, :default => nil
14
+ config_param :interval, :default => INTERVAL_MIN
15
+
16
+ config_param :tag, :string, :default => "cloudstack"
17
+ config_param :ssl, :bool, :default => true
18
+
19
+ attr_writer :before_events
20
+
21
+ def initialize
22
+ require "fog"
23
+ require "eventmachine"
24
+ init_eventmachine
25
+
26
+ @before_events_filepath = "logs/before_events.yml"
27
+
28
+ if File.exist?(@before_events_filepath)
29
+ @before_events = YAML.load_file(@before_events_filepath)
30
+ else
31
+ @before_events = nil
32
+ end
33
+
34
+ super
35
+ end
36
+
37
+ def configure(conf)
38
+ super
39
+ @conf = conf
40
+ unless @host && @apikey && @secretkey
41
+ raise ConfigError, "'host' and 'apikey' and 'secretkey' must be all specified."
42
+ end
43
+
44
+ if @interval < INTERVAL_MIN
45
+ raise ConfigError, "'interval' must be over #{INTERVAL_MIN}."
46
+ end
47
+ end
48
+
49
+ def start
50
+ super
51
+ run_reactor_thread
52
+ @thread = Thread.new(&method(:run))
53
+ $log.info "listening cloudstack api on #{@host}"
54
+ end
55
+
56
+ def shutdown
57
+ super
58
+ @thread.join
59
+ EM.stop if EM.reactor_running?
60
+ @reactor_thread.join if @reactor_thread
61
+ end
62
+
63
+ def run
64
+ EM.add_periodic_timer(@interval) do
65
+ emit_new_events
66
+ emit_usages
67
+ end
68
+ end
69
+
70
+ def emit_new_events
71
+ new_events = get_new_events
72
+ output_tag = "#{@tag}.event"
73
+ new_events.each do |event|
74
+ time = Time.parse(event["created"]).to_i
75
+ Engine.emit(output_tag, time, event)
76
+ end
77
+ end
78
+
79
+ def emit_usages
80
+ usages = get_usages
81
+ time = Engine.now
82
+ output_tag = "#{@tag}.usages"
83
+ Engine.emit(output_tag, time, usages)
84
+ end
85
+
86
+ def get_new_events
87
+ if @before_events
88
+ startdate = Time.parse(@before_events[0]["created"])
89
+ event_responses = cs.list_events(:startdate => startdate.strftime("%Y-%m-%d %H:%M:%S"), :domainid => @domain_id)
90
+ events = Array.new
91
+ event_responses["listeventsresponse"]["event"].each do |event|
92
+ unless Time.parse(event["created"]) == startdate
93
+ events.push event
94
+ end
95
+ end
96
+ else
97
+ events = cs.list_events(:domainid => @domain_id)["listeventsresponse"]["event"]
98
+ end
99
+
100
+ if events.size > 0
101
+ File.write(@before_events_filepath, events.to_yaml)
102
+ @before_events = events
103
+ end
104
+
105
+ events
106
+ end
107
+
108
+ def get_usages
109
+ usages_per_service_offering = Hash.new(0)
110
+ usages_per_disk_offering = Hash.new(0)
111
+ memory_usage = 0
112
+ cpu_usage = 0
113
+ root_volume_usage = 0
114
+ data_volume_usage = 0
115
+
116
+ vms_responses = cs.list_virtual_machines(:domainid=>@domain_id)
117
+ vms = vms_responses["listvirtualmachinesresponse"]["virtualmachine"]
118
+ vms.each do |vm|
119
+ memory_usage += vm["memory"].to_i
120
+ cpu_usage += vm["cpunumber"].to_i
121
+ usages_per_service_offering[vm["serviceofferingname"]] += 1
122
+ end
123
+
124
+ volumes_responses = cs.list_volumes(:domainid=>@domain_id)
125
+ volumes = volumes_responses["listvolumesresponse"]["volume"]
126
+ volumes.each do |volume|
127
+ case volume["type"]
128
+ when "ROOT"
129
+ root_volume_usage += volume["size"]
130
+ when "DATADISK"
131
+ data_volume_usage += volume["size"]
132
+ usages_per_disk_offering[volume["diskofferingname"]] += 1
133
+ end
134
+ end
135
+
136
+ results = {:vm_usage => vms.size,
137
+ :memory_usage => memory_usage,
138
+ :cpu_usage => cpu_usage,
139
+ :root_volume_usage => root_volume_usage,
140
+ :data_volume_usage => data_volume_usage,
141
+ :usages_per_service_offering => usages_per_service_offering,
142
+ :usages_per_disk_offering => usages_per_disk_offering,
143
+ }
144
+ end
145
+
146
+ def cs
147
+ @@cs ||= Fog::Compute.new(
148
+ :provider => 'CloudStack',
149
+ :cloudstack_api_key => @apikey,
150
+ :cloudstack_secret_access_key => @secretkey,
151
+ :cloudstack_host => @host,
152
+ :cloudstack_port => @port,
153
+ :cloudstack_path => @path,
154
+ :cloudstack_scheme => @protocol,
155
+ )
156
+ end
157
+
158
+ private
159
+
160
+ def run_reactor_thread
161
+ unless EM.reactor_running?
162
+ @reactor_thread = Thread.new { EM.run }
163
+ end
164
+ end
165
+
166
+ def init_eventmachine
167
+ EM.epoll; EM.kqueue
168
+ EM.error_handler do |ex|
169
+ $log.error("Eventmachine problem")
170
+ $log.error("#{ex}, tracelog : \n#{ex.backtrace.join("\n")}")
171
+ end
172
+ end
173
+ end
174
+ end
175
+
@@ -0,0 +1,48 @@
1
+ require 'test/unit'
2
+ require 'test_helper'
3
+ require 'lib/fluent/plugin/in_cloudstack.rb'
4
+ require 'pp'
5
+
6
+
7
+ class CloudStackInputTest < Test::Unit::TestCase
8
+ def setup
9
+ Fluent::Test.setup
10
+ end
11
+
12
+ CONFIG = %[
13
+ host localhost
14
+ apikey hoge
15
+ secretkey fuga
16
+ domain_id domain_id
17
+ ]
18
+
19
+
20
+ def create_driver(conf=CONFIG)
21
+ Fluent::Test::InputTestDriver.new(Fluent::CloudStackInput).configure(conf)
22
+ end
23
+
24
+ def test_configure
25
+ d = create_driver
26
+ assert_equal 'localhost', d.instance.host
27
+ assert_equal 'hoge', d.instance.apikey
28
+ assert_equal 'fuga', d.instance.secretkey
29
+ assert_equal 'domain_id', d.instance.domain_id
30
+ end
31
+
32
+
33
+ def test_get_events
34
+ d = create_driver
35
+
36
+ # d.instance.before_events = before_events_stub
37
+ end
38
+
39
+ def test_get_usage
40
+ d = create_driver
41
+
42
+ # d.instance.get_usages
43
+ end
44
+
45
+ end
46
+
47
+
48
+
@@ -0,0 +1,28 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+
4
+ begin
5
+ Bundler.setup(:default, :development)
6
+ rescue Bundler::BundlerError => e
7
+ $stderr.puts e.message
8
+ $stderr.puts "Run `bundle install` to install missing gems"
9
+ exit e.status_code
10
+ end
11
+
12
+ require 'test/unit'
13
+
14
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
15
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
16
+ require 'fluent/test'
17
+
18
+ unless ENV.has_key?('VERBOSE')
19
+ nulllogger = Object.new
20
+ nulllogger.instance_eval {|obj|
21
+ def method_missing(method, *args)
22
+ # pass
23
+ end
24
+ }
25
+ $log = nulllogger
26
+ end
27
+
28
+
metadata ADDED
@@ -0,0 +1,111 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fluent-plugin-cloudstack
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Yuichi UEMURA
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-10-27 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: fluentd
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 0.10.7
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 0.10.7
27
+ - !ruby/object:Gem::Dependency
28
+ name: fog
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: eventmachine
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description: cloudstack plugin for fluentd, a log collector
70
+ email:
71
+ - yuichi.u@gmail.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - ".gitignore"
77
+ - Gemfile
78
+ - Gemfile.lock
79
+ - README.textile
80
+ - Rakefile
81
+ - VERSION
82
+ - fluent-plugin-cloudstack.gemspec
83
+ - lib/fluent/plugin/in_cloudstack.rb
84
+ - test/plugin/in_cloudstack.rb
85
+ - test/test_helper.rb
86
+ homepage: https://github.com/u-ichi/fluent-plugin-cloudstack
87
+ licenses: []
88
+ metadata: {}
89
+ post_install_message:
90
+ rdoc_options: []
91
+ require_paths:
92
+ - lib
93
+ required_ruby_version: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ version: '0'
98
+ required_rubygems_version: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - ">="
101
+ - !ruby/object:Gem::Version
102
+ version: '0'
103
+ requirements: []
104
+ rubyforge_project:
105
+ rubygems_version: 2.1.10
106
+ signing_key:
107
+ specification_version: 4
108
+ summary: cloudstack plugin for fluentd, a log collector
109
+ test_files:
110
+ - test/plugin/in_cloudstack.rb
111
+ - test/test_helper.rb