├── .build.yml ├── .gitignore ├── CHANGELOG.md ├── Configuration.md ├── Dockerfile ├── Dockerfile_Build ├── Gruntfile.js ├── Installation.md ├── LICENSE ├── README.md ├── amc.dev.conf ├── common ├── alert.go ├── backup_restore.go ├── config.go ├── parser.go ├── remote_job.go ├── set.go ├── stats.go ├── sync_value.go ├── types.go └── utils.go ├── controllers ├── backup_restore.go ├── cluster.go ├── common.go ├── enterprise.go ├── main.go ├── main_enterprise.go ├── middleware │ └── sessions │ │ ├── cookie.go │ │ └── sessions.go ├── session.go ├── users.go └── xdr.go ├── deployment ├── common │ ├── amc.conf │ ├── amc.deb │ ├── amc.docker.sh │ ├── amc.other.sh │ ├── amc.rpm │ ├── amc.service │ └── systemd_after_install.sh └── release │ ├── darwin │ ├── LaunchAgents │ │ └── com.aerospike.amc.plist │ ├── Logs │ │ └── amc │ │ │ └── .placeholder │ └── amc │ │ ├── amc.conf │ │ └── uninstall.sh │ └── linux │ ├── etc │ └── amc │ │ └── amc.conf │ └── var │ └── log │ └── amc │ └── .placeholder ├── go-time-series ├── LICENSE ├── README.md ├── glide.lock ├── glide.yaml ├── level.go └── timeseries.go ├── go.mod ├── go.sum ├── mailer ├── mailer.go └── templates │ ├── alerts │ └── generic.html │ └── base.html ├── main_darwin.go ├── main_linux.go ├── make.sh ├── models ├── attr_aliases.go ├── backup.go ├── cluster.go ├── namespace.go ├── namespace_notifications.go ├── node.go ├── node_notifications.go ├── observer.go └── restore.go ├── package-lock.json ├── package.json ├── rrd ├── rrd.go ├── rrd_test.go └── simple_bucket.go ├── run.sh ├── server-dev.sh ├── static ├── css │ ├── alerts.css │ ├── common.css │ ├── fonts │ │ ├── MavenPro-Regular.ttf │ │ └── icomoon.ttf │ ├── grid │ │ └── 960.css │ ├── icons.css │ ├── jqgrid │ │ ├── images │ │ │ ├── ui-icons_2e83ff_256x240.png │ │ │ └── ui-icons_888888_256x240.png │ │ ├── nav.buttons.jquerui.css │ │ └── ui.jqgrid.css │ ├── jqueryui │ │ ├── images │ │ │ ├── animated-overlay.gif │ │ │ ├── ui-bg_flat_30_cccccc_40x100.png │ │ │ ├── ui-bg_flat_50_5c5c5c_40x100.png │ │ │ ├── ui-bg_glass_20_555555_1x400.png │ │ │ ├── ui-bg_glass_40_0078a3_1x400.png │ │ │ ├── ui-bg_glass_40_ffc73d_1x400.png │ │ │ ├── ui-bg_glass_75_d0e5f5_1x400.png │ │ │ ├── ui-bg_gloss-wave_25_333333_500x100.png │ │ │ ├── ui-bg_highlight-soft_80_eeeeee_1x100.png │ │ │ ├── ui-bg_inset-hard_100_fcfdfd_1x100.png │ │ │ ├── ui-bg_inset-soft_25_000000_1x100.png │ │ │ ├── ui-bg_inset-soft_30_f58400_1x100.png │ │ │ ├── ui-icons_222222_256x240.png │ │ │ ├── ui-icons_4b8e0b_256x240.png │ │ │ ├── ui-icons_a83300_256x240.png │ │ │ ├── ui-icons_cccccc_256x240.png │ │ │ └── ui-icons_ffffff_256x240.png │ │ └── jquery-ui-1.10.4.custom.min.css │ ├── sprite.css │ ├── sprite.png │ ├── timeseries.css │ └── vertical-tabs.css ├── images │ ├── arrow_down.svg │ ├── arrow_up.svg │ ├── bg-btn-blue.png │ ├── bg-btn-grey.png │ ├── cog.png │ ├── favicon.png │ ├── link.png │ ├── loading.gif │ └── sidepanelpattern.png ├── index.html └── js │ ├── collections │ ├── common │ │ └── MultiClusters.js │ ├── configs │ │ ├── namespaces.js │ │ ├── nodes.js │ │ ├── sindex.js │ │ └── xdr.js │ ├── dashboard │ │ ├── clusterwidenamespaces.js │ │ ├── namespaces.js │ │ ├── nodes.js │ │ └── xdrs.js │ ├── definitions │ │ ├── sets.js │ │ ├── sindexes.js │ │ ├── udf.js │ │ └── xdrs.js │ ├── jobs │ │ └── nodes.js │ ├── latency │ │ └── nodes.js │ └── statistics │ │ ├── namespaces.js │ │ ├── nodes.js │ │ ├── sindex.js │ │ └── xdr.js │ ├── config │ ├── app-config.js │ ├── var-details.js │ └── view-config.js │ ├── dev.app.build.js │ ├── helper │ ├── AjaxManager.js │ ├── authmanager.js │ ├── bulletchart.js │ ├── command-line.js │ ├── def-table.js │ ├── definitions │ │ ├── set-table.js │ │ ├── sindex-table.js │ │ ├── udf-table.js │ │ └── xdr-table.js │ ├── drilldown-charts.js │ ├── edit-config.js │ ├── job-table.js │ ├── jqgrid-helper.js │ ├── login.js │ ├── modal.js │ ├── namespace-clusterwide-table.js │ ├── namespace-table.js │ ├── node-table.js │ ├── notification.js │ ├── overlay.js │ ├── piechart.js │ ├── servicemanager.js │ ├── sessionmanager.js │ ├── stat-table.js │ ├── timechart-helper.js │ ├── toggle.js │ ├── usermanager.js │ ├── util.js │ └── xdr-table.js │ ├── libs │ ├── backbone │ │ ├── backbone-min.js │ │ ├── backbone.js │ │ └── backbone.poller.js │ ├── d3 │ │ ├── d3.js │ │ └── d3.layout.min.js │ ├── jquery │ │ └── consolidated-jquery-functionalities.min.js │ ├── require │ │ └── require.js │ ├── spin │ │ └── spin.min.js │ ├── timechart │ │ └── timechart.js │ └── underscore │ │ ├── underscore-min.js │ │ └── underscore.js │ ├── models │ ├── common │ │ ├── AlertEmailsModel.js │ │ ├── MultiCluster.js │ │ ├── PopupModel.js │ │ └── alertmodel.js │ ├── configs │ │ ├── backupmodel.js │ │ ├── clustermodel.js │ │ ├── restoremodel.js │ │ ├── roleadminmodel.js │ │ ├── statmodel.js │ │ └── useradminmodel.js │ ├── dashboard │ │ ├── clustermodel.js │ │ ├── clusterwidenamespacemodel.js │ │ ├── namespacemodel.js │ │ ├── nodemodel.js │ │ ├── throughputmodel.js │ │ └── xdrmodel.js │ ├── definitions │ │ ├── clustermodel.js │ │ ├── setsmodel.js │ │ ├── sindexmodel.js │ │ ├── storagemodel.js │ │ ├── udfmodel.js │ │ └── xdrmodel.js │ ├── jobs │ │ ├── clustermodel.js │ │ └── nodemodel.js │ ├── latency │ │ ├── clustermodel.js │ │ ├── nodeCentralisedModel.js │ │ └── nodemodel.js │ └── statistics │ │ ├── clustermodel.js │ │ ├── statmodel.js │ │ └── stattracker.js │ ├── onepage.js │ ├── prod.app.build.js │ ├── setup.js │ └── views │ ├── common │ ├── AlertEmailsView.js │ ├── MultiClusterView.js │ ├── alertview.js │ └── nodelistview.js │ ├── configs │ ├── backupview.js │ ├── restoreview.js │ ├── roleadminview.js │ ├── statview.js │ └── useradminview.js │ ├── dashboard │ ├── clusterwidenamespaceview.js │ ├── namespaceview.js │ ├── nodeview.js │ ├── pieview.js │ ├── summaryView.js │ ├── throughputview.js │ └── xdrview.js │ ├── definitions │ ├── setsview.js │ ├── sindexview.js │ ├── storageview.js │ ├── udfview.js │ └── xdrview.js │ ├── jobs │ └── nodeview.js │ ├── latency │ └── nodeview.js │ └── statistics │ ├── stattrackerview.js │ └── statview.js └── tools └── load ├── client.go ├── main └── main.go └── response └── types.go /.build.yml: -------------------------------------------------------------------------------- 1 | name: aerospike-console 2 | dir: src/github.com/aerospike-community/amc 3 | 4 | container: 5 | - base: 6 | - docker.qe.aerospike.com/build/amc:golang-1.11 7 | 8 | environment: 9 | GOPATH: /work/source 10 | BIN: $GOPATH/bin 11 | REPO: github.com/aerospike-community/amc 12 | CGO_ENABLED: 0 13 | 14 | build: 15 | - name: default 16 | script: 17 | - ls -la 18 | - cd src/$REPO 19 | - ./make.sh enterprise prod linux 20 | - ./make.sh community prod linux 21 | - ./make.sh enterprise prod darwin 22 | - ./make.sh community prod darwin 23 | artifact: 24 | - aerospike-amc-*.deb 25 | - aerospike-amc-*.rpm 26 | - aerospike-amc-*.gz 27 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode/ 2 | node_modules/ 3 | build/ 4 | amc.db3 5 | deployment/release/amc/opt/amc/amc 6 | deployment/release/amc/opt/amc/static 7 | deployment/release/amc/opt/amc/mailer 8 | amc 9 | *.todo 10 | amc.db.old 11 | amc.db 12 | 13 | aerospike-amc-enterprise-*.deb 14 | aerospike-amc-enterprise-*.rpm 15 | aerospike-amc-enterprise-*.tar.gz 16 | 17 | .71e384d8029d70a336275f921ad8b1f595c99da7 18 | .05294f73cd9a9a4b5633cc6b9b64eb362bddcae1 19 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:stretch-slim 2 | 3 | ARG AMC_VERSION=5.0.0 4 | 5 | RUN apt update -y \ 6 | && apt -y install wget procps \ 7 | && wget https://github.com/aerospike-community/amc/releases/download/${AMC_VERSION}/aerospike-amc-enterprise-${AMC_VERSION}_amd64.deb --no-check-certificate \ 8 | && dpkg -i aerospike-amc-enterprise-${AMC_VERSION}_amd64.deb \ 9 | && rm aerospike-amc-enterprise-${AMC_VERSION}_amd64.deb \ 10 | && dpkg -r wget ca-certificates \ 11 | && dpkg --purge wget ca-certificates \ 12 | && apt-get purge -y \ 13 | && apt autoremove -y 14 | 15 | COPY ./deployment/common/amc.docker.sh /opt/amc/amc.docker.sh 16 | 17 | EXPOSE 8081 18 | 19 | ENTRYPOINT [ "/opt/amc/amc.docker.sh", "amc" ] 20 | -------------------------------------------------------------------------------- /Dockerfile_Build: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | # build/golang:1.7 3 | ################################################################################ 4 | 5 | # Base Image 6 | FROM golang:1.7 7 | 8 | # Dependencies 9 | RUN apt-get update 10 | RUN apt-get install -y build-essential 11 | 12 | RUN apt-get install -y curl 13 | RUN curl -sL https://deb.nodesource.com/setup_6.x | bash - 14 | RUN apt-get install -y nodejs 15 | 16 | RUN npm install grunt -g 17 | 18 | RUN apt-get install -y ruby ruby-dev rubygems gcc make 19 | RUN gem install --no-ri --no-rdoc fpm 20 | RUN apt-get install -y rpm 21 | 22 | RUN apt-get install -y zip tar gzip 23 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function(grunt) { 2 | grunt.initConfig({ 3 | // clean directory 4 | clean: { 5 | build: 'build/' 6 | }, 7 | 8 | // copy directory 9 | copy: { 10 | build: { 11 | expand: true, 12 | src: 'static/**', 13 | dest: 'build/' 14 | } 15 | }, 16 | 17 | // revision javascript and css files 18 | filerev: { 19 | options: { 20 | algorithm: 'md5', 21 | length: 8 22 | }, 23 | js: { 24 | src: [ 25 | // exclude lib directory 26 | 'build/static/js/*.js', 27 | 'build/static/js/collections/**/*.js', 28 | 'build/static/js/config/**/*.js', 29 | 'build/static/js/helper/**/*.js', 30 | 'build/static/js/models/**/*.js', 31 | 'build/static/js/views/**/*.js', 32 | ] 33 | }, 34 | css: { 35 | src: 'build/static/css/**/*.css', 36 | }, 37 | }, 38 | 39 | // replace filenames with revisioned file names 40 | filerev_replace: { 41 | options: { 42 | assets_root: 'build', 43 | }, 44 | html: { 45 | src: 'build/static/index.html', 46 | }, 47 | }, 48 | 49 | // filerev_replace does not replace data-main argument supplied to 50 | // requirejs, doing that here 51 | replace: { 52 | requirejs: { 53 | src: 'build/static/index.html', 54 | overwrite: true, 55 | replacements: [{ 56 | // replace data-main with the revisioned file name 57 | from: 'static/js/setup', 58 | to: function(match) { 59 | var k, v; 60 | for(k in grunt.filerev.summary) { 61 | v = grunt.filerev.summary[k]; 62 | if(k.indexOf('static/js/setup') !== -1) { 63 | // remove prefix 'build/' and suffix '.js' 64 | return v.slice('build/'.length, -1*'.js'.length); 65 | } 66 | } 67 | return match; 68 | } 69 | }], 70 | }, 71 | }, 72 | 73 | // minify javascript files 74 | uglify: { 75 | options: { 76 | sourceMap: true, 77 | sourceMapIncludeSources: true, 78 | }, 79 | js: { 80 | files: [{ 81 | expand: true, 82 | src: ['build/static/js/**/*.js'], 83 | dest: '', // overwrite original files 84 | }] 85 | }, 86 | }, 87 | 88 | // minify css files 89 | cssmin: { 90 | css: { 91 | files: [{ 92 | expand: true, 93 | src: ['build/static/css/**/*.css'], 94 | dest: '', // overwrite original files 95 | }] 96 | } 97 | }, 98 | 99 | }); 100 | 101 | // Configure requirejs paths to serve revved files 102 | grunt.registerTask('require-paths', '', function() { 103 | var config = concatConfig(); 104 | var file = findMainConfigFile(); 105 | grunt.file.write(file, config); 106 | return; 107 | 108 | // concat revved config and original config 109 | function concatConfig() { 110 | var config = 'require.config({ paths: {'; 111 | var k, v; 112 | for(k in grunt.filerev.summary) { 113 | v = grunt.filerev.summary[k]; 114 | if(k.indexOf('.js') !== -1) { 115 | // remove prefix 'build/static/js/' and suffix '.js' 116 | k = k.slice('build/static/js/'.length, -1*'.js'.length); 117 | v = v.slice('build/static/js/'.length, -1*'.js'.length); 118 | config += "'" + k + "'" + ":" + "'" + v + "'" + ", \n"; 119 | } 120 | } 121 | config += '}});'; 122 | // add original config 123 | config += '\n' + grunt.file.read('static/js/setup.js'); 124 | return config; 125 | } 126 | 127 | // find the main config file for requirejs 128 | function findMainConfigFile() { 129 | var k, v; 130 | for(k in grunt.filerev.summary) { 131 | v = grunt.filerev.summary[k]; 132 | // setup.js is the main config file for requirejs 133 | if(k.indexOf('setup.js') !== -1) { 134 | return v; 135 | } 136 | } 137 | } 138 | }); 139 | 140 | // load modules 141 | grunt.loadNpmTasks('grunt-contrib-cssmin'); 142 | grunt.loadNpmTasks('grunt-contrib-clean'); 143 | grunt.loadNpmTasks('grunt-contrib-copy'); 144 | grunt.loadNpmTasks('grunt-contrib-uglify'); 145 | grunt.loadNpmTasks('grunt-filerev'); 146 | grunt.loadNpmTasks('grunt-filerev-replace'); 147 | grunt.loadNpmTasks('grunt-text-replace'); 148 | 149 | grunt.registerTask('default', ['clean', 'copy', 'filerev', 'filerev_replace', 'replace', 'require-paths', 'uglify', 'cssmin']); 150 | } 151 | 152 | -------------------------------------------------------------------------------- /Installation.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Upgrade to AMC 4.0 3 | description: Learn how to upgrade to AMC 4.0 4 | --- 5 | 6 | Upgrade to AMC 4.0 and above from previous versions. 7 | 8 | ### Debian Based Systems like Debian, Ubuntu 9 | 10 | 1. uninstall the older amc version 11 | ``` 12 | sudo dpkg -P aerospike-amc- 13 | ``` 14 | 15 | 2. install AMC 16 | ``` 17 | sudo dpkg -i aerospike-amc--.deb 18 | ``` 19 | 20 | 3. start AMC 21 | ``` 22 | sudo service amc start 23 | ``` 24 | 25 | 3. stop AMC 26 | ``` 27 | sudo service amc stop 28 | ``` 29 | 30 | ### RPM Based Systems like CentOS, Red Hat 31 | 1. uninstall the older amc version 32 | ``` 33 | sudo rpm -e aerospike-amc- 34 | ``` 35 | 36 | 2. install dependencies 37 | ``` 38 | sudo yum install -y initscripts 39 | ``` 40 | 41 | 3. install AMC 42 | ``` 43 | sudo rpm -i aerospike-amc--.rpm 44 | ``` 45 | 46 | 4. start AMC 47 | ``` 48 | sudo service amc start 49 | ``` 50 | 51 | 5. stop AMC 52 | ``` 53 | sudo service amc stop 54 | ``` 55 | 56 | ### zip installation 57 | 1. install AMC 58 | ``` 59 | tar -xvf aerospike-amc--.tar.gz -C / 60 | ``` 61 | 62 | 2. start AMC 63 | ``` 64 | sudo /etc/init.d/amc start 65 | ``` 66 | 67 | 3. stop AMC 68 | ``` 69 | sudo /etc/init.d/amc stop 70 | ``` 71 | 72 | ### MacOS 73 | 74 | 1. install AMC 75 | ``` 76 | sudo tar -xvf aerospike-amc---darwin.tar.gz -C /Library 77 | ``` 78 | 79 | 2. start AMC 80 | ``` 81 | sudo launchctl load /Library/LaunchAgents/com.aerospike.amc.plist 82 | ``` 83 | 84 | 3. stop AMC 85 | ``` 86 | sudo launchctl unload /Library/LaunchAgents/com.aerospike.amc.plist 87 | ``` 88 | 89 | -------------------------------------------------------------------------------- /amc.dev.conf: -------------------------------------------------------------------------------- 1 | [AMC] 2 | update_interval = 5 3 | #certfile = "" 4 | #keyfile = "" 5 | #Example : File paths should be double quoted. 6 | #certfile = "/home/amc/self-ssl.crt" 7 | #keyfile = "/home/amc/self-ssl.key" 8 | 9 | database = "/home/zohar/go/src/github.com/aerospike-community/amc/amc.db" 10 | 11 | bind = "0.0.0.0:8081" 12 | pidfile = "/tmp/amc.pid" 13 | loglevel = "debug" 14 | errorlog = "/home/zohar/go/src/github.com/aerospike-community/amc/amc.log" 15 | chdir = "/home/zohar/go/src/github.com/aerospike-community/amc/" 16 | static_dir = "/home/zohar/go/src/github.com/aerospike-community/amc/static" 17 | timeout = 150 18 | 19 | # when you start monitoring a cluster, it will be polled activaly in the background. 20 | # this setting determines how long will that clustered be kept after it is not polled anymore. 21 | # This setting will not affect the clusters in the [amc.clusters] section. 22 | # values <= 0 mean never remove. 23 | cluster_inactive_before_removal = 1800 24 | 25 | [amc.clusters] 26 | 27 | # [amc.clusters.db1] 28 | # host = "ubvm" 29 | #tls_name = 30 | # port = 3000 31 | #user = "admin" 32 | #password = "admin" 33 | #alias = 34 | 35 | [amc.clusters.db2] 36 | host = "172.17.0.3" 37 | #tls_name = "" 38 | port = 3000 39 | #user = "admin" 40 | #password = "admin" 41 | #alias = 42 | show_in_ui = true 43 | 44 | [mailer] 45 | template_path = "/home/zohar/go/src/github.com/aerospike-community/amc/mailer/templates" 46 | #host = "smtp.outlook.com" 47 | #port = 587 48 | #user = "" 49 | #password = "" 50 | #send_to = ["khosrow@aerospike.com"] 51 | accept_invalid_cert = true 52 | 53 | [basic_auth] 54 | # you can also set $AMC_AUTH_USER env variable 55 | #user = "admin" 56 | # you can also set $AMC_AUTH_PASSWORD env variable 57 | #password = "admin" 58 | 59 | [TLS] 60 | 61 | # name of cert files to add to the pool for TLS connections 62 | # All entries should be a string 63 | server_cert_pool = [ 64 | "/home/zohar/go/src/github.com/aerospike-community/amc/cert.pem", 65 | ] 66 | 67 | [tls.client_certs] 68 | 69 | # [tls.client_certs.a] 70 | # cert_file="/Users/khosrow/as_certs/ca/subject/ClusterName-a-Chainless/cert.pem" 71 | # key_file="/Users/khosrow/as_certs/ca/subject/ClusterName-a-Chainless/key.pem" 72 | 73 | # [tls.client_certs.b] 74 | # cert_file="/Users/khosrow/as_certs/ca/subject/ClusterName-a-Chainless/cluster_chainless_chain.pem" 75 | # key_file="/Users/khosrow/as_certs/ca/subject/ClusterName-a-Chainless/key.pem" 76 | -------------------------------------------------------------------------------- /common/parser.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import ( 4 | "bufio" 5 | "fmt" 6 | "strconv" 7 | "strings" 8 | ) 9 | 10 | // InfoParser struct 11 | type InfoParser struct { 12 | *bufio.Reader 13 | } 14 | 15 | // NewInfoParser - new info parser 16 | func NewInfoParser(s string) *InfoParser { 17 | return &InfoParser{bufio.NewReader(strings.NewReader(s))} 18 | } 19 | 20 | // Expect expect a value, assert if not expected value 21 | func (ip *InfoParser) Expect(s string) error { 22 | bytes := make([]byte, len(s)) 23 | v, err := ip.Read(bytes) 24 | if err != nil { 25 | return err 26 | } 27 | if string(bytes) != s { 28 | return fmt.Errorf("InfoParser: Wrong value. Expected %s, found %d", s, v) 29 | } 30 | return nil 31 | } 32 | 33 | // ReadUntil - read until delimiter 34 | func (ip *InfoParser) ReadUntil(delim byte) (string, error) { 35 | v, err := ip.ReadBytes(delim) 36 | 37 | switch len(v) { 38 | case 0: 39 | return string(v), err 40 | case 1: 41 | if v[0] == delim { 42 | return "", err 43 | } 44 | return string(v), err 45 | } 46 | return string(v[:len(v)-1]), err 47 | } 48 | 49 | // ReadFloat - read float 50 | func (ip *InfoParser) ReadFloat(delim byte) (float64, error) { 51 | s, err := ip.ReadUntil(delim) 52 | if err != nil { 53 | return 0, err 54 | } 55 | 56 | return strconv.ParseFloat(s, 64) 57 | } 58 | 59 | // func (ip *InfoParser) ReadTime(delim byte) (time.Time, error) { 60 | // s, err := ip.ReadUntil(delim) 61 | // if err != nil { 62 | // return time.Time{}, err 63 | // } 64 | 65 | // return time.Parse("2013-02-03 12:13:11-GMT", s) 66 | // } 67 | -------------------------------------------------------------------------------- /common/remote_job.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "io/ioutil" 7 | "net" 8 | "os" 9 | "strings" 10 | 11 | "golang.org/x/crypto/ssh" 12 | "golang.org/x/crypto/ssh/agent" 13 | ) 14 | 15 | // SSHCommand struct 16 | type SSHCommand struct { 17 | Path string 18 | Env []string 19 | Stdin io.Reader 20 | Stdout io.Writer 21 | Stderr io.Writer 22 | } 23 | 24 | // SSHClient struct 25 | type SSHClient struct { 26 | Config *ssh.ClientConfig 27 | Host string 28 | Port int 29 | } 30 | 31 | // RunCommand - run ssh command 32 | func (client *SSHClient) RunCommand(cmd *SSHCommand) error { 33 | var ( 34 | session *ssh.Session 35 | err error 36 | ) 37 | 38 | if session, err = client.newSession(); err != nil { 39 | return err 40 | } 41 | 42 | defer session.Close() 43 | 44 | if err = client.prepareCommand(session, cmd); err != nil { 45 | session.Close() 46 | return err 47 | } 48 | 49 | err = session.Run(cmd.Path) 50 | return err 51 | } 52 | 53 | // Session - return new ssh session 54 | func (client *SSHClient) Session(cmd *SSHCommand) (*ssh.Session, error) { 55 | return client.newSession() 56 | } 57 | 58 | // prepareCommand - prepare the command 59 | func (client *SSHClient) prepareCommand(session *ssh.Session, cmd *SSHCommand) error { 60 | for _, env := range cmd.Env { 61 | variable := strings.Split(env, "=") 62 | if len(variable) != 2 { 63 | continue 64 | } 65 | 66 | if err := session.Setenv(variable[0], variable[1]); err != nil { 67 | return err 68 | } 69 | } 70 | 71 | if cmd.Stdin != nil { 72 | stdin, err := session.StdinPipe() 73 | if err != nil { 74 | return fmt.Errorf("Unable to setup stdin for session: %v", err) 75 | } 76 | go io.Copy(stdin, cmd.Stdin) 77 | } 78 | 79 | if cmd.Stdout != nil { 80 | stdout, err := session.StdoutPipe() 81 | if err != nil { 82 | return fmt.Errorf("Unable to setup stdout for session: %v", err) 83 | } 84 | go io.Copy(cmd.Stdout, stdout) 85 | } 86 | 87 | if cmd.Stderr != nil { 88 | stderr, err := session.StderrPipe() 89 | if err != nil { 90 | return fmt.Errorf("Unable to setup stderr for session: %v", err) 91 | } 92 | go io.Copy(cmd.Stderr, stderr) 93 | } 94 | 95 | return nil 96 | } 97 | 98 | func (client *SSHClient) newSession() (*ssh.Session, error) { 99 | connection, err := ssh.Dial("tcp", fmt.Sprintf("%s:%d", client.Host, client.Port), client.Config) 100 | if err != nil { 101 | return nil, fmt.Errorf("Failed to dial: %s", err) 102 | } 103 | 104 | session, err := connection.NewSession() 105 | if err != nil { 106 | return nil, fmt.Errorf("Failed to create session: %s", err) 107 | } 108 | 109 | // modes := ssh.TerminalModes{ 110 | // // ssh.ECHO: 0, // disable echoing 111 | // ssh.TTY_OP_ISPEED: 14400, // input speed = 14.4kbaud 112 | // ssh.TTY_OP_OSPEED: 14400, // output speed = 14.4kbaud 113 | // } 114 | 115 | if err := session.RequestPty("xterm", 80, 40, nil); err != nil { 116 | session.Close() 117 | return nil, fmt.Errorf("request for pseudo terminal failed: %s", err) 118 | } 119 | 120 | return session, nil 121 | } 122 | 123 | // PublicKeyFile - return Public Key 124 | func PublicKeyFile(file string) ssh.AuthMethod { 125 | buffer, err := ioutil.ReadFile(file) 126 | if err != nil { 127 | return nil 128 | } 129 | 130 | key, err := ssh.ParsePrivateKey(buffer) 131 | if err != nil { 132 | return nil 133 | } 134 | return ssh.PublicKeys(key) 135 | } 136 | 137 | // SSHAgent - get agent 138 | func SSHAgent() ssh.AuthMethod { 139 | if sshAgent, err := net.Dial("unix", os.Getenv("SSH_AUTH_SOCK")); err == nil { 140 | return ssh.PublicKeysCallback(agent.NewClient(sshAgent).Signers) 141 | } 142 | return nil 143 | } 144 | 145 | // func main() { 146 | // // ssh.Password("your_password") 147 | // sshConfig := &ssh.ClientConfig{ 148 | // User: "jsmith", 149 | // Auth: []ssh.AuthMethod{ 150 | // SSHAgent(), 151 | // }, 152 | // } 153 | 154 | // client := &SSHClient{ 155 | // Config: sshConfig, 156 | // Host: "example.com", 157 | // Port: 22, 158 | // } 159 | 160 | // cmd := &SSHCommand{ 161 | // Path: "ls -l $LC_DIR", 162 | // Env: []string{"LC_DIR=/"}, 163 | // Stdin: os.Stdin, 164 | // Stdout: os.Stdout, 165 | // Stderr: os.Stderr, 166 | // } 167 | 168 | // fmt.Printf("Running command: %s\n", cmd.Path) 169 | // if err := client.RunCommand(cmd); err != nil { 170 | // fmt.Fprintf(os.Stderr, "command run error: %s\n", err) 171 | // os.Exit(1) 172 | // } 173 | // } 174 | -------------------------------------------------------------------------------- /common/set.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | // StrUniq is checking for uniqe strings 4 | func StrUniq(l []string) []string { 5 | if len(l) == 0 { 6 | return nil 7 | } 8 | 9 | set := map[string]struct{}{} 10 | for i := range l { 11 | set[l[i]] = struct{}{} 12 | } 13 | 14 | result := make([]string, 0, len(set)) 15 | for k := range set { 16 | result = append(result, k) 17 | } 18 | 19 | return result 20 | } 21 | -------------------------------------------------------------------------------- /common/sync_value.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import "sync" 4 | 5 | // SyncValue struct 6 | type SyncValue struct { 7 | value interface{} 8 | mutex sync.RWMutex 9 | } 10 | 11 | // NewSyncValue - new sync value 12 | func NewSyncValue(val interface{}) SyncValue { 13 | return SyncValue{ 14 | value: val, 15 | } 16 | } 17 | 18 | // Get - get sync value 19 | func (sv *SyncValue) Get() interface{} { 20 | sv.mutex.RLock() 21 | v := sv.value 22 | sv.mutex.RUnlock() 23 | return v 24 | } 25 | 26 | // Set - set sync value 27 | func (sv *SyncValue) Set(val interface{}) { 28 | sv.mutex.Lock() 29 | sv.value = val 30 | sv.mutex.Unlock() 31 | } 32 | -------------------------------------------------------------------------------- /common/types.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import ( 4 | "database/sql/driver" 5 | "time" 6 | ) 7 | 8 | // JSONRawString - Value should be a string 9 | type JSONRawString string 10 | 11 | // MarshalJSON returns *m as the JSON encoding of m. 12 | func (m *JSONRawString) MarshalJSON() ([]byte, error) { 13 | return []byte(*m), nil 14 | } 15 | 16 | // IndexType - Value should be a string 17 | type IndexType string 18 | 19 | var indexType = struct { 20 | STRING IndexType 21 | NUMERIC IndexType 22 | }{"string", "numeric"} 23 | 24 | // NullTime to store time and nullibility 25 | type NullTime struct { 26 | time time.Time 27 | valid bool // Valid is true if Time is not NULL 28 | } 29 | 30 | // Set - sets the time 31 | func (nt *NullTime) Set(t time.Time) { 32 | nt.time = t 33 | nt.valid = true 34 | } 35 | 36 | // Valid - check if Time is not NULL 37 | func (nt *NullTime) Valid() bool { 38 | return nt.valid 39 | } 40 | 41 | // Scan implements the Scanner interface. 42 | func (nt *NullTime) Scan(value interface{}) error { 43 | nt.time, nt.valid = value.(time.Time) 44 | return nil 45 | } 46 | 47 | // Value implements the driver Valuer interface. 48 | func (nt NullTime) Value() (driver.Value, error) { 49 | if !nt.valid { 50 | return nil, nil 51 | } 52 | return nt.time, nil 53 | } 54 | -------------------------------------------------------------------------------- /common/utils.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import ( 4 | "database/sql" 5 | "errors" 6 | "fmt" 7 | "math" 8 | "sort" 9 | "strconv" 10 | "strings" 11 | "time" 12 | ) 13 | 14 | // SplitHostPort - convert aerospike host string to basic parts 15 | func SplitHostPort(addr string) (host string, port int, err error) { 16 | addr = strings.Trim(addr, "\t\n\r ") 17 | if len(addr) == 0 { 18 | return "", 0, errors.New("Invalid address: " + addr) 19 | } 20 | 21 | index := strings.LastIndex(addr, ":") 22 | if index < 0 || len(addr) < index { 23 | return addr, 0, errors.New("Invalid address: " + addr) 24 | } 25 | 26 | portStr := addr[index+1:] 27 | if len(portStr) > 0 { 28 | var err error 29 | port, err = strconv.Atoi(portStr) 30 | if err != nil { 31 | return addr, 0, err 32 | } 33 | } 34 | return addr[:index], port, nil 35 | } 36 | 37 | // Round - convert float to rounded int 38 | func Round(val float64, roundOn float64, places int) (newVal float64) { 39 | var round float64 40 | pow := math.Pow(10, float64(places)) 41 | digit := pow * val 42 | _, div := math.Modf(digit) 43 | if div >= roundOn { 44 | round = math.Ceil(digit) 45 | } else { 46 | round = math.Floor(digit) 47 | } 48 | newVal = round / pow 49 | return 50 | } 51 | 52 | // DeleteEmpty - remove empty item from slice 53 | func DeleteEmpty(s []string) []string { 54 | var r []string 55 | for _, str := range s { 56 | if strings.Trim(str, " ") != "" { 57 | r = append(r, str) 58 | } 59 | } 60 | return r 61 | } 62 | 63 | // StrDiff - compare slices into added and remove slices 64 | func StrDiff(o, n []string) (added, removed []string) { 65 | for _, sn := range n { 66 | exists := false 67 | for _, so := range o { 68 | if sn == so { 69 | exists = true 70 | break 71 | } 72 | } 73 | if !exists { 74 | added = append(added, sn) 75 | } 76 | } 77 | 78 | for _, so := range o { 79 | exists := false 80 | for _, sn := range n { 81 | if sn == so { 82 | exists = true 83 | break 84 | } 85 | } 86 | if !exists { 87 | removed = append(removed, so) 88 | } 89 | } 90 | 91 | return added, removed 92 | } 93 | 94 | // Comma - convert integer into comma string 95 | func Comma(v int64, sep string) string { 96 | sign := "" 97 | 98 | // minin64 can't be negated to a usable value, so it has to be special cased. 99 | if v == math.MinInt64 { 100 | return "-9,223,372,036,854,775,808" 101 | } 102 | 103 | if v < 0 { 104 | sign = "-" 105 | v = 0 - v 106 | } 107 | 108 | parts := []string{"", "", "", "", "", "", ""} 109 | j := len(parts) - 1 110 | 111 | for v > 999 { 112 | parts[j] = strconv.FormatInt(v%1000, 10) 113 | switch len(parts[j]) { 114 | case 2: 115 | parts[j] = "0" + parts[j] 116 | case 1: 117 | parts[j] = "00" + parts[j] 118 | } 119 | v = v / 1000 120 | j-- 121 | } 122 | parts[j] = strconv.Itoa(int(v)) 123 | return sign + strings.Join(parts[j:], sep) 124 | } 125 | 126 | // SortStrings - sort slice (?) 127 | func SortStrings(s []string) []string { 128 | sort.Strings(s) 129 | return s 130 | } 131 | 132 | // ToNullString - convert string into sql.NullString 133 | func ToNullString(s string) sql.NullString { 134 | return sql.NullString{String: s, Valid: s != ""} 135 | } 136 | 137 | // MaxInt64 - Max function for Int64 138 | func MaxInt64(a, b int64) int64 { 139 | if a > b { 140 | return a 141 | } 142 | return b 143 | } 144 | 145 | // ParseTimeStrict parses a formatted string and returns the time value it 146 | // represents. The output is identical to time.Parse except it returns an 147 | // error for strings that don't format to the input value. 148 | // 149 | // An example where the output differs from time.Parse would be: 150 | // parseTimeStrict("1/2/06", "11/31/15") 151 | // - time.Parse returns "2015-12-01 00:00:00 +0000 UTC" 152 | // - parseTimeStrict returns an error 153 | func ParseTimeStrict(layout, value string) (time.Time, error) { 154 | t, err := time.Parse(layout, value) 155 | if err != nil { 156 | return t, fmt.Errorf("invalid date time: %q. Must follow the pattern %s", value, layout) 157 | } 158 | if t.Format(layout) != value { 159 | return t, fmt.Errorf("invalid date time: %q. Must follow the pattern %s", value, layout) 160 | } 161 | return t, nil 162 | } 163 | -------------------------------------------------------------------------------- /controllers/common.go: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import ( 4 | "github.com/aerospike-community/amc/models" 5 | ) 6 | 7 | //---------- 8 | // Handlers 9 | //---------- 10 | 11 | // NodeResult strunct 12 | type NodeResult struct { 13 | Node *models.Node 14 | Name string 15 | Status string 16 | Err error 17 | UnsetParams []string 18 | } 19 | 20 | func errorMap(err string) map[string]interface{} { 21 | return map[string]interface{}{ 22 | "status": "failure", 23 | "error": err, 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /controllers/main_enterprise.go: -------------------------------------------------------------------------------- 1 | // build enterprise 2 | 3 | package controllers 4 | 5 | import "github.com/labstack/echo/v4" 6 | 7 | func registerEnterprise(e *echo.Echo) { 8 | e.GET("/aerospike/service/clusters/:clusterUUID/get-current-user", sessionValidator(getClusterCurrentUser)) 9 | e.GET("/aerospike/service/clusters/:clusterUUID/get_user_roles", sessionValidator(getClusterUserRoles)) 10 | 11 | e.POST("/aerospike/service/clusters/:clusterUUID/initiate_backup", sessionValidator(postInitiateBackup)) 12 | e.GET("/aerospike/service/clusters/:clusterUUID/get_backup_progress", sessionValidator(getBackupProgress)) 13 | e.GET("/aerospike/service/clusters/:clusterUUID/get_successful_backups", sessionValidator(getSuccessfulBackups)) 14 | e.POST("/aerospike/service/clusters/:clusterUUID/get_available_backups", sessionValidator(getAvailableBackups)) 15 | 16 | e.POST("/aerospike/service/clusters/:clusterUUID/initiate_restore", sessionValidator(postInitiateRestore)) 17 | e.GET("/aerospike/service/clusters/:clusterUUID/get_restore_progress", sessionValidator(getRestoreProgress)) 18 | 19 | e.GET("/alert-emails", sessionValidator(getAlertEmails)) 20 | e.POST("/alert-emails", sessionValidator(postAlertEmails)) 21 | e.POST("/delete-alert-emails", sessionValidator(deleteAlertEmails)) 22 | 23 | e.GET("/aerospike/get_multicluster_view/:port", getMultiClusterView) 24 | 25 | e.POST("/aerospike/service/clusters/:clusterUUID/fire_cmd", sessionValidator(postClusterFireCmd)) 26 | e.GET("/aerospike/service/clusters/:clusterUUID/get_all_users", sessionValidator(getClusterAllUsers)) 27 | e.GET("/aerospike/service/clusters/:clusterUUID/get_all_roles", sessionValidator(getClusterAllRoles)) 28 | e.POST("/aerospike/service/clusters/:clusterUUID/add_user", sessionValidator(postClusterAddUser)) 29 | e.POST("/aerospike/service/clusters/:clusterUUID/user/:user/remove", sessionValidator(postClusterDropUser)) 30 | e.POST("/aerospike/service/clusters/:clusterUUID/user/:user/update", sessionValidator(postClusterUpdateUser)) 31 | e.POST("/aerospike/service/clusters/:clusterUUID/roles/:role/add_role", sessionValidator(postClusterAddRole)) 32 | e.POST("/aerospike/service/clusters/:clusterUUID/roles/:role/update", sessionValidator(postClusterUpdateRole)) 33 | e.POST("/aerospike/service/clusters/:clusterUUID/roles/:role/drop_role", sessionValidator(postClusterDropRole)) 34 | 35 | e.GET("/aerospike/service/clusters/:clusterUUID/latency/:nodes", sessionValidator(getNodeLatency)) 36 | e.GET("/aerospike/service/clusters/:clusterUUID/latency_history/:nodes", sessionValidator(getNodeLatencyHistory)) 37 | e.GET("/aerospike/service/clusters/:clusterUUID/nodes/:nodes/latency_history", sessionValidator(getNodesLatencyHistory)) 38 | e.POST("/aerospike/service/clusters/:clusterUUID/change_password", sessionValidator(postClusterChangePassword)) 39 | e.GET("/aerospike/service/clusters/:clusterUUID/alerts", sessionValidator(getClusterAlerts)) 40 | e.POST("/aerospike/service/clusters/:clusterUUID/nodes/:node/switch_xdr_off", sessionValidator(postSwitchXDROff)) 41 | e.POST("/aerospike/service/clusters/:clusterUUID/nodes/:node/switch_xdr_on", sessionValidator(postSwitchXDROn)) 42 | e.GET("/aerospike/service/clusters/:clusterUUID/xdr/:xdrPort/nodes/:nodes", sessionValidator(getClusterXdrNodes)) 43 | e.GET("/aerospike/service/clusters/:clusterUUID/xdr/:xdrPort/nodes/:nodes/allconfig", sessionValidator(getClusterXdrNodesAllConfig)) 44 | e.POST("/aerospike/service/clusters/:clusterUUID/xdr/:xdrPort/nodes/:nodes/setconfig", sessionValidator(setClusterXdrNodesConfig)) 45 | } 46 | 47 | func init() { 48 | registerEnterpriseAPI = registerEnterprise 49 | } 50 | -------------------------------------------------------------------------------- /controllers/middleware/sessions/cookie.go: -------------------------------------------------------------------------------- 1 | package sessions 2 | 3 | import "github.com/gorilla/sessions" 4 | 5 | // CookieStore used for storing session cookies 6 | type CookieStore interface { 7 | Store 8 | } 9 | 10 | // NewCookieStore used for cookieStore 11 | // Keys are defined in pairs to allow key rotation, but the common case is to set a single 12 | // authentication key and optionally an encryption key. 13 | // 14 | // The first key in a pair is used for authentication and the second for encryption. The 15 | // encryption key can be set to nil or omitted in the last pair, but the authentication key 16 | // is required in all pairs. 17 | // 18 | // It is recommended to use an authentication key with 32 or 64 bytes. The encryption key, 19 | // if set, must be either 16, 24, or 32 bytes to select AES-128, AES-192, or AES-256 modes. 20 | func NewCookieStore(keyPairs ...[]byte) CookieStore { 21 | return &cookieStore{sessions.NewCookieStore(keyPairs...)} 22 | } 23 | 24 | type cookieStore struct { 25 | *sessions.CookieStore 26 | } 27 | 28 | func (c *cookieStore) Options(options Options) { 29 | c.CookieStore.Options = &sessions.Options{ 30 | Path: options.Path, 31 | Domain: options.Domain, 32 | MaxAge: options.MaxAge, 33 | Secure: options.Secure, 34 | HttpOnly: options.HttpOnly, 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /controllers/session.go: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import ( 4 | "errors" 5 | "net/http" 6 | 7 | "github.com/labstack/echo/v4" 8 | uuid "github.com/satori/go.uuid" 9 | log "github.com/sirupsen/logrus" 10 | 11 | "github.com/aerospike-community/amc/common" 12 | "github.com/aerospike-community/amc/controllers/middleware/sessions" 13 | ) 14 | 15 | func sessionValidator(f func(c echo.Context) error) func(c echo.Context) error { 16 | return func(c echo.Context) error { 17 | sid, err := sessionID(c) 18 | if err != nil || !_observer.SessionExists(sid) { 19 | invalidateSession(c) 20 | return c.JSON(http.StatusUnauthorized, errorMap("invalid session : None")) 21 | } 22 | 23 | return f(c) 24 | } 25 | } 26 | 27 | func sessionID(c echo.Context) (string, error) { 28 | session := sessions.Default(c) 29 | id := session.Get("id") 30 | 31 | if id == nil || id.(string) == "" { 32 | return "", errors.New("Invalid session") 33 | } 34 | 35 | return id.(string), nil 36 | } 37 | 38 | func manageSession(c echo.Context) string { 39 | id, err := sessionID(c) 40 | if err != nil || id == "" { 41 | return setSession(c) 42 | } 43 | 44 | if !_observer.SessionExists(id) { 45 | return setSession(c) 46 | } 47 | 48 | return id 49 | } 50 | 51 | func invalidateSession(c echo.Context) { 52 | session := sessions.Default(c) 53 | session.Clear() 54 | if err := session.Save(); err != nil { 55 | log.Error(err) 56 | } 57 | } 58 | 59 | func setSession(c echo.Context) string { 60 | sid := "00000000-0000-0000-0000-000000000000" 61 | // commonity version is single-session 62 | if common.AMCIsEnterprise() { 63 | sid = uuid.NewV4().String() 64 | } 65 | 66 | session := sessions.Default(c) 67 | session.Options( 68 | sessions.Options{ 69 | Path: "/", 70 | // Domain: options.Domain, 71 | // MaxAge: 30 * 60, 72 | Secure: false, 73 | HttpOnly: true, 74 | }) 75 | session.Clear() 76 | session.Set("id", sid) 77 | if err := session.Save(); err != nil { 78 | log.Error(err) 79 | } 80 | 81 | return sid 82 | } 83 | -------------------------------------------------------------------------------- /deployment/common/amc.conf: -------------------------------------------------------------------------------- 1 | CONF files are platform dependant; please edit all of them -------------------------------------------------------------------------------- /deployment/common/amc.deb: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # amc Manage the amc app server 4 | # 5 | # chkconfig: 2345 95 01 6 | # description: amc is Aerospike Cloud's Application Server 7 | # processname: amc 8 | # config: /etc/amc.conf 9 | # pidfile: /var/run/amc.pid 10 | 11 | ### BEGIN INIT INFO 12 | # Provides: amc 13 | # Required-Start: $local_fs $network 14 | # Required-Stop: 15 | # Should-Start: 16 | # Should-Stop: 17 | # Default-Start: 2 3 4 5 18 | # Default-Stop: 0 1 6 19 | # Short-Description: Manage the amc app server 20 | # Description: amc is the Aerospike Cloud Application Server 21 | ### END INIT INFO 22 | 23 | # source function library 24 | #. /etc/init.d/functions 25 | . /lib/lsb/init-functions 26 | 27 | #set -x 28 | 29 | PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/opt/amc 30 | 31 | prog="amc" 32 | user="root" 33 | exec="/opt/amc/$prog" 34 | pidfile="/var/run/$prog.pid" 35 | logfile="/var/log/$prog.log" 36 | conffile="/etc/amc/amc.conf" 37 | confdir="/etc/amc" 38 | 39 | # pull in sysconfig settings 40 | [ -e /etc/sysconfig/$prog ] && . /etc/sysconfig/$prog 41 | 42 | export GOMAXPROCS=${GOMAXPROCS:-2} 43 | 44 | start() { 45 | [ -x $exec ] || exit 5 46 | 47 | # [ -f $conffile ] || exit 6 48 | # [ -d $confdir ] || exit 6 49 | 50 | umask 077 51 | touch $pidfile 52 | umask 022 53 | touch $logfile 54 | chown $user:$user $logfile $pidfile 55 | 56 | echo -n $"Starting $prog: " 57 | 58 | ## holy shell shenanigans, batman! 59 | ## daemon can't be backgrounded. we need the pid of the spawned process, 60 | ## which is actually done via runuser thanks to --user. you can't do "cmd 61 | ## &; action" but you can do "{cmd &}; action". 62 | ##start-stop-daemon --start –-background –-quiet –-pidfile $pidfile -c $user –-exec $exec —- -config-file=$conffile -config-dir=$confdir >> $logfile 63 | start-stop-daemon --start --pidfile $pidfile -c $user --exec $exec --background -C -m -- -config-file=$conffile -config-dir=$confdir >> $logfile 2>/dev/null 64 | 65 | RETVAL=$? 66 | echo $RETVAL 67 | 68 | return $RETVAL 69 | } 70 | 71 | stop() { 72 | echo -n $"Shutting down $prog: " 73 | ## graceful shutdown with SIGINT 74 | start-stop-daemon --stop --pidfile $pidfile 75 | RETVAL=$? 76 | echo $RETVAL 77 | return $RETVAL 78 | } 79 | 80 | status() { 81 | echo -n $"Status of $prog: " 82 | start-stop-daemon --status --pidfile $pidfile 83 | RETVAL=$? 84 | echo $RETVAL 85 | return $RETVAL 86 | } 87 | 88 | restart() { 89 | stop 90 | start 91 | } 92 | 93 | case "$1" in 94 | start) 95 | $1 96 | ;; 97 | stop) 98 | $1 99 | ;; 100 | restart) 101 | $1 102 | ;; 103 | status) 104 | $1 105 | ;; 106 | *) 107 | echo $"Usage: $0 {start|stop|status|restart}" 108 | exit 2 109 | esac 110 | 111 | exit $? 112 | -------------------------------------------------------------------------------- /deployment/common/amc.docker.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | PROJECT="/opt/amc" 4 | PIDFILE="/tmp/amc.pid" 5 | CONFIG="/etc/amc/amc.conf" 6 | 7 | CMD="${PROJECT}/amc -config-file=${CONFIG}" 8 | 9 | # Fill out conffile with above values 10 | if [ -f /etc/amc/amc.template.conf ]; then 11 | envsubst < /etc/amc/amc.template.conf > ${CONFIG} 12 | fi 13 | 14 | check_amc_status(){ 15 | status=1 16 | if [ -z "`ps aux | grep /opt/amc/amc | grep -v grep`" ]; then 17 | status=0 18 | fi 19 | echo $status 20 | } 21 | 22 | start_amc(){ 23 | status=$(check_amc_status) 24 | if [ $status -eq 0 ] ; then 25 | rm -f $PIDFILE 26 | fi 27 | exec ${CMD} 28 | } 29 | 30 | if [ "$1" = "amc" ]; then 31 | start_amc 32 | else 33 | # the command isn't amc so run the command the user specified 34 | exec "$@" 35 | fi 36 | -------------------------------------------------------------------------------- /deployment/common/amc.other.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | SIGNAL=${1:-status} 4 | 5 | PROJECT="/opt/amc" 6 | PIDFILE="/tmp/amc.pid" 7 | CONFIG="/etc/amc/amc.conf" 8 | 9 | CMD="${PROJECT}/amc -daemon -config-file=${CONFIG}" 10 | port="8081" 11 | check_amc_status(){ 12 | status=1 13 | if [ -z "`ps aux | grep /opt/amc/amc | grep -v grep`" ]; then 14 | status=0 15 | fi 16 | echo $status 17 | } 18 | 19 | start_amc(){ 20 | status=$(check_amc_status) 21 | if [ $status -eq 0 ] ; then 22 | rm -f $PIDFILE 23 | ${CMD} 24 | fi 25 | } 26 | 27 | stop_amc(){ 28 | status=$(check_amc_status) 29 | if [ $status -ne 0 ] ; then 30 | ${CMD} -signal stop 31 | fi 32 | } 33 | 34 | case "$SIGNAL" in 35 | start) 36 | start_amc 37 | ;; 38 | stop) 39 | stop_amc 40 | ;; 41 | status) 42 | status=$(check_amc_status) 43 | if [ $status -eq 0 ] ; then 44 | echo "stopped" 45 | else 46 | echo "running" 47 | fi 48 | ;; 49 | *) 50 | echo "Unrecognized signal" 51 | exit 1 52 | ;; 53 | esac 54 | -------------------------------------------------------------------------------- /deployment/common/amc.rpm: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # amc Aerospike's Management Console 4 | # 5 | # chkconfig: 2345 95 01 6 | # description: AMC is Aerospike's Management Console 7 | # processname: amc 8 | # config: /etc/amc.conf 9 | # pidfile: /var/run/amc.pid 10 | 11 | ### BEGIN INIT INFO 12 | # Provides: amc 13 | # Required-Start: $local_fs $network 14 | # Required-Stop: 15 | # Should-Start: 16 | # Should-Stop: 17 | # Default-Start: 2 3 4 5 18 | # Default-Stop: 0 1 6 19 | # Short-Description: Aerospike's Management Console 20 | # Description: AMC is Aerospike's Management Console 21 | ### END INIT INFO 22 | 23 | # source function library 24 | . /etc/rc.d/init.d/functions 25 | 26 | PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/opt/amc 27 | 28 | prog="amc" 29 | user="root" 30 | exec="/opt/amc/$prog" 31 | pidfile="/var/run/$prog.pid" 32 | lockfile="/var/lock/subsys/$prog" 33 | logfile="/var/log/$prog.log" 34 | conffile="/etc/amc/amc.conf" 35 | confdir="/etc/amc" 36 | 37 | # pull in sysconfig settings 38 | [ -e /etc/sysconfig/$prog ] && . /etc/sysconfig/$prog 39 | 40 | export GOMAXPROCS=${GOMAXPROCS:-2} 41 | 42 | start() { 43 | [ -x $exec ] || exit 5 44 | 45 | # [ -f $conffile ] || exit 6 46 | # [ -d $confdir ] || exit 6 47 | 48 | umask 077 49 | 50 | touch $logfile $pidfile 51 | chown $user:$user $logfile $pidfile 52 | 53 | echo -n $"Starting $prog: " 54 | 55 | ## holy shell shenanigans, batman! 56 | ## daemon can't be backgrounded. we need the pid of the spawned process, 57 | ## which is actually done via runuser thanks to --user. you can't do "cmd 58 | ## &; action" but you can do "{cmd &}; action". 59 | daemon \ 60 | --pidfile=$pidfile \ 61 | --user=$user \ 62 | " { $exec -config-file=$conffile -config-dir=$confdir &>> $logfile & } ; echo \$! >| $pidfile " 63 | 64 | RETVAL=$? 65 | echo 66 | 67 | [ $RETVAL -eq 0 ] && touch $lockfile 68 | 69 | return $RETVAL 70 | } 71 | 72 | stop() { 73 | echo -n $"Shutting down $prog: " 74 | ## graceful shutdown with SIGINT 75 | killproc -p $pidfile -b $exec -INT 76 | RETVAL=$? 77 | echo 78 | [ $RETVAL -eq 0 ] && rm -f $lockfile 79 | return $RETVAL 80 | } 81 | 82 | restart() { 83 | stop 84 | start 85 | } 86 | 87 | reload() { 88 | echo -n $"Reloading $prog: " 89 | killproc -p $pidfile -b $exec -HUP 90 | echo 91 | } 92 | 93 | force_reload() { 94 | restart 95 | } 96 | 97 | rh_status() { 98 | status -p "$pidfile" -l $prog $exec 99 | } 100 | 101 | rh_status_q() { 102 | rh_status >/dev/null 2>&1 103 | } 104 | 105 | case "$1" in 106 | start) 107 | rh_status_q && exit 0 108 | $1 109 | ;; 110 | stop) 111 | rh_status_q || exit 0 112 | $1 113 | ;; 114 | restart) 115 | $1 116 | ;; 117 | reload) 118 | rh_status_q || exit 7 119 | $1 120 | ;; 121 | force-reload) 122 | force_reload 123 | ;; 124 | status) 125 | rh_status 126 | ;; 127 | condrestart|try-restart) 128 | rh_status_q || exit 0 129 | restart 130 | ;; 131 | *) 132 | echo $"Usage: $0 {start|stop|status|restart|condrestart|try-restart|reload|force-reload}" 133 | exit 2 134 | esac 135 | 136 | exit $? 137 | -------------------------------------------------------------------------------- /deployment/common/amc.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Aerospike Management Console 3 | After=syslog.target network.target local-fs.target nss-lookup.target 4 | 5 | [Service] 6 | Type=simple 7 | WorkingDirectory=/opt/amc 8 | ExecStart=/opt/amc/amc 9 | Restart=on-failure 10 | LimitNOFILE=10000 11 | 12 | [Install] 13 | WantedBy=multi-user.target 14 | -------------------------------------------------------------------------------- /deployment/common/systemd_after_install.sh: -------------------------------------------------------------------------------- 1 | # move systemd startup 2 | cp /opt/amc/amc.service /etc/systemd/system/ 3 | systemctl enable amc.service 4 | -------------------------------------------------------------------------------- /deployment/release/darwin/LaunchAgents/com.aerospike.amc.plist: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | Label 7 | com.aerospike.amc 8 | ProgramArguments 9 | 10 | /Library/amc/amc 11 | -config-file=/Library/amc/amc.conf 12 | 13 | Sockets 14 | 15 | Listeners 16 | 17 | SockServiceName 18 | 6060 19 | 20 | 21 | KeepAlive 22 | 23 | StandardOutPath 24 | /Library/amc/amc.txt 25 | StandardErrorPath 26 | /Library/amc/amc.txt 27 | 28 | -------------------------------------------------------------------------------- /deployment/release/darwin/Logs/amc/.placeholder: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aerospike-community/amc/6eec0fdf877db255a77791aa87d8870ca1dc9b38/deployment/release/darwin/Logs/amc/.placeholder -------------------------------------------------------------------------------- /deployment/release/darwin/amc/amc.conf: -------------------------------------------------------------------------------- 1 | [AMC] 2 | update_interval = 5 3 | #certfile = "" 4 | #keyfile = "" 5 | #Example : File paths should be double quoted. 6 | #certfile = "/home/amc/self-ssl.crt" 7 | #keyfile = "/home/amc/self-ssl.key" 8 | # The following option forces the the server to only use TLS v1.2 as the minimum TLS version. 9 | #force_tls12=true 10 | # The following option forces the server to use TLS v1.2 with the following options, resulting in higher level of security: 11 | ## CurvePreferences will be {CurveP521, CurveP384, CurveP256} 12 | ## Client will prefer the server cipher suites 13 | ## CipherSuites will be { TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, TLS_RSA_WITH_AES_256_GCM_SHA384, TLS_RSA_WITH_AES_256_CBC_SHA } 14 | #max_tls_security=true 15 | 16 | # Backup will be done on the following machine. If a key is set, that will be used 17 | # If no key or password is set, SSH Agent will be tried 18 | # You must put all the string inside double-quotes. 19 | # Comment out the methods you don't need 20 | #backup_host_public_key_file = 21 | 22 | bind = "0.0.0.0:8081" 23 | pidfile = "/tmp/amc.pid" 24 | loglevel = "info" 25 | errorlog = "/Library/Logs/amc/amc.log" 26 | #proc_name = "amc" 27 | chdir = "/Library/amc/" 28 | static_dir = "/Library/amc/static" 29 | timeout = 10 30 | 31 | # when you start monitoring a cluster, it will be polled activaly in the background. 32 | # this setting determines how long will that clustered be kept after it is not polled anymore. 33 | # This setting will not affect the clusters in the [amc.clusters] section. 34 | # values <= 0 mean never remove. 35 | cluster_inactive_before_removal = 1800 36 | 37 | database = "/Library/amc/amc.db" 38 | 39 | # The following clusters will be automatically monitored on AMC start 40 | #[amc.clusters] 41 | # 42 | # [amc.clusters.db1] 43 | # host = "" 44 | # tls_name = 45 | # port = 3000 46 | # user = "" 47 | # password = "" 48 | # show_in_ui = true 49 | 50 | # [amc.clusters.db2] 51 | # host = "" 52 | # tls_name = 53 | # port = 3000 54 | # user = "" 55 | # password = "" 56 | # show_in_ui = true 57 | 58 | [mailer] 59 | template_path = "/Library/amc/mailer/templates" 60 | #host = "smtp." 61 | #port = 587 62 | #user = "" 63 | #password = "" 64 | #send_to = ["", ""] 65 | #from_address = "" 66 | #accept_invalid_cert = false 67 | 68 | [basic_auth] 69 | # you can also set $AMC_AUTH_USER env variable 70 | #user = "" 71 | # you can also set $AMC_AUTH_PASSWORD env variable 72 | #password = "" 73 | 74 | [TLS] 75 | 76 | # name of cert files to add to the pool for TLS connections 77 | # All entries should be a string 78 | # System certs are automatically added 79 | server_cert_pool = [ 80 | # "", 81 | # "", 82 | ] 83 | 84 | [tls.client_certs] 85 | 86 | # [tls.client_certs.a] 87 | # cert_file="" 88 | # key_file="" 89 | 90 | # [tls.client_certs.b] 91 | # cert_file="" 92 | # key_file="" 93 | -------------------------------------------------------------------------------- /deployment/release/darwin/amc/uninstall.sh: -------------------------------------------------------------------------------- 1 | #/bin/sh 2 | 3 | if [ `id -u` -ne 0 ] ; then 4 | echo "This script should be run as root only" 5 | exit 1 6 | fi 7 | 8 | set +e 9 | 10 | launchctl unload /Library/LaunchAgents/com.aerospike.amc.plist 11 | 12 | rm -rf /Library/amc 13 | rm -rf /Library/Logs/amc 14 | rm -rf /Library/LaunchAgents/com.aerospike.amc.plist 15 | 16 | echo "AMC was uninstalled successfully." 17 | -------------------------------------------------------------------------------- /deployment/release/linux/etc/amc/amc.conf: -------------------------------------------------------------------------------- 1 | [AMC] 2 | update_interval = 5 3 | #certfile = "" 4 | #keyfile = "" 5 | #Example : File paths should be double quoted. 6 | #certfile = "/home/amc/self-ssl.crt" 7 | #keyfile = "/home/amc/self-ssl.key" 8 | # The following option forces the the server to only use TLS v1.2 as the minimum TLS version. 9 | #force_tls12=true 10 | # The following option forces the server to use TLS v1.2 with the following options, resulting in higher level of security: 11 | ## CurvePreferences will be {CurveP521, CurveP384, CurveP256} 12 | ## Client will prefer the server cipher suites 13 | ## CipherSuites will be { TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, TLS_RSA_WITH_AES_256_GCM_SHA384, TLS_RSA_WITH_AES_256_CBC_SHA } 14 | #max_tls_security=true 15 | 16 | # Backup will be done on the following machine. If a key is set, that will be used 17 | # If no key or password is set, SSH Agent will be tried 18 | # You must put all the string inside double-quotes. 19 | # Comment out the methods you don't need 20 | #backup_host_public_key_file = 21 | 22 | bind = "0.0.0.0:8081" 23 | pidfile = "/var/run/amc.pid" 24 | loglevel = "info" 25 | errorlog = "/var/log/amc/amc.log" 26 | #proc_name = "amc" 27 | chdir = "/opt/amc/" 28 | static_dir = "/opt/amc/static" 29 | timeout = 10 30 | 31 | # when you start monitoring a cluster, it will be polled activaly in the background. 32 | # this setting determines how long will that clustered be kept after it is not polled anymore. 33 | # This setting will not affect the clusters in the [amc.clusters] section. 34 | # values <= 0 mean never remove. 35 | cluster_inactive_before_removal = 1800 36 | 37 | database = "/opt/amc/amc.db" 38 | 39 | # The following clusters will be automatically monitored on AMC start 40 | #[amc.clusters] 41 | # 42 | # [amc.clusters.db1] 43 | # host = "" 44 | # tls_name = 45 | # port = 3000 46 | # user = "" 47 | # password = "" 48 | # show_in_ui = true 49 | 50 | # [amc.clusters.db2] 51 | # host = "" 52 | # tls_name = 53 | # port = 3000 54 | # user = "" 55 | # password = "" 56 | # show_in_ui = true 57 | 58 | [mailer] 59 | template_path = "/opt/amc/mailer/templates" 60 | #host = "smtp." 61 | #port = 587 62 | #user = "" 63 | #password = "" 64 | #send_to = ["", ""] 65 | #from_address = "" 66 | #accept_invalid_cert = false 67 | 68 | [basic_auth] 69 | # you can also set $AMC_AUTH_USER env variable 70 | #user = "" 71 | # you can also set $AMC_AUTH_PASSWORD env variable 72 | #password = "" 73 | 74 | [TLS] 75 | 76 | # name of cert files to add to the pool for TLS connections 77 | # All entries should be a string 78 | # System certs are automatically added 79 | server_cert_pool = [ 80 | # "", 81 | # "", 82 | ] 83 | 84 | [tls.client_certs] 85 | 86 | # [tls.client_certs.a] 87 | # cert_file="" 88 | # key_file="" 89 | 90 | # [tls.client_certs.b] 91 | # cert_file="" 92 | # key_file="" 93 | -------------------------------------------------------------------------------- /deployment/release/linux/var/log/amc/.placeholder: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aerospike-community/amc/6eec0fdf877db255a77791aa87d8870ca1dc9b38/deployment/release/linux/var/log/amc/.placeholder -------------------------------------------------------------------------------- /go-time-series/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Neri Marschik 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /go-time-series/README.md: -------------------------------------------------------------------------------- 1 | # go-time-series 2 | 3 | 4 | [![License](http://img.shields.io/badge/license-MIT-red.svg?style=flat)](./LICENSE) 5 | [![GoDoc](https://godoc.org/github.com/codesuki/go-time-series?status.svg)](https://godoc.org/github.com/codesuki/go-time-series) 6 | [![Build Status](http://img.shields.io/travis/codesuki/go-time-series.svg?style=flat)](https://travis-ci.org/codesuki/go-time-series) 7 | [![codecov](https://codecov.io/gh/codesuki/go-time-series/branch/master/graph/badge.svg)](https://codecov.io/gh/codesuki/go-time-series) 8 | 9 | Time series implementation in Go. 10 | 11 | It is used in [go-trending](https://www.github.com/codesuki/go-trending) as a backend for a trending algorithm. 12 | The time series supports storing counts at different granularities, e.g. seconds, minutes, hours, ....
13 | In case of go-trending the time series is configured to have recent data available at small granularity, i.e. the recent 60 seconds, and historical data available at large granularity, i.e. the last few hours, days of data. 14 | 15 | A redis backend is planned. 16 | 17 | * Simple interface 18 | * Store time series data at different granularities 19 | * Use your own clock implementation, e.g. for testing or similar 20 | 21 | ## Examples 22 | 23 | ### Creating a time series with default settings 24 | The default settings use `time.Now()` as clock and `time.Second * 60`, `time.Minute * 60` and `time.Hour * 24` as granularities. 25 | 26 | ```go 27 | import "github.com/codesuki/go-time-series" 28 | 29 | ... 30 | 31 | ts, err := timeseries.NewTimeSeries() 32 | if err != nil { 33 | // handle error 34 | } 35 | ``` 36 | 37 | ### Creating a customized time series 38 | You can specify the clock and/or granularities to use. A clock must implement the `timeseries.Clock` interface. 39 | 40 | ```go 41 | import "github.com/codesuki/go-time-series" 42 | 43 | ... 44 | type clock struct {} 45 | func (c *clock) Now() { 46 | return time.Time{} // always returns the zero time 47 | } 48 | var myClock clock 49 | ... 50 | 51 | ts, err := timeseries.NewTimeSeries( 52 | timeseries.WithGranularities( 53 | []timeseries.Granularity{ 54 | {Granularity: time.Second, Count: 60}, 55 | {Granularity: time.Minute, Count: 60}, 56 | {Granularity: time.Hour, Count: 24}, 57 | {Granularity: time.Hour * 24, Count: 7}, 58 | }), 59 | timeseries.WithClock(&myClock), 60 | ) 61 | if err != nil { 62 | // handle error 63 | } 64 | ``` 65 | 66 | ### Filling the time series 67 | To fill the time series with counts, e.g. events, you can use two different functions. 68 | 69 | ```go 70 | import "github.com/codesuki/go-time-series" 71 | 72 | ... 73 | 74 | ts, err := timeseries.NewTimeSeries() 75 | if err != nil { 76 | // handle error 77 | } 78 | 79 | ts.Increase(2) // adds 2 to the counter at the current time 80 | ts.IncreaseAtTime(3, time.Now().Add(-2 * time.Minute)) // adds 3 to the counter 2 minutes ago 81 | ``` 82 | 83 | ### Querying the time series 84 | The `Range()` function takes 2 arguments, i.e. the start and end of a time span. 85 | `Recent()` is a small helper function that just uses `clock.Now()` as `end` in `Range`. 86 | Please refer to the [documentation](https://godoc.org/github.com/codesuki/go-time-series) for how `Range()` works exactly. There are some details depending on what range you query and what range is available. 87 | 88 | ```go 89 | import "github.com/codesuki/go-time-series" 90 | 91 | ... 92 | 93 | ts, err := timeseries.NewTimeSeries() 94 | if err != nil { 95 | // handle error 96 | } 97 | 98 | ts.Increase(2) // adds 2 to the counter at the current time 99 | // 1s passes 100 | ts.Increase(3) 101 | // 1s passes 102 | 103 | ts.Recent(5 * time.Second) // returns 5 104 | 105 | ts.Range(time.Now().Add(-5 * time.Second), time.Now()) // returns 5 106 | ``` 107 | 108 | ## Documentation 109 | GoDoc is located [here](https://godoc.org/github.com/codesuki/go-time-series) 110 | 111 | ## License 112 | go-time-series is [MIT licensed](./LICENSE). 113 | -------------------------------------------------------------------------------- /go-time-series/glide.lock: -------------------------------------------------------------------------------- 1 | hash: 80928db660f9141f86dec3e84b2757bb44620f19f055cacb698cba8ccd738218 2 | updated: 2016-10-07T14:25:01.423423679+09:00 3 | imports: [] 4 | testImports: 5 | - name: github.com/benbjohnson/clock 6 | version: a620c1cc9866f84a2550ad53f4f353ec030fa26b 7 | -------------------------------------------------------------------------------- /go-time-series/glide.yaml: -------------------------------------------------------------------------------- 1 | package: github.com/codesuki/go-time-series 2 | homepage: https://github.com/codesuki/go-time-series 3 | license: MIT 4 | import: [] 5 | testImport: 6 | - package: github.com/benbjohnson/clock 7 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/aerospike-community/amc 2 | 3 | go 1.16 4 | 5 | require ( 6 | github.com/BurntSushi/toml v0.3.1 7 | github.com/aerospike/aerospike-client-go/v5 v5.0.2 8 | github.com/gorilla/context v1.1.1 9 | github.com/gorilla/sessions v1.2.1 10 | github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 // indirect 11 | github.com/kennygrant/sanitize v1.2.4 12 | github.com/labstack/echo/v4 v4.3.0 13 | github.com/mattn/go-isatty v0.0.13 // indirect 14 | github.com/mcuadros/go-version v0.0.0-20190830083331-035f6764e8d2 15 | github.com/onsi/ginkgo v1.16.4 16 | github.com/onsi/gomega v1.13.0 17 | github.com/satori/go.uuid v1.2.0 18 | github.com/sevlyar/go-daemon v0.1.5 19 | github.com/sirupsen/logrus v1.8.1 20 | github.com/yuin/gopher-lua v0.0.0-20210529063254-f4c35e4016d9 // indirect 21 | golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a 22 | golang.org/x/net v0.0.0-20210525063256-abc453219eb5 // indirect 23 | golang.org/x/sys v0.0.0-20210603125802-9665404d3644 // indirect 24 | golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba // indirect 25 | gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect 26 | gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df 27 | modernc.org/b v1.0.1 // indirect 28 | modernc.org/db v1.0.1 // indirect 29 | modernc.org/file v1.0.2 // indirect 30 | modernc.org/golex v1.0.1 // indirect 31 | modernc.org/lldb v1.0.1 // indirect 32 | modernc.org/mathutil v1.4.0 // indirect 33 | modernc.org/ql v1.3.1 34 | modernc.org/strutil v1.1.1 // indirect 35 | modernc.org/zappy v1.0.3 // indirect 36 | ) 37 | -------------------------------------------------------------------------------- /mailer/mailer.go: -------------------------------------------------------------------------------- 1 | package mailer 2 | 3 | import ( 4 | "bytes" 5 | "crypto/tls" 6 | "fmt" 7 | "html/template" 8 | 9 | log "github.com/sirupsen/logrus" 10 | gomail "gopkg.in/gomail.v2" 11 | 12 | "github.com/aerospike-community/amc/common" 13 | ) 14 | 15 | func processTemplate(config *common.Config, tplName string, context interface{}) ([]byte, error) { 16 | 17 | defer func() { 18 | if r := recover(); r != nil { 19 | log.Error("Sending email failed with a panic: ", r) 20 | } 21 | }() 22 | 23 | t := template.Must(template.ParseFiles(config.Mailer.TemplatePath+"/"+tplName, config.Mailer.TemplatePath+"/base.html")) 24 | 25 | // Execute the template for each recipient. 26 | data := bytes.Buffer{} 27 | err := t.Execute(&data, context) 28 | if err != nil { 29 | log.Errorf("Error executing template `%s`, err: `%s`.", tplName, err) 30 | return nil, err 31 | } 32 | 33 | return data.Bytes(), nil 34 | } 35 | 36 | // SendMail - send email 37 | func SendMail(config *common.Config, tplName, subject string, context interface{}) error { 38 | body, err := processTemplate(config, tplName, context) 39 | if err != nil { 40 | return err 41 | } 42 | 43 | msg := gomail.NewMessage(gomail.SetEncoding(gomail.Unencoded)) 44 | msg.SetHeader("From", fmt.Sprintf("AMC <%s>", config.FromAddress())) 45 | msg.SetHeader("To", config.AlertEmails()...) 46 | msg.SetHeader("Subject", subject) 47 | msg.SetBody("text/html", string(body)) 48 | 49 | mailer := gomail.NewDialer(config.Mailer.Host, int(config.Mailer.Port), config.Mailer.User, config.Mailer.Password) 50 | // Allow invalid/self-signed certs if requested by user 51 | if config.Mailer.AcceptInvalidCert { 52 | if mailer.TLSConfig != nil { 53 | mailer.TLSConfig.InsecureSkipVerify = true 54 | } else { 55 | mailer.TLSConfig = &tls.Config{InsecureSkipVerify: true} 56 | } 57 | } 58 | if err := mailer.DialAndSend(msg); err != nil { 59 | return err 60 | } 61 | 62 | return nil 63 | } 64 | -------------------------------------------------------------------------------- /mailer/templates/alerts/generic.html: -------------------------------------------------------------------------------- 1 | {{define "content"}} 2 |

3 | {{.Title}} 4 |

5 |

6 |

Cluster: {{.Cluster}}

7 |

Node: {{.Node}}

8 |

Status: {{.Status}}

9 |

Message: {{.Message}}

10 |

11 | {{end}} 12 | 13 | {{template "base" .}} 14 | -------------------------------------------------------------------------------- /mailer/templates/base.html: -------------------------------------------------------------------------------- 1 | {{define "base"}} 2 | 4 | 5 | 6 | 7 | 8 | 9 | AMC Alert 10 | 26 | 49 | 50 | 51 |
52 | 53 | 54 | 76 | 77 |
55 | 56 | 57 | 60 | 61 | 62 | 64 | 65 | 66 | 73 | 74 |
58 |
 
59 |
67 |
68 | 69 | {{template "content" .}} 70 | 71 |
72 |
75 |
78 |
79 | 80 | 81 | {{end}} 82 | -------------------------------------------------------------------------------- /main_darwin.go: -------------------------------------------------------------------------------- 1 | // +build darwin 2 | 3 | package main 4 | 5 | import ( 6 | "flag" 7 | "net/http" 8 | _ "net/http/pprof" 9 | "runtime" 10 | "runtime/debug" 11 | 12 | log "github.com/sirupsen/logrus" 13 | 14 | "github.com/aerospike-community/amc/common" 15 | "github.com/aerospike-community/amc/controllers" 16 | ) 17 | 18 | var ( 19 | configFile = flag.String("config-file", "/etc/amc/amc.conf", "Configuration file.") 20 | configDir = flag.String("config-dir", "/etc/amc/", "Configuration dir.") 21 | profileMode = flag.Bool("profile", false, "Run benchmarks with profiler active on port 6060.") 22 | daemonMode = flag.Bool("daemon", false, "Run AMC in daemon mode.") 23 | daemonSignal = flag.String("signal", "", `send signal to the daemon 24 | stop — graceful shutdown.`) 25 | ) 26 | 27 | func main() { 28 | defer func() { 29 | if err := recover(); err != nil { 30 | log.Fatal(string(debug.Stack())) 31 | } 32 | }() 33 | 34 | runtime.GOMAXPROCS(runtime.NumCPU()) 35 | 36 | flag.Parse() 37 | 38 | // launch profiler if in profile mode 39 | if *profileMode { 40 | go func() { 41 | log.Println(http.ListenAndServe(":6060", nil)) 42 | }() 43 | } 44 | 45 | log.Infof("Trying to start the AMC server...") 46 | 47 | config := common.Config{} 48 | common.InitConfig(*configFile, *configDir, &config) 49 | 50 | // close the log file on exit 51 | defer func() { 52 | if config.LogFile != nil { 53 | config.LogFile.Close() 54 | } 55 | }() 56 | 57 | common.SetupDatabase(config.AMC.Database) 58 | controllers.Server(&config) 59 | } 60 | -------------------------------------------------------------------------------- /main_linux.go: -------------------------------------------------------------------------------- 1 | // +build !darwin 2 | 3 | package main 4 | 5 | import ( 6 | "flag" 7 | "io/ioutil" 8 | "net/http" 9 | _ "net/http/pprof" 10 | "os" 11 | "runtime" 12 | "runtime/debug" 13 | "syscall" 14 | 15 | "github.com/sevlyar/go-daemon" 16 | log "github.com/sirupsen/logrus" 17 | 18 | "github.com/aerospike-community/amc/common" 19 | "github.com/aerospike-community/amc/controllers" 20 | ) 21 | 22 | var ( 23 | configFile = flag.String("config-file", "/etc/amc/amc.conf", "Configuration file.") 24 | configDir = flag.String("config-dir", "/etc/amc/", "Configuration dir.") 25 | profileMode = flag.Bool("profile", false, "Run benchmarks with profiler active on port 6060.") 26 | daemonMode = flag.Bool("daemon", false, "Run AMC in daemon mode.") 27 | daemonSignal = flag.String("signal", "", `send signal to the daemon 28 | stop — graceful shutdown.`) 29 | ) 30 | 31 | func main() { 32 | defer func() { 33 | if err := recover(); err != nil { 34 | log.Fatal(string(debug.Stack())) 35 | } 36 | }() 37 | 38 | runtime.GOMAXPROCS(runtime.NumCPU()) 39 | 40 | flag.Parse() 41 | 42 | if *daemonSignal == "stop" { 43 | log.SetOutput(ioutil.Discard) 44 | } 45 | 46 | // launch profiler if in profile mode 47 | if *profileMode { 48 | go func() { 49 | log.Println(http.ListenAndServe(":6060", nil)) 50 | }() 51 | } 52 | 53 | log.Infof("Trying to start the AMC server...") 54 | 55 | config := common.Config{} 56 | common.InitConfig(*configFile, *configDir, &config) 57 | 58 | // close the log file on exit 59 | defer func() { 60 | if config.LogFile != nil { 61 | config.LogFile.Close() 62 | } 63 | }() 64 | 65 | /* 66 | 67 | manage daemon 68 | 69 | */ 70 | 71 | daemon.AddCommand(daemon.StringFlag(daemonSignal, "stop"), syscall.SIGTERM, shutdownHandler) 72 | 73 | cntxt := &daemon.Context{ 74 | PidFileName: config.AMC.PIDFile, 75 | PidFilePerm: 0644, 76 | LogFileName: config.AMC.ErrorLog, 77 | LogFilePerm: 0640, 78 | WorkDir: config.AMC.Chdir, 79 | Umask: 027, 80 | Args: flag.Args(), 81 | } 82 | 83 | if len(daemon.ActiveFlags()) > 0 { 84 | d, err := cntxt.Search() 85 | if err != nil { 86 | log.Fatalln("Unable to send signal to the daemon:", err) 87 | } 88 | if err := daemon.SendCommands(d); err != nil { 89 | log.Fatalln(err) 90 | } 91 | return 92 | } 93 | 94 | if *daemonMode { 95 | d, err := cntxt.Reborn() 96 | if err != nil { 97 | log.Fatalln(err) 98 | } 99 | if d != nil { 100 | return 101 | } 102 | defer cntxt.Release() 103 | 104 | common.SetupDatabase(config.AMC.Database) 105 | log.Infoln("Starting AMC daemon...") 106 | go controllers.Server(&config) 107 | log.Infoln("AMC daemon started.") 108 | 109 | err = daemon.ServeSignals() 110 | if err != nil { 111 | log.Errorln("Error: ", err) 112 | } 113 | log.Println("daemon terminated.") 114 | } else { 115 | common.SetupDatabase(config.AMC.Database) 116 | controllers.Server(&config) 117 | } 118 | } 119 | 120 | func shutdownHandler(sig os.Signal) error { 121 | log.Println("Shutting down AMC gracefully...") 122 | controllers.ShutdownServer() 123 | return daemon.ErrStop 124 | } 125 | -------------------------------------------------------------------------------- /models/attr_aliases.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | var nsAliases = map[string]string{} 4 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "amc", 3 | "version": "5.0.0", 4 | "description": "AMC client integrated with the new go server", 5 | "scripts": { 6 | "test": "echo \"Error: no test specified\" && exit 1" 7 | }, 8 | "author": "tejas@aerospike.com", 9 | "license": "AGPLv3", 10 | "devDependencies": { 11 | "grunt": "^1.2.1", 12 | "grunt-cli": "^1.3.2", 13 | "grunt-contrib-clean": "^2.0.0", 14 | "grunt-contrib-copy": "^1.0.0", 15 | "grunt-contrib-cssmin": "^3.0.0", 16 | "grunt-contrib-uglify": "^5.0.0", 17 | "grunt-filerev": "^2.3.1", 18 | "grunt-filerev-replace": "^0.1.5", 19 | "grunt-text-replace": "^0.4.0" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /rrd/rrd_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013-2016 Aerospike, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package rrd 16 | 17 | import ( 18 | "time" 19 | 20 | . "github.com/onsi/ginkgo" 21 | . "github.com/onsi/gomega" 22 | 23 | "testing" 24 | 25 | "github.com/aerospike-community/amc/common" 26 | ) 27 | 28 | func TestRRD(t *testing.T) { 29 | RegisterFailHandler(Fail) 30 | RunSpecs(t, "RRD Suite") 31 | } 32 | 33 | var _ = Describe("Stats Bucket", func() { 34 | 35 | It("must Add the first values correctly", func() { 36 | bucket := NewBucket(5, 10, true) 37 | Expect(bucket.LastValue()).To(BeNil()) 38 | 39 | tm1 := time.Now().Unix() 40 | val1 := float64(1) 41 | bucket.Add(tm1, val1) 42 | // fmt.Printf("%#v\n", *bucket) 43 | Expect(bucket.LastValue()).To(BeNil()) 44 | 45 | tm2 := tm1 + 5 46 | val2 := float64(2) 47 | bucket.Add(tm2, val2) 48 | 49 | // fmt.Printf("%#v\n", *bucket) 50 | 51 | expectedTm2 := tm1 + 5 52 | expectedVal2 := float64(1) / 5 // delta / resolution 53 | Expect(*bucket.LastValue()).To(Equal(*common.NewSinglePointValue(&expectedTm2, &expectedVal2))) 54 | 55 | tm3 := tm2 + 5 56 | val3 := float64(7) 57 | bucket.Add(tm3, val3) 58 | 59 | // fmt.Printf("%#v\n", *bucket) 60 | 61 | expectedTm3 := tm2 + 5 62 | expectedVal3 := float64(5) / 5 // delta / resolution 63 | Expect(*bucket.LastValue()).To(Equal(*common.NewSinglePointValue(&expectedTm3, &expectedVal3))) 64 | 65 | // skip two slots 66 | tm4 := tm3 + 15 67 | val4 := float64(22) 68 | bucket.Add(tm4, val4) 69 | 70 | // fmt.Printf("%#v\n", *bucket) 71 | 72 | expectedTm4 := tm3 + 15 73 | expectedVal4 := float64(15) / (3 * 5) // delta / (empty ticks * resolution) 74 | Expect(*bucket.LastValue()).To(Equal(*common.NewSinglePointValue(&expectedTm4, &expectedVal4))) 75 | 76 | // check inside values 77 | expectedTm4_1 := tm3 + 5 78 | expectedTm4_2 := tm3 + 10 79 | Expect(bucket.ValuesSince(time.Unix(tm1-1, 0))).To(Equal([]*common.SinglePointValue{ 80 | common.NewSinglePointValue(&expectedTm2, &expectedVal2), 81 | common.NewSinglePointValue(&expectedTm3, &expectedVal3), 82 | common.NewSinglePointValue(&expectedTm4_1, &expectedVal4), 83 | common.NewSinglePointValue(&expectedTm4_2, &expectedVal4), 84 | common.NewSinglePointValue(&expectedTm4, &expectedVal4), 85 | })) 86 | }) 87 | }) 88 | -------------------------------------------------------------------------------- /rrd/simple_bucket.go: -------------------------------------------------------------------------------- 1 | package rrd 2 | 3 | import ( 4 | "math" 5 | "sync" 6 | "time" 7 | 8 | // "github.com/sasha-s/go-deadlock" 9 | // log "github.com/sirupsen/logrus" 10 | 11 | "github.com/aerospike-community/amc/common" 12 | ) 13 | 14 | // SimpleBucket type struct 15 | type SimpleBucket struct { 16 | beginTime *int64 17 | resolution int 18 | 19 | values []interface{} 20 | offset int // determines the offset from beginTime in resolution steps 21 | 22 | lastValue interface{} 23 | lastTimestamp *int64 24 | 25 | mutex sync.RWMutex 26 | } 27 | 28 | // NewSimpleBucket - create simple bucket 29 | func NewSimpleBucket(resolution, size int) *SimpleBucket { 30 | if !common.AMCIsProd() { 31 | // log.Info("creating bucket...") 32 | } 33 | return &SimpleBucket{ 34 | resolution: 5, 35 | values: make([]interface{}, size), 36 | } 37 | } 38 | 39 | // Size - get bucket size 40 | func (b *SimpleBucket) Size() int { 41 | return len(b.values) 42 | } 43 | 44 | // Add - add to bucket 45 | func (b *SimpleBucket) Add(timestamp int64, val interface{}) { 46 | b.mutex.Lock() 47 | defer b.mutex.Unlock() 48 | 49 | // don't add out of order timestamps 50 | if b.lastTimestamp != nil && *b.lastTimestamp > timestamp { 51 | return 52 | } 53 | 54 | if b.beginTime == nil { 55 | b.beginTime = ×tamp 56 | } 57 | 58 | // protect against values set in the past 59 | if timestamp < *b.beginTime { 60 | return 61 | } 62 | 63 | var newOffset int64 = (timestamp - *b.beginTime) / int64(b.resolution) 64 | emptyTicks := int(newOffset) - b.offset 65 | 66 | if emptyTicks >= b.Size() { 67 | for i := range b.values { 68 | b.values[i] = nil 69 | } 70 | } else if emptyTicks > 1 { 71 | for i := b.offset; i <= emptyTicks; i++ { 72 | b.values[i%b.Size()] = &val 73 | } 74 | } 75 | 76 | b.offset = int(newOffset) 77 | b.values[b.offset%b.Size()] = &val 78 | b.lastTimestamp = ×tamp 79 | b.lastValue = val 80 | } 81 | 82 | // ValuesSince - get values since time 83 | func (b *SimpleBucket) ValuesSince(tm time.Time) []interface{} { 84 | b.mutex.RLock() 85 | defer b.mutex.RUnlock() 86 | 87 | // if map is empty, 88 | if b.beginTime == nil { 89 | return []interface{}{} 90 | } 91 | 92 | if tm.Unix() < *b.beginTime { 93 | tm = time.Unix(*b.beginTime, 0) 94 | } 95 | count := int(math.Ceil(float64((*b.beginTime+int64(b.offset*b.resolution))-tm.Unix()) / float64(b.resolution))) 96 | 97 | if count <= 0 { 98 | return []interface{}{} 99 | } 100 | 101 | if count > b.Size() { 102 | count = b.Size() 103 | } 104 | 105 | if count > b.offset { 106 | count = b.offset + 1 107 | } 108 | 109 | res := make([]interface{}, 0, count) 110 | for i := b.offset - count + 1; i <= b.offset; i++ { 111 | if v := b.values[i%b.Size()]; v != nil { 112 | res = append(res, v) 113 | } 114 | } 115 | 116 | return res 117 | } 118 | 119 | // LastValue - get last value 120 | func (b *SimpleBucket) LastValue() interface{} { 121 | b.mutex.RLock() 122 | defer b.mutex.RUnlock() 123 | 124 | return b.lastValue 125 | } 126 | -------------------------------------------------------------------------------- /run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -x 4 | set -e 5 | 6 | cd $GOPATH/src/github.com/aerospike-community/amc 7 | 8 | edition=${1:-enterprise} 9 | environ=${2:-dev} 10 | 11 | build=`date -u +%Y%m%d.%H%M%S` 12 | version=`git describe --tags $(git rev-list --tags --max-count=1)` 13 | # tag=`git rev-parse --short HEAD` 14 | version_build="$edition-$version" 15 | 16 | # build binary 17 | go build -race -a -o amc -tags $edition -ldflags "-X github.com/aerospike-community/amc/common.AMCEdition=$edition -X github.com/aerospike-community/amc/common.AMCBuild=$build -X github.com/aerospike-community/amc/common.AMCVersion=$version -X github.com/aerospike-community/amc/common.AMCEnv=$environ" 18 | 19 | ./amc -config-file=$GOPATH/src/github.com/aerospike-community/amc/amc.dev.conf 20 | -------------------------------------------------------------------------------- /server-dev.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -x 4 | set -e 5 | 6 | cd $GOPATH/src/github.com/aerospike-community/amc 7 | 8 | edition=$1 9 | edition=enterprise 10 | 11 | build=`date -u +%Y%m%d.%H%M%S` 12 | version=`git describe --tags $(git rev-list --tags --max-count=1)` 13 | # tag=`git rev-parse --short HEAD` 14 | version_build="$edition-$version" 15 | 16 | # build binary 17 | #godep go build -race -a -tags $edition -ldflags "-X github.com/aerospike-community/amc/common.AMCEdition=$edition -X github.com/aerospike-community/amc/common.AMCBuild=$build -X github.com/aerospike-community/amc/common.AMCVersion=$version -X github.com/aerospike-community/amc/common.AMCEnv=dev" -o amc . 18 | go build -race -a -tags $edition -ldflags "-X github.com/aerospike-community/amc/common.AMCEdition=$edition -X github.com/aerospike-community/amc/common.AMCBuild=$build -X github.com/aerospike-community/amc/common.AMCVersion=$version -X github.com/aerospike-community/amc/common.AMCEnv=dev" -o amc . 19 | 20 | ./amc -config-file=$GOPATH/src/github.com/aerospike-community/amc/amc.dev.conf -profile 21 | -------------------------------------------------------------------------------- /static/css/fonts/MavenPro-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aerospike-community/amc/6eec0fdf877db255a77791aa87d8870ca1dc9b38/static/css/fonts/MavenPro-Regular.ttf -------------------------------------------------------------------------------- /static/css/fonts/icomoon.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aerospike-community/amc/6eec0fdf877db255a77791aa87d8870ca1dc9b38/static/css/fonts/icomoon.ttf -------------------------------------------------------------------------------- /static/css/jqgrid/images/ui-icons_2e83ff_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aerospike-community/amc/6eec0fdf877db255a77791aa87d8870ca1dc9b38/static/css/jqgrid/images/ui-icons_2e83ff_256x240.png -------------------------------------------------------------------------------- /static/css/jqgrid/images/ui-icons_888888_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aerospike-community/amc/6eec0fdf877db255a77791aa87d8870ca1dc9b38/static/css/jqgrid/images/ui-icons_888888_256x240.png -------------------------------------------------------------------------------- /static/css/jqueryui/images/animated-overlay.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aerospike-community/amc/6eec0fdf877db255a77791aa87d8870ca1dc9b38/static/css/jqueryui/images/animated-overlay.gif -------------------------------------------------------------------------------- /static/css/jqueryui/images/ui-bg_flat_30_cccccc_40x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aerospike-community/amc/6eec0fdf877db255a77791aa87d8870ca1dc9b38/static/css/jqueryui/images/ui-bg_flat_30_cccccc_40x100.png -------------------------------------------------------------------------------- /static/css/jqueryui/images/ui-bg_flat_50_5c5c5c_40x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aerospike-community/amc/6eec0fdf877db255a77791aa87d8870ca1dc9b38/static/css/jqueryui/images/ui-bg_flat_50_5c5c5c_40x100.png -------------------------------------------------------------------------------- /static/css/jqueryui/images/ui-bg_glass_20_555555_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aerospike-community/amc/6eec0fdf877db255a77791aa87d8870ca1dc9b38/static/css/jqueryui/images/ui-bg_glass_20_555555_1x400.png -------------------------------------------------------------------------------- /static/css/jqueryui/images/ui-bg_glass_40_0078a3_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aerospike-community/amc/6eec0fdf877db255a77791aa87d8870ca1dc9b38/static/css/jqueryui/images/ui-bg_glass_40_0078a3_1x400.png -------------------------------------------------------------------------------- /static/css/jqueryui/images/ui-bg_glass_40_ffc73d_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aerospike-community/amc/6eec0fdf877db255a77791aa87d8870ca1dc9b38/static/css/jqueryui/images/ui-bg_glass_40_ffc73d_1x400.png -------------------------------------------------------------------------------- /static/css/jqueryui/images/ui-bg_glass_75_d0e5f5_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aerospike-community/amc/6eec0fdf877db255a77791aa87d8870ca1dc9b38/static/css/jqueryui/images/ui-bg_glass_75_d0e5f5_1x400.png -------------------------------------------------------------------------------- /static/css/jqueryui/images/ui-bg_gloss-wave_25_333333_500x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aerospike-community/amc/6eec0fdf877db255a77791aa87d8870ca1dc9b38/static/css/jqueryui/images/ui-bg_gloss-wave_25_333333_500x100.png -------------------------------------------------------------------------------- /static/css/jqueryui/images/ui-bg_highlight-soft_80_eeeeee_1x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aerospike-community/amc/6eec0fdf877db255a77791aa87d8870ca1dc9b38/static/css/jqueryui/images/ui-bg_highlight-soft_80_eeeeee_1x100.png -------------------------------------------------------------------------------- /static/css/jqueryui/images/ui-bg_inset-hard_100_fcfdfd_1x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aerospike-community/amc/6eec0fdf877db255a77791aa87d8870ca1dc9b38/static/css/jqueryui/images/ui-bg_inset-hard_100_fcfdfd_1x100.png -------------------------------------------------------------------------------- /static/css/jqueryui/images/ui-bg_inset-soft_25_000000_1x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aerospike-community/amc/6eec0fdf877db255a77791aa87d8870ca1dc9b38/static/css/jqueryui/images/ui-bg_inset-soft_25_000000_1x100.png -------------------------------------------------------------------------------- /static/css/jqueryui/images/ui-bg_inset-soft_30_f58400_1x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aerospike-community/amc/6eec0fdf877db255a77791aa87d8870ca1dc9b38/static/css/jqueryui/images/ui-bg_inset-soft_30_f58400_1x100.png -------------------------------------------------------------------------------- /static/css/jqueryui/images/ui-icons_222222_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aerospike-community/amc/6eec0fdf877db255a77791aa87d8870ca1dc9b38/static/css/jqueryui/images/ui-icons_222222_256x240.png -------------------------------------------------------------------------------- /static/css/jqueryui/images/ui-icons_4b8e0b_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aerospike-community/amc/6eec0fdf877db255a77791aa87d8870ca1dc9b38/static/css/jqueryui/images/ui-icons_4b8e0b_256x240.png -------------------------------------------------------------------------------- /static/css/jqueryui/images/ui-icons_a83300_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aerospike-community/amc/6eec0fdf877db255a77791aa87d8870ca1dc9b38/static/css/jqueryui/images/ui-icons_a83300_256x240.png -------------------------------------------------------------------------------- /static/css/jqueryui/images/ui-icons_cccccc_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aerospike-community/amc/6eec0fdf877db255a77791aa87d8870ca1dc9b38/static/css/jqueryui/images/ui-icons_cccccc_256x240.png -------------------------------------------------------------------------------- /static/css/jqueryui/images/ui-icons_ffffff_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aerospike-community/amc/6eec0fdf877db255a77791aa87d8870ca1dc9b38/static/css/jqueryui/images/ui-icons_ffffff_256x240.png -------------------------------------------------------------------------------- /static/css/sprite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aerospike-community/amc/6eec0fdf877db255a77791aa87d8870ca1dc9b38/static/css/sprite.png -------------------------------------------------------------------------------- /static/css/timeseries.css: -------------------------------------------------------------------------------- 1 | svg.timeseries{ 2 | display: block; 3 | } 4 | 5 | .timeseries.axis.y.line { 6 | stroke : #000000; 7 | stroke-width : 2px; 8 | } 9 | 10 | .timeseries.axis.x.line { 11 | stroke : #3355aa; 12 | stroke-width : 2px; 13 | 14 | } 15 | 16 | .timeseries.axis.tickline{ 17 | stroke : #888888; 18 | stroke-width : 1px; 19 | opacity : 0.6; 20 | stroke-dasharray : 2px 4px; 21 | z-index : 2; 22 | } 23 | 24 | .timeseries.axis.y.ticktext{ 25 | fill : #000000; 26 | font-size : 10px; 27 | font-weight : bold; 28 | } 29 | 30 | .timeseries.axis.x.ticktext{ 31 | fill : #666666; 32 | font-size: 0.7em; 33 | } 34 | 35 | .timeseries.path { 36 | stroke-width : 2px; 37 | z-index : 5; 38 | } 39 | 40 | .timeseries.bubble.container{ 41 | position : fixed; 42 | z-index : 1000; 43 | display : inline-block; 44 | pointer-events : none; 45 | box-shadow: -4px -2px 20px -5px black; 46 | } 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /static/css/vertical-tabs.css: -------------------------------------------------------------------------------- 1 | 2 | .wrapper 3 | { 4 | padding: 10px; 5 | min-height: 100px; 6 | } 7 | .wrapper h1, .wrapper h4, .wrapper p, .wrapper pre, .wrapper ul, .wrapper li 8 | { 9 | margin: 0; 10 | padding: 0; 11 | border: 0; 12 | vertical-align: baseline; 13 | background: transparent; 14 | } 15 | .wrapper li 16 | { 17 | 18 | outline: 0; 19 | text-decoration: none; 20 | -webkit-transition-property: background color; 21 | -moz-transition-property: background color; 22 | -o-transition-property: background color; 23 | -ms-transition-property: background color; 24 | transition-property: background color; 25 | -webkit-transition-duration: 0.12s; 26 | -moz-transition-duration: 0.12s; 27 | -o-transition-duration: 0.12s; 28 | -ms-transition-duration: 0.12s; 29 | transition-duration: 0.12s; 30 | -webkit-transition-timing-function: ease-out; 31 | -moz-transition-timing-function: ease-out; 32 | -o-transition-timing-function: ease-out; 33 | -ms-transition-timing-function: ease-out; 34 | transition-timing-function: ease-out; 35 | } 36 | #v-nav 37 | { 38 | height: 100%; 39 | margin: auto; 40 | color: #333; 41 | } 42 | #v-nav >ul 43 | { 44 | float: left; 45 | width: 213px; 46 | display: block; 47 | position: relative; 48 | top: 0; 49 | border: 1px solid #DDD; 50 | margin: auto 0 !important; 51 | padding:0; 52 | font-size: 0.8em; 53 | } 54 | #v-nav >ul >li 55 | { 56 | cursor: pointer; 57 | 58 | width: 180px; 59 | list-style-type: none; 60 | display: block; 61 | text-shadow: 0px 1px 1px #F2F1F0; 62 | font-size: 1.11em; 63 | position: relative; 64 | border-right-width: 0; 65 | border-bottom: 1px solid #DDD; 66 | margin: auto; 67 | padding: 8px 15px !important; 68 | background: whiteSmoke; 69 | background: -moz-linear-gradient(top, #ffffff 0%, #f2f2f2 100%); 70 | background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #ffffff), color-stop(100%, #f2f2f2)); 71 | background: -webkit-linear-gradient(top, #ffffff 0%, #f2f2f2 100%); 72 | background: -o-linear-gradient(top, #ffffff 0%, #f2f2f2 100%); 73 | background: -ms-linear-gradient(top, #ffffff 0%, #f2f2f2 100%); 74 | background: linear-gradient(top, #ffffff 0%, #f2f2f2 100%); 75 | } 76 | #v-nav >ul >li.current 77 | { 78 | color: black; 79 | border-right: none; 80 | z-index: 10; 81 | background: white; 82 | position: relative; 83 | moz-box-shadow: inset 0 0 35px 5px #fafbfd; 84 | -webkit-box-shadow: inset 0 0 35px 5px #fafbfd; 85 | box-shadow: inset 0 0 35px 5px #fafbfd; 86 | } 87 | #v-nav >ul >li.first.current 88 | { 89 | border-bottom: 1px solid #DDD; 90 | } 91 | #v-nav >ul >li.last 92 | { 93 | border-bottom: none; 94 | } 95 | #v-nav >div.tab-content 96 | { 97 | margin-left: 210px; 98 | border: 1px solid #ddd; 99 | background-color: #FFF; 100 | 101 | min-height: 350px; 102 | position: relative; 103 | z-index: 9; 104 | box-shadow: inset 0 0 35px 5px #fafbfd; 105 | display: none; 106 | padding: 10px 20px; 107 | } 108 | #v-nav >div.tab-content >h4 109 | { 110 | font-size: 1.1em; 111 | color: Black; 112 | border-bottom: 1px dotted #EEEDED; 113 | padding-top: 5px; 114 | padding-bottom: 5px; 115 | font-weight: normal; 116 | } 117 | @media screen and (max-width: 755px) { 118 | #v-nav >ul{ 119 | width: 104px; 120 | } 121 | 122 | #v-nav >ul >li{ 123 | width: 100px; 124 | 125 | padding-left: 2px !important; 126 | padding-right: 2px !important; 127 | } 128 | 129 | #v-nav >div.tab-content { 130 | margin-left: 104px; 131 | padding:8px; 132 | font-size:10px; 133 | 134 | text-align: center; 135 | } 136 | 137 | #v-nav >div.tab-content input{ 138 | display:block; 139 | width: 94% !important; 140 | text-align: center; 141 | 142 | } 143 | 144 | #v-nav >div.tab-content button{ 145 | width:80%; 146 | max-width:240px; 147 | } 148 | .runSubmit{ 149 | margin: 15px 0px 0px 0px; 150 | } 151 | 152 | .vsubmit{ 153 | margin: 15px 0px 0px 0px; 154 | } 155 | #applyConfig{ 156 | margin-right: 0.5%; 157 | margin-top: -1px; 158 | } 159 | #applyConfigBtn{ 160 | width: 35px; 161 | height: 20px; 162 | 163 | padding: 0; 164 | } 165 | 166 | #v-nav label{ 167 | float: none; 168 | 169 | } 170 | } -------------------------------------------------------------------------------- /static/images/arrow_down.svg: -------------------------------------------------------------------------------- 1 | 2 | 17 | 19 | 20 | 22 | image/svg+xml 23 | 25 | 26 | 27 | 28 | 29 | 31 | 48 | 52 | 55 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /static/images/arrow_up.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /static/images/bg-btn-blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aerospike-community/amc/6eec0fdf877db255a77791aa87d8870ca1dc9b38/static/images/bg-btn-blue.png -------------------------------------------------------------------------------- /static/images/bg-btn-grey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aerospike-community/amc/6eec0fdf877db255a77791aa87d8870ca1dc9b38/static/images/bg-btn-grey.png -------------------------------------------------------------------------------- /static/images/cog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aerospike-community/amc/6eec0fdf877db255a77791aa87d8870ca1dc9b38/static/images/cog.png -------------------------------------------------------------------------------- /static/images/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aerospike-community/amc/6eec0fdf877db255a77791aa87d8870ca1dc9b38/static/images/favicon.png -------------------------------------------------------------------------------- /static/images/link.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aerospike-community/amc/6eec0fdf877db255a77791aa87d8870ca1dc9b38/static/images/link.png -------------------------------------------------------------------------------- /static/images/loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aerospike-community/amc/6eec0fdf877db255a77791aa87d8870ca1dc9b38/static/images/loading.gif -------------------------------------------------------------------------------- /static/images/sidepanelpattern.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aerospike-community/amc/6eec0fdf877db255a77791aa87d8870ca1dc9b38/static/images/sidepanelpattern.png -------------------------------------------------------------------------------- /static/js/collections/configs/namespaces.js: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | *Copyright 2008-2014 by Aerospike, Inc. All rights reserved. 3 | *THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE. THE COPYRIGHT NOTICE 4 | *ABOVE DOES NOT EVIDENCE ANY ACTUAL OR INTENDED PUBLICATION. 5 | ******************************************************************************/ 6 | define(["jquery", "underscore", "backbone", "helper/util", "models/configs/statmodel", "views/configs/statview", "config/app-config", "config/view-config", "helper/edit-config"], function($, _, Backbone, Util, StatModel, StatView, AppConfig, ViewConfig, StatTable){ 7 | var NamespaceCollection = Backbone.Collection.extend({ 8 | model: StatModel, 9 | initVariables :function(){ 10 | }, 11 | initialize : function(){ 12 | this.statTableID = AppConfig.stat.statTableDiv; 13 | this.statList = AppConfig.namespaceConfigList; 14 | }, 15 | initializeGrid: function(){ 16 | // StatTable.startInitGrid(AppConfig.namespaceConfigList); 17 | }, 18 | clearAndInitGridData: function(){ 19 | $(AppConfig.stat.statTableDiv).jqGrid('clearGridData'); 20 | // StatTable.initAndSetGridData(AppConfig.namespaceConfigList); 21 | // $(AppConfig.stat.statTableDiv).trigger("reloadGrid"); 22 | }, 23 | addModel: function(address, clusterID, namespaceName){ 24 | var namespace = new StatModel(); 25 | namespace.setParamaters(address, clusterID, 'namespace', AppConfig.stat.statTableDiv, AppConfig.namespaceConfigList, namespaceName); 26 | namespace.colView = new StatView({el : ("[id='statListTable_" + address + "']")}); 27 | this.add(namespace); 28 | return namespace; 29 | } 30 | }); 31 | return NamespaceCollection; 32 | }); 33 | 34 | 35 | -------------------------------------------------------------------------------- /static/js/collections/configs/nodes.js: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | *Copyright 2008-2014 by Aerospike, Inc. All rights reserved. 3 | *THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE. THE COPYRIGHT NOTICE 4 | *ABOVE DOES NOT EVIDENCE ANY ACTUAL OR INTENDED PUBLICATION. 5 | ******************************************************************************/ 6 | define(["jquery", "underscore", "backbone", "helper/util", "models/configs/statmodel", "views/configs/statview", "config/app-config", "config/view-config", "helper/edit-config"], function($, _, Backbone, Util, StatModel, StatView, AppConfig, ViewConfig, StatTable){ 7 | var NodeCollection = Backbone.Collection.extend({ 8 | model: StatModel, 9 | initialize : function(){ 10 | }, 11 | initializeGrid: function(){ 12 | // StatTable.startInitGrid(AppConfig.nodeConfigList); 13 | }, 14 | clearAndInitGridData: function(){ 15 | $(AppConfig.stat.statTableDiv).jqGrid('clearGridData',true); 16 | //StatTable.initAndSetGridData(AppConfig.nodeConfigList); 17 | // $(AppConfig.stat.statTableDiv).trigger("reloadGrid"); 18 | }, 19 | addModel: function(address, clusterID, tobeUsed){ 20 | var node = new StatModel(); 21 | node.colView = new StatView({el : ("[id='statListTable_" + address + "']")}); 22 | this.add(node); 23 | node.setParamaters(address, clusterID, 'nodes', AppConfig.stat.statTableDiv, AppConfig.nodeConfigList, tobeUsed); 24 | return node; 25 | } 26 | }); 27 | return NodeCollection; 28 | }); 29 | 30 | 31 | -------------------------------------------------------------------------------- /static/js/collections/configs/sindex.js: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | *Copyright 2008-2014 by Aerospike, Inc. All rights reserved. 3 | *THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE. THE COPYRIGHT NOTICE 4 | *ABOVE DOES NOT EVIDENCE ANY ACTUAL OR INTENDED PUBLICATION. 5 | ******************************************************************************/ 6 | define(["jquery", "underscore", "backbone", "helper/util", "models/configs/statmodel", "views/configs/statview", "config/app-config", "config/view-config", "helper/edit-config"], function($, _, Backbone, Util, StatModel, StatView, AppConfig, ViewConfig, StatTable){ 7 | var SIndexesCollection = Backbone.Collection.extend({ 8 | model: StatModel, 9 | initialize : function(){ 10 | // this.statTableID = AppConfig.stat.statTableDiv; 11 | // this.statList = AppConfig.namespaceConfigList; 12 | }, 13 | initializeGrid: function(){ 14 | // StatTable.startInitGrid(AppConfig.sIndexStatsList); 15 | }, 16 | clearAndInitGridData: function(){ 17 | $(AppConfig.stat.statTableDiv).jqGrid('clearGridData'); 18 | // StatTable.initAndSetGridData(AppConfig.sIndexStatsList); 19 | // $(AppConfig.stat.statTableDiv).trigger("reloadGrid"); 20 | }, 21 | addModel: function(address, clusterID, tobeUsed){ 22 | var sIndex = new StatModel(); 23 | sIndex.colView = new StatView({el : ("[id='statListTable_" + address + "']")}); 24 | sIndex.setParamaters(address, clusterID, 'sindex', AppConfig.stat.statTableDiv, AppConfig.sIndexStatsList, tobeUsed); 25 | this.add(sIndex); 26 | return sIndex; 27 | } 28 | }); 29 | return SIndexesCollection; 30 | }); 31 | 32 | 33 | -------------------------------------------------------------------------------- /static/js/collections/configs/xdr.js: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | *Copyright 2008-2014 by Aerospike, Inc. All rights reserved. 3 | *THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE. THE COPYRIGHT NOTICE 4 | *ABOVE DOES NOT EVIDENCE ANY ACTUAL OR INTENDED PUBLICATION. 5 | ******************************************************************************/ 6 | define(["jquery", "underscore", "backbone", "helper/util", "models/configs/statmodel", "views/configs/statview", "config/app-config", "config/view-config", "helper/edit-config"], function($, _, Backbone, Util, StatModel, StatView, AppConfig, ViewConfig, StatTable){ 7 | var XDRCollection = Backbone.Collection.extend({ 8 | model: StatModel, 9 | initialize : function(){ 10 | this.statTableID = AppConfig.stat.statTableDiv; 11 | this.statList = AppConfig.xdrConfigList; 12 | }, 13 | initializeGrid: function(){ 14 | // StatTable.startInitGrid(AppConfig.xdrConfigList); 15 | }, 16 | clearAndInitGridData: function(){ 17 | $(AppConfig.stat.statTableDiv).jqGrid('clearGridData'); 18 | // StatTable.initAndSetGridData(AppConfig.xdrConfigList); 19 | // $(AppConfig.stat.statTableDiv).trigger("reloadGrid"); 20 | }, 21 | addModel: function(address, clusterID, xdrPort){ 22 | var xdr = new StatModel(); 23 | xdr.setParamaters(address, clusterID, 'xdr', AppConfig.stat.statTableDiv, AppConfig.xdrConfigList, xdrPort); 24 | xdr.colView = new StatView({el : ("[id='statListTable_" + address + "']")}); 25 | this.add(xdr); 26 | return xdr; 27 | } 28 | }); 29 | return XDRCollection; 30 | }); 31 | 32 | 33 | -------------------------------------------------------------------------------- /static/js/collections/definitions/sets.js: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Licensed to the Apache Software Foundation (ASF) under one 3 | or more contributor license agreements. See the NOTICE file 4 | distributed with this work for additional information 5 | regarding copyright ownership. The ASF licenses this file 6 | to you under the Apache License, Version 2.0 (the 7 | "License"); you may not use this file except in compliance 8 | with the License. You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, 13 | software distributed under the License is distributed on an 14 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | KIND, either express or implied. See the License for the 16 | specific language governing permissions and limitations 17 | under the License. 18 | ******************************************************************************/ 19 | 20 | define(["jquery", "underscore", "backbone", "helper/util", "models/statistics/statmodel", "views/statistics/statview", "config/app-config", "config/view-config", "helper/stat-table"], function($, _, Backbone, Util, StatModel, StatView, AppConfig, ViewConfig, StatTable){ 21 | var SetsCollection = Backbone.Collection.extend({ 22 | model: StatModel, 23 | initialize : function(){ 24 | // this.statTableID = AppConfig.stat.statTableDiv; 25 | // this.statList = AppConfig.xdrStatsList; 26 | }, 27 | initializeGrid: function(){ 28 | StatTable.startInitGrid(AppConfig.xdrStatsList); 29 | }, 30 | clearAndInitGridData: function(){ 31 | $(AppConfig.stat.statTableDiv).jqGrid('clearGridData'); 32 | StatTable.initAndSetGridData(AppConfig.xdrStatsList); 33 | $(AppConfig.stat.statTableDiv).trigger("reloadGrid"); 34 | }, 35 | addModel: function(address, clusterID, xdrPort){ 36 | var xdr = new StatModel({"update_interval" : 5}); 37 | xdr.setParamaters(address, clusterID, 'xdr', AppConfig.stat.statTableDiv, AppConfig.xdrStatsList, xdrPort); 38 | xdr.colView = new StatView(); 39 | this.add(xdr); 40 | return xdr; 41 | } 42 | }); 43 | return SetsCollection; 44 | }); 45 | 46 | 47 | -------------------------------------------------------------------------------- /static/js/collections/definitions/sindexes.js: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Licensed to the Apache Software Foundation (ASF) under one 3 | or more contributor license agreements. See the NOTICE file 4 | distributed with this work for additional information 5 | regarding copyright ownership. The ASF licenses this file 6 | to you under the Apache License, Version 2.0 (the 7 | "License"); you may not use this file except in compliance 8 | with the License. You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, 13 | software distributed under the License is distributed on an 14 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | KIND, either express or implied. See the License for the 16 | specific language governing permissions and limitations 17 | under the License. 18 | ******************************************************************************/ 19 | 20 | define(["jquery", "underscore", "backbone", "helper/util", "models/statistics/statmodel", "views/statistics/statview", "config/app-config", "config/view-config", "helper/stat-table"], function($, _, Backbone, Util, StatModel, StatView, AppConfig, ViewConfig, StatTable){ 21 | var SIndexCollection = Backbone.Collection.extend({ 22 | model: StatModel, 23 | initialize : function(){ 24 | // this.statTableID = AppConfig.stat.statTableDiv; 25 | // this.statList = AppConfig.xdrStatsList; 26 | }, 27 | initializeGrid: function(){ 28 | StatTable.startInitGrid(AppConfig.xdrStatsList); 29 | }, 30 | clearAndInitGridData: function(){ 31 | $(AppConfig.stat.statTableDiv).jqGrid('clearGridData'); 32 | StatTable.initAndSetGridData(AppConfig.xdrStatsList); 33 | $(AppConfig.stat.statTableDiv).trigger("reloadGrid"); 34 | }, 35 | addModel: function(address, clusterID, xdrPort){ 36 | var xdr = new StatModel({"update_interval" : 5}); 37 | xdr.setParamaters(address, clusterID, 'xdr', AppConfig.stat.statTableDiv, AppConfig.xdrStatsList, xdrPort); 38 | xdr.colView = new StatView({model: xdr}); 39 | this.add(xdr); 40 | return xdr; 41 | } 42 | }); 43 | return SIndexCollection; 44 | }); 45 | 46 | 47 | -------------------------------------------------------------------------------- /static/js/collections/definitions/udf.js: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Licensed to the Apache Software Foundation (ASF) under one 3 | or more contributor license agreements. See the NOTICE file 4 | distributed with this work for additional information 5 | regarding copyright ownership. The ASF licenses this file 6 | to you under the Apache License, Version 2.0 (the 7 | "License"); you may not use this file except in compliance 8 | with the License. You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, 13 | software distributed under the License is distributed on an 14 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | KIND, either express or implied. See the License for the 16 | specific language governing permissions and limitations 17 | under the License. 18 | ******************************************************************************/ 19 | 20 | define(["jquery", "underscore", "backbone", "helper/util", "models/statistics/statmodel", "views/statistics/statview", "config/app-config", "config/view-config", "helper/stat-table"], function($, _, Backbone, Util, StatModel, StatView, AppConfig, ViewConfig, StatTable){ 21 | var UDFCollection = Backbone.Collection.extend({ 22 | model: StatModel, 23 | initialize : function(){ 24 | // this.statTableID = AppConfig.stat.statTableDiv; 25 | // this.statList = AppConfig.xdrStatsList; 26 | }, 27 | initializeGrid: function(){ 28 | StatTable.startInitGrid(AppConfig.xdrStatsList); 29 | }, 30 | clearAndInitGridData: function(){ 31 | $(AppConfig.stat.statTableDiv).jqGrid('clearGridData'); 32 | StatTable.initAndSetGridData(AppConfig.xdrStatsList); 33 | $(AppConfig.stat.statTableDiv).trigger("reloadGrid"); 34 | }, 35 | addModel: function(address, clusterID, xdrPort){ 36 | var xdr = new StatModel({"update_interval" : 5}); 37 | xdr.setParamaters(address, clusterID, 'xdr', AppConfig.stat.statTableDiv, AppConfig.xdrStatsList, xdrPort); 38 | xdr.colView = new StatView(); 39 | this.add(xdr); 40 | return xdr; 41 | } 42 | }); 43 | return UDFCollection; 44 | }); 45 | 46 | 47 | -------------------------------------------------------------------------------- /static/js/collections/definitions/xdrs.js: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Licensed to the Apache Software Foundation (ASF) under one 3 | or more contributor license agreements. See the NOTICE file 4 | distributed with this work for additional information 5 | regarding copyright ownership. The ASF licenses this file 6 | to you under the Apache License, Version 2.0 (the 7 | "License"); you may not use this file except in compliance 8 | with the License. You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, 13 | software distributed under the License is distributed on an 14 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | KIND, either express or implied. See the License for the 16 | specific language governing permissions and limitations 17 | under the License. 18 | ******************************************************************************/ 19 | 20 | define(["jquery", "underscore", "backbone", "helper/util", "models/statistics/statmodel", "views/statistics/statview", "config/app-config", "config/view-config", "helper/stat-table"], function($, _, Backbone, Util, StatModel, StatView, AppConfig, ViewConfig, StatTable){ 21 | var XDRCollection = Backbone.Collection.extend({ 22 | model: StatModel, 23 | initialize : function(){ 24 | // this.statTableID = AppConfig.stat.statTableDiv; 25 | // this.statList = AppConfig.xdrStatsList; 26 | }, 27 | initializeGrid: function(){ 28 | StatTable.startInitGrid(AppConfig.xdrStatsList); 29 | }, 30 | clearAndInitGridData: function(){ 31 | $(AppConfig.stat.statTableDiv).jqGrid('clearGridData'); 32 | StatTable.initAndSetGridData(AppConfig.xdrStatsList); 33 | $(AppConfig.stat.statTableDiv).trigger("reloadGrid"); 34 | }, 35 | addModel: function(address, clusterID, xdrPort){ 36 | var xdr = new StatModel({"update_interval" : 5}); 37 | xdr.setParamaters(address, clusterID, 'xdr', AppConfig.stat.statTableDiv, AppConfig.xdrStatsList, xdrPort); 38 | xdr.colView = new StatView(); 39 | this.add(xdr); 40 | return xdr; 41 | } 42 | }); 43 | return XDRCollection; 44 | }); 45 | 46 | 47 | -------------------------------------------------------------------------------- /static/js/collections/jobs/nodes.js: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Licensed to the Apache Software Foundation (ASF) under one 3 | or more contributor license agreements. See the NOTICE file 4 | distributed with this work for additional information 5 | regarding copyright ownership. The ASF licenses this file 6 | to you under the Apache License, Version 2.0 (the 7 | "License"); you may not use this file except in compliance 8 | with the License. You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, 13 | software distributed under the License is distributed on an 14 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | KIND, either express or implied. See the License for the 16 | specific language governing permissions and limitations 17 | under the License. 18 | ******************************************************************************/ 19 | 20 | define(["jquery", "underscore", "backbone", "helper/util", "models/jobs/nodemodel", "views/jobs/nodeview", "config/app-config", "config/view-config", "helper/job-table"], function($, _, Backbone, Util, NodeModel, NodeView, AppConfig, ViewConfig, JobTable){ 21 | var PAGE_SIZE = 10; 22 | var NodeCollection = Backbone.Collection.extend({ 23 | model: NodeModel, 24 | initVariables :function(){ 25 | this.clusterSizeAlertShown = false; 26 | this.clusterIntegrityAlertShown = false; 27 | }, 28 | initialize : function(){ 29 | try{ 30 | this.initVariables(); 31 | JobTable.initNodeGrid(AppConfig.node.nodeTableDiv, ViewConfig.nodePieConfig, this.models, AppConfig.job.runningJobPager, PAGE_SIZE, 'inprogress'); 32 | JobTable.initNodeGrid(AppConfig.job.nodeTableCompletedJobsDiv, ViewConfig.nodePieConfig, this.models, AppConfig.job.completedJobPager, PAGE_SIZE, 'completed'); 33 | }catch(e){ 34 | console.info(e.toString()); 35 | } 36 | }, 37 | addModel: function(modelID, clusterID, status, container){ 38 | var node = new NodeModel({model_id:modelID, cluster_id:clusterID, status: status, container: container, page_size: PAGE_SIZE}); 39 | node.rowView = {}; 40 | this.add(node); 41 | } 42 | 43 | }); 44 | return NodeCollection; 45 | }); 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /static/js/collections/latency/nodes.js: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | *Copyright 2008-2014 by Aerospike, Inc. All rights reserved. 3 | *THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE. THE COPYRIGHT NOTICE 4 | *ABOVE DOES NOT EVIDENCE ANY ACTUAL OR INTENDED PUBLICATION. 5 | ******************************************************************************/ 6 | define(["jquery", "underscore", "backbone", "helper/util", "models/latency/nodemodel", 7 | "config/app-config", "config/view-config", "helper/job-table", "helper/AjaxManager"], 8 | function($, _, Backbone, Util, NodeModel, AppConfig, ViewConfig, JobTable, AjaxManager){ 9 | var NodeCollection = Backbone.Collection.extend({ 10 | model: NodeModel, 11 | initVariables :function(){ 12 | this.clusterSizeAlertShown = false; 13 | this.clusterIntegrityAlertShown = false; 14 | this.parent = {}; 15 | this.latencyHistory = {}; // map of node address to latency history 16 | this.historyFetched = false; 17 | this.latencyFetchError = false; 18 | }, 19 | initialize : function(){ 20 | try{ 21 | this.bind('add', this.onModelAdded, this); 22 | this.bind('remove', this.onModelRemoved, this); 23 | this.initVariables(); 24 | this._fetchLatencyHistory(); 25 | }catch(e){ 26 | console.log(e); 27 | } 28 | }, 29 | 30 | _fetchLatencyHistory: function() { 31 | var that = this; 32 | var url = AppConfig.baseUrl + window.AMCGLOBALS.persistent.clusterID + '/nodes/'; 33 | url += window.AMCGLOBALS.persistent.nodeList.join(','); 34 | url += '/latency_history'; 35 | 36 | AjaxManager.sendRequest(url, {}, 37 | function success(history) { 38 | that.historyFetched = true; 39 | that.latencyHistory = history; 40 | that._initNodes(); 41 | }, function error() { 42 | that.historyFetched = true; 43 | that.latencyFetchError = true; 44 | that._initNodes(); 45 | } 46 | ); 47 | }, 48 | 49 | _initNodes: function() { 50 | var that = this; 51 | this.each(function(model) { 52 | that._initNode(model); 53 | }); 54 | }, 55 | 56 | // initialize node based on fetch status 57 | _initNode: function(model) { 58 | var address = model.address; 59 | var history = this.latencyHistory[address]; 60 | try { 61 | if(this.latencyFetchError) { 62 | model.initLatencyHistoryOnError(); 63 | } else if(history) { 64 | model.initLatencyHistory(history); 65 | } else { 66 | console.log('INFO: History not yet fetched. Not initializing node ' + address); 67 | } 68 | } catch(e) { 69 | console.log(e); 70 | } 71 | }, 72 | 73 | addModel: function(modelID, address, clusterID, totalNodes){ 74 | var node = new NodeModel({model_id:modelID, address: address, cluster_id:clusterID, total_nodes:totalNodes}); 75 | var history = this.latencyHistory[address]; 76 | var that = this; 77 | var url; 78 | 79 | this.add(node); 80 | 81 | if(this.historyFetched) { 82 | if(history) { 83 | this._initNode(node); 84 | } else { 85 | url = AppConfig.baseUrl + window.AMCGLOBALS.persistent.clusterID + '/latency_history/' + address; 86 | AjaxManager.sendRequest(url, {}, 87 | function success(data) { 88 | that.latencyHistory[address] = data; 89 | that._initNode(node); 90 | }, 91 | function failure() { 92 | node.initLatencyHistoryOnError(); 93 | } 94 | ); 95 | } 96 | } 97 | }, 98 | onModelAdded: function(model, collection, options){ 99 | this.parent.nodes.push(model.address); 100 | Util.updateModelPoller(this.parent, AppConfig.updateInterval['nodes'], true); 101 | }, 102 | onModelRemoved: function(model, collection, options){ 103 | if(this.parent.nodes != null){ 104 | this.parent.nodes.splice(this.parent.nodes.indexOf(model.address),1); 105 | } 106 | $(AppConfig.node.nodeTableDiv).jqGrid('delRowData',/*AppConfig.node.nodeTablePrefix + */model.get("row_id")); 107 | } 108 | 109 | }); 110 | return NodeCollection; 111 | }); 112 | 113 | 114 | 115 | 116 | -------------------------------------------------------------------------------- /static/js/collections/statistics/namespaces.js: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Licensed to the Apache Software Foundation (ASF) under one 3 | or more contributor license agreements. See the NOTICE file 4 | distributed with this work for additional information 5 | regarding copyright ownership. The ASF licenses this file 6 | to you under the Apache License, Version 2.0 (the 7 | "License"); you may not use this file except in compliance 8 | with the License. You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, 13 | software distributed under the License is distributed on an 14 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | KIND, either express or implied. See the License for the 16 | specific language governing permissions and limitations 17 | under the License. 18 | ******************************************************************************/ 19 | 20 | define(["jquery", "underscore", "backbone", "helper/util", "models/statistics/statmodel", "views/statistics/statview", "config/app-config", "config/view-config", "helper/stat-table"], function($, _, Backbone, Util, StatModel, StatView, AppConfig, ViewConfig, StatTable){ 21 | var NamespaceCollection = Backbone.Collection.extend({ 22 | model: StatModel, 23 | initVariables :function(){ 24 | }, 25 | initialize : function(){ 26 | this.statTableID = AppConfig.stat.statTableDiv; 27 | this.statList = AppConfig.namespaceStatsList; 28 | }, 29 | initializeGrid: function(){ 30 | // StatTable.startInitGrid(AppConfig.namespaceStatsList); 31 | }, 32 | clearAndInitGridData: function(){ 33 | $(AppConfig.stat.statTableDiv).jqGrid('clearGridData'); 34 | // StatTable.initAndSetGridData(AppConfig.namespaceStatsList); 35 | // $(AppConfig.stat.statTableDiv).trigger("reloadGrid"); 36 | }, 37 | addModel: function(address, clusterID, namespaceName){ 38 | var namespace = new StatModel(); 39 | namespace.setParamaters(address, clusterID, 'namespace', AppConfig.stat.statTableDiv, AppConfig.namespaceStatsList, namespaceName); 40 | namespace.colView = new StatView({model: namespace, el : ("[id='statListTable_" + address + "']")}); 41 | this.add(namespace); 42 | return namespace; 43 | } 44 | }); 45 | return NamespaceCollection; 46 | }); 47 | 48 | 49 | -------------------------------------------------------------------------------- /static/js/collections/statistics/nodes.js: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Licensed to the Apache Software Foundation (ASF) under one 3 | or more contributor license agreements. See the NOTICE file 4 | distributed with this work for additional information 5 | regarding copyright ownership. The ASF licenses this file 6 | to you under the Apache License, Version 2.0 (the 7 | "License"); you may not use this file except in compliance 8 | with the License. You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, 13 | software distributed under the License is distributed on an 14 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | KIND, either express or implied. See the License for the 16 | specific language governing permissions and limitations 17 | under the License. 18 | ******************************************************************************/ 19 | 20 | define(["jquery", "underscore", "backbone", "helper/util", "models/statistics/statmodel", "views/statistics/statview", "config/app-config", "config/view-config", "helper/stat-table"], function($, _, Backbone, Util, StatModel, StatView, AppConfig, ViewConfig, StatTable){ 21 | var NodeCollection = Backbone.Collection.extend({ 22 | model: StatModel, 23 | initialize : function(){ 24 | }, 25 | initializeGrid: function(){ 26 | // StatTable.startInitGrid(AppConfig.nodeStatsList); 27 | }, 28 | clearAndInitGridData: function(){ 29 | $(AppConfig.stat.statTableDiv).jqGrid('clearGridData'); 30 | // StatTable.initAndSetGridData(AppConfig.nodeStatsList); 31 | // $(AppConfig.stat.statTableDiv).trigger("reloadGrid"); 32 | }, 33 | addModel: function(address, clusterID, tobeUsed){ 34 | var node = new StatModel(); 35 | node.colView = new StatView({model: node, el : ("[id='statListTable_" + address + "']")}); 36 | this.add(node); 37 | node.setParamaters(address, clusterID, 'nodes', AppConfig.stat.statTableDiv, AppConfig.nodeStatsList, tobeUsed); 38 | return node; 39 | } 40 | }); 41 | return NodeCollection; 42 | }); 43 | 44 | 45 | -------------------------------------------------------------------------------- /static/js/collections/statistics/sindex.js: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Licensed to the Apache Software Foundation (ASF) under one 3 | or more contributor license agreements. See the NOTICE file 4 | distributed with this work for additional information 5 | regarding copyright ownership. The ASF licenses this file 6 | to you under the Apache License, Version 2.0 (the 7 | "License"); you may not use this file except in compliance 8 | with the License. You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, 13 | software distributed under the License is distributed on an 14 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | KIND, either express or implied. See the License for the 16 | specific language governing permissions and limitations 17 | under the License. 18 | ******************************************************************************/ 19 | 20 | define(["jquery", "underscore", "backbone", "helper/util", "models/statistics/statmodel", "views/statistics/statview", "config/app-config", "config/view-config", "helper/stat-table"], function($, _, Backbone, Util, StatModel, StatView, AppConfig, ViewConfig, StatTable){ 21 | var SIndexesCollection = Backbone.Collection.extend({ 22 | model: StatModel, 23 | initialize : function(){ 24 | // this.statTableID = AppConfig.stat.statTableDiv; 25 | // this.statList = AppConfig.namespaceStatsList; 26 | }, 27 | initializeGrid: function(){ 28 | // StatTable.startInitGrid(AppConfig.sIndexStatsList); 29 | }, 30 | clearAndInitGridData: function(){ 31 | $(AppConfig.stat.statTableDiv).jqGrid('clearGridData'); 32 | // StatTable.initAndSetGridData(AppConfig.sIndexStatsList); 33 | // $(AppConfig.stat.statTableDiv).trigger("reloadGrid"); 34 | }, 35 | addModel: function(address, clusterID, tobeUsed){ 36 | var sIndex = new StatModel(); 37 | sIndex.colView = new StatView({model: sIndex, el : ("[id='statListTable_" + address + "']")}); 38 | sIndex.setParamaters(address, clusterID, 'sindex', AppConfig.stat.statTableDiv, AppConfig.sIndexStatsList, tobeUsed); 39 | this.add(sIndex); 40 | return sIndex; 41 | } 42 | }); 43 | return SIndexesCollection; 44 | }); 45 | 46 | 47 | -------------------------------------------------------------------------------- /static/js/collections/statistics/xdr.js: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Licensed to the Apache Software Foundation (ASF) under one 3 | or more contributor license agreements. See the NOTICE file 4 | distributed with this work for additional information 5 | regarding copyright ownership. The ASF licenses this file 6 | to you under the Apache License, Version 2.0 (the 7 | "License"); you may not use this file except in compliance 8 | with the License. You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, 13 | software distributed under the License is distributed on an 14 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | KIND, either express or implied. See the License for the 16 | specific language governing permissions and limitations 17 | under the License. 18 | ******************************************************************************/ 19 | 20 | define(["jquery", "underscore", "backbone", "helper/util", "models/statistics/statmodel", "views/statistics/statview", "config/app-config", "config/view-config", "helper/stat-table"], function($, _, Backbone, Util, StatModel, StatView, AppConfig, ViewConfig, StatTable){ 21 | var XDRCollection = Backbone.Collection.extend({ 22 | model: StatModel, 23 | initialize : function(){ 24 | this.statTableID = AppConfig.stat.statTableDiv; 25 | this.statList = AppConfig.xdrStatsList; 26 | }, 27 | initializeGrid: function(){ 28 | // StatTable.startInitGrid(AppConfig.xdrStatsList); 29 | }, 30 | clearAndInitGridData: function(){ 31 | $(AppConfig.stat.statTableDiv).jqGrid('clearGridData'); 32 | // StatTable.initAndSetGridData(AppConfig.xdrStatsList); 33 | // $(AppConfig.stat.statTableDiv).trigger("reloadGrid"); 34 | }, 35 | addModel: function(address, clusterID, xdrPort){ 36 | var xdr = new StatModel(); 37 | xdr.setParamaters(address, clusterID, 'xdr', AppConfig.stat.statTableDiv, AppConfig.xdrStatsList, xdrPort); 38 | xdr.colView = new StatView({model: xdr, el : ("[id='statListTable_" + address + "']")}); 39 | this.add(xdr); 40 | return xdr; 41 | } 42 | }); 43 | return XDRCollection; 44 | }); 45 | 46 | 47 | -------------------------------------------------------------------------------- /static/js/config/view-config.js: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Licensed to the Apache Software Foundation (ASF) under one 3 | or more contributor license agreements. See the NOTICE file 4 | distributed with this work for additional information 5 | regarding copyright ownership. The ASF licenses this file 6 | to you under the Apache License, Version 2.0 (the 7 | "License"); you may not use this file except in compliance 8 | with the License. You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, 13 | software distributed under the License is distributed on an 14 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | KIND, either express or implied. See the License for the 16 | specific language governing permissions and limitations 17 | under the License. 18 | ******************************************************************************/ 19 | 20 | define(["jquery", "underscore", "backbone" ], function($, _, Backbone){ 21 | var ViewConfig = { 22 | clusterPieConfig:{ 23 | width : 150, 24 | height : 150, 25 | outerRadius : 50, 26 | innerRadius : 40, 27 | textOffset : 5, 28 | tweenDuration : 1000, 29 | outerBorderWidth : 3, 30 | innerBorderWidth : 3, 31 | color : ["#61CAFF", "#FFFFFF"], 32 | textColor : ["#61CAFF", "#000000"] 33 | }, 34 | tablePieConfig: { 35 | width : 45, 36 | height : 50, 37 | outerRadius : 20, 38 | innerRadius : 0, 39 | textOffset : 5, 40 | tweenDuration : 1000, 41 | outerBorderWidth : 2, 42 | color : ["#61CAFF", "#FFFFFF"] 43 | }, 44 | throughputChartConfig: { 45 | gWidth : 440, 46 | gHeight : 250, 47 | initMaxY : 1000, 48 | initMinY : 0 49 | } 50 | 51 | }; 52 | 53 | return ViewConfig; 54 | 55 | 56 | }); -------------------------------------------------------------------------------- /static/js/dev.app.build.js: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Licensed to the Apache Software Foundation (ASF) under one 3 | or more contributor license agreements. See the NOTICE file 4 | distributed with this work for additional information 5 | regarding copyright ownership. The ASF licenses this file 6 | to you under the Apache License, Version 2.0 (the 7 | "License"); you may not use this file except in compliance 8 | with the License. You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, 13 | software distributed under the License is distributed on an 14 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | KIND, either express or implied. See the License for the 16 | specific language governing permissions and limitations 17 | under the License. 18 | ******************************************************************************/ 19 | 20 | ({ 21 | appDir : "../", 22 | baseUrl: "./js", 23 | dir: "../../script-build", 24 | 25 | paths: { 26 | //Libraries 27 | jquery: "libs/jquery/consolidated-jquery-functionalities.min", 28 | underscore: "libs/underscore/underscore", 29 | backbone: "libs/backbone/backbone", 30 | poller: "libs/backbone/backbone.poller.min", 31 | d3: "libs/d3/d3", 32 | d3Layout: "libs/d3/d3.layout.min", 33 | timechart: "libs/timechart/timechart", 34 | //Aerospike JS 35 | piechart: "helper/piechart", 36 | timeseriesChart: "helper/timechart-helper" 37 | } 38 | }) 39 | 40 | 41 | -------------------------------------------------------------------------------- /static/js/helper/AjaxManager.js: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Licensed to the Apache Software Foundation (ASF) under one 3 | or more contributor license agreements. See the NOTICE file 4 | distributed with this work for additional information 5 | regarding copyright ownership. The ASF licenses this file 6 | to you under the Apache License, Version 2.0 (the 7 | "License"); you may not use this file except in compliance 8 | with the License. You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, 13 | software distributed under the License is distributed on an 14 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | KIND, either express or implied. See the License for the 16 | specific language governing permissions and limitations 17 | under the License. 18 | ******************************************************************************/ 19 | 20 | define(["jquery","underscore","helper/util"],function($,_,Util){ 21 | var AjaxManager = { 22 | 23 | //Request type constants 24 | GET : "GET", 25 | POST : "POST", 26 | UPDATE : 'UPDATE', 27 | DELETE : 'DELETE', 28 | 29 | initAjaxFailureCatch : function(){ 30 | $(function(){ 31 | //setup ajax error handling 32 | $.ajaxSetup({ 33 | always : function(x){ 34 | if(typeof x.responseText !== 'undefined' && x.responseText.indexOf("Invalid cluster id") != -1){ 35 | Util.clusterIDReset(); 36 | } 37 | }, 38 | fail: function (x, status, error) { 39 | if (x.status == 401) { 40 | Util.showUserSessionInvalidateError(window.AMCGLOBALS.persistent.clusterID); 41 | } 42 | } 43 | }); 44 | }); 45 | }, 46 | 47 | //Send the ajax request 48 | sendRequest : function(url, customOption, successCallback, failCallback){ 49 | var defaultOptions = { 50 | type : this.GET, 51 | async : true, 52 | cache : true, 53 | data : {}, 54 | dataType : 'json', 55 | contentType : 'application/json; charset=utf-8' 56 | }; 57 | 58 | var options = $.extend({}, defaultOptions, customOption); 59 | 60 | //Actual send the ajax request 61 | var request = $.ajax({ 62 | type : options.type, 63 | url : url, 64 | async : options.async, 65 | cache : options.cache, 66 | data : options.data, 67 | headers : options.header || {} 68 | }) 69 | .done(function(data,textStatus, jqXHR ){ 70 | successCallback && successCallback(data); 71 | }) 72 | .fail(function(data,textStatus, errorThrown){ 73 | failCallback && failCallback(data,textStatus, errorThrown); 74 | }); 75 | 76 | return request; 77 | }, 78 | 79 | //This function will abort the ajax request 80 | abortAjaxRequest : function(request){ 81 | //Abort the ajax request, it is not completed 82 | if(request && request.readyState !== 4){ 83 | request.abort(); 84 | } 85 | } 86 | }; 87 | 88 | return AjaxManager; 89 | 90 | }); -------------------------------------------------------------------------------- /static/js/helper/def-table.js: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Licensed to the Apache Software Foundation (ASF) under one 3 | or more contributor license agreements. See the NOTICE file 4 | distributed with this work for additional information 5 | regarding copyright ownership. The ASF licenses this file 6 | to you under the Apache License, Version 2.0 (the 7 | "License"); you may not use this file except in compliance 8 | with the License. You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, 13 | software distributed under the License is distributed on an 14 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | KIND, either express or implied. See the License for the 16 | specific language governing permissions and limitations 17 | under the License. 18 | ******************************************************************************/ 19 | 20 | define(["jquery", "underscore", "backbone", "d3", "helper/jqgrid-helper", "helper/util", "config/app-config", "config/var-details"], function($, _, Backbone, D3, GridHelper, Util, AppConfig, VarDetails) { 21 | var StatTable = { 22 | 23 | 24 | 25 | }; 26 | 27 | return StatTable; 28 | }); -------------------------------------------------------------------------------- /static/js/helper/definitions/set-table.js: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Licensed to the Apache Software Foundation (ASF) under one 3 | or more contributor license agreements. See the NOTICE file 4 | distributed with this work for additional information 5 | regarding copyright ownership. The ASF licenses this file 6 | to you under the Apache License, Version 2.0 (the 7 | "License"); you may not use this file except in compliance 8 | with the License. You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, 13 | software distributed under the License is distributed on an 14 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | KIND, either express or implied. See the License for the 16 | specific language governing permissions and limitations 17 | under the License. 18 | ******************************************************************************/ 19 | 20 | define(["jquery", "underscore", "backbone", "d3", "helper/jqgrid-helper", "helper/util", "config/app-config"], function($, _, Backbone, D3, GridHelper, Util, AppConfig){ 21 | var XdrTable = { 22 | nodeTableIds: [], 23 | updateRowData: function(container, data, rowID){ 24 | data = XdrTable.getNodeListData(data); 25 | try{ 26 | if(!jQuery(container).getInd(rowID)){ 27 | jQuery(container).addRowData(rowID, data); 28 | }else{ 29 | jQuery(container).setRowData(rowID, data); 30 | } 31 | }catch(e){ 32 | console.info(e.toString()); 33 | } 34 | //NodeTable.nodeTableIds = GridHelper.maintainExpandedState(container, NodeTable.nodeTableIds); 35 | //$(container).trigger("reloadGrid"); 36 | }, 37 | getNodeListData: function(data){ 38 | data['esmt-bytes-shipped'] = GridHelper.formatExpandRow(data['esmt-bytes-shipped'], "size"); 39 | data['timediff_lastship_cur_secs'] = GridHelper.formatExpandRow(data['timediff_lastship_cur_secs'], "sec"); 40 | data['xdr_timelag'] = GridHelper.formatExpandRow(data['xdr_timelag'], "sec"); 41 | data['stat_recs_outstanding'] = GridHelper.formatExpandRow(data['stat_recs_outstanding'], "number"); 42 | data['stat_recs_shipped'] = GridHelper.formatExpandRow(data['stat_recs_shipped'], "number"); 43 | data['stat_recs_relogged'] = GridHelper.formatExpandRow(data['stat_recs_relogged'], "number"); 44 | data['cur_throughput'] = GridHelper.formatExpandRow(data['cur_throughput'], "number"); 45 | return data; 46 | }, 47 | initNodeGrid: function(container, pieConfig, models){ 48 | //$(container).jqGrid('GridDestroy'); 49 | var containerWidth = Math.max(window.innerWidth * 0.93, 750); 50 | var grid = jQuery(container).jqGrid({ 51 | datatype:'local', 52 | //data: nodeListData, 53 | hidegrid: false, 54 | colNames: AppConfig.xdrColumnNames, 55 | colModel: AppConfig.xdrListColumn, 56 | height:'auto', 57 | loadui : 'disable', 58 | loadonce:true, 59 | //ExpandColClick: true, 60 | subGrid: false, 61 | headertitles : true, 62 | //sortname: "address", 63 | //sortorder: "asc", 64 | //cmTemplate: {sortable:false}, 65 | width:containerWidth, 66 | loadComplete: function () { 67 | $(container).jqGrid('hideCol', 'subgrid'); 68 | $("#nodeStatListGrid1 .toggleSearchHeader").show(); 69 | } 70 | }); 71 | GridHelper.columnHeaderTitleFormatter(grid, AppConfig.xdrListColumn ); 72 | function handler() { 73 | if(window.AMCGLOBALS.activePage !== "definitions"){ 74 | window.removeEventListener("resize", handler,true); 75 | return; 76 | } 77 | $(container.selector).setGridWidth(Math.max(window.innerWidth * 0.93, 750)); 78 | } 79 | window.addEventListener('resize', handler, true); 80 | return grid; 81 | } 82 | 83 | }; 84 | 85 | return XdrTable; 86 | }); 87 | -------------------------------------------------------------------------------- /static/js/helper/definitions/udf-table.js: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Licensed to the Apache Software Foundation (ASF) under one 3 | or more contributor license agreements. See the NOTICE file 4 | distributed with this work for additional information 5 | regarding copyright ownership. The ASF licenses this file 6 | to you under the Apache License, Version 2.0 (the 7 | "License"); you may not use this file except in compliance 8 | with the License. You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, 13 | software distributed under the License is distributed on an 14 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | KIND, either express or implied. See the License for the 16 | specific language governing permissions and limitations 17 | under the License. 18 | ******************************************************************************/ 19 | 20 | define(["jquery", "underscore", "backbone", "d3", "helper/jqgrid-helper", "helper/util", "config/app-config"], function($, _, Backbone, D3, GridHelper, Util, AppConfig){ 21 | var XdrTable = { 22 | nodeTableIds: [], 23 | updateRowData: function(container, data, rowID){ 24 | data = XdrTable.getNodeListData(data); 25 | try{ 26 | if(!jQuery(container).getInd(rowID)){ 27 | jQuery(container).addRowData(rowID, data); 28 | }else{ 29 | jQuery(container).setRowData(rowID, data); 30 | } 31 | }catch(e){ 32 | console.info(e.toString()); 33 | } 34 | //NodeTable.nodeTableIds = GridHelper.maintainExpandedState(container, NodeTable.nodeTableIds); 35 | //$(container).trigger("reloadGrid"); 36 | }, 37 | getNodeListData: function(data){ 38 | data['esmt-bytes-shipped'] = GridHelper.formatExpandRow(data['esmt-bytes-shipped'], "size"); 39 | data['timediff_lastship_cur_secs'] = GridHelper.formatExpandRow(data['timediff_lastship_cur_secs'], "sec"); 40 | data['xdr_timelag'] = GridHelper.formatExpandRow(data['xdr_timelag'], "sec"); 41 | data['stat_recs_outstanding'] = GridHelper.formatExpandRow(data['stat_recs_outstanding'], "number"); 42 | data['stat_recs_shipped'] = GridHelper.formatExpandRow(data['stat_recs_shipped'], "number"); 43 | data['stat_recs_relogged'] = GridHelper.formatExpandRow(data['stat_recs_relogged'], "number"); 44 | data['cur_throughput'] = GridHelper.formatExpandRow(data['cur_throughput'], "number"); 45 | return data; 46 | }, 47 | initNodeGrid: function(container, pieConfig, models){ 48 | //$(container).jqGrid('GridDestroy'); 49 | var containerWidth = Math.max(window.innerWidth * 0.93, 750); 50 | var grid = jQuery(container).jqGrid({ 51 | datatype:'local', 52 | //data: nodeListData, 53 | hidegrid: false, 54 | colNames: AppConfig.xdrColumnNames, 55 | colModel: AppConfig.xdrListColumn, 56 | height:'auto', 57 | loadui : 'disable', 58 | loadonce:true, 59 | //ExpandColClick: true, 60 | subGrid: false, 61 | headertitles : true, 62 | //sortname: "address", 63 | //sortorder: "asc", 64 | //cmTemplate: {sortable:false}, 65 | width:containerWidth, 66 | loadComplete: function () { 67 | $(container).jqGrid('hideCol', 'subgrid'); 68 | } 69 | }); 70 | GridHelper.columnHeaderTitleFormatter(grid, AppConfig.xdrListColumn ); 71 | function handler() { 72 | if(window.AMCGLOBALS.activePage !== "definitions"){ 73 | window.removeEventListener("resize", handler,true); 74 | return; 75 | } 76 | $(container.selector).setGridWidth(Math.max(window.innerWidth * 0.93, 750)); 77 | } 78 | window.addEventListener('resize', handler, true); 79 | return grid; 80 | } 81 | 82 | }; 83 | 84 | return XdrTable; 85 | }); 86 | -------------------------------------------------------------------------------- /static/js/helper/definitions/xdr-table.js: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Licensed to the Apache Software Foundation (ASF) under one 3 | or more contributor license agreements. See the NOTICE file 4 | distributed with this work for additional information 5 | regarding copyright ownership. The ASF licenses this file 6 | to you under the Apache License, Version 2.0 (the 7 | "License"); you may not use this file except in compliance 8 | with the License. You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, 13 | software distributed under the License is distributed on an 14 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | KIND, either express or implied. See the License for the 16 | specific language governing permissions and limitations 17 | under the License. 18 | ******************************************************************************/ 19 | 20 | define(["jquery", "underscore", "backbone", "d3", "helper/jqgrid-helper", "helper/util", "config/app-config"], function($, _, Backbone, D3, GridHelper, Util, AppConfig){ 21 | var XdrTable = { 22 | nodeTableIds: [], 23 | updateRowData: function(container, data, rowID){ 24 | data = XdrTable.getNodeListData(data); 25 | try{ 26 | if(!jQuery(container).getInd(rowID)){ 27 | jQuery(container).addRowData(rowID, data); 28 | }else{ 29 | jQuery(container).setRowData(rowID, data); 30 | } 31 | }catch(e){ 32 | console.info(e.toString()); 33 | } 34 | //NodeTable.nodeTableIds = GridHelper.maintainExpandedState(container, NodeTable.nodeTableIds); 35 | //$(container).trigger("reloadGrid"); 36 | }, 37 | getNodeListData: function(data){ 38 | data['esmt-bytes-shipped'] = GridHelper.formatExpandRow(data['esmt-bytes-shipped'], "size"); 39 | data['timediff_lastship_cur_secs'] = GridHelper.formatExpandRow(data['timediff_lastship_cur_secs'], "sec"); 40 | data['xdr_timelag'] = GridHelper.formatExpandRow(data['xdr_timelag'], "sec"); 41 | data['stat_recs_outstanding'] = GridHelper.formatExpandRow(data['stat_recs_outstanding'], "number"); 42 | data['stat_recs_shipped'] = GridHelper.formatExpandRow(data['stat_recs_shipped'], "number"); 43 | data['stat_recs_relogged'] = GridHelper.formatExpandRow(data['stat_recs_relogged'], "number"); 44 | data['cur_throughput'] = GridHelper.formatExpandRow(data['cur_throughput'], "number"); 45 | return data; 46 | }, 47 | initNodeGrid: function(container, pieConfig, models){ 48 | //$(container).jqGrid('GridDestroy'); 49 | var grid = jQuery(container).jqGrid({ 50 | datatype:'local', 51 | //data: nodeListData, 52 | hidegrid: false, 53 | colNames: AppConfig.xdrColumnNames, 54 | colModel: AppConfig.xdrListColumn, 55 | height:'auto', 56 | loadui : 'disable', 57 | loadonce:true, 58 | //ExpandColClick: true, 59 | subGrid: false, 60 | headertitles : true, 61 | //sortname: "address", 62 | //sortorder: "asc", 63 | //cmTemplate: {sortable:false}, 64 | width: Math.max(window.innerWidth * 0.93, 750), 65 | loadComplete: function () { 66 | $(container).jqGrid('hideCol', 'subgrid'); 67 | } 68 | }); 69 | GridHelper.columnHeaderTitleFormatter(grid, AppConfig.xdrListColumn ); 70 | function handler() { 71 | if(window.AMCGLOBALS.activePage !== "dashboard"){ 72 | window.removeEventListener("resize", handler,true); 73 | return; 74 | } 75 | $(container.selector).setGridWidth(Math.max(window.innerWidth * 0.93, 750)); 76 | } 77 | window.addEventListener('resize', handler, true); 78 | return grid; 79 | } 80 | 81 | }; 82 | 83 | return XdrTable; 84 | }); 85 | -------------------------------------------------------------------------------- /static/js/helper/modal.js: -------------------------------------------------------------------------------- 1 | define(['jquery', 'underscore', 'models/common/PopupModel'], function($, _, PopupModel) { 2 | var modal = { 3 | showModalDialog : function(DOM, modalSettings, submit, cancel){ 4 | $("#ModalWrapper").remove(); 5 | $("body").append(DOM); 6 | $("#ModalWrapper").dialog(_.extend({ 7 | modal: true, 8 | resizable: false 9 | }, modalSettings)); 10 | 11 | if(submit){ 12 | $("#ModalSubmit").on("click", submit); 13 | } 14 | 15 | if(cancel){ 16 | $("#ModalCancel").on("click", cancel); 17 | } 18 | 19 | $("#modalBody .modal-content").on("keydown", function(e){ 20 | if (e.keyCode === 13) { 21 | submit(e); 22 | } 23 | }); 24 | $(window).resize(function() { 25 | $("#ModalWrapper").dialog("option", "position", "center"); 26 | }); 27 | }, 28 | 29 | hideModalDialog : function(){ 30 | $("#ModalWrapper").remove(); 31 | }, 32 | 33 | confirmModal: function(title, content, onselect, oncancel) { 34 | var popupModel = new PopupModel({ 35 | cancelButtonValue: 'Cancel', 36 | content: '
' + content + '
', 37 | modalClass: 'user-popup', 38 | submitButtonValue: 'OK', 39 | title: title, 40 | }); 41 | var DOM = _.template($("#ModalTemplate").text(), popupModel.toJSON()); 42 | var modalSettings = {width: '600px', closeOnEscape: true, dialogClass: 'no-dialog-title'}; 43 | 44 | var success = function() { 45 | modal.hideModalDialog(); 46 | onselect && onselect(); 47 | }; 48 | var cancel = function() { 49 | modal.hideModalDialog(); 50 | oncancel && oncancel(); 51 | }; 52 | modal.showModalDialog(DOM, modalSettings, success, cancel); 53 | }, 54 | 55 | messageModal: function(title, content, callback) { 56 | var popupModel = new PopupModel({ 57 | showCancelButton: false, 58 | content: '
' + content + '
', 59 | modalClass: 'user-popup', 60 | submitButtonValue: 'OK', 61 | title: '' + title + '', 62 | }); 63 | var DOM = _.template($("#ModalTemplate").text(), popupModel.toJSON()); 64 | var modalSettings = {width: '600px', closeOnEscape: true, dialogClass: 'no-dialog-title'}; 65 | 66 | var success = function() { 67 | modal.hideModalDialog(); 68 | callback && callback(); 69 | }; 70 | modal.showModalDialog(DOM, modalSettings, success); 71 | }, 72 | }; 73 | 74 | return modal; 75 | }); 76 | 77 | 78 | -------------------------------------------------------------------------------- /static/js/helper/notification.js: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Licensed to the Apache Software Foundation (ASF) under one 3 | or more contributor license agreements. See the NOTICE file 4 | distributed with this work for additional information 5 | regarding copyright ownership. The ASF licenses this file 6 | to you under the Apache License, Version 2.0 (the 7 | "License"); you may not use this file except in compliance 8 | with the License. You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, 13 | software distributed under the License is distributed on an 14 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | KIND, either express or implied. See the License for the 16 | specific language governing permissions and limitations 17 | under the License. 18 | ******************************************************************************/ 19 | 20 | define(["jquery"], function($){ 21 | 22 | var Notification = { 23 | toastNotification : function(notificationType, message, timeout, showNotificationAsModel){ 24 | var notificationObj = { 25 | text : message, 26 | layout : "center", 27 | type : notificationType, 28 | timeout : (timeout == null ? 1000 : timeout), 29 | model : (showNotificationAsModel == null ? false : showNotificationAsModel), 30 | closeWith: ["click"] 31 | 32 | }; 33 | if(this.toastMsg != null){ 34 | /*Destroying old notification message*/ 35 | if ($("#" + this.toastMsg.options.id).parent()) { 36 | $("#" + this.toastMsg.options.id).parent().remove(); 37 | } 38 | } 39 | this.toastMsg = noty(notificationObj); 40 | }, 41 | 42 | cleanUp : function(){ 43 | $.noty.closeAll(); 44 | $(".noty_bar").parent().remove(); 45 | } 46 | }; 47 | 48 | return Notification; 49 | }); -------------------------------------------------------------------------------- /static/js/helper/overlay.js: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Licensed to the Apache Software Foundation (ASF) under one 3 | or more contributor license agreements. See the NOTICE file 4 | distributed with this work for additional information 5 | regarding copyright ownership. The ASF licenses this file 6 | to you under the Apache License, Version 2.0 (the 7 | "License"); you may not use this file except in compliance 8 | with the License. You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, 13 | software distributed under the License is distributed on an 14 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | KIND, either express or implied. See the License for the 16 | specific language governing permissions and limitations 17 | under the License. 18 | ******************************************************************************/ 19 | 20 | define(["libs/spin/spin.min"], function(Spinner){ 21 | var _defaults = { 22 | lines: 13, // The number of lines to draw 23 | length: 8, // The length of each line 24 | width: 3, // The line thickness 25 | radius: 7, // The radius of the inner circle 26 | corners: 1, // Corner roundness (0..1) 27 | rotate: 0, // The rotation offset 28 | direction: 1, // 1: clockwise, -1: counterclockwise 29 | color: '#000', // #rgb or #rrggbb or array of colors 30 | speed: 1.3, // Rounds per second 31 | trail: 60, // Afterglow percentage 32 | shadow: false, // Whether to render a shadow 33 | hwaccel: false, // Whether to use hardware acceleration 34 | className: 'spinner', // The CSS class to assign to the spinner 35 | zIndex: 2e9, // The z-index (defaults to 2000000000) 36 | top: '50%', // Top position relative to parent 37 | left: '50%' // Left position relative to parent 38 | }; 39 | 40 | var OverlayLoader = function(elementId,options){ 41 | options = options || {}; 42 | var options = _.extend(_defaults,options) ; 43 | this.spinner = new Spinner(options).spin(document.getElementById(elementId)); 44 | }; 45 | 46 | OverlayLoader.prototype.stopOverlay = function(){ 47 | this.spinner.stop(); 48 | }; 49 | 50 | var Overlay = function(elementId, options){ 51 | if(typeof elementId !== 'undefined'){ 52 | var overlay = new OverlayLoader(elementId, options); 53 | return overlay; 54 | } 55 | return null; 56 | 57 | }; 58 | 59 | return Overlay; 60 | }); 61 | -------------------------------------------------------------------------------- /static/js/helper/sessionmanager.js: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | *Copyright 2008-2014 by Aerospike, Inc. All rights reserved. 3 | *THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE. THE COPYRIGHT NOTICE 4 | *ABOVE DOES NOT EVIDENCE ANY ACTUAL OR INTENDED PUBLICATION. 5 | ******************************************************************************/ 6 | 7 | define(["jquery","config/app-config"],function($,AppConfig){ 8 | var SessionManager = { 9 | putItemIntoSession : function(key, value) { 10 | try{ 11 | sessionStorage.setItem(key,value); 12 | return value; 13 | } catch(e){ 14 | alert('Your web browser does not support storing settings locally. In Safari, the most common cause of this is using "Private Browsing Mode". Some settings may not save or some features may not work properly for you.'); 15 | } 16 | }, 17 | 18 | getItemFromSession : function(key) { 19 | return sessionStorage.getItem(key); 20 | }, 21 | 22 | removeItemFromSession : function(key) { 23 | var value = localStorage.getItem(key); 24 | if(value !== undefined || value !== null) { 25 | sessionStorage.removeItem(key); 26 | return value; 27 | } 28 | return null; 29 | }, 30 | 31 | cleanupLocalUserSession : function(){ 32 | this._cleanupusersession_(); 33 | }, 34 | 35 | _cleanupusersession_ : function(){ 36 | this.removeItemFromSession(AppConfig.sessionKeys.username); 37 | this.removeItemFromSession(AppConfig.sessionKeys.isSecurityEnable); 38 | this.removeItemFromSession(AppConfig.sessionKeys.userClusterId); 39 | } 40 | } 41 | 42 | return SessionManager; 43 | }); -------------------------------------------------------------------------------- /static/js/helper/usermanager.js: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | *Copyright 2008-2014 by Aerospike, Inc. All rights reserved. 3 | *THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE. THE COPYRIGHT NOTICE 4 | *ABOVE DOES NOT EVIDENCE ANY ACTUAL OR INTENDED PUBLICATION. 5 | ******************************************************************************/ 6 | define(["jquery","helper/servicemanager","helper/notification","config/app-config","helper/AjaxManager"], 7 | function($,ServiceManager,Notification,AppConfig,AjaxManager){ 8 | 9 | var usermanager = { 10 | showUserHomePage : function(){ 11 | var scm = ServiceManager.serviceComponentMap; 12 | var seedNode = window.AMCGLOBALS.persistent.seedNode; 13 | if(ServiceManager.isUserHasAccessToService(scm.DASHBOARD_PAGE.SERVICE_KEY)){ 14 | window.location.hash = "dashboard/" + (seedNode !== null ? seedNode :""); 15 | } else if(ServiceManager.isUserHasAccessToService(scm.STATISTIC_PAGE.SERVICE_KEY)){ 16 | window.location.hash = "statistics/" + (seedNode !== null ? seedNode :""); 17 | } else if(ServiceManager.isUserHasAccessToService(scm.DEFINITION_PAGE.SERVICE_KEY)){ 18 | window.location.hash = "definitions/" + (seedNode !== null ? seedNode :""); 19 | } else if(ServiceManager.isUserHasAccessToService(scm.JOBS_PAGE.SERVICE_KEY)){ 20 | window.location.hash = "jobs/" + (seedNode !== null ? seedNode :""); 21 | } else if(ServiceManager.isUserHasAccessToService(scm.LATENCY_PAGE.SERVICE_KEY)){ 22 | window.location.hash = "latency/" + (seedNode !== null ? seedNode :""); 23 | } else if(ServiceManager.isUserHasAccessToService(scm.MANAGE_PAGE.SERVICE_KEY)){ 24 | window.location.hash = "admin-console/" + (seedNode !== null ? seedNode :""); 25 | } else { 26 | Notification.toastNotification("red","You don't have access to any module",false,true); 27 | } 28 | }, 29 | 30 | getUserHomePageByRoles : function(roles){ 31 | var url = window.location.protocol + "//"+window.location.host; 32 | if(roles.length === 1 && roles.indexOf("user-admin") !== -1){ 33 | return url + "/#admin-console"; 34 | } else { 35 | return url + "/#dashboard"; 36 | } 37 | }, 38 | 39 | getDefaultActivePageByRoles : function(roles){ 40 | if(roles.length === 1 && roles.indexOf("user-admin") !== -1){ 41 | return "admin-console"; 42 | } else { 43 | return "dashboard"; 44 | } 45 | }, 46 | 47 | /* 48 | * This method will fetch all currently monitoring cluster information in current session 49 | */ 50 | getCurrentMonitoringCluster : function(successCallback,failureCallback,isSynchronous){ 51 | if(isSynchronous == null || (typeof isSynchronous === "undefined")) { 52 | isSynchronous = false; 53 | } 54 | AjaxManager.sendRequest(AppConfig.urls.GET_CURRENT_MONITORING_CLUSTESR, {async:isSynchronous}, successCallback,failureCallback); 55 | } 56 | }; 57 | return usermanager; 58 | }); -------------------------------------------------------------------------------- /static/js/libs/backbone/backbone.js: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Licensed to the Apache Software Foundation (ASF) under one 3 | or more contributor license agreements. See the NOTICE file 4 | distributed with this work for additional information 5 | regarding copyright ownership. The ASF licenses this file 6 | to you under the Apache License, Version 2.0 (the 7 | "License"); you may not use this file except in compliance 8 | with the License. You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, 13 | software distributed under the License is distributed on an 14 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | KIND, either express or implied. See the License for the 16 | specific language governing permissions and limitations 17 | under the License. 18 | ******************************************************************************/ 19 | 20 | 21 | define(["jquery", "underscore", 'libs/backbone/backbone-min'], function($, _){ 22 | $.noConflict(); 23 | return Backbone.noConflict(); 24 | }); -------------------------------------------------------------------------------- /static/js/libs/spin/spin.min.js: -------------------------------------------------------------------------------- 1 | //fgnass.github.com/spin.js#v2.0.1 2 | /** 3 | * Copyright (c) 2011-2014 Felix Gnass 4 | * Licensed under the MIT license 5 | */ 6 | !function(a,b){"object"==typeof exports?module.exports=b():"function"==typeof define&&define.amd?define(b):a.Spinner=b()}(this,function(){"use strict";function a(a,b){var c,d=document.createElement(a||"div");for(c in b)d[c]=b[c];return d}function b(a){for(var b=1,c=arguments.length;c>b;b++)a.appendChild(arguments[b]);return a}function c(a,b,c,d){var e=["opacity",b,~~(100*a),c,d].join("-"),f=.01+c/d*100,g=Math.max(1-(1-a)/b*(100-f),a),h=j.substring(0,j.indexOf("Animation")).toLowerCase(),i=h&&"-"+h+"-"||"";return l[e]||(m.insertRule("@"+i+"keyframes "+e+"{0%{opacity:"+g+"}"+f+"%{opacity:"+a+"}"+(f+.01)+"%{opacity:1}"+(f+b)%100+"%{opacity:"+a+"}100%{opacity:"+g+"}}",m.cssRules.length),l[e]=1),e}function d(a,b){var c,d,e=a.style;for(b=b.charAt(0).toUpperCase()+b.slice(1),d=0;d',c)}m.addRule(".spin-vml","behavior:url(#default#VML)"),h.prototype.lines=function(a,d){function f(){return e(c("group",{coordsize:k+" "+k,coordorigin:-j+" "+-j}),{width:k,height:k})}function h(a,h,i){b(m,b(e(f(),{rotation:360/d.lines*a+"deg",left:~~h}),b(e(c("roundrect",{arcsize:d.corners}),{width:j,height:d.width,left:d.radius,top:-d.width>>1,filter:i}),c("fill",{color:g(d.color,a),opacity:d.opacity}),c("stroke",{opacity:0}))))}var i,j=d.length+d.width,k=2*j,l=2*-(d.width+d.length)+"px",m=e(f(),{position:"absolute",top:l,left:l});if(d.shadow)for(i=1;i<=d.lines;i++)h(i,-2,"progid:DXImageTransform.Microsoft.Blur(pixelradius=2,makeshadow=1,shadowopacity=.3)");for(i=1;i<=d.lines;i++)h(i);return b(a,m)},h.prototype.opacity=function(a,b,c,d){var e=a.firstChild;d=d.shadow&&d.lines||0,e&&b+d>1)+"px"})}for(var i,k=0,l=(f.lines-1)*(1-f.direction)/2;k" + (response.get('address')) + " cannot be monitored here as it belongs to a different cluster"); 54 | } 55 | var row = response.rowView; 56 | row.render(response, response.attributes); 57 | }catch(e){ 58 | console.info(e.toString()); 59 | } 60 | 61 | if(this.clusterID !== window.AMCGLOBALS.persistent.clusterID){ 62 | this.clusterID = window.AMCGLOBALS.persistent.clusterID; 63 | } 64 | 65 | if(typeof response.attributes.error !== 'undefined' && response.attributes.error.indexOf("Invalid cluster id") != -1){ 66 | delete response.attributes.error; 67 | Util.clusterIDReset(); 68 | } 69 | }, 70 | fetchError: function(response){ 71 | if(response.CID !== window.AMCGLOBALS.currentCID){ 72 | response.destroy(); return; 73 | } 74 | try{ 75 | var row = response.rowView; 76 | row.renderNetworkError(response); 77 | }catch(e){ 78 | console.info(e.toString()); 79 | } 80 | 81 | } 82 | 83 | 84 | }); 85 | 86 | return NodeModel; 87 | }); 88 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /static/js/models/dashboard/xdrmodel.js: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | *Copyright 2008-2014 by Aerospike, Inc. All rights reserved. 3 | *THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE. THE COPYRIGHT NOTICE 4 | *ABOVE DOES NOT EVIDENCE ANY ACTUAL OR INTENDED PUBLICATION. 5 | ******************************************************************************/ 6 | define(["underscore", "backbone", "poller", "config/app-config", "helper/util"], function(_, Backbone, Poller, AppConfig, Util){ 7 | var XdrModel = Backbone.Model.extend({ 8 | idAttribute : "address", 9 | 10 | initVariables :function(){ 11 | this.totalNodes = +this.get("total_nodes"); 12 | this.address = this.get("address"); 13 | this.clusterID = window.AMCGLOBALS.persistent.clusterID; 14 | }, 15 | initialize :function(){ 16 | this.CID = window.AMCGLOBALS.currentCID; 17 | try{ 18 | this.initVariables(); 19 | this.startEventListeners(); 20 | }catch(e){ 21 | console.info(e.toString()); 22 | } 23 | 24 | }, 25 | 26 | startEventListeners : function (){ 27 | var that = this; 28 | }, 29 | 30 | fetchSuccess: function(response){ 31 | if(response.CID !== window.AMCGLOBALS.currentCID){ 32 | response.destroy(); return; 33 | } 34 | 35 | try{ 36 | if(typeof(response.attributes["error"]) !== "undefined") 37 | return; 38 | var row = response.rowView; 39 | row.render(response, response.attributes); 40 | }catch(e){ 41 | console.info(e); 42 | } 43 | 44 | if(this.clusterID !== window.AMCGLOBALS.persistent.clusterID){ 45 | this.clusterID = window.AMCGLOBALS.persistent.clusterID; 46 | 47 | } 48 | 49 | if(typeof response.attributes.error !== 'undefined' && response.attributes.error.indexOf("Invalid cluster id") != -1){ 50 | delete response.attributes.error; 51 | Util.clusterIDReset(); 52 | } 53 | }, 54 | fetchError: function(response){ 55 | if(response.CID !== window.AMCGLOBALS.currentCID){ 56 | response.destroy(); return; 57 | } 58 | try{ 59 | var row = response.rowView; 60 | row.renderNetworkError(response); 61 | }catch(e){ 62 | console.info(e.toString()); 63 | } 64 | } 65 | }); 66 | 67 | return XdrModel; 68 | }); 69 | 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /static/js/models/definitions/xdrmodel.js: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Licensed to the Apache Software Foundation (ASF) under one 3 | or more contributor license agreements. See the NOTICE file 4 | distributed with this work for additional information 5 | regarding copyright ownership. The ASF licenses this file 6 | to you under the Apache License, Version 2.0 (the 7 | "License"); you may not use this file except in compliance 8 | with the License. You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, 13 | software distributed under the License is distributed on an 14 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | KIND, either express or implied. See the License for the 16 | specific language governing permissions and limitations 17 | under the License. 18 | ******************************************************************************/ 19 | 20 | define(["underscore", "backbone", "poller", "views/definitions/sindexview", "helper/definitions/sindex-table", "config/app-config", "helper/util"], function(_, Backbone, Poller, SIndexView, SIndexTable, AppConfig, Util){ 21 | var SIndexModel = Backbone.Model.extend({ 22 | initialize: function(){ 23 | this.CID = window.AMCGLOBALS.currentCID; 24 | this.initVariables(); 25 | this.startEventListeners(this); 26 | }, 27 | initVariables: function(){ 28 | this.clusterID = window.AMCGLOBALS.persistent.clusterID;//this.get("cluster_id"); 29 | this.isInitialized = false; 30 | this.views = {}; 31 | this.indexListFull = {}; 32 | var tableWidth = ($(".table-container.box-container").width() - 70); 33 | SIndexTable.initGrid($(AppConfig.sindex.tableDiv), AppConfig.secondaryIndexDefList, AppConfig.secondaryIndexDefListColumn, tableWidth); 34 | }, 35 | url: function(){ 36 | return AppConfig.baseUrl + window.AMCGLOBALS.persistent.clusterID/*this.clusterID*/ + '/namespaces/' + window.AMCGLOBALS.persistent.namespaceName + '/sindexes'; 37 | }, 38 | fetchSuccess: function(response){ 39 | if(response.CID !== window.AMCGLOBALS.currentCID){ 40 | response.destroy(); return; 41 | } 42 | 43 | if(!this.model.isInitialized){ 44 | this.model.initSIndexView(response); 45 | this.model.isInitialized = true; 46 | }else{ 47 | 48 | } 49 | this.stop(); 50 | 51 | if(this.clusterID !== window.AMCGLOBALS.persistent.clusterID){ 52 | this.clusterID = window.AMCGLOBALS.persistent.clusterID; 53 | 54 | } 55 | 56 | if(typeof response.attributes.error !== 'undefined' && response.attributes.error.indexOf("Invalid cluster id") != -1){ 57 | delete response.attributes.error; 58 | Util.clusterIDReset(); 59 | } 60 | }, 61 | 62 | startEventListeners : function (){ 63 | var that = this; 64 | function viewDestroy(){ 65 | $(document).off("view:Destroy", viewDestroy); 66 | that.destroy(); 67 | }; 68 | 69 | $(document).off("view:Destroy", viewDestroy).on("view:Destroy", viewDestroy); 70 | }, 71 | 72 | initSIndexView: function(model){ 73 | var modelData = model.attributes; 74 | var indexData = modelData.indexes; 75 | model.indexList = _.pluck(indexData, 'indexname'); 76 | 77 | for(var i in model.indexList){ 78 | for(var j in indexData){ 79 | if(indexData[j].indexname === model.indexList[i]){ 80 | model.indexListFull[model.indexList[i]] = indexData[j]; 81 | break; 82 | } 83 | } 84 | } 85 | 86 | for(var index in model.indexListFull){ 87 | model.views[index] = new SIndexView({tableDiv:AppConfig.sindex.tableDiv,indexName:index ,model: this}); 88 | model.views[index].render(model, model.indexListFull[index], index); 89 | 90 | } 91 | 92 | }, 93 | fetchError: function(response){ 94 | if(response.CID !== window.AMCGLOBALS.currentCID){ 95 | response.destroy(); return; 96 | } 97 | 98 | var that = this; 99 | try{ 100 | //DISPLAY ERROR 101 | }catch(e){ 102 | console.info(e.toString()); 103 | } 104 | }, 105 | 106 | 107 | 108 | }); 109 | 110 | return SIndexModel; 111 | }); 112 | -------------------------------------------------------------------------------- /static/js/setup.js: -------------------------------------------------------------------------------- 1 | require.config({ 2 | paths: { 3 | //Libraries 4 | jquery: "libs/jquery/consolidated-jquery-functionalities.min", 5 | underscore: "libs/underscore/underscore", 6 | backbone: "libs/backbone/backbone", 7 | poller: "libs/backbone/backbone.poller", 8 | d3: "libs/d3/d3", 9 | d3Layout: "libs/d3/d3.layout.min", 10 | timechart: "libs/timechart/timechart", 11 | }, 12 | shim: { 13 | 'backbone': { 14 | deps: ['underscore', 'jquery'], 15 | } 16 | } 17 | }); 18 | 19 | require(["onepage"],function(onepage){ 20 | onepage(); 21 | }); 22 | -------------------------------------------------------------------------------- /static/js/views/common/AlertEmailsView.js: -------------------------------------------------------------------------------- 1 | define(['jquery', 'underscore', 'backbone', 'helper/notification', 'helper/modal'], 2 | function($, _, Backbone, Notification, modal) { 3 | function validateEmail(email) { 4 | // see http://stackoverflow.com/questions/46155/validate-email-address-in-javascript 5 | var re = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; 6 | return re.test(email); 7 | } 8 | 9 | var TOAST_TIMEOUT = 3*1000; 10 | 11 | var AlertEmailsView = Backbone.View.extend({ 12 | initialize: function() { 13 | _.bindAll(this, 'addEmail', 'removeEmail', 'render'); 14 | this.listenTo(this.model, 'change', this.render, this); 15 | }, 16 | 17 | render: function() { 18 | var emails = this.model.attributes.emails; 19 | var tmpl = this.template(emails); 20 | this.$el.html(tmpl); 21 | return this; 22 | }, 23 | 24 | events: { 25 | 'click li .icon-cancel-circle': 'removeEmail', 26 | 'click button': 'addEmail', 27 | }, 28 | 29 | removeEmail: function(evt) { 30 | var that = this; 31 | var email = evt.target.parentElement.innerText; 32 | var emails = [email]; 33 | var content = 'Remove email: ' + email + ' from receving alerts'; 34 | 35 | modal.confirmModal('Remove Email', content, success); 36 | return; 37 | 38 | function success() { 39 | that.model.remove(emails, 40 | function success() { 41 | Notification.toastNotification('green', 'Email: ' + email + ' removed successfully', TOAST_TIMEOUT); 42 | }, 43 | function failure() { 44 | Notification.toastNotification('red', 'Unable to remove email: ' + email, TOAST_TIMEOUT); 45 | } 46 | ); 47 | } 48 | }, 49 | 50 | addEmail: function() { 51 | var that = this; 52 | var input = this.$('form input[name=email]'); 53 | var email = input.val(); 54 | var valid = validateEmail(email); 55 | var err = this.$('.err-text'); 56 | if(!valid) { 57 | err.show(); 58 | window.setTimeout(function() { 59 | err.hide(); 60 | }, 2000); 61 | return; 62 | } 63 | err.hide(); 64 | 65 | var content = 'Add email: ' + email + ' to receive alerts'; 66 | modal.confirmModal('Add Email', content, success); 67 | return; 68 | 69 | function success() { 70 | input.val(''); 71 | that.model.add([email], 72 | function success() { 73 | Notification.toastNotification('green', 'Email: ' + email + ' added successfully', TOAST_TIMEOUT); 74 | }, 75 | function failure() { 76 | Notification.toastNotification('red', 'Unable to add email: ' + email, TOAST_TIMEOUT); 77 | } 78 | ); 79 | } 80 | }, 81 | 82 | template: function(emails) { 83 | var tmpl = '
    '; 84 | if(!emails || emails.length === 0) { 85 | tmpl += '
  • No emails configured to receive alerts

  • '; 86 | } else { 87 | _.each(emails, function(email) { 88 | tmpl += '
  • ' + 89 | '' + 90 | email + 91 | '
  • '; 92 | }); 93 | }; 94 | tmpl += '
'; 95 | 96 | tmpl += '
' + 97 | '' + 98 | '' + 99 | '' + 100 | '
'; 101 | return tmpl; 102 | }, 103 | }); 104 | 105 | return AlertEmailsView; 106 | }); 107 | 108 | 109 | 110 | 111 | 112 | -------------------------------------------------------------------------------- /static/js/views/configs/statview.js: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | *Copyright 2008-2014 by Aerospike, Inc. All rights reserved. 3 | *THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE. THE COPYRIGHT NOTICE 4 | *ABOVE DOES NOT EVIDENCE ANY ACTUAL OR INTENDED PUBLICATION. 5 | ******************************************************************************/ 6 | define(["jquery", "underscore", "backbone", "helper/edit-config", "helper/jqgrid-helper", "config/view-config", "config/app-config" ], function($, _, Backbone, StatTable, GridHelper, ViewConfig, AppConfig){ 7 | 8 | var StatView = Backbone.View.extend({ 9 | initialize: function( options ){ 10 | this.el = options.el; 11 | }, 12 | 13 | lazyRender: function(event){ 14 | event.data.model.colView.render(event.data.model); 15 | }, 16 | 17 | render: function(model){ 18 | if( !window.AMCGLOBALS.pageSpecific.configGridSet ) 19 | StatTable.startInitGrid([]); 20 | 21 | window.AMCGLOBALS.pageSpecific.configGridSet = true; 22 | 23 | if( this.attrList == null ){ 24 | switch(model.modelType){ 25 | case "nodes" : 26 | this.attrList = "nodeConfigList"; break; 27 | case "namespace" : 28 | this.attrList = "namespaceConfigList"; break; 29 | case "xdr" : 30 | this.attrList = "xdrConfigList"; break; 31 | } 32 | 33 | window.AMCGLOBALS.pageSpecific.lazyRender = window.AMCGLOBALS.pageSpecific.lazyRender || []; 34 | window.AMCGLOBALS.pageSpecific.lazyRendered = window.AMCGLOBALS.pageSpecific.lazyRendered || []; 35 | window.AMCGLOBALS.pageSpecific.statListGenerated = ! _.isEmpty( AppConfig[this.attrList] ); 36 | 37 | if(!window.AMCGLOBALS.pageSpecific.statListGenerated && model['attributes'].node_status === "on" && (model.modelType !== "xdr" || model['attributes'].xdr_status === "on") ){ 38 | window.AMCGLOBALS.pageSpecific.statListGenerated = true; 39 | AppConfig[this.attrList] = _.keys(model['attributes']); 40 | } 41 | 42 | model.statList = AppConfig[this.attrList]; 43 | if( _.isEmpty( $('#statListTable').jqGrid('getGridParam','data') ) && window.AMCGLOBALS.pageSpecific.statListGenerated ){ 44 | StatTable.initAndSetGridData(AppConfig[this.attrList], model.modelType); 45 | window.$(AppConfig.stat.statTableDiv).trigger("renderall", [window.AMCGLOBALS.pageSpecific.lazyRender]); 46 | } 47 | } 48 | 49 | if( !_.isEmpty( _.difference( window.AMCGLOBALS.persistent.selectedNodes, window.AMCGLOBALS.pageSpecific.lazyRender) ) && !window.AMCGLOBALS.pageSpecific.statListGenerated && (model['attributes'].node_status === "off" || model['attributes'].xdr_status === "off") ){ 50 | window.AMCGLOBALS.pageSpecific.lazyRender.push(model.address); 51 | 52 | if( _.isEmpty( _.difference( window.AMCGLOBALS.persistent.selectedNodes, window.AMCGLOBALS.pageSpecific.lazyRender) ) ) 53 | window.$(AppConfig.stat.statTableDiv).trigger("renderall", [window.AMCGLOBALS.pageSpecific.lazyRender]); 54 | } else{ 55 | 56 | window.AMCGLOBALS.pageSpecific.lazyRendered.push(model.address); 57 | 58 | if( _.isEmpty( _.difference( window.AMCGLOBALS.pageSpecific.lazyRender, window.AMCGLOBALS.pageSpecific.lazyRendered) ) ){ 59 | window.AMCGLOBALS.pageSpecific.lazyRender = []; 60 | window.AMCGLOBALS.pageSpecific.lazyRendered = []; 61 | } 62 | 63 | Util.checkVisibilityAndCall(this, function(){ 64 | if(model['attributes']['node_status'] === "off"){ 65 | StatTable.updateRowData(model.statTableID, model.modelType, model.statList, model.address, model['attributes'], 'Node Down'); 66 | }else{ 67 | StatTable.updateRowData(model.statTableID, model.modelType, model.statList, model.address, model['attributes']); 68 | } 69 | }, "horizontal", "#nodeStatListGrid .ui-jqgrid-bdiv"); 70 | 71 | } 72 | }, 73 | renderNetworkError: function(model){ 74 | StatTable.updateRowData(model.statTableID, model.modelType, model.statList, model.address, model['attributes'], 'N/E'); 75 | }, 76 | 77 | 78 | }); 79 | 80 | return StatView; 81 | }); 82 | -------------------------------------------------------------------------------- /static/js/views/dashboard/pieview.js: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Licensed to the Apache Software Foundation (ASF) under one 3 | or more contributor license agreements. See the NOTICE file 4 | distributed with this work for additional information 5 | regarding copyright ownership. The ASF licenses this file 6 | to you under the Apache License, Version 2.0 (the 7 | "License"); you may not use this file except in compliance 8 | with the License. You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, 13 | software distributed under the License is distributed on an 14 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | KIND, either express or implied. See the License for the 16 | specific language governing permissions and limitations 17 | under the License. 18 | ******************************************************************************/ 19 | 20 | define(["jquery", "underscore", "backbone", "d3", "helper/drilldown-charts", "config/view-config", "helper/util"], function($, _, Backbone, D3, PieChart, ViewConfig, Util){ 21 | var ClusterView = Backbone.View.extend({ 22 | pieChartHolder: null, 23 | initialize: function(){ 24 | this.el = this.options.el; 25 | }, 26 | render: function(data){ 27 | var pieChartData = this.getRelationshipArray(data); 28 | try{ 29 | if( !isNaN(data.used) && !isNaN(data.free)){ 30 | if(!this.pieChartHolder){ 31 | $(this.el+' .pie_chart').empty(); 32 | this.pieChartHolder = new healthChart(this.el+' .pie_chart', 150, 150, 20, true); 33 | } 34 | this.pieChartHolder.updatePieData(pieChartData); 35 | }else{ 36 | //Display Error 37 | } 38 | }catch(e){ 39 | if(!this.pieChartHolder){ 40 | this.pieChartHolder = new healthChart(this.el+' .pie_chart', 150, 150, 20, true); 41 | } 42 | this.pieChartHolder.updatePieData(pieChartData); 43 | console.info(e.toString()); 44 | } 45 | 46 | }, 47 | getRelationshipArray : function(data){ 48 | var parent = []; 49 | parent.push({name : "totalFree", title : "Total Free", value : data.free, color : "#999", children : []}); 50 | parent.push({name : "totalUsed", title : "Total Used", value : data.used, color : "#0e90d2", children : []}); 51 | 52 | for(var node in data.details){ 53 | parent[0].children.push({value : data.details[node].free, title : node, color : window.AMCGLOBALS.persistent.nodesColorList[node], name : "free[" + node + "]"}); 54 | parent[1].children.push({value : data.details[node].used, title : node, color : window.AMCGLOBALS.persistent.nodesColorList[node], name : "used[" + node + "]"}); 55 | } 56 | 57 | return parent; 58 | } 59 | }); 60 | 61 | return ClusterView; 62 | }); -------------------------------------------------------------------------------- /static/js/views/dashboard/throughputview.js: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Licensed to the Apache Software Foundation (ASF) under one 3 | or more contributor license agreements. See the NOTICE file 4 | distributed with this work for additional information 5 | regarding copyright ownership. The ASF licenses this file 6 | to you under the Apache License, Version 2.0 (the 7 | "License"); you may not use this file except in compliance 8 | with the License. You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, 13 | software distributed under the License is distributed on an 14 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | KIND, either express or implied. See the License for the 16 | specific language governing permissions and limitations 17 | under the License. 18 | ******************************************************************************/ 19 | 20 | define(["jquery", "underscore", "backbone", "d3", "timechart", "helper/timechart-helper", "config/view-config", "config/app-config"], function($, _, Backbone, D3, TimeChart, TimeseriesChart, ViewConfig, AppConfig){ 21 | var ThroughputView = Backbone.View.extend({ 22 | initialize: function(){ 23 | this.el = this.options.el; 24 | this.chartDiv = this.options.chartDiv; 25 | this.legendDiv = this.options.legendDiv; 26 | this.xAxisDiv = this.options.xAxisDiv; 27 | this.slider = this.options.slider; 28 | this.tpsDiv = this.options.tpsDiv; 29 | this.chartType = this.options.chartType; 30 | this.chartID = null; 31 | 32 | }, 33 | render: function(newData, oldData, numberOfDataPoints){ 34 | if(newData !== null && Object.getOwnPropertyNames(newData).length > 0) 35 | TimeseriesChart.updateTimeseriesData(newData, oldData, this.chartID, this.legendDiv); 36 | if(!this.chartID){ 37 | this.chartID = TimeseriesChart.initTimeSeriesChart(AMCGLOBALS.pageSpecific.charts[ this.chartType + "ChartType"], this.chartDiv, this.legendDiv, this.xAxisDiv, this.slider, ViewConfig.throughputChartConfig, oldData, numberOfDataPoints); 38 | }else{ 39 | Util.checkVisibilityAndCall(this, function(){ 40 | TimeseriesChart.updateTimeSeriesChart(this.chartID, oldData, this.legendDiv, numberOfDataPoints); 41 | TimeseriesChart.updateTPS(this.tpsDiv, oldData, this.chartType); 42 | }); 43 | } 44 | }, 45 | 46 | initializeTPS: function(history){ 47 | TimeseriesChart.initTPS(history, this.tpsDiv); 48 | }, 49 | 50 | remove: function(){ 51 | if(this.chartID){ 52 | this.chartID.remove(); 53 | } 54 | } 55 | }); 56 | 57 | return ThroughputView; 58 | }); 59 | -------------------------------------------------------------------------------- /static/js/views/definitions/setsview.js: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Licensed to the Apache Software Foundation (ASF) under one 3 | or more contributor license agreements. See the NOTICE file 4 | distributed with this work for additional information 5 | regarding copyright ownership. The ASF licenses this file 6 | to you under the Apache License, Version 2.0 (the 7 | "License"); you may not use this file except in compliance 8 | with the License. You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, 13 | software distributed under the License is distributed on an 14 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | KIND, either express or implied. See the License for the 16 | specific language governing permissions and limitations 17 | under the License. 18 | ******************************************************************************/ 19 | 20 | define(["jquery", "underscore", "backbone", "helper/definitions/sindex-table", "helper/jqgrid-helper", "config/view-config", "config/app-config" ], function($, _, Backbone, SIndexTable, GridHelper, ViewConfig, AppConfig){ 21 | 22 | var SetsView = Backbone.View.extend({ 23 | initialize: function(){ 24 | this.tableDiv = this.options.tableDiv; 25 | this.indexName = this.options.indexName; 26 | }, 27 | render: function(model, newData, rowID){ 28 | newData = this.formatRowData(newData, rowID); 29 | SIndexTable.updateRowData(this.tableDiv, newData, rowID); 30 | 31 | }, 32 | renderNetworkError: function(model, newData, rowID){ 33 | SIndexTable.updateRowData(this.tableDiv, newData, rowID); 34 | }, 35 | formatRowData: function(newData, rowID){ 36 | if(newData['sync_state'] !== 'synced'){ 37 | newData['sync_state'] = 'YES'; 38 | }else{ 39 | var synButtonID = 'sIndexTable_'+rowID; 40 | newData['sync_state'] = '
NO
' 41 | //ADD EVENT LISTENER 'NO' 42 | $('#'+synButtonID).click(function(e){ 43 | $("#syncedDialog").dialog({ 44 | dialogClass: 'sync-dialog' 45 | }); 46 | }); 47 | } 48 | if(typeof newData['enable-xdr'] === 'undefined'){ 49 | newData['enable-xdr'] = 'Not Supported'; 50 | } 51 | 52 | return newData; 53 | }, 54 | 55 | }); 56 | 57 | return SetsView; 58 | }); 59 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /static/js/views/definitions/xdrview.js: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Licensed to the Apache Software Foundation (ASF) under one 3 | or more contributor license agreements. See the NOTICE file 4 | distributed with this work for additional information 5 | regarding copyright ownership. The ASF licenses this file 6 | to you under the Apache License, Version 2.0 (the 7 | "License"); you may not use this file except in compliance 8 | with the License. You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, 13 | software distributed under the License is distributed on an 14 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | KIND, either express or implied. See the License for the 16 | specific language governing permissions and limitations 17 | under the License. 18 | ******************************************************************************/ 19 | 20 | define(["jquery", "underscore", "backbone", "helper/definitions/sindex-table", "helper/jqgrid-helper", "config/view-config", "config/app-config" ], function($, _, Backbone, SIndexTable, GridHelper, ViewConfig, AppConfig){ 21 | 22 | var SIndexView = Backbone.View.extend({ 23 | initialize: function(){ 24 | this.tableDiv = this.options.tableDiv; 25 | this.indexName = this.options.indexName; 26 | }, 27 | render: function(model, newData, rowID){ 28 | newData = this.formatRowData(newData, rowID); 29 | SIndexTable.updateRowData(this.tableDiv, newData, rowID); 30 | 31 | }, 32 | renderNetworkError: function(model){ 33 | }, 34 | formatRowData: function(newData, rowID){ 35 | if(newData['sync_state'] !== 'synced'){ 36 | newData['sync_state'] = 'YES'; 37 | }else{ 38 | var synButtonID = 'sIndexTable_'+rowID; 39 | newData['sync_state'] = '
NO
' 40 | //ADD EVENT LISTENER 'NO' 41 | $('#'+synButtonID).click(function(e){ 42 | $("#syncedDialog").dialog({ 43 | dialogClass: 'sync-dialog' 44 | }); 45 | }); 46 | } 47 | 48 | return newData; 49 | }, 50 | 51 | }); 52 | 53 | return SIndexView; 54 | }); 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /static/js/views/jobs/nodeview.js: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Licensed to the Apache Software Foundation (ASF) under one 3 | or more contributor license agreements. See the NOTICE file 4 | distributed with this work for additional information 5 | regarding copyright ownership. The ASF licenses this file 6 | to you under the Apache License, Version 2.0 (the 7 | "License"); you may not use this file except in compliance 8 | with the License. You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, 13 | software distributed under the License is distributed on an 14 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | KIND, either express or implied. See the License for the 16 | specific language governing permissions and limitations 17 | under the License. 18 | ******************************************************************************/ 19 | 20 | define(["jquery", "underscore", "backbone", "helper/job-table", "helper/jqgrid-helper", "config/view-config", "config/app-config" ], function($, _, Backbone, JobTable, GridHelper, ViewConfig, AppConfig){ 21 | 22 | var NodeView = Backbone.View.extend({ 23 | isInitialized: false, 24 | initialize: function(){ 25 | this.rowID = this.options.rowID; 26 | this.modelID = this.options.modelID; 27 | this.jobID = this.options.jobID; 28 | }, 29 | removeRow: function(){ 30 | var selRow = $('#'+this.rowID), 31 | nextRow = selRow.next(); 32 | 33 | if (nextRow.hasClass('ui-subgrid')) { 34 | nextRow.remove(); 35 | } 36 | 37 | $(AppConfig.node.nodeTableDiv).delRowData(this.rowID); 38 | $(AppConfig.job.nodeTableCompletedJobsDiv).delRowData(this.rowID); 39 | 40 | var jobs = $("#nodeListTable tr").not(".jqgfirstrow"); 41 | var completedJobs = $("#nodeListTableCompletedJobs tr").not(".jqgfirstrow"); 42 | 43 | if( jobs.length === 0 ){ 44 | $("#nodeListTable").addClass("no-jobs"); 45 | } 46 | 47 | if( completedJobs.length === 0 ){ 48 | $("#nodeListTable").addClass("no-jobs"); 49 | } 50 | 51 | this.remove(); 52 | }, 53 | render: function(container, job, model){ 54 | this.createJobListRow(container, job, this.rowID, this.jobID, model, false); 55 | }, 56 | renderNetworkError: function(container, job, model){ 57 | this.createJobListRow(container, job, this.rowID, this.jobID, model, true); 58 | }, 59 | createJobListRow: function(container, data, rowID, jobID, model, isError){ 60 | $(container).removeClass("no-jobs"); 61 | JobTable.createOrUpdateRow(container, data, rowID, model, isError); 62 | JobTable.updateRow(container, data, rowID); 63 | if(!isError){ 64 | window.setTimeout(function() { 65 | data['mem_pie_chart'] = GridHelper.jqCustomPieFormatter(null, container, rowID, ViewConfig.tablePieConfig, data['mem_arr'], 5); 66 | }, 200); 67 | } 68 | 69 | if(model.subGridEnabled[rowID] === true){ 70 | var expandContainer = container.substr(1)+'_'+ rowID; 71 | var tableHtmlStr = ""; 72 | if(Util.versionCompare(data.build,"3.6.0") >= 0){ 73 | tableHtmlStr = GridHelper.create2LevelTable("job","nodeExpanded_"+ rowID, "expandDynamic", data); 74 | }else{ 75 | tableHtmlStr = GridHelper.create2LevelTable("jobOldVersion","nodeExpanded_"+ rowID, "expandDynamic", data); 76 | } 77 | $("#" + expandContainer).html(tableHtmlStr); 78 | } 79 | } 80 | 81 | 82 | }); 83 | 84 | return NodeView; 85 | }); 86 | 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /tools/load/main/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | "sync" 6 | 7 | "github.com/aerospike-community/amc/tools/load" 8 | ) 9 | 10 | const nconn = 10 // connections per cluster 11 | 12 | func main() { 13 | 14 | // base url of the AMC server 15 | load.BaseURL = "http://localhost:8082/aerospike/service/clusters/" 16 | 17 | // instances of the aerospike clusters 18 | var clients []load.Client = []load.Client{ 19 | {IP: "172.17.0.2", Port: "3000"}, 20 | {IP: "172.17.0.5", Port: "7000", Username: "all", Password: "all"}, 21 | {IP: "192.168.121.116", Port: "3000", Username: "admin", Password: "admin"}, 22 | {IP: "192.168.121.116", Port: "3000", Username: "subadmin", Password: "subadmin"}, 23 | } 24 | 25 | var wg sync.WaitGroup 26 | for i := 0; i < len(clients); i++ { 27 | cc := clients[i] 28 | for j := 0; j < nconn; j++ { 29 | c := load.Client{ 30 | IP: cc.IP, 31 | Port: cc.Port, 32 | Username: cc.Username, 33 | Password: cc.Password, 34 | TLSName: cc.TLSName, 35 | } 36 | err := c.Connect() 37 | if err != nil { 38 | log.Println(err.Error()) 39 | break 40 | } 41 | c.Start(&wg) 42 | } 43 | } 44 | 45 | wg.Wait() 46 | } 47 | -------------------------------------------------------------------------------- /tools/load/response/types.go: -------------------------------------------------------------------------------- 1 | package response 2 | 3 | // Basic type struct 4 | type Basic struct { 5 | Nodes []string 6 | Namespaces []string 7 | } 8 | 9 | // Connect type struct 10 | type Connect struct { 11 | ClusterID string `json:"cluster_id"` 12 | Status string 13 | } 14 | --------------------------------------------------------------------------------