hieraviz 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|