hieraviz 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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-node=\""+title+"\">Info</span>" +
52
- "<span class=\"showparams\" data-node=\""+title+"\">Params</span>" +
53
- "<span class=\"showallparams\" data-node=\""+title+"\">AllParams</span>" +
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.innerText.toLowerCase();
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.node;
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
- build_top(title);
103
- build_params(meat, title, j);
104
- rebuild_nav(title);
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.node;
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.node;
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
@@ -1,3 +1,5 @@
1
- footer
1
+ <span class="puppetdb">
2
+ <%= settings.configdata['puppetdb']['host'] %>
3
+ </span>
2
4
  <span class="debug">
3
5
  </span>
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 -%>
@@ -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">
@@ -0,0 +1,4 @@
1
+ <div class="meat text">
2
+ <h1>Raw Data</h1>
3
+ <pre><%= @data %></pre>
4
+ </div>
data/app/views/farms.erb CHANGED
@@ -8,7 +8,7 @@
8
8
  </form>
9
9
  <ul>
10
10
  <% @farms.each do |farm| %>
11
- <li class="farm"><%= farm %></li>
11
+ <li class="farm" data-item="<%= farm %>"><%= farm %></li>
12
12
  <% end %>
13
13
  </ul>
14
14
  </div>
data/app/views/home.erb CHANGED
@@ -1,3 +1,8 @@
1
1
  <div class="meat text">
2
- Welcome to hieraviz
2
+ Welcome to hieraviz<br>
3
+
4
+ <% if settings.configdata['debug'] -%>
5
+ <%= session['access_token'] %><br>
6
+ <pre><%= Hieraviz::Store.get session['access_token'] if session['access_token'] %></pre>
3
7
  </div>
8
+ <% end %>
@@ -2,7 +2,8 @@
2
2
  <script async="async" src="js/modules.js"></script>
3
3
  <% end %>
4
4
 
5
- <pre class="meat">
6
- WIP
7
- </pre>
5
+ <div class="meat">
6
+ <br>
7
+ <div>Work In Progress</div>
8
+ </div>
8
9
 
data/app/views/nodes.erb CHANGED
@@ -8,7 +8,7 @@
8
8
  </form>
9
9
  <ul>
10
10
  <% @nodes.each do |node| %>
11
- <li class="node" data-node="<%= node %>"><%= node %></li>
11
+ <li class="node" data-item="<%= node %>"><%= node %></li>
12
12
  <% end %>
13
13
  </ul>
14
14
  </div>
@@ -2,7 +2,7 @@
2
2
  <script src="js/resources.js"></script>
3
3
  <% end %>
4
4
 
5
- <pre class="meat">
6
- WIP
7
- </pre>
8
-
5
+ <div class="meat">
6
+ <br>
7
+ <div>Work In Progress</div>
8
+ </div>
@@ -0,0 +1,6 @@
1
+ <div class="meat text">
2
+ <h1>Store</h1>
3
+ <%= session['access_token'] %><br>
4
+ <pre><%= Hieraviz::Store.dump %></pre>
5
+ <pre><%= Hieraviz::Store.tmpdir %></pre>
6
+ </div>
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('..', __FILE__)
28
+ BetterErrors.application_root = File.expand_path('../../', __FILE__)
25
29
  end
26
30
 
27
- helpers do
28
- def check_cookie
29
- if !session[:hieraviz_key]
30
- newkey = Digest::SHA1.hexdigest(Time.new.to_s)
31
- store.set(:hieraviz_key, newkey)
32
- session[:hieraviz_key] = newkey
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
- def verify_key(key)
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
- use Rack::Auth::Basic, "Puppet Private Access" do |username, password|
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
- erb :farms
122
+ @username = check_authorization
123
+ erb :modules
62
124
  end
63
125
 
64
126
  get '/resources' do
65
- erb :farms
127
+ @username = check_authorization
128
+ erb :resources
66
129
  end
67
130
 
68
- get '/logout' do
69
- erb :logout, layout: :_layout
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
@@ -1,16 +1,53 @@
1
1
  module Hieraviz
2
- class Store
2
+ module Store
3
+ extend self
3
4
 
4
- def initialize
5
- @data = {}
5
+ def data
6
+ @_data ||= Hash.new
6
7
  end
7
8
 
8
9
  def set(key, value)
9
- @data[key.to_sym] = value
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
- @data[key.to_sym]
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
@@ -1,5 +1,7 @@
1
1
  require "hieraviz/version"
2
+ require "hieraviz/config"
2
3
  require "hieraviz/store"
4
+ require "hieraviz/auth_gitlab"
3
5
 
4
6
  module Hieraviz
5
7
  # Your code goes here...
@@ -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 "when GET /v1/nodes" do
6
- it "replies 200" do
7
- get '/nodes'
8
- expect(last_response).to be_ok
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
@@ -1,4 +1,5 @@
1
1
  require 'spec_helper'
2
+ require 'sinatra_helper'
2
3
 
3
4
  describe HieravizApp::Web do
4
5
 
@@ -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