hieraviz 0.0.1 → 0.0.2
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 +4 -4
- data/CHANGELOG.md +5 -0
- data/README.md +4 -4
- data/app/apiv1.rb +34 -0
- data/app/common.rb +2 -8
- data/app/main.rb +3 -0
- data/app/public/css/main.css +46 -2
- data/app/public/js/farms.js +3 -2
- data/app/public/js/fetch.js +381 -0
- data/app/public/js/main.js +24 -1
- data/app/public/js/nodes.js +25 -13
- data/app/views/_foot.erb +3 -1
- data/app/views/_head.erb +9 -0
- data/app/views/_layout.erb +5 -0
- data/app/views/data.erb +4 -0
- data/app/views/farms.erb +1 -1
- data/app/views/home.erb +6 -1
- data/app/views/modules.erb +4 -3
- data/app/views/nodes.erb +1 -1
- data/app/views/resources.erb +4 -4
- data/app/views/store.erb +6 -0
- data/app/web.rb +91 -18
- data/lib/hieraviz/auth_gitlab.rb +59 -0
- data/lib/hieraviz/config.rb +20 -0
- data/lib/hieraviz/store.rb +43 -6
- data/lib/hieraviz.rb +2 -0
- data/spec/app/apiv1_spec.rb +7 -4
- data/spec/app/web_spec.rb +1 -0
- data/spec/files/config.yml +10 -0
- data/spec/lib/auth_gitlab_spec.rb +26 -0
- data/spec/lib/config_spec.rb +20 -0
- data/spec/lib/store_spec.rb +127 -0
- data/spec/sinatra_helper.rb +10 -0
- data/spec/spec_helper.rb +20 -8
- metadata +57 -4
- data/app/config/hieraviz.default.yml +0 -13
- data/app/config/hieraviz.yml +0 -13
data/app/public/js/nodes.js
CHANGED
@@ -48,9 +48,9 @@ ready( () => {
|
|
48
48
|
function build_top(title) {
|
49
49
|
meat.innerHTML = "<h3>Node "+title+"</h3>";
|
50
50
|
addTo(meat, "<div class=\"nodenav\">" +
|
51
|
-
"<span class=\"showinfo\" data-
|
52
|
-
"<span class=\"showparams\" data-
|
53
|
-
"<span class=\"showallparams\" data-
|
51
|
+
"<span class=\"showinfo\" data-item=\""+title+"\">Info</span>" +
|
52
|
+
"<span class=\"showparams\" data-item=\""+title+"\">Params</span>" +
|
53
|
+
"<span class=\"showallparams\" data-item=\""+title+"\">AllParams</span>" +
|
54
54
|
"</div>");
|
55
55
|
addTo(meat, "<div class=\"paramfilter\">" +
|
56
56
|
"<input type=\"text\" name=\"paramfilter\" />" +
|
@@ -81,7 +81,7 @@ ready( () => {
|
|
81
81
|
item.addEventListener('click', (ev) => {
|
82
82
|
start_wait();
|
83
83
|
el = ev.target;
|
84
|
-
action = el.
|
84
|
+
action = el.textContent.toLowerCase();
|
85
85
|
fetch('/v1/node/' + title + '/' + action).
|
86
86
|
then(res => res.json()).
|
87
87
|
then(j => {
|
@@ -92,42 +92,54 @@ ready( () => {
|
|
92
92
|
});
|
93
93
|
}
|
94
94
|
|
95
|
+
function show_error(meat, message) {
|
96
|
+
meat.innerHTML = "<div class=\"error\">" + message + "</div>\n";
|
97
|
+
}
|
98
|
+
|
95
99
|
var Node = {
|
96
100
|
params: function(el) {
|
97
101
|
start_wait(meat);
|
98
|
-
title = el.dataset.
|
99
|
-
fetch('/v1/node/' + title).
|
102
|
+
title = el.dataset.item;
|
103
|
+
fetch('/v1/node/' + title, auth_header()).
|
100
104
|
then(res => res.json()).
|
101
105
|
then(j => {
|
102
|
-
|
103
|
-
|
104
|
-
|
106
|
+
console.log(auth_header().headers.getAll('x-auth'));
|
107
|
+
if (j.error != undefined) {
|
108
|
+
show_error(meat, j['error']);
|
109
|
+
} else {
|
110
|
+
build_top(title);
|
111
|
+
build_params(meat, title, j);
|
112
|
+
rebuild_nav(title);
|
113
|
+
update_footer('/v1/node/' + title);
|
114
|
+
}
|
105
115
|
end_wait(meat);
|
106
116
|
});
|
107
117
|
},
|
108
118
|
|
109
119
|
info: function(el) {
|
110
120
|
start_wait(meat);
|
111
|
-
title = el.dataset.
|
112
|
-
fetch('/v1/node/' + title + '/info').
|
121
|
+
title = el.dataset.item;
|
122
|
+
fetch('/v1/node/' + title + '/info', auth_header()).
|
113
123
|
then(res => res.json()).
|
114
124
|
then(j => {
|
115
125
|
build_top(title);
|
116
126
|
build_info(meat, title, j);
|
117
127
|
rebuild_nav(title);
|
128
|
+
update_footer('/v1/node/' + title + '/info');
|
118
129
|
end_wait(meat);
|
119
130
|
});
|
120
131
|
},
|
121
132
|
|
122
133
|
allparams: function(el) {
|
123
134
|
start_wait(meat);
|
124
|
-
title = el.dataset.
|
125
|
-
fetch('/v1/node/' + title + '/all').
|
135
|
+
title = el.dataset.item;
|
136
|
+
fetch('/v1/node/' + title + '/all', auth_header()).
|
126
137
|
then(res => res.json()).
|
127
138
|
then(j => {
|
128
139
|
build_top(title);
|
129
140
|
build_info(meat, title, j);
|
130
141
|
rebuild_nav(title);
|
142
|
+
update_footer('/v1/node/' + title + '/all');
|
131
143
|
end_wait(meat);
|
132
144
|
});
|
133
145
|
},
|
data/app/views/_foot.erb
CHANGED
data/app/views/_head.erb
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
<%= settings.app_name %>
|
4
4
|
</a>
|
5
5
|
</div>
|
6
|
+
<% if session[:access_token] -%>
|
6
7
|
<div class="nav">
|
7
8
|
<a href="/nodes" class="nodes">Nodes</a>
|
8
9
|
<a href="/farms" class="farms">Farms</a>
|
@@ -10,5 +11,13 @@
|
|
10
11
|
<a href="/resources" class="resources">Resources</a>
|
11
12
|
</div>
|
12
13
|
<div class="auth">
|
14
|
+
<div class="username">
|
15
|
+
identified as <b><%= @username %></b>
|
16
|
+
</div>
|
13
17
|
<a href="/logout" id="logout">Logout</a>
|
14
18
|
</div>
|
19
|
+
<% else -%>
|
20
|
+
<div class="auth">
|
21
|
+
<a href="/login" id="login">Connect</a>
|
22
|
+
</div>
|
23
|
+
<% end -%>
|
data/app/views/_layout.erb
CHANGED
@@ -5,7 +5,11 @@
|
|
5
5
|
<%= @title if @title %>
|
6
6
|
</title>
|
7
7
|
<link href="css/main.css" rel="stylesheet" type="text/css">
|
8
|
+
<script src="js/fetch.js"></script>
|
8
9
|
<script src="js/main.js"></script>
|
10
|
+
<% if session['access_token'] -%>
|
11
|
+
<script>var session_key = "<%= session['access_token'] %>";</script>
|
12
|
+
<% end -%>
|
9
13
|
<%= yield_content :more_js %>
|
10
14
|
</head>
|
11
15
|
<body>
|
@@ -14,6 +18,7 @@
|
|
14
18
|
<%= erb :_head, :layout => false %>
|
15
19
|
</div>
|
16
20
|
<div class="content">
|
21
|
+
<%= styled_flash %>
|
17
22
|
<%= yield %>
|
18
23
|
</div>
|
19
24
|
<div class="foot">
|
data/app/views/data.erb
ADDED
data/app/views/farms.erb
CHANGED
data/app/views/home.erb
CHANGED
data/app/views/modules.erb
CHANGED
data/app/views/nodes.erb
CHANGED
data/app/views/resources.erb
CHANGED
data/app/views/store.erb
ADDED
data/app/web.rb
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
require 'sinatra/content_for'
|
2
|
+
require 'sinatra/flash'
|
2
3
|
|
3
4
|
require 'better_errors'
|
4
|
-
require 'digest/sha1'
|
5
5
|
require 'dotenv'
|
6
|
+
require 'oauth2'
|
6
7
|
|
7
8
|
require 'hieracles'
|
8
9
|
require 'hieraviz'
|
@@ -12,61 +13,133 @@ require File.expand_path '../common.rb', __FILE__
|
|
12
13
|
module HieravizApp
|
13
14
|
class Web < Common
|
14
15
|
helpers Sinatra::ContentFor
|
16
|
+
register Sinatra::Flash
|
15
17
|
|
16
18
|
configure do
|
19
|
+
set :session_secret, settings.configdata['session_seed']
|
17
20
|
set :public_folder, Proc.new { File.join(root, "public") }
|
18
21
|
set :views_folder, Proc.new { File.join(root, "views") }
|
19
22
|
set :erb, layout: :_layout
|
23
|
+
enable :sessions
|
20
24
|
end
|
21
25
|
|
22
26
|
configure :development do
|
23
27
|
use BetterErrors::Middleware
|
24
|
-
BetterErrors.application_root = File.expand_path('
|
28
|
+
BetterErrors.application_root = File.expand_path('../../', __FILE__)
|
25
29
|
end
|
26
30
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
31
|
+
case settings.configdata['auth_method']
|
32
|
+
when 'http'
|
33
|
+
|
34
|
+
use Rack::Auth::Basic, "Puppet Private Access" do |username, password|
|
35
|
+
username == settings.configdata['http_auth']['username'] &&
|
36
|
+
password == settings.configdata['http_auth']['password']
|
37
|
+
end
|
38
|
+
|
39
|
+
get '/logout' do
|
40
|
+
erb :logout, layout: :_layout
|
41
|
+
end
|
42
|
+
|
43
|
+
helpers do
|
44
|
+
def check_authorization
|
45
|
+
set :username, settings.configdata['http_auth']['username']
|
46
|
+
true
|
33
47
|
end
|
34
48
|
end
|
35
|
-
|
36
|
-
|
49
|
+
|
50
|
+
when 'gitlab'
|
51
|
+
|
52
|
+
set :oauth, Hieraviz::AuthGitlab.new(settings.configdata['gitlab_auth'])
|
53
|
+
|
54
|
+
def get_username
|
55
|
+
if session['access_token']
|
56
|
+
session_info = Hieraviz::Store.get(session['access_token'], settings.configdata['session_renew'])
|
57
|
+
if session_info
|
58
|
+
session_info['username']
|
59
|
+
else
|
60
|
+
''
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def check_authorization
|
66
|
+
if !session['access_token']
|
67
|
+
redirect settings.oauth.login_url(request)
|
68
|
+
else
|
69
|
+
session_info = Hieraviz::Store.get(session['access_token'], settings.configdata['session_renew'])
|
70
|
+
if !session_info
|
71
|
+
if !settings.oauth.authorized?(session['access_token'])
|
72
|
+
flash[:fatal] = "Sorry you are not authorized to read puppet repo on gitlab."
|
73
|
+
redirect '/'
|
74
|
+
else
|
75
|
+
Hieraviz::Store.set session['access_token'], settings.oauth.user_info(session['access_token'])
|
76
|
+
session_info = Hieraviz::Store.get(session['access_token'], settings.configdata['session_renew'])
|
77
|
+
end
|
78
|
+
end
|
79
|
+
session_info['username']
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
get '/login' do
|
84
|
+
redirect settings.oauth.login_url(request)
|
85
|
+
end
|
86
|
+
|
87
|
+
get '/logged-in' do
|
88
|
+
access_token = settings.oauth.access_token(request, params[:code])
|
89
|
+
session[:access_token] = access_token.token
|
90
|
+
Hieraviz::Store.set access_token.token, settings.oauth.user_info(access_token.token)
|
91
|
+
flash['info'] = "Successfully authenticated with the server"
|
92
|
+
redirect '/'
|
93
|
+
end
|
94
|
+
|
95
|
+
get '/logout' do
|
96
|
+
session.clear
|
97
|
+
redirect '/'
|
37
98
|
end
|
38
|
-
end
|
39
99
|
|
40
|
-
|
41
|
-
username == settings.configdata['http_auth']['username'] &&
|
42
|
-
password == settings.configdata['http_auth']['password']
|
100
|
+
else
|
43
101
|
end
|
44
102
|
|
45
103
|
|
46
104
|
get '/' do
|
105
|
+
@username = get_username
|
47
106
|
erb :home
|
48
107
|
end
|
49
108
|
|
50
109
|
get '/nodes' do
|
110
|
+
@username = check_authorization
|
51
111
|
@nodes = Hieracles::Registry.nodes(settings.config)
|
52
112
|
erb :nodes
|
53
113
|
end
|
54
114
|
|
55
115
|
get '/farms' do
|
116
|
+
@username = check_authorization
|
56
117
|
@farms = Hieracles::Registry.farms(settings.config)
|
57
118
|
erb :farms
|
58
119
|
end
|
59
120
|
|
60
121
|
get '/modules' do
|
61
|
-
|
122
|
+
@username = check_authorization
|
123
|
+
erb :modules
|
62
124
|
end
|
63
125
|
|
64
126
|
get '/resources' do
|
65
|
-
|
127
|
+
@username = check_authorization
|
128
|
+
erb :resources
|
66
129
|
end
|
67
130
|
|
68
|
-
get '/
|
69
|
-
|
131
|
+
get '/store' do
|
132
|
+
# Hieraviz::Store.set 'woot', 'nada'
|
133
|
+
erb :store
|
134
|
+
end
|
135
|
+
|
136
|
+
get '/user' do
|
137
|
+
if session[:access_token]
|
138
|
+
@data = settings.oauth.user_info(session[:access_token])
|
139
|
+
else
|
140
|
+
@data = 'nada'
|
141
|
+
end
|
142
|
+
erb :data
|
70
143
|
end
|
71
144
|
|
72
145
|
not_found do
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'oauth2'
|
2
|
+
|
3
|
+
module Hieraviz
|
4
|
+
class AuthGitlab
|
5
|
+
|
6
|
+
def initialize(settings)
|
7
|
+
@@client ||= OAuth2::Client.new(
|
8
|
+
settings['application_id'],
|
9
|
+
settings['secret'],
|
10
|
+
:site => settings['host']
|
11
|
+
)
|
12
|
+
@settings = settings
|
13
|
+
end
|
14
|
+
|
15
|
+
def access_token(request, code)
|
16
|
+
@@client.auth_code.get_token(code, :redirect_uri => redirect_uri(request))
|
17
|
+
end
|
18
|
+
|
19
|
+
def get_response(url, token)
|
20
|
+
access_token = OAuth2::AccessToken.new(@@client, token)
|
21
|
+
begin
|
22
|
+
JSON.parse(access_token.get(url).body)
|
23
|
+
rescue Exception => e
|
24
|
+
{ 'error' => JSON.parse(e.message.split(/\n/)[1])['message'] }
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
|
29
|
+
def redirect_uri(request)
|
30
|
+
uri = URI.parse(request.url)
|
31
|
+
uri.path = '/logged-in'
|
32
|
+
uri.query = nil
|
33
|
+
uri.to_s
|
34
|
+
end
|
35
|
+
|
36
|
+
def login_url(request)
|
37
|
+
@@client.auth_code.authorize_url(:redirect_uri => redirect_uri(request))
|
38
|
+
end
|
39
|
+
|
40
|
+
def authorized?(token)
|
41
|
+
if @settings['resource_required']
|
42
|
+
resp = get_response(@settings['resource_required'], token)
|
43
|
+
if resp['error'] ||
|
44
|
+
(resp[@settings['required_response_key']] &&
|
45
|
+
resp[@settings['required_response_key']] != resp[@settings['required_response_value']])
|
46
|
+
false
|
47
|
+
else
|
48
|
+
true
|
49
|
+
end
|
50
|
+
end
|
51
|
+
true
|
52
|
+
end
|
53
|
+
|
54
|
+
def user_info(token)
|
55
|
+
get_response('/api/v3/user', token)
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Hieraviz
|
2
|
+
module Config
|
3
|
+
extend self
|
4
|
+
|
5
|
+
def load
|
6
|
+
@_config ||= YAML.load_file(configfile)
|
7
|
+
end
|
8
|
+
|
9
|
+
def configfile
|
10
|
+
file = ENV['HIERAVIZ_CONFIG_FILE'] || File.join("config", "hieraviz.yml")
|
11
|
+
file = File.join(root, file) unless file[0] == '/'
|
12
|
+
file
|
13
|
+
end
|
14
|
+
|
15
|
+
def root
|
16
|
+
File.expand_path('../../../', __FILE__)
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
data/lib/hieraviz/store.rb
CHANGED
@@ -1,16 +1,53 @@
|
|
1
1
|
module Hieraviz
|
2
|
-
|
2
|
+
module Store
|
3
|
+
extend self
|
3
4
|
|
4
|
-
def
|
5
|
-
@
|
5
|
+
def data
|
6
|
+
@_data ||= Hash.new
|
6
7
|
end
|
7
8
|
|
8
9
|
def set(key, value)
|
9
|
-
|
10
|
+
File.open(tmpfile(key), 'w') do |f|
|
11
|
+
f.print Marshal::dump(value)
|
12
|
+
end
|
13
|
+
data[key] = value
|
10
14
|
end
|
11
15
|
|
12
|
-
def get(key)
|
13
|
-
|
16
|
+
def get(key, expiration=false)
|
17
|
+
f = tmpfile(key)
|
18
|
+
if File.exist?(f) && expiration && expired?(f, expiration)
|
19
|
+
File.unlink(f)
|
20
|
+
end
|
21
|
+
if File.exist?(f)
|
22
|
+
data[key] ||= Marshal::load(File.read(f).chomp)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def dump
|
27
|
+
data
|
28
|
+
end
|
29
|
+
|
30
|
+
def tmpfile(name)
|
31
|
+
File.join tmpdir, name.gsub(/[^a-z0-9]/,'')
|
32
|
+
end
|
33
|
+
|
34
|
+
def tmpdir
|
35
|
+
@_tmpdir ||= init_tmpdir
|
36
|
+
end
|
37
|
+
|
38
|
+
def init_tmpdir
|
39
|
+
config = Hieraviz::Config.load
|
40
|
+
tmp = config['tmpdir'] || '/tmp'
|
41
|
+
begin
|
42
|
+
FileUtils.mkdir_p(tmp) unless Dir.exist?(tmp)
|
43
|
+
rescue Exception => e
|
44
|
+
tmp = '/tmp'
|
45
|
+
end
|
46
|
+
tmp
|
47
|
+
end
|
48
|
+
|
49
|
+
def expired?(file, duration)
|
50
|
+
Time.now - duration > File.mtime(file)
|
14
51
|
end
|
15
52
|
|
16
53
|
end
|
data/lib/hieraviz.rb
CHANGED
data/spec/app/apiv1_spec.rb
CHANGED
@@ -1,11 +1,14 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
+
require 'sinatra_helper'
|
2
3
|
|
3
4
|
describe HieravizApp::ApiV1 do
|
4
5
|
|
5
|
-
context "
|
6
|
-
|
7
|
-
|
8
|
-
|
6
|
+
context "without any auth" do
|
7
|
+
context "when GET /v1/nodes" do
|
8
|
+
it "replies error" do
|
9
|
+
get '/nodes'
|
10
|
+
expect(last_response).not_to be_ok
|
11
|
+
end
|
9
12
|
end
|
10
13
|
end
|
11
14
|
|
data/spec/app/web_spec.rb
CHANGED
data/spec/files/config.yml
CHANGED
@@ -2,11 +2,21 @@
|
|
2
2
|
basepath: "spec/files/puppet"
|
3
3
|
classpath: "farm_modules/%s/manifests/init.pp"
|
4
4
|
hierafile: "hiera.yml"
|
5
|
+
session_seed: "toto"
|
6
|
+
tmpdir: "spec/files/tmp"
|
5
7
|
usedb: false
|
6
8
|
puppetdb:
|
7
9
|
usessl: false
|
8
10
|
host: puppetdb.example.com
|
9
11
|
port: 8080
|
12
|
+
auth_method: http
|
10
13
|
http_auth:
|
11
14
|
username: 'toto'
|
12
15
|
password: 'toto'
|
16
|
+
gitlab_auth:
|
17
|
+
host: https://gitlab.example.com
|
18
|
+
application_id: xxxid
|
19
|
+
secret: xxxsecret
|
20
|
+
resource_required: '/api/v3/projects/group%2Fpuppet'
|
21
|
+
required_response_key: 'id'
|
22
|
+
required_response_value: '42'
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Hieraviz::AuthGitlab do
|
4
|
+
|
5
|
+
describe '.new' do
|
6
|
+
end
|
7
|
+
|
8
|
+
describe '.access_token' do
|
9
|
+
end
|
10
|
+
|
11
|
+
describe '.get_response' do
|
12
|
+
end
|
13
|
+
|
14
|
+
describe '.redirect_uri' do
|
15
|
+
end
|
16
|
+
|
17
|
+
describe '.login_url' do
|
18
|
+
end
|
19
|
+
|
20
|
+
describe '.authorized?' do
|
21
|
+
end
|
22
|
+
|
23
|
+
describe '.user_info' do
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Hieraviz::Config do
|
4
|
+
|
5
|
+
describe '.load' do
|
6
|
+
let(:expected) { "spec/files/puppet" }
|
7
|
+
it { expect(Hieraviz::Config.load['basepath']).to eq expected }
|
8
|
+
end
|
9
|
+
|
10
|
+
describe '.configfile' do
|
11
|
+
let(:expected) { File.expand_path('../../files/config.yml', __FILE__) }
|
12
|
+
it { expect(Hieraviz::Config.configfile).to eq expected }
|
13
|
+
end
|
14
|
+
|
15
|
+
describe '.root' do
|
16
|
+
let(:expected) { File.expand_path('../../../', __FILE__) }
|
17
|
+
it { expect(Hieraviz::Config.root).to eq expected }
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|