instrumental_tools 1.0.0 → 1.1.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (36) hide show
  1. checksums.yaml +4 -4
  2. data/BUILD.md +15 -0
  3. data/CHANGELOG.md +17 -1
  4. data/CUSTOM_METRICS.md +4 -0
  5. data/INSTALL.md +12 -7
  6. data/README.md +2 -2
  7. data/Rakefile +202 -64
  8. data/TEST.md +18 -0
  9. data/bin/instrument_server +31 -15
  10. data/chef/.kitchen.yml +10 -1
  11. data/chef/instrumental_tools/attributes/default.rb +29 -2
  12. data/chef/instrumental_tools/recipes/default.rb +188 -17
  13. data/chef/instrumental_tools/templates/default/instrument_server.erb +46 -0
  14. data/chef/instrumental_tools/templates/{instrumental.yml.erb → default/instrumental.yml.erb} +6 -6
  15. data/chef/omnibus.sh +27 -0
  16. data/conf/instrumental.yml +6 -6
  17. data/examples/README.md +1 -0
  18. data/examples/redis/README.md +10 -0
  19. data/examples/redis/redis_info.sh +10 -0
  20. data/ext/Rakefile +1 -0
  21. data/ext/mkrf_conf.rb +18 -0
  22. data/instrumental_tools.gemspec +8 -2
  23. data/lib/instrumental_tools/metric_script_executor.rb +45 -6
  24. data/lib/instrumental_tools/server_controller.rb +4 -1
  25. data/lib/instrumental_tools/system_inspector.rb +3 -0
  26. data/lib/instrumental_tools/system_inspector/win32.rb +85 -0
  27. data/lib/instrumental_tools/version.rb +1 -1
  28. data/test/integration/default/serverspec/instrumental_tools_spec.rb +32 -16
  29. data/win32/Makefile +18 -0
  30. data/win32/installer.nsis.erb +242 -0
  31. data/win32/logo.ico +0 -0
  32. data/win32/src/instrumental/InstrumentServerProcess.cs +147 -0
  33. data/win32/src/instrumental/InstrumentServerProcessWorker.cs +89 -0
  34. data/win32/src/instrumental/InstrumentServerService.cs +146 -0
  35. data/win32/src/instrumental/InstrumentServerServiceInstaller.cs +60 -0
  36. metadata +36 -7
data/TEST.md CHANGED
@@ -7,3 +7,21 @@ bundle exec kitchen verify
7
7
  ```
8
8
 
9
9
  to test installation and setup procedures for the `instrumental_tools` command. You must have [Vagrant](https://www.vagrantup.com/) installed; currently the KitchenCI integration is setup to use [VMWare Fusion](http://www.vmware.com/products/fusion) and the [VMWare Fusion Vagrant provider](https://www.vagrantup.com/vmware); you can configure a separate provider for your specific setup by change the `provider` flag in the `.kitchen.yml` file for your particular setup.
10
+
11
+ ## Windows
12
+
13
+ Ensure you have the `winrm` vagrant plugin installed.
14
+
15
+ ```
16
+ vagrant plugin install vagrant-winrm
17
+ ```
18
+
19
+
20
+ To ensure you have a Windows Vagrant image, perform the following steps in a separate directory to build a Windows evaluation image:
21
+
22
+ ```
23
+ git clone https://github.com/boxcutter/windows.git
24
+ cd windows
25
+ make virtualbox/eval-win2012r2-standard
26
+ vagrant box add windows-2012r2 ./box/virtualbox/eval-win2012r2-standard-nocm-1.0.4.box
27
+ ```
@@ -27,19 +27,28 @@ def require_api_key(options, parser)
27
27
  end
28
28
  end
29
29
 
30
+ def coerce_path(path)
31
+ if File::ALT_SEPARATOR
32
+ File.join(*path.split(File::ALT_SEPARATOR))
33
+ else
34
+ path
35
+ end
36
+ end
37
+
30
38
 
31
39
  cur_directory = Dir.pwd
32
40
  home_directory = Dir.home rescue nil
33
41
  script_location = File.expand_path(File.dirname(__FILE__))
34
42
  tmp_dir = Dir.tmpdir
35
43
  script_data_directory = [cur_directory, home_directory, script_location, tmp_dir].compact.detect { |dir| File.writable?(dir) }
44
+ windows = RUBY_PLATFORM =~ /(mswin|win32|mingw)/i
36
45
 
37
46
  default_script_directory = File.join(script_data_directory, '.instrumental_scripts')
38
47
  default_command = :foreground
39
48
 
40
49
  options = {
41
50
  :collector => 'collector.instrumentalapp.com',
42
- :port => '8000',
51
+ :port => '8001',
43
52
  :hostname => Socket.gethostname,
44
53
  :pid_location => File.join(script_data_directory, 'instrument_server.pid'),
45
54
  :log_location => File.join(script_data_directory, 'instrument_server.log'),
@@ -63,13 +72,13 @@ Default command: #{default_command.to_s}
63
72
  end
64
73
 
65
74
  opts.on('-f', '--config-file PATH', "Config file with location of your API key (default #{options[:config_file]})") do |path|
66
- options[:config_file] = path
75
+ options[:config_file] = coerce_path(path)
67
76
  end
68
77
 
69
78
  opts.on('-c', '--collector COLLECTOR[:PORT]', "Collector (default #{options[:collector]}:#{options[:port]})") do |collector|
70
- address, port = collector.split(':')
79
+ address, port = collector.split(':')
71
80
  options[:collector] = address
72
- options[:port] = port if port
81
+ options[:port] = port if port
73
82
  end
74
83
 
75
84
  opts.on('-H', '--hostname HOSTNAME', "Hostname to report as (default #{options[:hostname]})") do |hostname|
@@ -77,11 +86,11 @@ Default command: #{default_command.to_s}
77
86
  end
78
87
 
79
88
  opts.on('-p', '--pid LOCATION', "Where daemon PID file is located (default #{options[:pid_location]})") do |pid_location|
80
- options[:pid_location] = pid_location
89
+ options[:pid_location] = coerce_path(pid_location)
81
90
  end
82
91
 
83
92
  opts.on('-l', '--log LOCATION', "Where to put the instrument_server log file (default #{options[:log_location]})") do |log_location|
84
- options[:log_location] = log_location
93
+ options[:log_location] = coerce_path(log_location)
85
94
  end
86
95
 
87
96
  opts.on('-r', '--report-interval INTERVAL_IN_SECONDS', "How often to report metrics to Instrumental (default #{options[:report_interval]})") do |interval|
@@ -93,15 +102,17 @@ Default command: #{default_command.to_s}
93
102
  end
94
103
 
95
104
  opts.on('-s', '--script-location PATH_TO_DIRECTORY', "Directory where local scripts for custom metrics are located (default #{options[:script_location]})") do |path|
96
- options[:script_location] = path
105
+ options[:script_location] = coerce_path(path)
97
106
  end
98
107
 
99
- opts.on('-u', '--user USER_TO_RUN_AS', "User to run instrument_server as. You must have permissions to drop privileges to this user.") do |u|
100
- options[:user] = u
108
+ if !windows
109
+ opts.on('-u', '--user USER_TO_RUN_AS', "User to run instrument_server as. You must have permissions to drop privileges to this user.") do |u|
110
+ options[:user] = u
111
+ end
101
112
  end
102
113
 
103
114
  opts.on('-t', '--temp-dir TEMP_DIRECTORY', "Where to store temporary files (default #{options[:tmp_location]})") do |t|
104
- options[:tmp_location] = t
115
+ options[:tmp_location] = coerce_path(t)
105
116
  end
106
117
 
107
118
  opts.on('--debug', "Print all sent metrics to the log") do
@@ -112,11 +123,16 @@ Default command: #{default_command.to_s}
112
123
  puts opts
113
124
  exit
114
125
  end
126
+
127
+ opts.on('-v', '--version', 'Display version') do
128
+ puts "instrument_server: #{Instrumental::Tools::VERSION}"
129
+ exit 0
130
+ end
115
131
  end
116
132
 
117
133
  option_parser.parse!
118
134
 
119
- if options[:user]
135
+ if options[:user] && !windows
120
136
  desired_uid = Etc.getpwnam(options[:user]).uid
121
137
  Process::Sys.setuid(desired_uid)
122
138
  if desired_uid && desired_uid != 0
@@ -171,11 +187,11 @@ if options[:enable_scripts]
171
187
  raise "The directory #{options[:script_location]} does not exist."
172
188
  end
173
189
 
174
- stat = File::Stat.new(File.expand_path(options[:script_location]))
175
-
176
- if !stat.owned? || ((stat.mode & 0xFFF) ^ 0O700) != 0
190
+ stat = File::Stat.new(File.expand_path(options[:script_location]))
191
+ correct_mode = windows || ((stat.mode & 0xFFF) ^ 0O700) === 0
192
+ unless stat.owned? && correct_mode
177
193
  uid = Process.uid
178
- username = Etc.getpwuid(uid).name
194
+ username = Etc.getpwuid(uid).try(:name)
179
195
  raise "The directory #{options[:script_location]} is writable/readable by others. Please ensure it is only writable / readable by user/uid #{username}/#{uid}"
180
196
  end
181
197
 
@@ -1,16 +1,25 @@
1
1
  ---
2
2
  driver:
3
3
  name: vagrant
4
- provider: vmware_fusion
4
+ synced_folders:
5
+ - ["../", "/tools-root"]
6
+ customize:
7
+ memory: 2048
5
8
 
6
9
  provisioner:
7
10
  name: chef_solo
11
+ chef_omnibus_url: "https://raw.githubusercontent.com/expectedbehavior/instrumental_tools/master/chef/omnibus.sh"
8
12
 
9
13
  platforms:
10
14
  - name: ubuntu-12.04
11
15
  - name: centos-6.6
16
+ - name: "d11wtq/gentoo"
17
+ - name: "windows-2012r2"
12
18
 
13
19
  suites:
14
20
  - name: default
15
21
  run_list: ["instrumental_tools"]
16
22
  attributes:
23
+ instrumental:
24
+ use_local: true
25
+ local_path: "/tools-root/"
@@ -1,2 +1,29 @@
1
- default[:instrumental] = {}
2
- default[:instrumental][:api_key] = nil
1
+ default[:instrumental] = {}
2
+ default[:instrumental][:api_key] = nil
3
+
4
+ default[:instrumental][:version] = "1.1.2"
5
+ default[:instrumental][:repo] = "https://s3.amazonaws.com/instrumental-tools"
6
+
7
+ default[:instrumental][:curl_path] = "/usr/bin/curl"
8
+ default[:instrumental][:wget_path] = "/usr/bin/wget"
9
+
10
+ default[:instrumental][:dest_init_file] = "/etc/init.d/instrument_server"
11
+
12
+ default[:instrumental][:enable_scripts] = false
13
+
14
+
15
+ if node[:platform_family] == "windows"
16
+ default[:instrumental][:destination_dir] = "C:\\Program Files (x86)\\Instrumental Tools"
17
+ default[:instrumental][:config_file] = "C:\\Program Files (x86)\\Instrumental Tools\\etc\\instrumental.yml"
18
+ default[:instrumental][:script_dir] = "C:\\Program Files (x86)\\Instrumental Tools\\scripts"
19
+ else
20
+ default[:instrumental][:destination_dir] = "/opt/instrumental-tools/"
21
+ default[:instrumental][:config_file] = "/etc/instrumental.yml"
22
+ default[:instrumental][:script_dir] = "/opt/instrumental-tools/.scripts"
23
+ default[:instrumental][:pid_file] = "/opt/instrumental-tools/instrument_server.pid"
24
+ default[:instrumental][:log_file] = "/opt/instrumental-tools/instrument_server.log"
25
+ default[:instrumental][:user] = "nobody"
26
+ end
27
+
28
+ default[:instrumental][:use_local] = false
29
+ default[:instrumental][:local_path] = nil
@@ -1,21 +1,192 @@
1
- packagecloud_repo "expectedbehavior/instrumental" do
2
- case node["platform_family"]
3
- when "debian"
4
- type "deb"
5
- when "rhel"
6
- type "rpm"
1
+ supported_platforms = %w{debian rhel fedora arch gentoo slackware suse}
2
+ version = node["instrumental"]["version"]
3
+ arch = case node["kernel"]["machine"]
4
+ when "i386"
5
+ "x86"
6
+ else
7
+ node["kernel"]["machine"]
8
+ end
9
+ pkg_arch = case node["kernel"]["machine"]
10
+ when "x86_64"
11
+ "amd64"
12
+ else
13
+ node["kernel"]["machine"]
14
+ end
15
+ file_name = case node["platform_family"]
16
+ when "osx"
17
+ "instrumental-tools_%s_osx.tar.gz" % version
18
+ when "debian"
19
+ "instrumental-tools_%s_%s.deb" % [version, pkg_arch]
20
+ when "rhel", "fedora"
21
+ "instrumental-tools_%s_%s.rpm" % [version, pkg_arch]
22
+ when "windows"
23
+ "instrumental-tools_%s_win32.exe" % version
24
+ else
25
+ "instrumental-tools_%s_linux-%s.tar.gz" % [version, arch]
26
+ end
27
+
28
+ local_path = ::File.join(node[:instrumental][:local_path], file_name)
29
+ dest_dir = node[:instrumental][:destination_dir]
30
+ conf_file = node[:instrumental][:config_file]
31
+ remote_name = "%s/%s/%s" % [node[:instrumental][:repo], version, file_name]
32
+ package_destination = ::File.join(dest_dir, file_name)
33
+
34
+ case node["platform_family"]
35
+ when "debian", "rhel", "fedora"
36
+ if node[:instrumental][:use_local]
37
+ package "instrumental-tools" do
38
+ action :install
39
+ source local_path
40
+ provider node["platform_family"] == "debian" ? Chef::Provider::Package::Dpkg : Chef::Provider::Package::Yum
41
+ end
42
+ else
43
+ packagecloud_repo "expectedbehavior/instrumental" do
44
+ case node["platform_family"]
45
+ when "debian"
46
+ type "deb"
47
+ when "rhel", "fedora"
48
+ type "rpm"
49
+ end
50
+ end
51
+
52
+ package "instrumental-tools" do
53
+ action :upgrade
54
+ version node["instrumental"]["version"]
55
+ end
7
56
  end
8
- end
9
57
 
10
- package "instrumental-tools" do
11
- action :upgrade
12
- end
58
+ template conf_file do
59
+ source "instrumental.yml.erb"
60
+ mode "0440"
61
+ owner "nobody"
62
+ variables(
63
+ :api_key => node[:instrumental][:api_key]
64
+ )
65
+ end
66
+
67
+ template node["instrumental"]["dest_init_file"] do
68
+ source "instrument_server.erb"
69
+ mode "0755"
70
+ owner "nobody"
71
+ variables(
72
+ :dest_dir => dest_dir,
73
+ :config_file => conf_file,
74
+ :enable_scripts => !!node[:instrumental][:enable_scripts],
75
+ :script_dir => node[:instrumental][:script_dir],
76
+ :log_file => node[:instrumental][:log_file],
77
+ :pid_file => node[:instrumental][:pid_file],
78
+ :user => node[:instrumental][:user]
79
+ )
80
+ end
81
+
82
+ service "instrument_server" do
83
+ action :restart
84
+ end
85
+
86
+ when "arch", "gentoo", "slackware", "suse", "osx"
87
+
88
+ local_path = "%s/%s" % [dest_dir, file_name]
89
+
90
+ directory dest_dir do
91
+ owner "nobody"
92
+ action :create
93
+ recursive true
94
+ end
13
95
 
14
- template "/etc/instrumental.yml" do
15
- source "instrumental.yml.erb"
16
- mode "0440"
17
- owner "nobody"
18
- variables(
19
- :api_key => node[:instrumental][:api_key]
20
- )
96
+
97
+ if node[:instrumental][:use_local]
98
+ execute "copy_instrumental_tools_package" do
99
+ command "cp %s %s" % [local_path, package_destination]
100
+ cwd dest_dir
101
+ user "nobody"
102
+ end
103
+ else
104
+ remote_file package_destination do
105
+ source remote_name
106
+ user "nobody"
107
+ end
108
+ end
109
+
110
+ execute "untar_instrumental_tools_package" do
111
+ command "tar --strip-components=3 -zxvf %s" % file_name
112
+ user "nobody"
113
+ cwd dest_dir
114
+ only_if { ::File.exists?(local_path) }
115
+ end
116
+
117
+ template node["instrumental"]["dest_init_file"] do
118
+ source "instrument_server.erb"
119
+ mode "0755"
120
+ owner "nobody"
121
+ variables(
122
+ :dest_dir => dest_dir,
123
+ :config_file => conf_file,
124
+ :enable_scripts => !!node[:instrumental][:enable_scripts],
125
+ :script_dir => node[:instrumental][:script_dir],
126
+ :log_file => node[:instrumental][:log_file],
127
+ :pid_file => node[:instrumental][:pid_file],
128
+ :user => node[:instrumental][:user]
129
+ )
130
+ end
131
+
132
+ template conf_file do
133
+ source "instrumental.yml.erb"
134
+ mode "0440"
135
+ owner "nobody"
136
+ variables(
137
+ :api_key => node[:instrumental][:api_key]
138
+ )
139
+ end
140
+
141
+ service "instrument_server" do
142
+ action [:enable, :start]
143
+ status_command "pgrep instrument_server"
144
+ supports :restart => true, :reload => true, :status => false
145
+ end
146
+ when "windows"
147
+
148
+ directory dest_dir do
149
+ action :create
150
+ recursive true
151
+ end
152
+
153
+ if node[:instrumental][:enable_scripts]
154
+ directory node[:instrumental][:script_dir] do
155
+ action :create
156
+ recursive true
157
+ end
158
+ end
159
+
160
+ extra_args = if node[:instrumental][:enable_scripts]
161
+ '/SD "%s" /E' % node[:instrumental][:script_dir]
162
+ else
163
+ ""
164
+ end
165
+
166
+ if node[:instrumental][:use_local]
167
+ execute "install-tools" do
168
+ command 'call "%s" %s /S /D=%s' % [local_path, extra_args, dest_dir]
169
+ end
170
+ else
171
+ remote_file package_destination do
172
+ source remote_name
173
+ action :create
174
+ end
175
+ execute "install-tools" do
176
+ command 'call "%s" %s /S /D=%s' % [package_destination, extra_args, dest_dir]
177
+ end
178
+ end
179
+
180
+ template conf_file do
181
+ source "instrumental.yml.erb"
182
+ variables(
183
+ :api_key => node[:instrumental][:api_key]
184
+ )
185
+ end
186
+
187
+ service "Instrument Server" do
188
+ action [:enable, :start]
189
+ end
190
+ else
191
+ Chef::Log.warn("The platform %s is not supported, instrumental_tools will not be installed" % node["platform_family"])
21
192
  end
@@ -0,0 +1,46 @@
1
+ #! /bin/sh
2
+ ### BEGIN INIT INFO
3
+ # Provides: instrument_server
4
+ # Required-Start: $all
5
+ # Required-Stop: $all
6
+ # Default-Start: 2 3 4 5
7
+ # Default-Stop: 0 1 6
8
+ # Short-Description: Start instrument_server at boot to provide system metrics
9
+ # Description: Report system level metrics to the Instrumental service (https://instrumentalapp.com/)
10
+ ### END INIT INFO
11
+
12
+ set -e
13
+
14
+ DIRECTORY="<%= @dest_dir %>"
15
+ CONFIG_FILE="<%= @config_file %>"
16
+ TMPDIR=$DIRECTORY
17
+ PID="<%= @pid_file %>"
18
+ LOG="<%= @log_file %>"
19
+ SCRIPT_LOCATION="<%= @script_dir %>"
20
+ USER_TO_RUN_AS="<%= @user %>"
21
+ ARGS="-f ${CONFIG_FILE} -p ${PID} -l ${LOG} -s ${SCRIPT_LOCATION} -u ${USER_TO_RUN_AS} -t ${TMPDIR} <%= '-e' if @enable_scripts %>"
22
+ PROCESS="${DIRECTORY}instrument_server ${ARGS}"
23
+
24
+ case "$1" in
25
+ start)
26
+ $PROCESS start
27
+ ;;
28
+ stop)
29
+ $PROCESS stop
30
+ ;;
31
+ restart)
32
+ $PROCESS restart
33
+ ;;
34
+ status)
35
+ $PROCESS status
36
+ ;;
37
+ force-reload)
38
+ $PROCESS stop && $PROCESS clean && $PROCESS start
39
+ ;;
40
+ *)
41
+ echo "Usage: /etc/init.d/instrumental-tools {start|stop|restart|status}"
42
+ exit 1
43
+ ;;
44
+ esac
45
+
46
+ exit 0