Skip to content

Commit

Permalink
Initial public release 1.0.0
Browse files Browse the repository at this point in the history
  • Loading branch information
Erik Dalén committed Jul 1, 2014
0 parents commit cd2142d
Show file tree
Hide file tree
Showing 29 changed files with 1,574 additions and 0 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/.project
/.settings
/node_modules
/dist
13 changes: 13 additions & 0 deletions COPYING
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
Copyright 2014 Spotify

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
149 changes: 149 additions & 0 deletions Gruntfile.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
module.exports = (grunt) ->
url = require('url')
puppetdb = url.parse(grunt.option('puppetdb') or 'http://127.0.0.1:8080/')
properties = grunt.file.readJSON('package.json')

# Define the configuration for all the tasks
grunt.initConfig
connect:
rules: [ # We use the example config for local development
from: '^/config.js$'
to: '/config.js.example'
]
server:
options:
port: 8000
hostname: 'localhost'
base: 'dist'
keepalive: true
middleware: (connect, options) ->
proxy = require('grunt-connect-proxy/lib/utils').proxyRequest
rewriteRules = require('grunt-connect-rewrite/lib/utils').rewriteRequest
[
# Include the proxy first
proxy

# Then rewrite rules
rewriteRules

# Serve static files.
connect.static(options.base[0])

# Make empty directories browsable.
connect.directory(options.base[0])
]
proxies: [
context: '/api'
host: puppetdb.hostname
port: puppetdb.port or 443
https: puppetdb.protocol is 'https:'
rewrite:
'^/api': ''
]

watch:
coffee:
files: 'app/**/*.coffee'
tasks: ['coffeeify']
static:
files: ['app/**/*.html', 'app/**/*.css', 'app/config.js.example', 'app/favicon.ico']
tasks: ['copy:src']

coffeeify:
options:
debug: true
files:
src: [
'app/**/*.coffee'
]
dest: 'dist/app.js'

copy:
src:
expand: true
cwd: 'app/'
src: ['**/*.html', '**/*.css', 'config.js.example', 'favicon.ico']
dest: 'dist/'
dependencies:
expand: true
cwd: 'node_modules/'
src: [
'jquery/dist/**'
'semantic/build/packaged/**'
'moment/moment.js'
]
dest: 'dist/lib/'

coffee:
compile:
options:
sourceMap: true
expand: true,
cwd: 'app/',
src: ['*.coffee', 'controllers/**/*.coffee', 'services/**/*.coffee'],
dest: 'app/'
ext: '.js'

jshint:
options:
eqeqeq: true
indent: 2
noarg: true
camelcase: true
forin: true
immed: true
latedef: true
newcap: true
noempty: true
nonbsp: true
nonew: true
strict: true
trailing: true
reporter: require('jshint-stylish')

all: [
'app/**/*.js'
]

coffeelint:
options:
configFile: 'coffeelint.json'
all: ['app/**/*.coffee', 'Gruntfile.coffee']

debian_package:
options:
maintainer: properties.author
files:
expand: true
cwd: 'dist'
src: [ '**' ]
dest: "/usr/share/#{properties.name}/"

clean: ['dist', 'tmp']

mocha_casperjs:
files:
src: ['test/**/*.coffee']

grunt.loadNpmTasks 'grunt-contrib-copy'
grunt.loadNpmTasks 'grunt-coffeeify'
grunt.loadNpmTasks 'grunt-contrib-jshint'
grunt.loadNpmTasks 'grunt-coffeelint'
grunt.loadNpmTasks 'grunt-contrib-connect'
grunt.loadNpmTasks 'grunt-connect-rewrite'
grunt.loadNpmTasks 'grunt-connect-proxy'
grunt.loadNpmTasks 'grunt-contrib-coffee'
grunt.loadNpmTasks 'grunt-contrib-watch'
grunt.loadNpmTasks 'grunt-contrib-clean'
grunt.loadNpmTasks 'grunt-debian-package'
grunt.loadNpmTasks 'grunt-mocha-casperjs'

grunt.registerTask 'serve', [
'configureRewriteRules'
'configureProxies:server'
'connect:server'
]
grunt.registerTask 'build', ['clean', 'coffeeify', 'copy']
grunt.registerTask 'build_debian', ['build', 'debian_package']
grunt.registerTask 'default', ['build']
grunt.registerTask 'test', ['mocha_casperjs']
64 changes: 64 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# Puppet Explorer - Never sailed straighter

### Overview

Puppet Explorer is a web application for PuppetDB that lets you explore your
Puppet data.
It is made using AngularJS and CoffeeScript and runs entirely on the client
side, so the only backend that is needed is PuppetDB itself and a web server to
share the static resources.

It has the same query language as the popular Puppet module
[dalen-puppetdbquery](https://forge.puppetlabs.com/dalen/puppetdbquery).
This lets you easily filter for a selection of nodes and show the events or
facts for only them. So you can handle hosts as groups without needing to have
predefined groups, just make them up as you need and click on the pie charts to
drill down further.

All views in the application are made to be able to link directly to them, so
it is easy to share information you find with coworkers.

It has support for multiple PuppetDB servers.

### Dependencies

It is using the V4 PuppetDB API, so therefore it needs PuppetDB 2.0. This is
currently marked as experimental, so PuppetDB 2.1 will likely break
compatibility but we should be able to create a fix for that quickly.

### Screenshots

##### The dashboard:
![The dashboard](screenshots/dashboard.png)

##### Node search:
![Node search](screenshots/nodelist.png)

##### Events view and filtering:
![Events view](screenshots/events.png)

##### Facts view:
![Facts view](screenshots/facts.png)

### Development and local testing

Install all required dependencies using `npm install`, then you can build the
application using `grunt`. The results will be located in the `dist` directory.

Use `grunt serve` to start a local web server pointing to a local PuppetDB
instance.

Optionally you can use the `--puppetdb=url` option to specify a URL to proxy
PuppetDB connections to. Another way is to create a SSH tunnel to your PuppetDB
server, `ssh -L 8080:localhost:8080 puppetdb.example.com`.

With `grunt watch` it will rebuild any source files that changes and put the
results in the `dist` directory.

To build a Debian package use `grunt build_debian`, this requires the
`devscripts` and `debhelper` packages to be installed.

### See also

* [Puppetboard](https://github.com/nedap/puppetboard)
* [Puppet Enterprise](http://puppetlabs.com/puppet/puppet-enterprise)
48 changes: 48 additions & 0 deletions app/app.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
require('semantic/build/packaged/javascript/semantic')
require('angular')
require('angular-route')
require('angular-animate')
require('angular-moment/angular-moment')
require('angular-google-chart/ng-google-chart')

angular.module('app', [
'ngRoute'
'ngAnimate'
'googlechart'
'angularMoment'
]).run ($rootScope, $location, $http, Pagination) ->
# Make the $location service available in root scope
$rootScope.location = $location
$rootScope.isLoading = -> ($http.pendingRequests.length isnt 0)
$rootScope.pagination = Pagination
$rootScope.clearError = ->
$rootScope.error = null
$rootScope.$on('queryChange', $rootScope.clearError)

angular.module('app').factory '$exceptionHandler', ($injector, $log) ->
(exception, cause) ->
$log.error exception, cause
unless cause
$rootScope = $injector.get('$rootScope')
$rootScope.error = exception.message

angular.module('app').config ($routeProvider) ->
$routeProvider.when('/dashboard',
templateUrl: 'controllers/dashboard/dashboard.tpl.html'
controller: 'DashboardCtrl'
).when('/nodes',
templateUrl: 'controllers/nodelist/nodelist.tpl.html'
controller: 'NodeListCtrl'
controllerAs: 'nodeList'
reloadOnSearch: false
).when('/events',
templateUrl: 'controllers/events/events.tpl.html'
controller: 'EventsCtrl'
controllerAs: 'events'
reloadOnSearch: false
).when('/facts',
templateUrl: 'controllers/facts/facts.tpl.html'
controller: 'FactsCtrl'
controllerAs: 'facts'
reloadOnSearch: false
).otherwise redirectTo: '/dashboard'
21 changes: 21 additions & 0 deletions app/config.js.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// List of PuppetDB servers, pairs of name and URL
// The first one will be used as the default server
PUPPETDB_SERVERS = [
['production', '/api'],
['testing', '/api']
];

// A list of important facts that you want shown in the node detail view
NODE_FACTS = [
'operatingsystem',
'operatingsystemrelease',
'manufacturer',
'productname',
'processorcount',
'memorytotal',
'ipaddress'
];

// Google Analytics settings
GA_TRACKING_ID = 'UA-XXXXXXXX-YY';
GA_DOMAIN = 'auto';
14 changes: 14 additions & 0 deletions app/controllers/dashboard/dashboard.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
angular.module("app").controller "DashboardCtrl", ($scope, PuppetDB) ->
getBean = (name, scope, multiply = 1, bean = 'com.puppetlabs.puppetdb.query.population') ->
PuppetDB.query("metrics/mbean/#{bean}:type=default,name=#{name}")
.success (data) ->
$scope[scope] = (angular.fromJson(data).Value * multiply)
.toLocaleString()
.replace(/^(.*\..).*/, "$1")
.error (data) ->
console?.log "Could not get #{name} from PuppetDB"

getBean('num-nodes', 'activeNodes')
getBean('num-resources', 'resources')
getBean('avg-resources-per-node', 'avgResources')
getBean('pct-resource-dupes', 'resDuplication', 100)
Loading

0 comments on commit cd2142d

Please sign in to comment.