├── .github
├── ISSUE_TEMPLATE.md
└── PULL_REQUEST_TEMPLATE.md
├── .gitignore
├── .go-version
├── .project
├── LICENSE
├── README.md
├── RELEASE_VERSION
├── Vagrantfile
├── build.sh
├── bump_release_version_and_tag
├── conf
├── orchestrator-sample.conf.json
└── orchestrator-simple.conf.json
├── doc
├── FAQ.md
├── Home.md
├── Orchestrator-Manual.md
├── Orchestrator-deployment.md
├── Orchestrator-first-steps.md
├── Orchestrator-for-developers.md
├── Orchestrator-high-availability.md
└── images
│ ├── orchestator-cm-co-masters.png
│ ├── orchestator-cm-simple-drag-master.png
│ ├── orchestrator-about.png
│ ├── orchestrator-audit-small.png
│ ├── orchestrator-deployment.png
│ ├── orchestrator-discover.png
│ ├── orchestrator-instance-modal.png
│ ├── orchestrator-introduction-screenshot.png
│ ├── orchestrator-problems.png
│ ├── orchestrator-pseudo-gtid-dead-relay-master-begin-drag.png
│ ├── orchestrator-pseudo-gtid-dead-relay-master-drop.png
│ ├── orchestrator-pseudo-gtid-dead-relay-master-refactored-1.png
│ ├── orchestrator-pseudo-gtid-dead-relay-master.png
│ ├── orchestrator-simple-drag-hover.png
│ ├── orchestrator-simple-drag.png
│ ├── orchestrator-simple-dropped.png
│ ├── orchestrator-simple-with-problems.png
│ └── orchestrator-simple.png
├── etc
└── init.d
│ └── orchestrator.bash
├── go
├── agent
│ ├── agent.go
│ └── agent_dao.go
├── app
│ ├── cli.go
│ └── http.go
├── attributes
│ ├── attributes.go
│ └── attributes_dao.go
├── cmd
│ └── orchestrator
│ │ └── main.go
├── config
│ ├── cli_flags.go
│ └── config.go
├── db
│ └── db.go
├── discovery
│ └── discovery.go
├── http
│ ├── agents_api.go
│ ├── api.go
│ ├── httpbase.go
│ └── web.go
├── inst
│ ├── analysis.go
│ ├── analysis_dao.go
│ ├── audit.go
│ ├── audit_dao.go
│ ├── binlog.go
│ ├── candidate_database_instance.go
│ ├── cluster.go
│ ├── cluster_alias.go
│ ├── cluster_alias_dao.go
│ ├── cluster_domain_dao.go
│ ├── downtime_dao.go
│ ├── instance.go
│ ├── instance_binlog.go
│ ├── instance_binlog_dao.go
│ ├── instance_dao.go
│ ├── instance_dao_test.go
│ ├── instance_key.go
│ ├── instance_key_map.go
│ ├── instance_test.go
│ ├── instance_topology.go
│ ├── instance_topology_dao.go
│ ├── instance_topology_test.go
│ ├── instance_utils.go
│ ├── maintenance.go
│ ├── maintenance_dao.go
│ ├── master_equivalence.go
│ ├── master_equivalence_dao.go
│ ├── oracle_gtid_set.go
│ ├── oracle_gtid_set_entry.go
│ ├── pool.go
│ ├── pool_dao.go
│ ├── postponed_functions.go
│ ├── process.go
│ ├── process_dao.go
│ ├── resolve.go
│ └── resolve_dao.go
├── logic
│ ├── async_request.go
│ ├── async_request_dao.go
│ ├── disable_recovery.go
│ ├── orchestrator.go
│ ├── topology_recovery.go
│ └── topology_recovery_dao.go
├── metrics
│ └── graphite.go
├── os
│ └── process.go
├── process
│ ├── access_token_dao.go
│ ├── election_dao.go
│ ├── health_dao.go
│ ├── host.go
│ └── token.go
└── ssl
│ ├── ssl.go
│ └── ssl_test.go
├── resources
├── metrics
│ └── orchestrator-grafana.json
├── public
│ ├── bootstrap
│ │ ├── css
│ │ │ ├── bootstrap-theme.css
│ │ │ ├── bootstrap-theme.css.map
│ │ │ ├── bootstrap-theme.min.css
│ │ │ ├── bootstrap.css
│ │ │ ├── bootstrap.css.map
│ │ │ └── bootstrap.min.css
│ │ ├── fonts
│ │ │ ├── glyphicons-halflings-regular.eot
│ │ │ ├── glyphicons-halflings-regular.svg
│ │ │ ├── glyphicons-halflings-regular.ttf
│ │ │ └── glyphicons-halflings-regular.woff
│ │ └── js
│ │ │ └── bootstrap.min.js
│ ├── css
│ │ └── orchestrator.css
│ ├── images
│ │ ├── ajax-loader.gif
│ │ ├── booking-logo-32.png
│ │ ├── booking-logo-s.png
│ │ ├── keep-calm-and-let-orchestrator-handle-it-transp-m.png
│ │ ├── octocat-logo-32.png
│ │ ├── outbrain-logo-32.png
│ │ ├── outbrain-logo-s.png
│ │ └── tile.png
│ └── js
│ │ ├── agent.js
│ │ ├── agents.js
│ │ ├── audit-failure-detection.js
│ │ ├── audit-recovery.js
│ │ ├── audit.js
│ │ ├── bootbox.min.js
│ │ ├── cluster-analysis-shared.js
│ │ ├── cluster-pools.js
│ │ ├── cluster-tree.js
│ │ ├── cluster.js
│ │ ├── clusters-analysis.js
│ │ ├── clusters.js
│ │ ├── common.js
│ │ ├── corex-jquery.js
│ │ ├── corex.js
│ │ ├── d3.v3.min.js
│ │ ├── discover.js
│ │ ├── instance-problems.js
│ │ ├── jquery-ui.min.js
│ │ ├── jquery.cookie-1.4.1.min.js
│ │ ├── jquery.min.js
│ │ ├── long-queries.js
│ │ ├── md5.js
│ │ ├── orchestrator.js
│ │ ├── search.js
│ │ ├── seed-shared.js
│ │ ├── seed.js
│ │ ├── seeds.js
│ │ └── status.js
├── sql
│ └── pseudo-gtid.sql
└── templates
│ ├── about.tmpl
│ ├── agent.tmpl
│ ├── agent_seed_details.tmpl
│ ├── agents.tmpl
│ ├── audit.tmpl
│ ├── audit_failure_detection.tmpl
│ ├── audit_recovery.tmpl
│ ├── cluster.tmpl
│ ├── cluster_pools.tmpl
│ ├── clusters.tmpl
│ ├── clusters_analysis.tmpl
│ ├── discover.tmpl
│ ├── faq.tmpl
│ ├── home.tmpl
│ ├── keep-calm.tmpl
│ ├── layout.tmpl
│ ├── long_queries.tmpl
│ ├── search.tmpl
│ ├── seeds.tmpl
│ └── status.tmpl
├── tests
└── integration
│ └── instance_dao_test.go
├── vagrant
├── README.md
├── admin-build.sh
├── base-build.sh
├── db1-build.sh
├── db1-my.cnf
├── db2-build.sh
├── db2-my.cnf
├── db3-build.sh
├── db3-my.cnf
├── db4-build.sh
└── db4-my.cnf
└── vendor
├── github.com
├── codegangsta
│ └── inject
│ │ ├── .gitignore
│ │ ├── LICENSE
│ │ ├── README.md
│ │ ├── inject.go
│ │ ├── translations
│ │ └── README_zh_cn.md
│ │ └── update_readme.sh
├── cyberdelia
│ └── go-metrics-graphite
│ │ ├── AUTHORS
│ │ ├── LICENSE
│ │ ├── README.md
│ │ └── graphite.go
├── go-martini
│ └── martini
│ │ ├── .gitignore
│ │ ├── Godeps
│ │ └── Godeps.json
│ │ ├── LICENSE
│ │ ├── README.md
│ │ ├── env.go
│ │ ├── go_version.go
│ │ ├── logger.go
│ │ ├── martini.go
│ │ ├── recovery.go
│ │ ├── response_writer.go
│ │ ├── return_handler.go
│ │ ├── router.go
│ │ ├── static.go
│ │ ├── translations
│ │ ├── README_de_DE.md
│ │ ├── README_es_ES.md
│ │ ├── README_fr_FR.md
│ │ ├── README_ja_JP.md
│ │ ├── README_ko_kr.md
│ │ ├── README_pl_PL.md
│ │ ├── README_pt_br.md
│ │ ├── README_ru_RU.md
│ │ ├── README_tr_TR.md
│ │ ├── README_zh_cn.md
│ │ └── README_zh_tw.md
│ │ └── wercker.yml
├── go-sql-driver
│ └── mysql
│ │ ├── AUTHORS
│ │ ├── CHANGELOG.md
│ │ ├── CONTRIBUTING.md
│ │ ├── ISSUE_TEMPLATE.md
│ │ ├── LICENSE
│ │ ├── PULL_REQUEST_TEMPLATE.md
│ │ ├── README.md
│ │ ├── appengine.go
│ │ ├── benchmark_test.go
│ │ ├── buffer.go
│ │ ├── collations.go
│ │ ├── connection.go
│ │ ├── const.go
│ │ ├── driver.go
│ │ ├── driver_test.go
│ │ ├── dsn.go
│ │ ├── dsn_test.go
│ │ ├── errors.go
│ │ ├── errors_test.go
│ │ ├── infile.go
│ │ ├── packets.go
│ │ ├── result.go
│ │ ├── rows.go
│ │ ├── statement.go
│ │ ├── transaction.go
│ │ ├── utils.go
│ │ └── utils_test.go
├── howeyc
│ └── gopass
│ │ ├── .travis.yml
│ │ ├── LICENSE.txt
│ │ ├── README.md
│ │ ├── pass.go
│ │ └── pass_test.go
├── martini-contrib
│ ├── auth
│ │ ├── LICENSE
│ │ ├── README.md
│ │ ├── basic.go
│ │ ├── util.go
│ │ └── wercker.yml
│ ├── gzip
│ │ ├── LICENSE
│ │ ├── README.md
│ │ ├── gzip.go
│ │ └── wercker.yml
│ ├── oauth2
│ │ └── oauth2.go
│ └── render
│ │ ├── LICENSE
│ │ ├── README.md
│ │ ├── fixtures
│ │ ├── basic
│ │ │ ├── admin
│ │ │ │ └── index.tmpl
│ │ │ ├── another_layout.tmpl
│ │ │ ├── content.tmpl
│ │ │ ├── current_layout.tmpl
│ │ │ ├── delims.tmpl
│ │ │ ├── hello.tmpl
│ │ │ ├── hypertext.html
│ │ │ └── layout.tmpl
│ │ └── custom_funcs
│ │ │ └── index.tmpl
│ │ ├── render.go
│ │ └── wercker.yml
├── outbrain
│ └── golib
│ │ ├── log
│ │ └── log.go
│ │ ├── math
│ │ └── math.go
│ │ ├── sqlutils
│ │ └── sqlutils.go
│ │ ├── tests
│ │ └── spec.go
│ │ └── util
│ │ └── text.go
├── oxtoacart
│ └── bpool
│ │ ├── LICENSE
│ │ ├── README.md
│ │ ├── bpool.go
│ │ ├── bufferpool.go
│ │ ├── bytepool.go
│ │ └── sizedbufferpool.go
├── patrickmn
│ └── go-cache
│ │ ├── CONTRIBUTORS
│ │ ├── LICENSE
│ │ ├── README.md
│ │ ├── cache.go
│ │ ├── cache_test.go
│ │ ├── sharded.go
│ │ └── sharded_test.go
└── rcrowley
│ └── go-metrics
│ ├── .gitignore
│ ├── .travis.yml
│ ├── LICENSE
│ ├── README.md
│ ├── cmd
│ ├── metrics-bench
│ │ └── metrics-bench.go
│ ├── metrics-example
│ │ └── metrics-example.go
│ └── never-read
│ │ └── never-read.go
│ ├── counter.go
│ ├── counter_test.go
│ ├── debug.go
│ ├── debug_test.go
│ ├── ewma.go
│ ├── ewma_test.go
│ ├── exp
│ └── exp.go
│ ├── gauge.go
│ ├── gauge_float64.go
│ ├── gauge_float64_test.go
│ ├── gauge_test.go
│ ├── graphite.go
│ ├── graphite_test.go
│ ├── healthcheck.go
│ ├── histogram.go
│ ├── histogram_test.go
│ ├── json.go
│ ├── json_test.go
│ ├── librato
│ ├── client.go
│ └── librato.go
│ ├── log.go
│ ├── memory.md
│ ├── meter.go
│ ├── meter_test.go
│ ├── metrics.go
│ ├── metrics_test.go
│ ├── opentsdb.go
│ ├── opentsdb_test.go
│ ├── registry.go
│ ├── registry_test.go
│ ├── runtime.go
│ ├── runtime_cgo.go
│ ├── runtime_gccpufraction.go
│ ├── runtime_no_cgo.go
│ ├── runtime_no_gccpufraction.go
│ ├── runtime_test.go
│ ├── sample.go
│ ├── sample_test.go
│ ├── stathat
│ └── stathat.go
│ ├── syslog.go
│ ├── timer.go
│ ├── timer_test.go
│ ├── validate.sh
│ ├── writer.go
│ └── writer_test.go
├── golang.org
└── x
│ └── crypto
│ └── ssh
│ └── terminal
│ ├── terminal.go
│ ├── terminal_test.go
│ ├── util.go
│ ├── util_bsd.go
│ ├── util_linux.go
│ ├── util_plan9.go
│ └── util_windows.go
├── gopkg.in
└── gcfg.v1
│ ├── LICENSE
│ ├── README
│ ├── doc.go
│ ├── example_test.go
│ ├── go1_0.go
│ ├── go1_2.go
│ ├── issues_test.go
│ ├── read.go
│ ├── read_test.go
│ ├── scanner
│ ├── errors.go
│ ├── example_test.go
│ ├── scanner.go
│ └── scanner_test.go
│ ├── set.go
│ ├── testdata
│ ├── gcfg_test.gcfg
│ └── gcfg_unicode_test.gcfg
│ ├── token
│ ├── position.go
│ ├── position_test.go
│ ├── serialize.go
│ ├── serialize_test.go
│ └── token.go
│ └── types
│ ├── bool.go
│ ├── doc.go
│ ├── enum.go
│ ├── enum_test.go
│ ├── int.go
│ ├── int_test.go
│ ├── scan.go
│ └── scan_test.go
└── vendor.json
/.github/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | # orchestrator upstream has moved
2 |
3 | **NOTE**: `orchestrator` development is now active on https://github.com/github/orchestrator, where Issues and Pull Requests are accepted.
4 |
5 | This repository is no longer the upstream and latest version of `orchestrator`.
6 |
7 | Please submit your Issue at https://github.com/github/orchestrator/issues/new
8 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | # orchestrator upstream has moved
2 |
3 | **NOTE**: `orchestrator` development is now active on https://github.com/github/orchestrator, where Issues and Pull Requests are accepted.
4 |
5 | This repository is no longer the upstream and latest version of `orchestrator`.
6 |
7 | Please submit your Pull Request with the https://github.com/github/orchestrator repository.
8 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | conf/orchestrator.conf.json
2 | .DS_Store
3 | .vagrant/
4 | vagrant/admin-post-install.sh
5 | vagrant/db-post-install.sh
6 | vagrant/db1-post-install.sh
7 | vagrant/db2-post-install.sh
8 | vagrant/db3-post-install.sh
9 | vagrant/db4-post-install.sh
10 | vagrant/vagrant-ssh-key
11 | vagrant/vagrant-ssh-key.pub
12 | Godeps/_workspace
13 |
--------------------------------------------------------------------------------
/.go-version:
--------------------------------------------------------------------------------
1 | 1.5
2 |
--------------------------------------------------------------------------------
/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | orchestrator
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/RELEASE_VERSION:
--------------------------------------------------------------------------------
1 | 1.5.7
2 |
--------------------------------------------------------------------------------
/Vagrantfile:
--------------------------------------------------------------------------------
1 | DEVELOPMENT_DIR = File.join(ENV['HOME'], 'Development')
2 |
3 | ENV['VAGRANT_SERVER_URL'] = "https://atlas.hashicorp.com" if ENV['VAGRANT_SERVER_URL'].nil? || ENV['VAGRANT_SERVER_URL'].empty?
4 | ENV['VAGRANT_DEFAULT_PROVIDER'] = 'virtualbox' if ENV['VAGRANT_DEFAULT_PROVIDER'].nil? || ENV['VAGRANT_DEFAULT_PROVIDER'].empty?
5 | BOX = ENV['VAGRANT_BOX'].nil? || ENV['VAGRANT_BOX'].empty? ? 'nrel/CentOS-6.6-x86_64' : ENV['VAGRANT_BOX']
6 |
7 | VAGRANTFILE_API_VERSION = "2"
8 |
9 | system("
10 | if [[ #{ARGV[0]} = 'up' ]] && [[ ! -e 'vagrant/vagrant-ssh-key' ]]; then
11 | ssh-keygen -t rsa -b 768 -N '' -q -f vagrant/vagrant-ssh-key
12 | fi
13 | ")
14 |
15 | Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
16 | config.vm.box = BOX
17 | config.vm.box_download_insecure = true
18 | config.vm.box_check_update = false
19 | config.vm.provider 'virtualbox' do |vb|
20 | vb.customize ['modifyvm', :id, '--nictype1', 'virtio']
21 | vb.customize ['modifyvm', :id, '--nictype2', 'virtio']
22 | end
23 |
24 | config.vm.synced_folder '.', '/orchestrator', type: 'rsync',
25 | rsync__auto: true,
26 | rsync__exclude: ".git/"
27 |
28 | (0..4).each do |n|
29 | name = (n > 0 ? ("db" + n.to_s) : "admin")
30 | config.vm.define name do |db|
31 | db.vm.hostname = name
32 | db.vm.network "private_network", ip: "192.168.57.20" + n.to_s
33 | db.vm.provision "shell", path: "vagrant/base-build.sh"
34 | if name == "admin"
35 | db.vm.network "forwarded_port", guest:3000, host:3000
36 | end
37 | end
38 | end
39 | end
40 |
--------------------------------------------------------------------------------
/bump_release_version_and_tag:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | #
3 | # Simple script to update the release version and tag according to that value.
4 | # - release version now stored in RELEASE_VERSION e.g. 1.4.571
5 | # - the tag usually is of the form v1.4.571.
6 | #
7 | # If there's a difference between current code and there are no pending changes
8 | # then:
9 | # - the current version will be increased by one
10 | # - the RELEASE_VERSION updated accordingly
11 | # - a new tag will be created
12 | # - the tag will be pushed to origin (may need fixing)
13 |
14 | diff=$(git diff)
15 | rc=$?
16 | if [ $rc != 0 ]; then
17 | echo "git diff failed. Doing nothing"
18 | exit 0
19 | fi
20 | if [ -n "$diff" ]; then
21 | echo "Some pending changes need committing. Doing nothing"
22 | exit 0
23 | fi
24 | old_version=$(cat RELEASE_VERSION)
25 | old_tag=v$old_version
26 | diff=$(git diff $old_tag)
27 | rc=$?
28 | if [ $rc = 128 ]; then
29 | echo "git diff $old_tag failed. Revision unknown. Doing nothing"
30 | exit 0
31 | fi
32 | if [ $rc != 0 ]; then
33 | echo "git diff $old_tag failed. Doing nothing"
34 | exit 0
35 | fi
36 | if [ -z "$diff" ]; then
37 | echo "No differences against $old_version. Doing nothing"
38 | exit 0
39 | fi
40 |
41 | echo "We need to bump the version"
42 | echo "OLD: version: $old_version, tag: $old_tag"
43 | # now generate a new version.
44 | last_digit=$(echo "$old_version" | sed -e 's/.*\.//')
45 | new_digit=$(($last_digit + 1))
46 | new_version=$(echo "$old_version" | sed -e "s/\.[0-9]*$/.$new_digit/")
47 | new_tag=v$new_version
48 | echo "NEW: version: $new_version, tag: $new_tag"
49 | echo "Modifying RELEASE_VERSION..."
50 | echo "$new_version" > RELEASE_VERSION
51 | echo "Committing change to RELEASE_VERSION..."
52 | git add RELEASE_VERSION
53 | git commit -m"bump RELEASE_VERSION from $old_version to $new_version"
54 | echo "Adding new tag: $new_tag"
55 | git tag $new_tag
56 | echo "Pushing changes and new tag..."
57 | git push
58 | git push origin $new_tag
59 |
--------------------------------------------------------------------------------
/doc/Home.md:
--------------------------------------------------------------------------------
1 | # orchestrator upstream has moved
2 |
3 | **NOTE**: `orchestrator` development is now active on https://github.com/github/orchestrator, where Issues and Pull Requests are accepted.
4 |
5 | This repository is no longer the upstream and latest version of `orchestrator`.
6 |
7 | The documentation in this repository is not up-to-date.
8 |
9 | ---
10 | Welcome to the _orchestrator_ wiki!
11 |
12 | * [Manual](Orchestrator-Manual)
13 | * [Manual, Table of Contents](Orchestrator-Manual#toc)
14 | * [Orchestrator deployment](Orchestrator-deployment)
15 | * [Orchestrator first steps](Orchestrator-first-steps)
16 | * [Orchestrator for developers](Orchestrator-for-developers)
17 | * [FAQ](FAQ)
18 |
--------------------------------------------------------------------------------
/doc/Orchestrator-high-availability.md:
--------------------------------------------------------------------------------
1 | # orchestrator upstream has moved
2 |
3 | **NOTE**: `orchestrator` development is now active on https://github.com/github/orchestrator, where Issues and Pull Requests are accepted.
4 |
5 | This repository is no longer the upstream and latest version of `orchestrator`.
6 |
7 | The documentation in this repository is not up-to-date.
8 |
9 | ---
10 | ## Orchestrator High Availability
11 |
12 | _Orchestrator_ makes your MySQL topologies available, but what makes _orchestrator_ highly available?
13 |
14 | Before drilling down into the details, we should first observe that orchestrator is a service that runs with a MySQL backend. Thus, we need to substantiate the HA of both these components, as well as the continued correctness in the failover process of either of the two or of both.
15 |
16 | ### High Availability of the Orchestrator service
17 |
18 | ### High Availability of the Orchestrator backend database
19 |
20 | At this time _Orchestrator_ relies on a MySQL backend. The state of the clusters is persisted to tables and is queried via SQL. It is worth considering the following:
21 |
22 | - The backend database is very small, and is linear with your number of servers. For most setups it's a matter of a few MB and well below 1GB, depending on history configuration, rate of polling etc. This easily allows for a fully in-memory database even on simplest machines.
23 |
24 | - Write rate is low
25 |
26 | To that extent you may use one of the following solutions in order to make the backend database highly available:
27 |
28 | - 2-node MySQL Cluster
29 | This is a synchronous solution; anything you write on one node is guaranteed to exist on the second. Data is available and up to date even in the face of a death of one server.
30 | Suggestion: abstract via HAProxy with `first` load-balancing algorithm.
31 | > NOTE: right now table creation explicitly creates tables using InnoDB engine; you may `ALTER TABLE ... ENGINE=NDB`
32 |
33 | - 3-node Galera/XtraDB cluster
34 | This is a synchronous solution; anything you write on one node is guaranteed to exist on both other servers.
35 | Galera is eventually consistent.
36 | Data is available and up to date even in the face of a death of one server.
37 | Suggestion: abstract via HAProxy with `first` load-balancing algorithm.
38 |
39 | - 2-node active-passive master-master configuration
40 |
41 | > NOTE: there has been an initial discussion on supporting Consul/etcd as backend datastore; there is no pending work on that at this time.
42 |
--------------------------------------------------------------------------------
/doc/images/orchestator-cm-co-masters.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/outbrain-inc/orchestrator/2a6e4b7a96934b11c3dacb0b2fa4be814f168eef/doc/images/orchestator-cm-co-masters.png
--------------------------------------------------------------------------------
/doc/images/orchestator-cm-simple-drag-master.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/outbrain-inc/orchestrator/2a6e4b7a96934b11c3dacb0b2fa4be814f168eef/doc/images/orchestator-cm-simple-drag-master.png
--------------------------------------------------------------------------------
/doc/images/orchestrator-about.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/outbrain-inc/orchestrator/2a6e4b7a96934b11c3dacb0b2fa4be814f168eef/doc/images/orchestrator-about.png
--------------------------------------------------------------------------------
/doc/images/orchestrator-audit-small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/outbrain-inc/orchestrator/2a6e4b7a96934b11c3dacb0b2fa4be814f168eef/doc/images/orchestrator-audit-small.png
--------------------------------------------------------------------------------
/doc/images/orchestrator-deployment.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/outbrain-inc/orchestrator/2a6e4b7a96934b11c3dacb0b2fa4be814f168eef/doc/images/orchestrator-deployment.png
--------------------------------------------------------------------------------
/doc/images/orchestrator-discover.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/outbrain-inc/orchestrator/2a6e4b7a96934b11c3dacb0b2fa4be814f168eef/doc/images/orchestrator-discover.png
--------------------------------------------------------------------------------
/doc/images/orchestrator-instance-modal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/outbrain-inc/orchestrator/2a6e4b7a96934b11c3dacb0b2fa4be814f168eef/doc/images/orchestrator-instance-modal.png
--------------------------------------------------------------------------------
/doc/images/orchestrator-introduction-screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/outbrain-inc/orchestrator/2a6e4b7a96934b11c3dacb0b2fa4be814f168eef/doc/images/orchestrator-introduction-screenshot.png
--------------------------------------------------------------------------------
/doc/images/orchestrator-problems.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/outbrain-inc/orchestrator/2a6e4b7a96934b11c3dacb0b2fa4be814f168eef/doc/images/orchestrator-problems.png
--------------------------------------------------------------------------------
/doc/images/orchestrator-pseudo-gtid-dead-relay-master-begin-drag.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/outbrain-inc/orchestrator/2a6e4b7a96934b11c3dacb0b2fa4be814f168eef/doc/images/orchestrator-pseudo-gtid-dead-relay-master-begin-drag.png
--------------------------------------------------------------------------------
/doc/images/orchestrator-pseudo-gtid-dead-relay-master-drop.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/outbrain-inc/orchestrator/2a6e4b7a96934b11c3dacb0b2fa4be814f168eef/doc/images/orchestrator-pseudo-gtid-dead-relay-master-drop.png
--------------------------------------------------------------------------------
/doc/images/orchestrator-pseudo-gtid-dead-relay-master-refactored-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/outbrain-inc/orchestrator/2a6e4b7a96934b11c3dacb0b2fa4be814f168eef/doc/images/orchestrator-pseudo-gtid-dead-relay-master-refactored-1.png
--------------------------------------------------------------------------------
/doc/images/orchestrator-pseudo-gtid-dead-relay-master.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/outbrain-inc/orchestrator/2a6e4b7a96934b11c3dacb0b2fa4be814f168eef/doc/images/orchestrator-pseudo-gtid-dead-relay-master.png
--------------------------------------------------------------------------------
/doc/images/orchestrator-simple-drag-hover.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/outbrain-inc/orchestrator/2a6e4b7a96934b11c3dacb0b2fa4be814f168eef/doc/images/orchestrator-simple-drag-hover.png
--------------------------------------------------------------------------------
/doc/images/orchestrator-simple-drag.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/outbrain-inc/orchestrator/2a6e4b7a96934b11c3dacb0b2fa4be814f168eef/doc/images/orchestrator-simple-drag.png
--------------------------------------------------------------------------------
/doc/images/orchestrator-simple-dropped.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/outbrain-inc/orchestrator/2a6e4b7a96934b11c3dacb0b2fa4be814f168eef/doc/images/orchestrator-simple-dropped.png
--------------------------------------------------------------------------------
/doc/images/orchestrator-simple-with-problems.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/outbrain-inc/orchestrator/2a6e4b7a96934b11c3dacb0b2fa4be814f168eef/doc/images/orchestrator-simple-with-problems.png
--------------------------------------------------------------------------------
/doc/images/orchestrator-simple.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/outbrain-inc/orchestrator/2a6e4b7a96934b11c3dacb0b2fa4be814f168eef/doc/images/orchestrator-simple.png
--------------------------------------------------------------------------------
/etc/init.d/orchestrator.bash:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # orchestrator daemon
3 | # chkconfig: 345 20 80
4 | # description: orchestrator daemon
5 | # processname: orchestrator
6 |
7 |
8 | # Script credit: http://werxltd.com/wp/2012/01/05/simple-init-d-script-template/
9 |
10 | DAEMON_PATH="/usr/local/orchestrator"
11 |
12 | DAEMON=orchestrator
13 | DAEMONOPTS="--verbose http"
14 |
15 | NAME=orchestrator
16 | DESC="orchestrator: MySQL replication management and visualization"
17 | PIDFILE=/var/run/$NAME.pid
18 | SCRIPTNAME=/etc/init.d/$NAME
19 |
20 | ulimit -n 16384
21 |
22 | # The file /etc/orchestrator_profile can be used to inject pre-service execution
23 | # scripts, such as exporting variables or whatever. It's yours!
24 | [ -f /etc/orchestrator_profile ] && . /etc/orchestrator_profile
25 |
26 | case "$1" in
27 | start)
28 | printf "%-50s" "Starting $NAME..."
29 | cd $DAEMON_PATH
30 | PID=$(./$DAEMON $DAEMONOPTS >> /var/log/${NAME}.log 2>&1 & echo $!)
31 | #echo "Saving PID" $PID " to " $PIDFILE
32 | if [ -z $PID ]; then
33 | printf "%s\n" "Fail"
34 | exit 1
35 | elif [ -z "$(ps axf | awk '{print $1}' | grep ${PID})" ]; then
36 | printf "%s\n" "Fail"
37 | exit 1
38 | else
39 | echo $PID > $PIDFILE
40 | printf "%s\n" "Ok"
41 | fi
42 | ;;
43 | status)
44 | printf "%-50s" "Checking $NAME..."
45 | if [ -f $PIDFILE ]; then
46 | PID=$(cat $PIDFILE)
47 | if [ -z "$(ps axf | awk '{print $1}' | grep ${PID})" ]; then
48 | printf "%s\n" "Process dead but pidfile exists"
49 | exit 1
50 | else
51 | echo "Running"
52 | fi
53 | else
54 | printf "%s\n" "Service not running"
55 | exit 1
56 | fi
57 | ;;
58 | stop)
59 | printf "%-50s" "Stopping $NAME"
60 | PID=$(cat $PIDFILE)
61 | cd $DAEMON_PATH
62 | if [ -f $PIDFILE ]; then
63 | kill -TERM $PID
64 | rm -f $PIDFILE
65 | # Wait for orchestrator to stop otherwise restart may fail.
66 | # (The newly restarted process may be unable to bind to the
67 | # currently bound socket.)
68 | while ps -p $PID >/dev/null 2>&1; do
69 | printf "."
70 | sleep 1
71 | done
72 | printf "\n"
73 | printf "Ok\n"
74 | else
75 | printf "%s\n" "pidfile not found"
76 | exit 1
77 | fi
78 | ;;
79 | restart)
80 | $0 stop
81 | $0 start
82 | ;;
83 | reload)
84 | PID=$(cat $PIDFILE)
85 | cd $DAEMON_PATH
86 | if [ -f $PIDFILE ]; then
87 | kill -HUP $PID
88 | printf "%s\n" "Ok"
89 | else
90 | printf "%s\n" "pidfile not found"
91 | exit 1
92 | fi
93 | ;;
94 | *)
95 | echo "Usage: $0 {status|start|stop|restart|reload}"
96 | exit 1
97 | esac
98 |
--------------------------------------------------------------------------------
/go/agent/agent.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2014 Outbrain Inc.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | package agent
18 |
19 | import "github.com/outbrain/orchestrator/go/inst"
20 |
21 | // LogicalVolume describes an LVM volume
22 | type LogicalVolume struct {
23 | Name string
24 | GroupName string
25 | Path string
26 | IsSnapshot bool
27 | SnapshotPercent float64
28 | }
29 |
30 | // Mount describes a file system mount point
31 | type Mount struct {
32 | Path string
33 | Device string
34 | LVPath string
35 | FileSystem string
36 | IsMounted bool
37 | DiskUsage int64
38 | MySQLDataPath string
39 | MySQLDiskUsage int64
40 | }
41 |
42 | // Agent presents the data of an agent
43 | type Agent struct {
44 | Hostname string
45 | Port int
46 | Token string
47 | LastSubmitted string
48 | AvailableLocalSnapshots []string
49 | AvailableSnapshots []string
50 | LogicalVolumes []LogicalVolume
51 | MountPoint Mount
52 | MySQLRunning bool
53 | MySQLDiskUsage int64
54 | MySQLPort int64
55 | MySQLDatadirDiskFree int64
56 | MySQLErrorLogTail []string
57 | }
58 |
59 | // SeedOperation makes for the high level data & state of a seed operation
60 | type SeedOperation struct {
61 | SeedId int64
62 | TargetHostname string
63 | SourceHostname string
64 | StartTimestamp string
65 | EndTimestamp string
66 | IsComplete bool
67 | IsSuccessful bool
68 | }
69 |
70 | // SeedOperationState represents a single state (step) in a seed operation
71 | type SeedOperationState struct {
72 | SeedStateId int64
73 | SeedId int64
74 | StateTimestamp string
75 | Action string
76 | ErrorMessage string
77 | }
78 |
79 | // Build an instance key for a given agent
80 | func (this *Agent) GetInstance() *inst.InstanceKey {
81 | return &inst.InstanceKey{Hostname: this.Hostname, Port: int(this.MySQLPort)}
82 | }
83 |
--------------------------------------------------------------------------------
/go/attributes/attributes.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2014 Outbrain Inc.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | package attributes
18 |
19 | // HostAttributes presnts attributes submitted by a host
20 | type HostAttributes struct {
21 | Hostname string
22 | AttributeName string
23 | AttributeValue string
24 | SubmitTimestamp string
25 | ExpireTimestamp string
26 | }
27 |
--------------------------------------------------------------------------------
/go/config/cli_flags.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2015 Shlomi Noach, courtesy Booking.com
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | package config
18 |
19 | // CLIFlags stores some command line flags that are globally available in the process' lifetime
20 | type CLIFlags struct {
21 | Noop *bool
22 | SkipUnresolve *bool
23 | SkipUnresolveCheck *bool
24 | BinlogFile *string
25 | Databaseless *bool
26 | GrabElection *bool
27 | Version *bool
28 | Statement *string
29 | PromotionRule *string
30 | ConfiguredVersion string
31 | }
32 |
33 | var RuntimeCLIFlags CLIFlags
34 |
--------------------------------------------------------------------------------
/go/inst/audit.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2014 Outbrain Inc.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | package inst
18 |
19 | // Audit presents a single audit entry (namely in the database)
20 | type Audit struct {
21 | AuditId int64
22 | AuditTimestamp string
23 | AuditType string
24 | AuditInstanceKey InstanceKey
25 | Message string
26 | }
27 |
--------------------------------------------------------------------------------
/go/inst/cluster_alias.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2015 Shlomi Noach, courtesy Booking.com
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | package inst
18 |
19 | // SetClusterAlias will write (and override) a single cluster name mapping
20 | func SetClusterAlias(clusterName string, alias string) error {
21 | return WriteClusterAlias(clusterName, alias)
22 | }
23 |
24 | // GetClusterByAlias returns the cluster name associated with given alias.
25 | // The function returns with error when:
26 | // - No cluster is associated with the alias
27 | // - More than one cluster is associated with the alias
28 | func GetClusterByAlias(alias string) (string, error) {
29 | return ReadClusterNameByAlias(alias)
30 | }
31 |
--------------------------------------------------------------------------------
/go/inst/cluster_domain_dao.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2015 Shlomi Noach, courtesy Booking.com
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | package inst
18 |
19 | import (
20 | "github.com/outbrain/golib/log"
21 | "github.com/outbrain/orchestrator/go/config"
22 | "github.com/outbrain/orchestrator/go/db"
23 | )
24 |
25 | // WriteClusterDomainName will write (and override) the domain name of a cluster
26 | func WriteClusterDomainName(clusterName string, domainName string) error {
27 | writeFunc := func() error {
28 | _, err := db.ExecOrchestrator(`
29 | insert into
30 | cluster_domain_name (cluster_name, domain_name, last_registered)
31 | values
32 | (?, ?, NOW())
33 | on duplicate key update
34 | domain_name=values(domain_name),
35 | last_registered=values(last_registered)
36 | `,
37 | clusterName, domainName)
38 | return log.Errore(err)
39 | }
40 | return ExecDBWriteFunc(writeFunc)
41 | }
42 |
43 | // ExpireClusterDomainName expires cluster_domain_name entries that haven't been updated recently.
44 | func ExpireClusterDomainName() error {
45 | writeFunc := func() error {
46 | _, err := db.ExecOrchestrator(`
47 | delete from cluster_domain_name
48 | where last_registered < NOW() - INTERVAL ? MINUTE
49 | `, config.Config.ExpiryHostnameResolvesMinutes,
50 | )
51 | return log.Errore(err)
52 | }
53 | return ExecDBWriteFunc(writeFunc)
54 | }
55 |
--------------------------------------------------------------------------------
/go/inst/maintenance.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2014 Outbrain Inc.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | package inst
18 |
19 | import (
20 | "github.com/outbrain/orchestrator/go/config"
21 | )
22 |
23 | // Maintenance indicates a maintenance entry (also in the database)
24 | type Maintenance struct {
25 | MaintenanceId uint
26 | Key InstanceKey
27 | BeginTimestamp string
28 | SecondsElapsed uint
29 | IsActive bool
30 | Owner string
31 | Reason string
32 | }
33 |
34 | var maintenanceOwner string = ""
35 |
36 | func GetMaintenanceOwner() string {
37 | if maintenanceOwner != "" {
38 | return maintenanceOwner
39 | }
40 | return config.Config.MaintenanceOwner
41 | }
42 |
43 | func SetMaintenanceOwner(owner string) {
44 | maintenanceOwner = owner
45 | }
46 |
--------------------------------------------------------------------------------
/go/inst/master_equivalence.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2015 Shlomi Noach, courtesy Booking.com
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | package inst
18 |
19 | // InstanceBinlogCoordinates is a convenice wrapper for instance key + binlog coordinates
20 | type InstanceBinlogCoordinates struct {
21 | Key InstanceKey
22 | Coordinates BinlogCoordinates
23 | }
24 |
--------------------------------------------------------------------------------
/go/inst/oracle_gtid_set.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2015 Shlomi Noach, courtesy Booking.com
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | package inst
18 |
19 | import (
20 | "strings"
21 | )
22 |
23 | // OracleGtidSet represents a set of GTID ranges as depicted by Retrieved_Gtid_Set, Executed_Gtid_Set or @@gtid_purged.
24 | type OracleGtidSet struct {
25 | GtidEntries [](*OracleGtidSetEntry)
26 | }
27 |
28 | // Example input: `230ea8ea-81e3-11e4-972a-e25ec4bd140a:1-10539,
29 | // 316d193c-70e5-11e5-adb2-ecf4bb2262ff:1-8935:8984-6124596,
30 | // 321f5c0d-70e5-11e5-adb2-ecf4bb2262ff:1-56`
31 | func ParseGtidSet(gtidSet string) (res *OracleGtidSet, err error) {
32 | res = &OracleGtidSet{}
33 |
34 | gtidSet = strings.TrimSpace(gtidSet)
35 | if gtidSet == "" {
36 | return res, nil
37 | }
38 | entries := strings.Split(gtidSet, ",")
39 | for _, entry := range entries {
40 | if gtidRange, err := NewOracleGtidSetEntry(entry); err == nil {
41 | res.GtidEntries = append(res.GtidEntries, gtidRange)
42 | } else {
43 | return res, err
44 | }
45 | }
46 | return res, nil
47 | }
48 |
49 | // RemoveUUID removes entries that belong to given UUID.
50 | // By way of how this works there can only be one entry matching our UUID, but we generalize.
51 | // We keep order of entries.
52 | func (this *OracleGtidSet) RemoveUUID(uuid string) (removed bool) {
53 | filteredEntries := [](*OracleGtidSetEntry){}
54 | for _, entry := range this.GtidEntries {
55 | if entry.UUID == uuid {
56 | removed = true
57 | } else {
58 | filteredEntries = append(filteredEntries, entry)
59 | }
60 | }
61 | if removed {
62 | this.GtidEntries = filteredEntries
63 | }
64 | return removed
65 | }
66 |
67 | func (this OracleGtidSet) String() string {
68 | tokens := []string{}
69 | for _, entry := range this.GtidEntries {
70 | tokens = append(tokens, entry.String())
71 | }
72 | return strings.Join(tokens, ",\n")
73 | }
74 |
--------------------------------------------------------------------------------
/go/inst/oracle_gtid_set_entry.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2015 Shlomi Noach, courtesy Booking.com
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | package inst
18 |
19 | import (
20 | "fmt"
21 | "strings"
22 | )
23 |
24 | // OracleGtidSetEntry represents an entry in a set of GTID ranges,
25 | // for example, the entry: "316d193c-70e5-11e5-adb2-ecf4bb2262ff:1-8935:8984-6124596" (may include gaps)
26 | type OracleGtidSetEntry struct {
27 | UUID string
28 | Ranges string
29 | }
30 |
31 | // NewOracleGtidSetEntry parses a single entry text
32 | func NewOracleGtidSetEntry(gtidRangeString string) (*OracleGtidSetEntry, error) {
33 | gtidRangeString = strings.TrimSpace(gtidRangeString)
34 | tokens := strings.SplitN(gtidRangeString, ":", 2)
35 | if len(tokens) != 2 {
36 | return nil, fmt.Errorf("Cannot parse OracleGtidSetEntry from %s", gtidRangeString)
37 | }
38 | if tokens[0] == "" {
39 | return nil, fmt.Errorf("Unexpected UUID: %s", tokens[0])
40 | }
41 | if tokens[1] == "" {
42 | return nil, fmt.Errorf("Unexpected GTID range: %s", tokens[1])
43 | }
44 | gtidRange := &OracleGtidSetEntry{UUID: tokens[0], Ranges: tokens[1]}
45 | return gtidRange, nil
46 | }
47 |
48 | // String returns a user-friendly string representation of this entry
49 | func (this OracleGtidSetEntry) String() string {
50 | return fmt.Sprintf("%s:%s", this.UUID, this.Ranges)
51 | }
52 |
--------------------------------------------------------------------------------
/go/inst/pool.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2015 Shlomi Noach, courtesy Booking.com
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | package inst
18 |
19 | import (
20 | "strings"
21 |
22 | "github.com/outbrain/orchestrator/go/config"
23 |
24 | "github.com/outbrain/golib/log"
25 | )
26 |
27 | // PoolInstancesMap lists instance keys per pool name
28 | type PoolInstancesMap map[string]([]*InstanceKey)
29 |
30 | // ClusterPoolInstance is an instance mapping a cluster, pool & instance
31 | type ClusterPoolInstance struct {
32 | ClusterName string
33 | ClusterAlias string
34 | Pool string
35 | Hostname string
36 | Port int
37 | }
38 |
39 | func ApplyPoolInstances(pool string, instancesList string) error {
40 | var instanceKeys [](*InstanceKey)
41 | if instancesList != "" {
42 | instancesStrings := strings.Split(instancesList, ",")
43 | for _, instanceString := range instancesStrings {
44 |
45 | instanceKey, err := ParseInstanceKeyLoose(instanceString)
46 | if config.Config.SupportFuzzyPoolHostnames {
47 | instanceKey = ReadFuzzyInstanceKeyIfPossible(instanceKey)
48 | }
49 | log.Debugf("%+v", instanceKey)
50 | if err != nil {
51 | return log.Errore(err)
52 | }
53 |
54 | instanceKeys = append(instanceKeys, instanceKey)
55 | }
56 | }
57 | writePoolInstances(pool, instanceKeys)
58 | return nil
59 | }
60 |
--------------------------------------------------------------------------------
/go/inst/postponed_functions.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2015 Shlomi Noach, courtesy Booking.com
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | package inst
18 |
19 | import (
20 | "github.com/outbrain/golib/log"
21 | )
22 |
23 | type PostponedFunctionsContainer struct {
24 | PostponedFunctions [](func() error)
25 | }
26 |
27 | func NewPostponedFunctionsContainer() *PostponedFunctionsContainer {
28 | postponedFunctionsContainer := &PostponedFunctionsContainer{}
29 | postponedFunctionsContainer.PostponedFunctions = [](func() error){}
30 | return postponedFunctionsContainer
31 | }
32 |
33 | func (this *PostponedFunctionsContainer) AddPostponedFunction(f func() error) {
34 | this.PostponedFunctions = append(this.PostponedFunctions, f)
35 | }
36 |
37 | func (this *PostponedFunctionsContainer) InvokePostponed() (err error) {
38 | if len(this.PostponedFunctions) == 0 {
39 | return
40 | }
41 | log.Debugf("PostponedFunctionsContainer: invoking %+v postponed functions", len(this.PostponedFunctions))
42 | for _, postponedFunction := range this.PostponedFunctions {
43 | ferr := postponedFunction()
44 | if err == nil {
45 | err = ferr
46 | }
47 | }
48 | return err
49 | }
50 |
--------------------------------------------------------------------------------
/go/inst/process.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2014 Outbrain Inc.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | package inst
18 |
19 | // Process presents a MySQL executing thread (as observed by PROCESSLIST)
20 | type Process struct {
21 | InstanceHostname string
22 | InstancePort int
23 | Id int64
24 | User string
25 | Host string
26 | Db string
27 | Command string
28 | Time int64
29 | State string
30 | Info string
31 | StartedAt string
32 | }
33 |
--------------------------------------------------------------------------------
/go/logic/async_request.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2015 Shlomi Noach, courtesy Booking.com
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | package logic
18 |
19 | import (
20 | "github.com/outbrain/orchestrator/go/inst"
21 | )
22 |
23 | // AsyncRequest represents an entry in the async_request table
24 | type AsyncRequest struct {
25 | Id int64
26 | Story string
27 | Command string
28 | OperatedInstanceKey *inst.InstanceKey
29 | DestinationKey *inst.InstanceKey
30 | Pattern string
31 | GTIDHint inst.OperationGTIDHint
32 | }
33 |
34 | func NewEmptyAsyncRequest() *AsyncRequest {
35 | asyncRequest := &AsyncRequest{}
36 | asyncRequest.GTIDHint = inst.GTIDHintNeutral
37 | return asyncRequest
38 | }
39 |
40 | func NewAsyncRequest(story string, command string, instanceKey *inst.InstanceKey, destinationKey *inst.InstanceKey, pattern string, gtidHint inst.OperationGTIDHint) *AsyncRequest {
41 | asyncRequest := NewEmptyAsyncRequest()
42 | asyncRequest.Story = story
43 | asyncRequest.Command = command
44 | asyncRequest.OperatedInstanceKey = instanceKey
45 | asyncRequest.DestinationKey = destinationKey
46 | asyncRequest.Pattern = pattern
47 | asyncRequest.GTIDHint = gtidHint
48 | return asyncRequest
49 | }
50 |
51 | func NewSimpleAsyncRequest(story string, command string, instanceKey *inst.InstanceKey) *AsyncRequest {
52 | asyncRequest := NewEmptyAsyncRequest()
53 | asyncRequest.Story = story
54 | asyncRequest.Command = command
55 | asyncRequest.OperatedInstanceKey = instanceKey
56 | asyncRequest.DestinationKey = nil
57 | asyncRequest.Pattern = ""
58 | return asyncRequest
59 | }
60 |
--------------------------------------------------------------------------------
/go/logic/disable_recovery.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2015 Shlomi Noach, courtesy Booking.com
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | package logic
18 |
19 | // This file holds wrappers around routines to check if global
20 | // recovery is disabled or not.
21 | //
22 | // This is determined by looking in the table
23 | // orchestrator.global_recovery_disable for a value 1. Note: for
24 | // recoveries to actually happen this must be configured explicitly
25 | // in orchestrator.conf.json. This setting is an emergency brake
26 | // to quickly be able to prevent recoveries happening in some large
27 | // outage type situation. Maybe this value should be cached etc
28 | // but we won't be doing that many recoveries at once so the load
29 | // on this table is expected to be very low. It should be fine to
30 | // go to the database each time.
31 |
32 | import (
33 | "github.com/outbrain/golib/log"
34 | "github.com/outbrain/golib/sqlutils"
35 | "github.com/outbrain/orchestrator/go/db"
36 | )
37 |
38 | // IsRecoveryDisabled returns true if Recoveries are disabled globally
39 | func IsRecoveryDisabled() (bool, error) {
40 | var (
41 | disabled bool // default is false!
42 | err error
43 | )
44 | query := `
45 | SELECT
46 | COUNT(*) as mycount
47 | FROM
48 | global_recovery_disable
49 | WHERE
50 | disable_recovery=?
51 | `
52 | err = db.QueryOrchestrator(query, sqlutils.Args(1), func(m sqlutils.RowMap) error {
53 | mycount := m.GetInt("mycount")
54 | disabled = (mycount > 0)
55 | return nil
56 | })
57 | if err != nil {
58 | err = log.Errorf("recovery.IsRecoveryDisabled(): %v", err)
59 | }
60 | return disabled, err
61 | }
62 |
63 | // DisableRecovery ensures recoveries are disabled globally
64 | func DisableRecovery() error {
65 | _, err := db.ExecOrchestrator(`
66 | INSERT IGNORE INTO global_recovery_disable
67 | (disable_recovery)
68 | VALUES (1)
69 | `,
70 | )
71 | return err
72 | }
73 |
74 | // EnableRecovery ensures recoveries are enabled globally
75 | func EnableRecovery() error {
76 | _, err := db.ExecOrchestrator(`
77 | DELETE FROM global_recovery_disable
78 | `,
79 | )
80 | return err
81 | }
82 |
--------------------------------------------------------------------------------
/go/metrics/graphite.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2014 Outbrain Inc.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | package metrics
18 |
19 | import (
20 | "github.com/cyberdelia/go-metrics-graphite"
21 | "github.com/outbrain/golib/log"
22 | "github.com/outbrain/orchestrator/go/config"
23 | "github.com/outbrain/orchestrator/go/process"
24 | "github.com/rcrowley/go-metrics"
25 | "net"
26 | "strings"
27 | "time"
28 | )
29 |
30 | var graphiteTickCallbacks [](func())
31 |
32 | // InitGraphiteMetrics is called once in the lifetime of the app, after config has been loaded
33 | func InitGraphiteMetrics() error {
34 | if config.Config.GraphiteAddr == "" {
35 | return nil
36 | }
37 | if config.Config.GraphitePollSeconds <= 0 {
38 | return nil
39 | }
40 | if config.Config.GraphitePath == "" {
41 | return log.Errorf("No graphite path provided (see GraphitePath config variable). Will not log to graphite")
42 | }
43 | addr, err := net.ResolveTCPAddr("tcp", config.Config.GraphiteAddr)
44 | if err != nil {
45 | return log.Errore(err)
46 | }
47 | graphitePathHostname := process.ThisHostname
48 | if config.Config.GraphiteConvertHostnameDotsToUnderscores {
49 | graphitePathHostname = strings.Replace(graphitePathHostname, ".", "_", -1)
50 | }
51 | graphitePath := config.Config.GraphitePath
52 | graphitePath = strings.Replace(graphitePath, "{hostname}", graphitePathHostname, -1)
53 |
54 | log.Debugf("Will log to graphite on %+v, %+v", config.Config.GraphiteAddr, graphitePath)
55 |
56 | graphiteCallbackTick := time.Tick(time.Duration(config.Config.GraphitePollSeconds) * time.Second)
57 | go func() {
58 | go graphite.Graphite(metrics.DefaultRegistry, 1*time.Minute, graphitePath, addr)
59 | for range graphiteCallbackTick {
60 | for _, f := range graphiteTickCallbacks {
61 | go f()
62 | }
63 | }
64 | }()
65 |
66 | return nil
67 | }
68 |
69 | func OnGraphiteTick(f func()) {
70 | graphiteTickCallbacks = append(graphiteTickCallbacks, f)
71 | }
72 |
--------------------------------------------------------------------------------
/go/process/host.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2015 Shlomi Noach, courtesy Booking.com
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | package process
18 |
19 | import (
20 | "github.com/outbrain/golib/log"
21 | "os"
22 | )
23 |
24 | var ThisHostname string
25 |
26 | func init() {
27 | var err error
28 | ThisHostname, err = os.Hostname()
29 | if err != nil {
30 | log.Fatalf("Cannot resolve self hostname; required. Aborting. %+v", err)
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/go/process/token.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2014 Outbrain Inc.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | package process
18 |
19 | import (
20 | "crypto/rand"
21 | "crypto/sha256"
22 | "encoding/hex"
23 | )
24 |
25 | func GetHash(input []byte) string {
26 | hasher := sha256.New()
27 | hasher.Write(input)
28 | return hex.EncodeToString(hasher.Sum(nil))
29 | }
30 |
31 | func GetRandomData() []byte {
32 | size := 64
33 | rb := make([]byte, size)
34 | _, _ = rand.Read(rb)
35 | return rb
36 | }
37 |
38 | // Token is used to identify and validate requests to this service
39 | type Token struct {
40 | Hash string
41 | }
42 |
43 | var ProcessToken *Token = NewToken()
44 |
45 | func NewToken() *Token {
46 | return &Token{
47 | Hash: GetHash(GetRandomData()),
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/resources/public/bootstrap/fonts/glyphicons-halflings-regular.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/outbrain-inc/orchestrator/2a6e4b7a96934b11c3dacb0b2fa4be814f168eef/resources/public/bootstrap/fonts/glyphicons-halflings-regular.eot
--------------------------------------------------------------------------------
/resources/public/bootstrap/fonts/glyphicons-halflings-regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/outbrain-inc/orchestrator/2a6e4b7a96934b11c3dacb0b2fa4be814f168eef/resources/public/bootstrap/fonts/glyphicons-halflings-regular.ttf
--------------------------------------------------------------------------------
/resources/public/bootstrap/fonts/glyphicons-halflings-regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/outbrain-inc/orchestrator/2a6e4b7a96934b11c3dacb0b2fa4be814f168eef/resources/public/bootstrap/fonts/glyphicons-halflings-regular.woff
--------------------------------------------------------------------------------
/resources/public/images/ajax-loader.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/outbrain-inc/orchestrator/2a6e4b7a96934b11c3dacb0b2fa4be814f168eef/resources/public/images/ajax-loader.gif
--------------------------------------------------------------------------------
/resources/public/images/booking-logo-32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/outbrain-inc/orchestrator/2a6e4b7a96934b11c3dacb0b2fa4be814f168eef/resources/public/images/booking-logo-32.png
--------------------------------------------------------------------------------
/resources/public/images/booking-logo-s.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/outbrain-inc/orchestrator/2a6e4b7a96934b11c3dacb0b2fa4be814f168eef/resources/public/images/booking-logo-s.png
--------------------------------------------------------------------------------
/resources/public/images/keep-calm-and-let-orchestrator-handle-it-transp-m.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/outbrain-inc/orchestrator/2a6e4b7a96934b11c3dacb0b2fa4be814f168eef/resources/public/images/keep-calm-and-let-orchestrator-handle-it-transp-m.png
--------------------------------------------------------------------------------
/resources/public/images/octocat-logo-32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/outbrain-inc/orchestrator/2a6e4b7a96934b11c3dacb0b2fa4be814f168eef/resources/public/images/octocat-logo-32.png
--------------------------------------------------------------------------------
/resources/public/images/outbrain-logo-32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/outbrain-inc/orchestrator/2a6e4b7a96934b11c3dacb0b2fa4be814f168eef/resources/public/images/outbrain-logo-32.png
--------------------------------------------------------------------------------
/resources/public/images/outbrain-logo-s.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/outbrain-inc/orchestrator/2a6e4b7a96934b11c3dacb0b2fa4be814f168eef/resources/public/images/outbrain-logo-s.png
--------------------------------------------------------------------------------
/resources/public/images/tile.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/outbrain-inc/orchestrator/2a6e4b7a96934b11c3dacb0b2fa4be814f168eef/resources/public/images/tile.png
--------------------------------------------------------------------------------
/resources/public/js/agents.js:
--------------------------------------------------------------------------------
1 |
2 | $(document).ready(function () {
3 | showLoader();
4 | activateRefreshTimer();
5 |
6 | $.get(appUrl("/api/agents"), function (agents) {
7 | displayAgents(agents);
8 | }, "json");
9 | function displayAgents(agents) {
10 | hideLoader();
11 |
12 | agents.forEach(function (agent) {
13 | $("#agents").append('
');
14 | var popoverElement = $("#agents [data-agent-name='" + agent.Hostname + "'].popover");
15 | //var title = agent.Hostname;
16 | //popoverElement.find("h3 a").html(title);
17 | var contentHtml = ''
18 | + ''
19 | + agent.Hostname
20 | + ' '
21 | ;
22 | popoverElement.find(".popover-content").html(contentHtml);
23 | });
24 |
25 | $("div.popover").popover();
26 | $("div.popover").show();
27 |
28 | if (agents.length == 0) {
29 | addAlert("No agents found");
30 | }
31 | }
32 | });
33 |
--------------------------------------------------------------------------------
/resources/public/js/audit.js:
--------------------------------------------------------------------------------
1 |
2 | $(document).ready(function () {
3 | showLoader();
4 | var apiUri = "/api/audit/"+currentPage();
5 | if (auditHostname()) {
6 | apiUri = "/api/audit/instance/"+auditHostname()+"/"+auditPort()+"/"+currentPage();
7 | }
8 | $.get(appUrl(apiUri), function (auditEntries) {
9 | displayAudit(auditEntries);
10 | }, "json");
11 | function displayAudit(auditEntries) {
12 | var baseWebUri = appUrl("/web/audit/");
13 | if (auditHostname()) {
14 | baseWebUri += "instance/"+auditHostname()+"/"+auditPort()+"/";
15 | }
16 | hideLoader();
17 | auditEntries.forEach(function (audit) {
18 | var row = jQuery(' ');
19 | jQuery(' ', { text: audit.AuditTimestamp }).appendTo(row);
20 | jQuery(' ', { text: audit.AuditType }).appendTo(row);
21 | if (audit.AuditInstanceKey.Hostname) {
22 | var uri = appUrl("/web/audit/instance/"+audit.AuditInstanceKey.Hostname+"/"+audit.AuditInstanceKey.Port);
23 | $(' ', { text: audit.AuditInstanceKey.Hostname+":"+audit.AuditInstanceKey.Port , href: uri}).wrap($(" ")).parent().appendTo(row);
24 | } else {
25 | jQuery(' ', { text: audit.AuditInstanceKey.Hostname+":"+audit.AuditInstanceKey.Port }).appendTo(row);
26 | }
27 | jQuery(' ', { text: audit.Message }).appendTo(row);
28 | row.appendTo('#audit tbody');
29 | });
30 | if (currentPage() <= 0) {
31 | $("#audit .pager .previous").addClass("disabled");
32 | }
33 | if (auditEntries.length == 0) {
34 | $("#audit .pager .next").addClass("disabled");
35 | }
36 | $("#audit .pager .previous").not(".disabled").find("a").click(function() {
37 | window.location.href = baseWebUri+(currentPage() - 1);
38 | });
39 | $("#audit .pager .next").not(".disabled").find("a").click(function() {
40 | window.location.href = baseWebUri+(currentPage() + 1);
41 | });
42 | $("#audit .pager .disabled a").click(function() {
43 | return false;
44 | });
45 | }
46 | });
47 |
--------------------------------------------------------------------------------
/resources/public/js/cluster-analysis-shared.js:
--------------------------------------------------------------------------------
1 | var interestingAnalysis = {
2 | "DeadMaster" : true,
3 | "DeadMasterAndSlaves" : true,
4 | "DeadMasterAndSomeSlaves" : true,
5 | "DeadMasterWithoutSlaves" : true,
6 | "UnreachableMasterWithStaleSlaves": true,
7 | "UnreachableMaster" : true,
8 | "AllMasterSlavesNotReplicating" : true,
9 | "AllMasterSlavesNotReplicatingOrDead" : true,
10 | "AllMasterSlavesStale" : true,
11 | "DeadCoMaster" : true,
12 | "DeadCoMasterAndSomeSlaves" : true,
13 | "DeadIntermediateMaster" : true,
14 | "DeadIntermediateMasterWithSingleSlaveFailingToConnect" : true,
15 | "DeadIntermediateMasterWithSingleSlave" : true,
16 | "DeadIntermediateMasterAndSomeSlaves" : true,
17 | "AllIntermediateMasterSlavesFailingToConnectOrDead" : true,
18 | "AllIntermediateMasterSlavesNotReplicating" : true,
19 | "UnreachableIntermediateMaster" : true,
20 | "BinlogServerFailingToConnectToMaster" : true,
21 | };
22 |
--------------------------------------------------------------------------------
/resources/public/js/common.js:
--------------------------------------------------------------------------------
1 | function Instance(){
2 |
3 | }
4 | Instance.createElement = function (instance){
5 | return $('');
6 | }
--------------------------------------------------------------------------------
/resources/public/js/discover.js:
--------------------------------------------------------------------------------
1 |
2 | $(document).ready(function () {
3 | $('button[data-btn=discover-instance]').unbind("click");
4 | $('button[data-btn=discover-instance]').click(function() {
5 |
6 | if (!$("#discoverHostName").val()) {
7 | return addAlert("You must enter a host name");
8 | }
9 | if (!$("#discoverPort").val()) {
10 | return addAlert("You must enter a port");
11 | }
12 | discover($("#discoverHostName").val(), $("#discoverPort").val())
13 | return false;
14 | });
15 | $("#discoverHostName").focus();
16 | });
17 |
18 | function discover(hostname, port) {
19 | showLoader();
20 | var uri = "/api/discover/"+hostname+"/"+port;
21 | $.get(appUrl(uri), function (operationResult) {
22 | hideLoader();
23 | if (operationResult.Code == "ERROR" || operationResult.Details == null) {
24 | addAlert(operationResult.Message)
25 | } else {
26 | var instance = operationResult.Details;
27 | addInfo('Discovered '
28 | +instance.Key.Hostname+":"+instance.Key.Port+' '
29 | );
30 | }
31 | }, "json");
32 |
33 | }
--------------------------------------------------------------------------------
/resources/public/js/instance-problems.js:
--------------------------------------------------------------------------------
1 | $(document).ready(function() {
2 | showLoader();
3 |
4 | var problemsURI = "/api/problems";
5 | if (typeof currentClusterName != "undefined") {
6 | problemsURI += "/" + currentClusterName();
7 | }
8 | $.get(appUrl(problemsURI), function(instances) {
9 | if (instances == null) {
10 | instances = [];
11 | }
12 | $.get(appUrl("/api/maintenance"), function(maintenanceList) {
13 | normalizeInstances(instances, maintenanceList);
14 | displayProblemInstances(instances);
15 | }, "json");
16 | }, "json");
17 |
18 | function displayProblemInstances(instances) {
19 | hideLoader();
20 |
21 | function SortByProblemOrder(instance0, instance1) {
22 | var orderDiff = instance0.problemOrder - instance1.problemOrder;
23 | if (orderDiff != 0) return orderDiff;
24 | var orderDiff = instance1.SlaveLagSeconds.Int64 - instance0.SlaveLagSeconds.Int64;
25 | if (orderDiff != 0) return orderDiff;
26 | orderDiff = instance0.title.localeCompare(instance1.title);
27 | if (orderDiff != 0) return orderDiff;
28 | return 0;
29 | }
30 | instances.sort(SortByProblemOrder);
31 |
32 | var countProblemInstances = 0;
33 | instances.forEach(function(instance) {
34 | var considerInstance = instance.hasProblem
35 | if (countProblemInstances >= 1000) {
36 | considerInstance = false;
37 | }
38 | if (considerInstance) {
39 | var li = $(" ");
40 | var instanceEl = Instance.createElement(instance).addClass("instance-problem").appendTo(li);
41 | $("#instance_problems ul").append(li);
42 |
43 | //var popoverElement = $("#instance_problems [data-nodeid='" + instance.id + "'].popover");
44 | renderInstanceElement(instanceEl, instance, "problems"); //popoverElement
45 | instanceEl.click(function() {
46 | openNodeModal(instance);
47 | return false;
48 | });
49 | if (countProblemInstances == 0) {
50 | // First problem instance
51 | $("#instance_problems_button").addClass("btn-" + instance.renderHint)
52 | }
53 | countProblemInstances += 1;
54 | }
55 | });
56 | if (countProblemInstances > 0 && (autoshowProblems() == "true") && ($.cookie("anonymize") != "true")) {
57 | $("#instance_problems .dropdown-toggle").dropdown('toggle');
58 | }
59 | if (countProblemInstances == 0) {
60 | $("#instance_problems").hide();
61 | }
62 |
63 | $("div.popover").popover();
64 | $("div.popover").show();
65 | }
66 | });
67 |
--------------------------------------------------------------------------------
/resources/public/js/jquery.cookie-1.4.1.min.js:
--------------------------------------------------------------------------------
1 | /*! jquery.cookie v1.4.1 | MIT */
2 | !function(a){"function"==typeof define&&define.amd?define(["jquery"],a):"object"==typeof exports?a(require("jquery")):a(jQuery)}(function(a){function b(a){return h.raw?a:encodeURIComponent(a)}function c(a){return h.raw?a:decodeURIComponent(a)}function d(a){return b(h.json?JSON.stringify(a):String(a))}function e(a){0===a.indexOf('"')&&(a=a.slice(1,-1).replace(/\\"/g,'"').replace(/\\\\/g,"\\"));try{return a=decodeURIComponent(a.replace(g," ")),h.json?JSON.parse(a):a}catch(b){}}function f(b,c){var d=h.raw?b:e(b);return a.isFunction(c)?c(d):d}var g=/\+/g,h=a.cookie=function(e,g,i){if(void 0!==g&&!a.isFunction(g)){if(i=a.extend({},h.defaults,i),"number"==typeof i.expires){var j=i.expires,k=i.expires=new Date;k.setTime(+k+864e5*j)}return document.cookie=[b(e),"=",d(g),i.expires?"; expires="+i.expires.toUTCString():"",i.path?"; path="+i.path:"",i.domain?"; domain="+i.domain:"",i.secure?"; secure":""].join("")}for(var l=e?void 0:{},m=document.cookie?document.cookie.split("; "):[],n=0,o=m.length;o>n;n++){var p=m[n].split("="),q=c(p.shift()),r=p.join("=");if(e&&e===q){l=f(r,g);break}e||void 0===(r=f(r))||(l[q]=r)}return l};h.defaults={},a.removeCookie=function(b,c){return void 0===a.cookie(b)?!1:(a.cookie(b,"",a.extend({},c,{expires:-1})),!a.cookie(b))}});
--------------------------------------------------------------------------------
/resources/public/js/search.js:
--------------------------------------------------------------------------------
1 |
2 | $(document).ready(function () {
3 | $("#searchInput").val(currentSearchString());
4 |
5 |
6 | showLoader();
7 | $.get(appUrl("/api/search/"+currentSearchString()), function (instances) {
8 | $.get(appUrl("/api/maintenance"),
9 | function (maintenanceList) {
10 | normalizeInstances(instances, maintenanceList);
11 | displaySearchInstances(instances);
12 | }, "json");
13 | }, "json");
14 | function displaySearchInstances(instances) {
15 | hideLoader();
16 | instances.forEach(function (instance) {
17 | var instanceEl = Instance.createElement(instance).addClass("instance-search").appendTo("#searchResults");
18 | renderInstanceElement(instanceEl, instance, "search");
19 | instanceEl.find("h3").click(function () {
20 | openNodeModal(instance);
21 | return false;
22 | });
23 | });
24 |
25 | if (instances.length == 0) {
26 | addAlert("No search results found for "+currentSearchString());
27 | }
28 | }
29 | });
30 |
--------------------------------------------------------------------------------
/resources/public/js/seed-shared.js:
--------------------------------------------------------------------------------
1 |
2 | function appendSeedDetails(seed, selector) {
3 | var row = '';
4 | var statusMessage;
5 | if (seed.IsComplete) {
6 | statusMessage = (seed.IsSuccessful ? 'Success ' : 'Fail ');
7 | } else {
8 | statusMessage = 'Active ';
9 | }
10 | row += '' + statusMessage + ' ';
11 | row += '' + seed.SeedId + ' ';
12 | row += ''+seed.TargetHostname+' ';
13 | row += ''+seed.SourceHostname+' ';
14 | row += '' + seed.StartTimestamp + ' ';
15 | row += '' + (seed.IsComplete ? seed.EndTimestamp : 'Abort ') + ' ';
16 | row += ' ';
17 | $(selector).append(row);
18 | hideLoader();
19 | }
20 |
21 | function appendSeedState(seedState) {
22 | var action = seedState.Action;
23 | action = action.replace(/Copied ([0-9]+).([0-9]+) bytes (.*$)/, function(match, match1, match2, match3) {
24 | return "Copied " + toHumanFormat(match1) + " / " + toHumanFormat(match2) + " " + match3;
25 | });
26 | var row = '';
27 | row += '' + seedState.StateTimestamp + ' ';
28 | row += '' + action + ' ';
29 | row += '' + seedState.ErrorMessage + ' ';
30 | row += ' ';
31 | $("[data-agent=seed_states]").append(row);
32 | hideLoader();
33 | }
34 |
35 | $("body").on("click", "button[data-command=abort-seed]", function(event) {
36 | var seedId = $(event.target).attr("data-seed-id");
37 | var sourceHost = $(event.target).attr("data-seed-source-host");
38 | var targetHost = $(event.target).attr("data-seed-target-host");
39 |
40 | var message = "Are you sure you wish to abort seed " + seedId + " from " +
41 | sourceHost + "
to " +
42 | targetHost + "
?";
43 | bootbox.confirm(message, function(confirm) {
44 | if (confirm) {
45 | showLoader();
46 | $.get(appUrl("/api/agent-abort-seed/"+seedId), function (operationResult) {
47 | hideLoader();
48 | if (operationResult.Code == "ERROR") {
49 | addAlert(operationResult.Message)
50 | } else {
51 | location.reload();
52 | }
53 | }, "json");
54 | }
55 | });
56 | });
57 |
--------------------------------------------------------------------------------
/resources/public/js/seed.js:
--------------------------------------------------------------------------------
1 |
2 | $(document).ready(function () {
3 | showLoader();
4 |
5 | $.get(appUrl("/api/agent-seed-details/"+currentSeedId()), function (seedArray) {
6 | showLoader();
7 | seedArray.forEach(function (seed) {
8 | appendSeedDetails(seed, "[data-agent=seed_details]");
9 | if (!seed.IsComplete) {
10 | activateRefreshTimer();
11 | }
12 | });
13 | }, "json");
14 |
15 | $.get(appUrl("/api/agent-seed-states/"+currentSeedId()), function (seedStates) {
16 | showLoader();
17 | seedStates.forEach(function (seedState) {
18 | appendSeedState(seedState);
19 | });
20 | }, "json");
21 | });
22 |
--------------------------------------------------------------------------------
/resources/public/js/seeds.js:
--------------------------------------------------------------------------------
1 |
2 | $(document).ready(function () {
3 | showLoader();
4 |
5 | $.get(appUrl("/api/seeds"), function (seeds) {
6 | showLoader();
7 | var hasActive = false;
8 | seeds.forEach(function (seed) {
9 | appendSeedDetails(seed, "[data-agent=seed_details]");
10 | if (!seed.IsComplete) {
11 | hasActive = true;
12 | }
13 | });
14 | if (hasActive) {
15 | activateRefreshTimer();
16 | }
17 | }, "json");
18 | });
19 |
--------------------------------------------------------------------------------
/resources/public/js/status.js:
--------------------------------------------------------------------------------
1 |
2 | function addStatusTableData(name, column1, column2) {
3 | $("#orchestratorStatusTable").append(
4 | '' + name + ' ' +
5 | '' + column1 + '
' +
6 | '' + column2 + '
'
7 | );
8 | }
9 | function addStatusActionButton(name, uri) {
10 | $("#orchestratorStatus .panel-footer").append(
11 | ''+name+' '
12 | );
13 | var button = $('#orchestratorStatus .panel-footer button:last');
14 | button.click(function(){
15 | apiCommand("/api/"+uri);
16 | });
17 |
18 | console.log(button)
19 | }
20 |
21 | $(document).ready(function () {
22 | var statusObject = $("#orchestratorStatus .panel-body");
23 | $.get(appUrl("/api/health/"), function (health) {
24 | statusObject.prepend(''+health.Message+' ')
25 | health.Details.AvailableNodes.forEach(function(node) {
26 | var values = node.split(";");
27 | var hostname = values[0];
28 | var token = values[1];
29 | var app_version = values[2];
30 | var message = hostname;
31 | if (hostname + ";" + token == health.Details.ActiveNode) {
32 | message += ' [Active] ';
33 | }
34 | if (hostname == health.Details.Hostname) {
35 | message += ' [This node] ';
36 | }
37 | addStatusTableData("Available node", message, app_version);
38 | })
39 |
40 | var userId = getUserId();
41 | if (userId == "") {
42 | userId = "[unknown]"
43 | }
44 | var userStatus = (isAuthorizedForAction() ? "admin" : "read only");
45 | addStatusTableData("You", userId + ", " + userStatus, "");
46 |
47 | if (isAuthorizedForAction()) {
48 | addStatusActionButton("Reload configuration", "reload-configuration");
49 | addStatusActionButton("Reset hostname resolve cache", "reset-hostname-resolve-cache");
50 | addStatusActionButton("Reelect", "reelect");
51 | }
52 |
53 | }, "json");
54 | });
55 |
--------------------------------------------------------------------------------
/resources/templates/about.tmpl:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | About
5 |
6 |
7 |
8 | Orchestrator is a MySQL replication topology management and visualization tool, allowing for:
9 |
10 | Detection and investigation of replication clusters
11 | Safe topology refactoring: moving slaves around the topology
12 | Sleek topology visualization
13 | Replication problems visualization
14 | Topology changes via intuitive drag & drop
15 | Maintenance mode declaration and enforcement
16 | Auditing of operations
17 | More...
18 |
19 |
20 |
21 | Refactoring the topology is a matter of a simple drag & drop. Orchestrator will keep you safe by disallowing invalid replication topologies (e.g. replicating from ROW based to STATEMENT based, from 5.5 to 5.1 etc.)
22 |
23 |
24 | Orchestrator can serve in different modes:
25 |
26 |
27 | Command line interface
28 |
29 |
30 | Web API
31 |
32 |
33 | Web interface
34 |
35 |
36 |
37 |
38 |
39 | Orchestrator is developed at GitHub to answer for the difficulty in managing and recovering replication topologies.
40 |
41 |
42 | Orchestrator is released as open source under the
43 | Apache 2.0 license and is available at:
44 | https://github.com/github/orchestrator
45 |
46 |
47 | Developed by Shlomi Noach.
48 |
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/resources/templates/agent_seed_details.tmpl:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
8 | Seed
9 |
10 |
11 |
12 |
13 | Seed details
14 |
15 |
16 |
17 |
18 | Status
19 | Id
20 | Target host
21 | Source host
22 | Seed start time
23 | Seed end time
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 | Seed states
34 |
35 |
36 |
37 |
38 | State start time
39 | State action
40 | Error message
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
55 |
56 |
57 |
--------------------------------------------------------------------------------
/resources/templates/agents.tmpl:
--------------------------------------------------------------------------------
1 |
16 |
17 |
18 |
19 |
20 |
21 |
23 |
24 |
--------------------------------------------------------------------------------
/resources/templates/audit.tmpl:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
8 |
9 |
10 |
11 | Audit time
12 | Type
13 | Instance
14 | message
15 |
16 |
17 |
18 |
19 |
20 |
24 |
25 |
26 |
27 |
28 |
29 |
42 |
43 |
--------------------------------------------------------------------------------
/resources/templates/audit_failure_detection.tmpl:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
8 |
9 |
10 |
11 | Analysis
12 | Failed instance
13 | Affected
14 | Cluster name
15 | Cluster alias
16 | Detect time
17 |
18 |
19 |
20 |
21 |
22 |
26 |
27 |
28 |
29 |
30 |
31 |
40 |
41 |
--------------------------------------------------------------------------------
/resources/templates/audit_recovery.tmpl:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
8 |
9 |
10 |
11 | Analysis
12 | Failed instance
13 | Affected
14 | Cluster name
15 | Cluster alias
16 | Start time
17 | End time
18 | Successor instance
19 |
20 |
21 |
22 |
23 |
24 |
28 |
29 |
30 |
31 |
32 |
33 |
46 |
47 |
--------------------------------------------------------------------------------
/resources/templates/cluster.tmpl:
--------------------------------------------------------------------------------
1 |
36 |
37 |
38 |
39 |
40 | Move
41 |
42 |
43 |
49 |
50 |
51 |
52 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
--------------------------------------------------------------------------------
/resources/templates/cluster_pools.tmpl:
--------------------------------------------------------------------------------
1 |
16 |
17 |
18 |
19 |
20 |
21 |
30 |
31 |
--------------------------------------------------------------------------------
/resources/templates/clusters.tmpl:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/resources/templates/clusters_analysis.tmpl:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/resources/templates/discover.tmpl:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Discover a new instance
5 |
6 |
7 |
8 |
9 | Enter a MySQL hostname and a port. Orchestrator will try and resolve the CNAME.
10 |
11 |
12 | If running in discovery mode, orchestrator will also attempt to discover the entire topology the instance belongs to.
13 |
14 |
15 |
16 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/resources/templates/home.tmpl:
--------------------------------------------------------------------------------
1 |
2 |
Orchestrator
3 |
4 | Welcome! Orchestrator is your MySQL replication visualization and management tool.
5 |
6 |
7 |
8 | Orchestrator is familiar with
replication cluster(s) at this moment. Click "Clusters" on top navigation bar too see them. If you have more replication clusters you wish to visualize and manage, please let orchestrator know about them by going to the discovery page .
9 |
10 |
11 | Orchestrator is a multi-tiered application. It executes as a command line tool - you can move slaves around the topology and do most other stuff. It also serves as Web API. In fact, there is little to the web interface you're using right
12 | now - it's mostly client cosmetics; all operations in this web interface are based on web API calls.
13 |
14 |
15 |
16 |
17 | It seems like this is your initial installation of orchestrator : there are no known clusters at this stage.
18 |
19 |
20 | Your next task is to let orchestrator know about your replication topologies. Pick one server from each topology (this could be either master or slave). Orchestrator will attempt to connect to such a server, and auto-discover the entire
21 | replication tree by recursively crawling the server's master and slaves.
22 |
23 |
24 | Once discovered (and allow for a few minutes for complete replication graph detection), you will be able to easily change your topology via drag & drop, start & stop your slaves, start/end maintenance modes and get quick insight into replication problems.
25 |
26 |
27 | Make sure your configuration file has the proper credentials for accessing all those remote MySQL servers. You will need the SUPER
and PROCESS
privileges on any node you wish to be able to discover. Make sure to run the
28 | following on masters of your topologies; fill in your own host name (limit '%'
to a specific host), user and password:
29 |
30 | GRANT SUPER, PROCESS ON *.* TO 'orchestrator'@'%' IDENTIFIED BY 'secret';
31 |
32 |
33 |
34 | Start discovery now
35 |
36 |
37 |
38 |
39 |
40 |
41 |
55 |
--------------------------------------------------------------------------------
/resources/templates/keep-calm.tmpl:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/resources/templates/long_queries.tmpl:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
14 |
15 |
--------------------------------------------------------------------------------
/resources/templates/search.tmpl:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
10 |
11 |
--------------------------------------------------------------------------------
/resources/templates/seeds.tmpl:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
8 | Seeds
9 |
10 |
11 |
12 |
13 | Seed details
14 |
15 |
16 |
17 |
18 | Status
19 | Id
20 | Target host
21 | Source host
22 | Seed start time
23 | Seed end time
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/resources/templates/status.tmpl:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Status
5 |
6 |
10 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/vagrant/README.md:
--------------------------------------------------------------------------------
1 | Orchestrator Vagrant Instructions
2 | =================================
3 |
4 | Orchestrator's Vagrant defaults to installing five (5) CentOS 6.6 boxes in the following replication topology, with a separate "admin" node:
5 |
6 | ```
7 | db1<->db2
8 | | |
9 | v v
10 | db3 db4
11 | ```
12 |
13 | It is possible to override what gets installed by the use of environmental variables:
14 |
15 | ```
16 | VAGRANT_SERVER_URL defaults to 'https://atlas.hashicorp.com'
17 | VAGRANT_DEFAULT_PROVIDER defaults to 'virtualbox'
18 | VAGRANT_BOX defaults to 'nrel/CentOS-6.6-x86_64
19 | ```
20 |
21 | The MySQL configuration is such that it is the minimum required to set up replication. For testing such features as delayed replication, RBR/SBR, GTID, it is simply a matter of editing the `vagrant/dbX-my.cnf` before running the `vagrant up` command.
22 |
23 | FAQ
24 | ===
25 |
26 | Q: By default, there are still a lot of steps that I have to do within each virtual machine to get going
27 |
28 | A: That is by design. Vagrant will execute `db-post-install.sh`, `dbX-post-install.sh`, and `admin-post-install.sh` in the `vagrant/` directory (they are `.gitignore`'d) for any custom work that you want to have done (i.e. build Orchestrator, etc etc)
29 |
30 | Q: I run some other distribution of Linux. Why don't you support that?
31 |
32 | A: Pull Requests are welcome! If you update any of the `vagrant/*.sh` scripts, they must work with at least CentOS 6 and Ubuntu 12
33 |
34 | Tips & Tricks
35 | =============
36 |
37 | Specify GTID Usage
38 | ------------------
39 |
40 | If you want to use GTID Replication, you must update all of the `vagrant/dbX-my.cnf` files with the following options in `[mysqld]`:
41 |
42 | ```
43 | enforce-gtid-consistency
44 | gtid-mode=ON
45 | ```
46 |
47 | Specify RBR/SBR
48 | ---------------
49 |
50 | `vagrant/dbX-my.cnf` files are copied directly to the virtual machines. If you'd like to specify SBR/RBR/MIXED, add one of the following lines to the `[mysqld]` section of the `my.cnf` template:
51 |
52 | ```
53 | binlog_format=MIXED
54 | binlog_format=STATEMENT
55 | binlog_format=ROW
56 | ```
57 |
58 | This is not global because we want to be able to test out non-standard replication configurations.
59 |
60 | Use VMWare vs. VirtualBox
61 | -------------------------
62 |
63 | ```
64 | %> export VAGRANT_DEFAULT_PROVIDER='vmware_fusion'
65 | %> vagrant up
66 | ```
67 |
68 | CentOS
69 | ------
70 |
71 | This is the default. Nothing special is required:
72 |
73 | ```
74 | %> vagrant up
75 | ```
76 |
77 | Ubuntu
78 | ------
79 |
80 | ```
81 | %> export VAGRANT_SERVER_URL="https://atlas.hashicorp.com"
82 | %> export VAGRANT_BOX='chef/ubuntu-12.04'
83 | %> vagrant up
84 | ```
85 |
86 | TO DO
87 | =====
88 |
89 | - Support other MySQL's (5.5, 5.7, MariaDB)
90 | - Support customizable replication configurations
91 | - Better `my.cnf` templates
92 |
93 |
--------------------------------------------------------------------------------
/vagrant/admin-build.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # Install orchestrator
4 | rpm -i /tmp/orchestrator-release/orchestrator*.rpm
5 | /sbin/chkconfig orchestrator on
6 | cp /usr/local/orchestrator/orchestrator-sample.conf.json /etc/orchestrator.conf.json
7 | /sbin/service orchestrator start
8 |
9 | echo '* * * * * root /usr/bin/orchestrator -c discover -i db1' > /etc/cron.d/orchestrator-discovery
10 |
11 | # Discover instances
12 | /usr/bin/orchestrator -c discover -i localhost
--------------------------------------------------------------------------------
/vagrant/db1-build.sh:
--------------------------------------------------------------------------------
1 | if [[ -e /etc/debian_version ]]; then
2 | sudo cp /orchestrator/vagrant/db1-my.cnf /etc/mysql/my.cnf
3 | sudo /etc/init.d/mysql restart
4 | fi
5 |
6 | /usr/bin/mysql -uroot -ss -e 'GRANT REPLICATION SLAVE ON *.* TO "repl"@"192.168.57.%" IDENTIFIED BY "vagrant_repl"'
7 | /usr/bin/mysql -uroot -ss -e 'CHANGE MASTER TO MASTER_HOST="192.168.57.202", MASTER_USER="repl", MASTER_PASSWORD="vagrant_repl", MASTER_CONNECT_RETRY=10, MASTER_RETRY_COUNT=36'
8 | /usr/bin/mysql -uroot -ss -e 'START SLAVE'
9 |
--------------------------------------------------------------------------------
/vagrant/db1-my.cnf:
--------------------------------------------------------------------------------
1 | [mysqld]
2 | datadir=/var/lib/mysql
3 | user=mysql
4 | # Disabling symbolic-links is recommended to prevent assorted security risks
5 | symbolic-links=0
6 | server_id=1
7 | log_bin
8 | log-slave-updates
9 | report-host=db1
10 |
11 | [mysqld_safe]
12 | log-error=/var/log/mysqld.log
13 | pid-file=/var/run/mysqld/mysqld.pid
14 |
--------------------------------------------------------------------------------
/vagrant/db2-build.sh:
--------------------------------------------------------------------------------
1 | if [[ -e /etc/debian_version ]]; then
2 | sudo cp /orchestrator/vagrant/db1-my.cnf /etc/mysql/my.cnf
3 | sudo /etc/init.d/mysql restart
4 | fi
5 |
6 | /usr/bin/mysql -uroot -ss -e 'GRANT REPLICATION SLAVE ON *.* TO "repl"@"192.168.57.%" IDENTIFIED BY "vagrant_repl"'
7 | /usr/bin/mysql -uroot -ss -e 'CHANGE MASTER TO MASTER_HOST="192.168.57.201", MASTER_USER="repl", MASTER_PASSWORD="vagrant_repl", MASTER_CONNECT_RETRY=10, MASTER_RETRY_COUNT=36'
8 | /usr/bin/mysql -uroot -ss -e 'START SLAVE'
9 |
--------------------------------------------------------------------------------
/vagrant/db2-my.cnf:
--------------------------------------------------------------------------------
1 | [mysqld]
2 | datadir=/var/lib/mysql
3 | user=mysql
4 | # Disabling symbolic-links is recommended to prevent assorted security risks
5 | symbolic-links=0
6 | server_id=2
7 | log_bin
8 | log-slave-updates
9 | report-host=db2
10 |
11 | [mysqld_safe]
12 | log-error=/var/log/mysqld.log
13 | pid-file=/var/run/mysqld/mysqld.pid
14 |
--------------------------------------------------------------------------------
/vagrant/db3-build.sh:
--------------------------------------------------------------------------------
1 | if [[ -e /etc/debian_version ]]; then
2 | sudo cp /orchestrator/vagrant/db1-my.cnf /etc/mysql/my.cnf
3 | sudo /etc/init.d/mysql restart
4 | fi
5 |
6 | /usr/bin/mysql -uroot -ss -e 'GRANT REPLICATION SLAVE ON *.* TO "repl"@"192.168.57.%" IDENTIFIED BY "vagrant_repl"'
7 | /usr/bin/mysql -uroot -ss -e 'CHANGE MASTER TO MASTER_HOST="192.168.57.201", MASTER_USER="repl", MASTER_PASSWORD="vagrant_repl", MASTER_CONNECT_RETRY=10, MASTER_RETRY_COUNT=36'
8 | /usr/bin/mysql -uroot -ss -e 'START SLAVE'
9 |
--------------------------------------------------------------------------------
/vagrant/db3-my.cnf:
--------------------------------------------------------------------------------
1 | [mysqld]
2 | datadir=/var/lib/mysql
3 | user=mysql
4 | # Disabling symbolic-links is recommended to prevent assorted security risks
5 | symbolic-links=0
6 | server_id=3
7 | log_bin
8 | log-slave-updates
9 | report-host=db3
10 |
11 | [mysqld_safe]
12 | log-error=/var/log/mysqld.log
13 | pid-file=/var/run/mysqld/mysqld.pid
14 |
--------------------------------------------------------------------------------
/vagrant/db4-build.sh:
--------------------------------------------------------------------------------
1 | if [[ -e /etc/debian_version ]]; then
2 | sudo cp /orchestrator/vagrant/db1-my.cnf /etc/mysql/my.cnf
3 | sudo /etc/init.d/mysql restart
4 | fi
5 |
6 | /usr/bin/mysql -uroot -ss -e 'GRANT REPLICATION SLAVE ON *.* TO "repl"@"192.168.57.%" IDENTIFIED BY "vagrant_repl"'
7 | /usr/bin/mysql -uroot -ss -e 'CHANGE MASTER TO MASTER_HOST="192.168.57.202", MASTER_USER="repl", MASTER_PASSWORD="vagrant_repl", MASTER_CONNECT_RETRY=10, MASTER_RETRY_COUNT=36'
8 | /usr/bin/mysql -uroot -ss -e 'START SLAVE'
9 |
--------------------------------------------------------------------------------
/vagrant/db4-my.cnf:
--------------------------------------------------------------------------------
1 | [mysqld]
2 | datadir=/var/lib/mysql
3 | user=mysql
4 | # Disabling symbolic-links is recommended to prevent assorted security risks
5 | symbolic-links=0
6 | server_id=4
7 | log_bin
8 | log-slave-updates
9 | report-host=db4
10 |
11 | [mysqld_safe]
12 | log-error=/var/log/mysqld.log
13 | pid-file=/var/run/mysqld/mysqld.pid
14 |
--------------------------------------------------------------------------------
/vendor/github.com/codegangsta/inject/.gitignore:
--------------------------------------------------------------------------------
1 | inject
2 | inject.test
3 |
--------------------------------------------------------------------------------
/vendor/github.com/codegangsta/inject/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2013 Jeremy Saenz
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of
6 | this software and associated documentation files (the "Software"), to deal in
7 | the Software without restriction, including without limitation the rights to
8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 | the Software, and to permit persons to whom the Software is furnished to do so,
10 | 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, FITNESS
17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/vendor/github.com/codegangsta/inject/translations/README_zh_cn.md:
--------------------------------------------------------------------------------
1 | # inject
2 | --
3 | import "github.com/codegangsta/inject"
4 |
5 | inject包提供了多种对实体的映射和依赖注入方式。
6 |
7 | ## 用法
8 |
9 | #### func InterfaceOf
10 |
11 | ```go
12 | func InterfaceOf(value interface{}) reflect.Type
13 | ```
14 | 函数InterfaceOf返回指向接口类型的指针。如果传入的value值不是指向接口的指针,将抛出一个panic异常。
15 |
16 | #### type Applicator
17 |
18 | ```go
19 | type Applicator interface {
20 | // 在Type map中维持对结构体中每个域的引用并用'inject'来标记
21 | // 如果注入失败将会返回一个error.
22 | Apply(interface{}) error
23 | }
24 | ```
25 |
26 | Applicator接口表示到结构体的依赖映射关系。
27 |
28 | #### type Injector
29 |
30 | ```go
31 | type Injector interface {
32 | Applicator
33 | Invoker
34 | TypeMapper
35 | // SetParent用来设置父injector. 如果在当前injector的Type map中找不到依赖,
36 | // 将会继续从它的父injector中找,直到返回error.
37 | SetParent(Injector)
38 | }
39 | ```
40 |
41 | Injector接口表示对结构体、函数参数的映射和依赖注入。
42 |
43 | #### func New
44 |
45 | ```go
46 | func New() Injector
47 | ```
48 | New创建并返回一个Injector.
49 |
50 | #### type Invoker
51 |
52 | ```go
53 | type Invoker interface {
54 | // Invoke尝试将interface{}作为一个函数来调用,并基于Type为函数提供参数。
55 | // 它将返回reflect.Value的切片,其中存放原函数的返回值。
56 | // 如果注入失败则返回error.
57 | Invoke(interface{}) ([]reflect.Value, error)
58 | }
59 | ```
60 |
61 | Invoker接口表示通过反射进行函数调用。
62 |
63 | #### type TypeMapper
64 |
65 | ```go
66 | type TypeMapper interface {
67 | // 基于调用reflect.TypeOf得到的类型映射interface{}的值。
68 | Map(interface{}) TypeMapper
69 | // 基于提供的接口的指针映射interface{}的值。
70 | // 该函数仅用来将一个值映射为接口,因为接口无法不通过指针而直接引用到。
71 | MapTo(interface{}, interface{}) TypeMapper
72 | // 为直接插入基于类型和值的map提供一种可能性。
73 | // 它使得这一类直接映射成为可能:无法通过反射直接实例化的类型参数,如单向管道。
74 | Set(reflect.Type, reflect.Value) TypeMapper
75 | // 返回映射到当前类型的Value. 如果Type没被映射,将返回对应的零值。
76 | Get(reflect.Type) reflect.Value
77 | }
78 | ```
79 |
80 | TypeMapper接口用来表示基于类型到接口值的映射。
81 |
82 |
83 | ## 译者
84 |
85 | 张强 (qqbunny@yeah.net)
--------------------------------------------------------------------------------
/vendor/github.com/codegangsta/inject/update_readme.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | go get github.com/robertkrimen/godocdown/godocdown
3 | godocdown > README.md
4 |
--------------------------------------------------------------------------------
/vendor/github.com/cyberdelia/go-metrics-graphite/AUTHORS:
--------------------------------------------------------------------------------
1 | These people have provided bug fixes, new features or improved the documentation.
2 |
3 | * Daniel Garcia
4 | * Peter Teichman
5 | * Phillip Kovalev
6 | * Richard Crowley
7 | * Timothée Peignier
8 | * Tomás Senart
9 |
--------------------------------------------------------------------------------
/vendor/github.com/cyberdelia/go-metrics-graphite/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright 2015 Timothée Peignier. All rights reserved.
2 |
3 | Redistribution and use in source and binary forms, with or without modification,
4 | are permitted provided that the following conditions are met:
5 |
6 | 1. Redistributions of source code must retain the above copyright notice,
7 | this list of conditions and the following disclaimer.
8 |
9 | 2. Redistributions in binary form must reproduce the above copyright notice,
10 | this list of conditions and the following disclaimer in the documentation
11 | and/or other materials provided with the distribution.
12 |
13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
14 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
17 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 |
--------------------------------------------------------------------------------
/vendor/github.com/cyberdelia/go-metrics-graphite/README.md:
--------------------------------------------------------------------------------
1 | This is a reporter for the [go-metrics](https://github.com/rcrowley/go-metrics)
2 | library which will post the metrics to Graphite. It was originally part of the
3 | `go-metrics` library itself, but has been split off to make maintenance of
4 | both the core library and the client easier.
5 |
6 | ### Usage
7 |
8 | ```go
9 | import "github.com/cyberdelia/go-metrics-graphite"
10 |
11 |
12 | go graphite.Graphite(metrics.DefaultRegistry,
13 | 1*time.Second, "some.prefix", addr)
14 | ```
15 |
16 | ### Migrating from `rcrowley/go-metrics` implementation
17 |
18 | Simply modify the import from `"github.com/rcrowley/go-metrics/librato"` to
19 | `"github.com/cyberdelia/go-metrics-graphite"` and it should Just Work.
20 |
--------------------------------------------------------------------------------
/vendor/github.com/go-martini/martini/.gitignore:
--------------------------------------------------------------------------------
1 | # Compiled Object files, Static and Dynamic libs (Shared Objects)
2 | *.o
3 | *.a
4 | *.so
5 |
6 | # Folders
7 | _obj
8 | _test
9 |
10 | # Architecture specific extensions/prefixes
11 | *.[568vq]
12 | [568vq].out
13 |
14 | *.cgo1.go
15 | *.cgo2.c
16 | _cgo_defun.c
17 | _cgo_gotypes.go
18 | _cgo_export.*
19 |
20 | _testmain.go
21 |
22 | *.exe
23 | *.test
24 |
25 | /.godeps
26 | /.envrc
27 |
28 | # Godeps
29 | Godeps/_workspace
30 | Godeps/Readme
31 |
--------------------------------------------------------------------------------
/vendor/github.com/go-martini/martini/Godeps/Godeps.json:
--------------------------------------------------------------------------------
1 | {
2 | "ImportPath": "github.com/go-martini/martini",
3 | "GoVersion": "go1.4.2",
4 | "Deps": [
5 | {
6 | "ImportPath": "github.com/codegangsta/inject",
7 | "Comment": "v1.0-rc1-10-g33e0aa1",
8 | "Rev": "33e0aa1cb7c019ccc3fbe049a8262a6403d30504"
9 | }
10 | ]
11 | }
12 |
--------------------------------------------------------------------------------
/vendor/github.com/go-martini/martini/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Jeremy Saenz
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of
6 | this software and associated documentation files (the "Software"), to deal in
7 | the Software without restriction, including without limitation the rights to
8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 | the Software, and to permit persons to whom the Software is furnished to do so,
10 | 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, FITNESS
17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/vendor/github.com/go-martini/martini/env.go:
--------------------------------------------------------------------------------
1 | package martini
2 |
3 | import (
4 | "os"
5 | )
6 |
7 | // Envs
8 | const (
9 | Dev string = "development"
10 | Prod string = "production"
11 | Test string = "test"
12 | )
13 |
14 | // Env is the environment that Martini is executing in. The MARTINI_ENV is read on initialization to set this variable.
15 | var Env = Dev
16 | var Root string
17 |
18 | func setENV(e string) {
19 | if len(e) > 0 {
20 | Env = e
21 | }
22 | }
23 |
24 | func init() {
25 | setENV(os.Getenv("MARTINI_ENV"))
26 | var err error
27 | Root, err = os.Getwd()
28 | if err != nil {
29 | panic(err)
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/vendor/github.com/go-martini/martini/go_version.go:
--------------------------------------------------------------------------------
1 | // +build !go1.1
2 |
3 | package martini
4 |
5 | func MartiniDoesNotSupportGo1Point0() {
6 | "Martini requires Go 1.1 or greater."
7 | }
8 |
--------------------------------------------------------------------------------
/vendor/github.com/go-martini/martini/logger.go:
--------------------------------------------------------------------------------
1 | package martini
2 |
3 | import (
4 | "log"
5 | "net/http"
6 | "time"
7 | )
8 |
9 | // Logger returns a middleware handler that logs the request as it goes in and the response as it goes out.
10 | func Logger() Handler {
11 | return func(res http.ResponseWriter, req *http.Request, c Context, log *log.Logger) {
12 | start := time.Now()
13 |
14 | addr := req.Header.Get("X-Real-IP")
15 | if addr == "" {
16 | addr = req.Header.Get("X-Forwarded-For")
17 | if addr == "" {
18 | addr = req.RemoteAddr
19 | }
20 | }
21 |
22 | log.Printf("Started %s %s for %s", req.Method, req.URL.Path, addr)
23 |
24 | rw := res.(ResponseWriter)
25 | c.Next()
26 |
27 | log.Printf("Completed %v %s in %v\n", rw.Status(), http.StatusText(rw.Status()), time.Since(start))
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/vendor/github.com/go-martini/martini/return_handler.go:
--------------------------------------------------------------------------------
1 | package martini
2 |
3 | import (
4 | "github.com/codegangsta/inject"
5 | "net/http"
6 | "reflect"
7 | )
8 |
9 | // ReturnHandler is a service that Martini provides that is called
10 | // when a route handler returns something. The ReturnHandler is
11 | // responsible for writing to the ResponseWriter based on the values
12 | // that are passed into this function.
13 | type ReturnHandler func(Context, []reflect.Value)
14 |
15 | func defaultReturnHandler() ReturnHandler {
16 | return func(ctx Context, vals []reflect.Value) {
17 | rv := ctx.Get(inject.InterfaceOf((*http.ResponseWriter)(nil)))
18 | res := rv.Interface().(http.ResponseWriter)
19 | var responseVal reflect.Value
20 | if len(vals) > 1 && vals[0].Kind() == reflect.Int {
21 | res.WriteHeader(int(vals[0].Int()))
22 | responseVal = vals[1]
23 | } else if len(vals) > 0 {
24 | responseVal = vals[0]
25 | }
26 | if canDeref(responseVal) {
27 | responseVal = responseVal.Elem()
28 | }
29 | if isByteSlice(responseVal) {
30 | res.Write(responseVal.Bytes())
31 | } else {
32 | res.Write([]byte(responseVal.String()))
33 | }
34 | }
35 | }
36 |
37 | func isByteSlice(val reflect.Value) bool {
38 | return val.Kind() == reflect.Slice && val.Type().Elem().Kind() == reflect.Uint8
39 | }
40 |
41 | func canDeref(val reflect.Value) bool {
42 | return val.Kind() == reflect.Interface || val.Kind() == reflect.Ptr
43 | }
44 |
--------------------------------------------------------------------------------
/vendor/github.com/go-martini/martini/wercker.yml:
--------------------------------------------------------------------------------
1 | box: wercker/golang@1.1.1
--------------------------------------------------------------------------------
/vendor/github.com/go-sql-driver/mysql/AUTHORS:
--------------------------------------------------------------------------------
1 | # This is the official list of Go-MySQL-Driver authors for copyright purposes.
2 |
3 | # If you are submitting a patch, please add your name or the name of the
4 | # organization which holds the copyright to this list in alphabetical order.
5 |
6 | # Names should be added to this file as
7 | # Name
8 | # The email address is not required for organizations.
9 | # Please keep the list sorted.
10 |
11 |
12 | # Individual Persons
13 |
14 | Aaron Hopkins
15 | Arne Hormann
16 | Carlos Nieto
17 | Chris Moos
18 | Daniel Nichter
19 | Daniël van Eeden
20 | DisposaBoy
21 | Frederick Mayle
22 | Gustavo Kristic
23 | Hanno Braun
24 | Henri Yandell
25 | Hirotaka Yamamoto
26 | INADA Naoki
27 | James Harr
28 | Jian Zhen
29 | Joshua Prunier
30 | Julien Lefevre
31 | Julien Schmidt
32 | Kamil Dziedzic
33 | Kevin Malachowski
34 | Leonardo YongUk Kim
35 | Luca Looz
36 | Lucas Liu
37 | Luke Scott
38 | Michael Woolnough
39 | Nicola Peduzzi
40 | Paul Bonser
41 | Runrioter Wung
42 | Soroush Pour
43 | Stan Putrya
44 | Stanley Gunawan
45 | Xiaobing Jiang
46 | Xiuming Chen
47 |
48 | # Organizations
49 |
50 | Barracuda Networks, Inc.
51 | Google Inc.
52 | Stripe Inc.
53 |
--------------------------------------------------------------------------------
/vendor/github.com/go-sql-driver/mysql/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing Guidelines
2 |
3 | ## Reporting Issues
4 |
5 | Before creating a new Issue, please check first if a similar Issue [already exists](https://github.com/go-sql-driver/mysql/issues?state=open) or was [recently closed](https://github.com/go-sql-driver/mysql/issues?direction=desc&page=1&sort=updated&state=closed).
6 |
7 | ## Contributing Code
8 |
9 | By contributing to this project, you share your code under the Mozilla Public License 2, as specified in the LICENSE file.
10 | Don't forget to add yourself to the AUTHORS file.
11 |
12 | ### Code Review
13 |
14 | Everyone is invited to review and comment on pull requests.
15 | If it looks fine to you, comment with "LGTM" (Looks good to me).
16 |
17 | If changes are required, notice the reviewers with "PTAL" (Please take another look) after committing the fixes.
18 |
19 | Before merging the Pull Request, at least one [team member](https://github.com/go-sql-driver?tab=members) must have commented with "LGTM".
20 |
21 | ## Development Ideas
22 |
23 | If you are looking for ideas for code contributions, please check our [Development Ideas](https://github.com/go-sql-driver/mysql/wiki/Development-Ideas) Wiki page.
24 |
--------------------------------------------------------------------------------
/vendor/github.com/go-sql-driver/mysql/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | ### Issue description
2 | Tell us what should happen and what happens instead
3 |
4 | ### Example code
5 | ```go
6 | If possible, please enter some example code here to reproduce the issue.
7 | ```
8 |
9 | ### Error log
10 | ```
11 | If you have an error log, please paste it here.
12 | ```
13 |
14 | ### Configuration
15 | *Driver version (or git SHA):*
16 |
17 | *Go version:* run `go version` in your console
18 |
19 | *Server version:* E.g. MySQL 5.6, MariaDB 10.0.20
20 |
21 | *Server OS:* E.g. Debian 8.1 (Jessie), Windows 10
22 |
--------------------------------------------------------------------------------
/vendor/github.com/go-sql-driver/mysql/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | ### Description
2 | Please explain the changes you made here.
3 |
4 | ### Checklist
5 | - [ ] Code compiles correctly
6 | - [ ] Created tests which fail without the change (if possible)
7 | - [ ] All tests passing
8 | - [ ] Extended the README / documentation, if necessary
9 | - [ ] Added myself / the copyright holder to the AUTHORS file
10 |
--------------------------------------------------------------------------------
/vendor/github.com/go-sql-driver/mysql/appengine.go:
--------------------------------------------------------------------------------
1 | // Go MySQL Driver - A MySQL-Driver for Go's database/sql package
2 | //
3 | // Copyright 2013 The Go-MySQL-Driver Authors. All rights reserved.
4 | //
5 | // This Source Code Form is subject to the terms of the Mozilla Public
6 | // License, v. 2.0. If a copy of the MPL was not distributed with this file,
7 | // You can obtain one at http://mozilla.org/MPL/2.0/.
8 |
9 | // +build appengine
10 |
11 | package mysql
12 |
13 | import (
14 | "appengine/cloudsql"
15 | )
16 |
17 | func init() {
18 | RegisterDial("cloudsql", cloudsql.Dial)
19 | }
20 |
--------------------------------------------------------------------------------
/vendor/github.com/go-sql-driver/mysql/errors_test.go:
--------------------------------------------------------------------------------
1 | // Go MySQL Driver - A MySQL-Driver for Go's database/sql package
2 | //
3 | // Copyright 2013 The Go-MySQL-Driver Authors. All rights reserved.
4 | //
5 | // This Source Code Form is subject to the terms of the Mozilla Public
6 | // License, v. 2.0. If a copy of the MPL was not distributed with this file,
7 | // You can obtain one at http://mozilla.org/MPL/2.0/.
8 |
9 | package mysql
10 |
11 | import (
12 | "bytes"
13 | "log"
14 | "testing"
15 | )
16 |
17 | func TestErrorsSetLogger(t *testing.T) {
18 | previous := errLog
19 | defer func() {
20 | errLog = previous
21 | }()
22 |
23 | // set up logger
24 | const expected = "prefix: test\n"
25 | buffer := bytes.NewBuffer(make([]byte, 0, 64))
26 | logger := log.New(buffer, "prefix: ", 0)
27 |
28 | // print
29 | SetLogger(logger)
30 | errLog.Print("test")
31 |
32 | // check result
33 | if actual := buffer.String(); actual != expected {
34 | t.Errorf("expected %q, got %q", expected, actual)
35 | }
36 | }
37 |
38 | func TestErrorsStrictIgnoreNotes(t *testing.T) {
39 | runTests(t, dsn+"&sql_notes=false", func(dbt *DBTest) {
40 | dbt.mustExec("DROP TABLE IF EXISTS does_not_exist")
41 | })
42 | }
43 |
--------------------------------------------------------------------------------
/vendor/github.com/go-sql-driver/mysql/result.go:
--------------------------------------------------------------------------------
1 | // Go MySQL Driver - A MySQL-Driver for Go's database/sql package
2 | //
3 | // Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved.
4 | //
5 | // This Source Code Form is subject to the terms of the Mozilla Public
6 | // License, v. 2.0. If a copy of the MPL was not distributed with this file,
7 | // You can obtain one at http://mozilla.org/MPL/2.0/.
8 |
9 | package mysql
10 |
11 | type mysqlResult struct {
12 | affectedRows int64
13 | insertId int64
14 | }
15 |
16 | func (res *mysqlResult) LastInsertId() (int64, error) {
17 | return res.insertId, nil
18 | }
19 |
20 | func (res *mysqlResult) RowsAffected() (int64, error) {
21 | return res.affectedRows, nil
22 | }
23 |
--------------------------------------------------------------------------------
/vendor/github.com/go-sql-driver/mysql/rows.go:
--------------------------------------------------------------------------------
1 | // Go MySQL Driver - A MySQL-Driver for Go's database/sql package
2 | //
3 | // Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved.
4 | //
5 | // This Source Code Form is subject to the terms of the Mozilla Public
6 | // License, v. 2.0. If a copy of the MPL was not distributed with this file,
7 | // You can obtain one at http://mozilla.org/MPL/2.0/.
8 |
9 | package mysql
10 |
11 | import (
12 | "database/sql/driver"
13 | "io"
14 | )
15 |
16 | type mysqlField struct {
17 | tableName string
18 | name string
19 | flags fieldFlag
20 | fieldType byte
21 | decimals byte
22 | }
23 |
24 | type mysqlRows struct {
25 | mc *mysqlConn
26 | columns []mysqlField
27 | }
28 |
29 | type binaryRows struct {
30 | mysqlRows
31 | }
32 |
33 | type textRows struct {
34 | mysqlRows
35 | }
36 |
37 | type emptyRows struct{}
38 |
39 | func (rows *mysqlRows) Columns() []string {
40 | columns := make([]string, len(rows.columns))
41 | if rows.mc != nil && rows.mc.cfg.ColumnsWithAlias {
42 | for i := range columns {
43 | if tableName := rows.columns[i].tableName; len(tableName) > 0 {
44 | columns[i] = tableName + "." + rows.columns[i].name
45 | } else {
46 | columns[i] = rows.columns[i].name
47 | }
48 | }
49 | } else {
50 | for i := range columns {
51 | columns[i] = rows.columns[i].name
52 | }
53 | }
54 | return columns
55 | }
56 |
57 | func (rows *mysqlRows) Close() error {
58 | mc := rows.mc
59 | if mc == nil {
60 | return nil
61 | }
62 | if mc.netConn == nil {
63 | return ErrInvalidConn
64 | }
65 |
66 | // Remove unread packets from stream
67 | err := mc.readUntilEOF()
68 | if err == nil {
69 | if err = mc.discardResults(); err != nil {
70 | return err
71 | }
72 | }
73 |
74 | rows.mc = nil
75 | return err
76 | }
77 |
78 | func (rows *binaryRows) Next(dest []driver.Value) error {
79 | if mc := rows.mc; mc != nil {
80 | if mc.netConn == nil {
81 | return ErrInvalidConn
82 | }
83 |
84 | // Fetch next row from stream
85 | return rows.readRow(dest)
86 | }
87 | return io.EOF
88 | }
89 |
90 | func (rows *textRows) Next(dest []driver.Value) error {
91 | if mc := rows.mc; mc != nil {
92 | if mc.netConn == nil {
93 | return ErrInvalidConn
94 | }
95 |
96 | // Fetch next row from stream
97 | return rows.readRow(dest)
98 | }
99 | return io.EOF
100 | }
101 |
102 | func (rows emptyRows) Columns() []string {
103 | return nil
104 | }
105 |
106 | func (rows emptyRows) Close() error {
107 | return nil
108 | }
109 |
110 | func (rows emptyRows) Next(dest []driver.Value) error {
111 | return io.EOF
112 | }
113 |
--------------------------------------------------------------------------------
/vendor/github.com/go-sql-driver/mysql/transaction.go:
--------------------------------------------------------------------------------
1 | // Go MySQL Driver - A MySQL-Driver for Go's database/sql package
2 | //
3 | // Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved.
4 | //
5 | // This Source Code Form is subject to the terms of the Mozilla Public
6 | // License, v. 2.0. If a copy of the MPL was not distributed with this file,
7 | // You can obtain one at http://mozilla.org/MPL/2.0/.
8 |
9 | package mysql
10 |
11 | type mysqlTx struct {
12 | mc *mysqlConn
13 | }
14 |
15 | func (tx *mysqlTx) Commit() (err error) {
16 | if tx.mc == nil || tx.mc.netConn == nil {
17 | return ErrInvalidConn
18 | }
19 | err = tx.mc.exec("COMMIT")
20 | tx.mc = nil
21 | return
22 | }
23 |
24 | func (tx *mysqlTx) Rollback() (err error) {
25 | if tx.mc == nil || tx.mc.netConn == nil {
26 | return ErrInvalidConn
27 | }
28 | err = tx.mc.exec("ROLLBACK")
29 | tx.mc = nil
30 | return
31 | }
32 |
--------------------------------------------------------------------------------
/vendor/github.com/howeyc/gopass/.travis.yml:
--------------------------------------------------------------------------------
1 | language: go
2 |
3 | os:
4 | - linux
5 | - osx
6 |
7 | go:
8 | - 1.3
9 | - 1.4
10 | - 1.5
11 | - tip
12 |
--------------------------------------------------------------------------------
/vendor/github.com/howeyc/gopass/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright (c) 2012 Chris Howey
2 |
3 | Permission to use, copy, modify, and distribute this software for any
4 | purpose with or without fee is hereby granted, provided that the above
5 | copyright notice and this permission notice appear in all copies.
6 |
7 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
10 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
12 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
13 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14 |
--------------------------------------------------------------------------------
/vendor/github.com/howeyc/gopass/README.md:
--------------------------------------------------------------------------------
1 | # getpasswd in Go [](https://godoc.org/github.com/howeyc/gopass) [](http://travis-ci.org/howeyc/gopass)
2 |
3 | Retrieve password from user terminal or piped input without echo.
4 |
5 | Verified on BSD, Linux, and Windows.
6 |
7 | Example:
8 | ```go
9 | package main
10 |
11 | import "fmt"
12 | import "github.com/howeyc/gopass"
13 |
14 | func main() {
15 | fmt.Printf("Password: ")
16 |
17 | // Silent. For printing *'s use gopass.GetPasswdMasked()
18 | pass, err := gopass.GetPasswd()
19 | if err != nil {
20 | // Handle gopass.ErrInterrupted or getch() read error
21 | }
22 |
23 | // Do something with pass
24 | }
25 | ```
26 |
27 | Caution: Multi-byte characters not supported!
28 |
--------------------------------------------------------------------------------
/vendor/github.com/howeyc/gopass/pass.go:
--------------------------------------------------------------------------------
1 | package gopass
2 |
3 | import (
4 | "errors"
5 | "fmt"
6 | "io"
7 | "os"
8 |
9 | "golang.org/x/crypto/ssh/terminal"
10 | )
11 |
12 | var defaultGetCh = func() (byte, error) {
13 | buf := make([]byte, 1)
14 | if n, err := os.Stdin.Read(buf); n == 0 || err != nil {
15 | if err != nil {
16 | return 0, err
17 | }
18 | return 0, io.EOF
19 | }
20 | return buf[0], nil
21 | }
22 |
23 | var (
24 | ErrInterrupted = errors.New("Interrupted")
25 |
26 | // Provide variable so that tests can provide a mock implementation.
27 | getch = defaultGetCh
28 | )
29 |
30 | // getPasswd returns the input read from terminal.
31 | // If masked is true, typing will be matched by asterisks on the screen.
32 | // Otherwise, typing will echo nothing.
33 | func getPasswd(masked bool) ([]byte, error) {
34 | var err error
35 | var pass, bs, mask []byte
36 | if masked {
37 | bs = []byte("\b \b")
38 | mask = []byte("*")
39 | }
40 |
41 | if terminal.IsTerminal(int(os.Stdin.Fd())) {
42 | if oldState, err := terminal.MakeRaw(int(os.Stdin.Fd())); err != nil {
43 | return pass, err
44 | } else {
45 | defer terminal.Restore(int(os.Stdin.Fd()), oldState)
46 | }
47 | }
48 |
49 | for {
50 | if v, e := getch(); e != nil {
51 | err = e
52 | break
53 | } else if v == 127 || v == 8 {
54 | if l := len(pass); l > 0 {
55 | pass = pass[:l-1]
56 | fmt.Print(string(bs))
57 | }
58 | } else if v == 13 || v == 10 {
59 | break
60 | } else if v == 3 {
61 | err = ErrInterrupted
62 | break
63 | } else if v != 0 {
64 | pass = append(pass, v)
65 | fmt.Print(string(mask))
66 | }
67 | }
68 | fmt.Println()
69 | return pass, err
70 | }
71 |
72 | // GetPasswd returns the password read from the terminal without echoing input.
73 | // The returned byte array does not include end-of-line characters.
74 | func GetPasswd() ([]byte, error) {
75 | return getPasswd(false)
76 | }
77 |
78 | // GetPasswdMasked returns the password read from the terminal, echoing asterisks.
79 | // The returned byte array does not include end-of-line characters.
80 | func GetPasswdMasked() ([]byte, error) {
81 | return getPasswd(true)
82 | }
83 |
--------------------------------------------------------------------------------
/vendor/github.com/martini-contrib/auth/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2013 Jeremy Saenz
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of
6 | this software and associated documentation files (the "Software"), to deal in
7 | the Software without restriction, including without limitation the rights to
8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 | the Software, and to permit persons to whom the Software is furnished to do so,
10 | 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, FITNESS
17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/vendor/github.com/martini-contrib/auth/README.md:
--------------------------------------------------------------------------------
1 | # auth [](https://app.wercker.com/project/bykey/8e5237b01b52f169a1274fad9a89617b)
2 | Martini middleware/handler for http basic authentication.
3 |
4 | [API Reference](http://godoc.org/github.com/martini-contrib/auth)
5 |
6 | ## Simple Usage
7 |
8 | Use `auth.Basic` to authenticate against a pre-defined username and password:
9 |
10 | ~~~ go
11 | import (
12 | "github.com/go-martini/martini"
13 | "github.com/martini-contrib/auth"
14 | )
15 |
16 | func main() {
17 | m := martini.Classic()
18 | // authenticate every request
19 | m.Use(auth.Basic("username", "secretpassword"))
20 | m.Run()
21 | }
22 | ~~~
23 |
24 | ## Advanced Usage
25 |
26 | Using `auth.BasicFunc` lets you authenticate on a per-user level, by checking
27 | the username and password in the callback function:
28 |
29 | ~~~ go
30 | import (
31 | "github.com/go-martini/martini"
32 | "github.com/martini-contrib/auth"
33 | )
34 |
35 | func main() {
36 | m := martini.Classic()
37 | // authenticate every request
38 | m.Use(auth.BasicFunc(func(username, password string) bool {
39 | return username == "admin" && password == "guessme"
40 | }))
41 | m.Run()
42 | }
43 | ~~~
44 |
45 | Note that checking usernames and passwords with string comparison might be
46 | susceptible to timing attacks. To avoid that, use `auth.SecureCompare` instead:
47 |
48 | ~~~ go
49 | m.Use(auth.BasicFunc(func(username, password string) bool {
50 | return auth.SecureCompare(username, "admin") && auth.SecureCompare(password, "guessme")
51 | }))
52 | }
53 | ~~~
54 |
55 | Upon successful authentication, the username is available to all subsequent
56 | handlers via the `auth.User` type:
57 |
58 | ~~~ go
59 | m.Get("/", func(user auth.User) string {
60 | return "Welcome, " + string(user)
61 | })
62 | }
63 | ~~~
64 |
65 | ## Authors
66 | * [Jeremy Saenz](http://github.com/codegangsta)
67 | * [Brendon Murphy](http://github.com/bemurphy)
68 |
--------------------------------------------------------------------------------
/vendor/github.com/martini-contrib/auth/basic.go:
--------------------------------------------------------------------------------
1 | package auth
2 |
3 | import (
4 | "encoding/base64"
5 | "github.com/go-martini/martini"
6 | "net/http"
7 | "strings"
8 | )
9 |
10 | // User is the authenticated username that was extracted from the request.
11 | type User string
12 |
13 | // BasicRealm is used when setting the WWW-Authenticate response header.
14 | var BasicRealm = "Authorization Required"
15 |
16 | // Basic returns a Handler that authenticates via Basic Auth. Writes a http.StatusUnauthorized
17 | // if authentication fails.
18 | func Basic(username string, password string) martini.Handler {
19 | var siteAuth = base64.StdEncoding.EncodeToString([]byte(username + ":" + password))
20 | return func(res http.ResponseWriter, req *http.Request, c martini.Context) {
21 | auth := req.Header.Get("Authorization")
22 | if !SecureCompare(auth, "Basic "+siteAuth) {
23 | unauthorized(res)
24 | return
25 | }
26 | c.Map(User(username))
27 | }
28 | }
29 |
30 | // BasicFunc returns a Handler that authenticates via Basic Auth using the provided function.
31 | // The function should return true for a valid username/password combination.
32 | func BasicFunc(authfn func(string, string) bool) martini.Handler {
33 | return func(res http.ResponseWriter, req *http.Request, c martini.Context) {
34 | auth := req.Header.Get("Authorization")
35 | if len(auth) < 6 || auth[:6] != "Basic " {
36 | unauthorized(res)
37 | return
38 | }
39 | b, err := base64.StdEncoding.DecodeString(auth[6:])
40 | if err != nil {
41 | unauthorized(res)
42 | return
43 | }
44 | tokens := strings.SplitN(string(b), ":", 2)
45 | if len(tokens) != 2 || !authfn(tokens[0], tokens[1]) {
46 | unauthorized(res)
47 | return
48 | }
49 | c.Map(User(tokens[0]))
50 | }
51 | }
52 |
53 | func unauthorized(res http.ResponseWriter) {
54 | res.Header().Set("WWW-Authenticate", "Basic realm=\""+BasicRealm+"\"")
55 | http.Error(res, "Not Authorized", http.StatusUnauthorized)
56 | }
57 |
--------------------------------------------------------------------------------
/vendor/github.com/martini-contrib/auth/util.go:
--------------------------------------------------------------------------------
1 | package auth
2 |
3 | import (
4 | "crypto/sha256"
5 | "crypto/subtle"
6 | )
7 |
8 | // SecureCompare performs a constant time compare of two strings to limit timing attacks.
9 | func SecureCompare(given string, actual string) bool {
10 | givenSha := sha256.Sum256([]byte(given))
11 | actualSha := sha256.Sum256([]byte(actual))
12 |
13 | return subtle.ConstantTimeCompare(givenSha[:], actualSha[:]) == 1
14 | }
15 |
--------------------------------------------------------------------------------
/vendor/github.com/martini-contrib/auth/wercker.yml:
--------------------------------------------------------------------------------
1 | box: wercker/golang@1.1.1
--------------------------------------------------------------------------------
/vendor/github.com/martini-contrib/gzip/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2013 Jeremy Saenz
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of
6 | this software and associated documentation files (the "Software"), to deal in
7 | the Software without restriction, including without limitation the rights to
8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 | the Software, and to permit persons to whom the Software is furnished to do so,
10 | 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, FITNESS
17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/vendor/github.com/martini-contrib/gzip/README.md:
--------------------------------------------------------------------------------
1 | # gzip [](https://app.wercker.com/project/bykey/186d65e4d8160cf274ffc5835e6d9795)
2 | Gzip middleware for Martini.
3 |
4 | [API Reference](http://godoc.org/github.com/martini-contrib/gzip)
5 |
6 | ## Usage
7 |
8 | ~~~ go
9 | import (
10 | "github.com/go-martini/martini"
11 | "github.com/martini-contrib/gzip"
12 | )
13 |
14 | func main() {
15 | m := martini.Classic()
16 | // gzip every request
17 | m.Use(gzip.All())
18 | m.Run()
19 | }
20 |
21 | ~~~
22 |
23 | Make sure to include the Gzip middleware above other middleware that alter the response body (like the render middleware).
24 |
25 | ## Changing compression level
26 |
27 | You can set compression level using gzip.Options:
28 |
29 | ~~~ go
30 | import (
31 | "github.com/go-martini/martini"
32 | "github.com/martini-contrib/gzip"
33 | )
34 |
35 | func main() {
36 | m := martini.Classic()
37 | // gzip every request with maximum compression level
38 | m.Use(gzip.All(gzip.Options{
39 | CompressionLevel: gzip.BestCompression,
40 | }))
41 | m.Run()
42 | }
43 | ~~~
44 |
45 | The compression level can be DefaultCompression or any integer value between BestSpeed and BestCompression inclusive.
46 |
47 | ## Authors
48 | * [Jeremy Saenz](http://github.com/codegangsta)
49 | * [Shane Logsdon](http://github.com/slogsdon)
50 |
--------------------------------------------------------------------------------
/vendor/github.com/martini-contrib/gzip/wercker.yml:
--------------------------------------------------------------------------------
1 | box: wercker/golang@1.1.1
--------------------------------------------------------------------------------
/vendor/github.com/martini-contrib/render/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2013 Jeremy Saenz
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of
6 | this software and associated documentation files (the "Software"), to deal in
7 | the Software without restriction, including without limitation the rights to
8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 | the Software, and to permit persons to whom the Software is furnished to do so,
10 | 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, FITNESS
17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/vendor/github.com/martini-contrib/render/fixtures/basic/admin/index.tmpl:
--------------------------------------------------------------------------------
1 | Admin {{.}}
2 |
--------------------------------------------------------------------------------
/vendor/github.com/martini-contrib/render/fixtures/basic/another_layout.tmpl:
--------------------------------------------------------------------------------
1 | another head
2 | {{ yield }}
3 | another foot
4 |
--------------------------------------------------------------------------------
/vendor/github.com/martini-contrib/render/fixtures/basic/content.tmpl:
--------------------------------------------------------------------------------
1 | {{ . }}
2 |
--------------------------------------------------------------------------------
/vendor/github.com/martini-contrib/render/fixtures/basic/current_layout.tmpl:
--------------------------------------------------------------------------------
1 | {{ current }} head
2 | {{ yield }}
3 | {{ current }} foot
4 |
--------------------------------------------------------------------------------
/vendor/github.com/martini-contrib/render/fixtures/basic/delims.tmpl:
--------------------------------------------------------------------------------
1 | Hello {[{.}]}
--------------------------------------------------------------------------------
/vendor/github.com/martini-contrib/render/fixtures/basic/hello.tmpl:
--------------------------------------------------------------------------------
1 | Hello {{.}}
2 |
--------------------------------------------------------------------------------
/vendor/github.com/martini-contrib/render/fixtures/basic/hypertext.html:
--------------------------------------------------------------------------------
1 | Hypertext!
2 |
--------------------------------------------------------------------------------
/vendor/github.com/martini-contrib/render/fixtures/basic/layout.tmpl:
--------------------------------------------------------------------------------
1 | head
2 | {{ yield }}
3 | foot
4 |
--------------------------------------------------------------------------------
/vendor/github.com/martini-contrib/render/fixtures/custom_funcs/index.tmpl:
--------------------------------------------------------------------------------
1 | {{ myCustomFunc }}
2 |
--------------------------------------------------------------------------------
/vendor/github.com/martini-contrib/render/wercker.yml:
--------------------------------------------------------------------------------
1 | box: wercker/golang@1.1.1
--------------------------------------------------------------------------------
/vendor/github.com/outbrain/golib/math/math.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2014 Shlomi Noach.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | package math
18 |
19 | func MinInt(i1, i2 int) int {
20 | if i1 < i2 {
21 | return i1
22 | }
23 | return i2
24 | }
25 |
26 | func MaxInt(i1, i2 int) int {
27 | if i1 > i2 {
28 | return i1
29 | }
30 | return i2
31 | }
32 |
33 | func MinInt64(i1, i2 int64) int64 {
34 | if i1 < i2 {
35 | return i1
36 | }
37 | return i2
38 | }
39 |
40 | func MaxInt64(i1, i2 int64) int64 {
41 | if i1 > i2 {
42 | return i1
43 | }
44 | return i2
45 | }
46 |
47 | func MinUInt(i1, i2 uint) uint {
48 | if i1 < i2 {
49 | return i1
50 | }
51 | return i2
52 | }
53 |
54 | func MaxUInt(i1, i2 uint) uint {
55 | if i1 > i2 {
56 | return i1
57 | }
58 | return i2
59 | }
60 |
61 | func MinUInt64(i1, i2 uint64) uint64 {
62 | if i1 < i2 {
63 | return i1
64 | }
65 | return i2
66 | }
67 |
68 | func MaxUInt64(i1, i2 uint64) uint64 {
69 | if i1 > i2 {
70 | return i1
71 | }
72 | return i2
73 | }
74 |
75 | func MinString(i1, i2 string) string {
76 | if i1 < i2 {
77 | return i1
78 | }
79 | return i2
80 | }
81 |
82 | func MaxString(i1, i2 string) string {
83 | if i1 > i2 {
84 | return i1
85 | }
86 | return i2
87 | }
88 |
89 | // TernaryString acts like a "? :" C-style ternary operator for strings
90 | func TernaryString(condition bool, resTrue string, resFalse string) string {
91 | if condition {
92 | return resTrue
93 | }
94 | return resFalse
95 | }
96 |
97 | // TernaryString acts like a "? :" C-style ternary operator for ints
98 | func TernaryInt(condition bool, resTrue int, resFalse int) int {
99 | if condition {
100 | return resTrue
101 | }
102 | return resFalse
103 | }
104 |
105 | // AbsInt is an ABS function for int type
106 | func AbsInt(i int) int {
107 | if i >= 0 {
108 | return i
109 | }
110 | return -i
111 | }
112 |
113 | // AbsInt64 is an ABS function for int64 type
114 | func AbsInt64(i int64) int64 {
115 | if i >= 0 {
116 | return i
117 | }
118 | return -i
119 | }
120 |
--------------------------------------------------------------------------------
/vendor/github.com/outbrain/golib/tests/spec.go:
--------------------------------------------------------------------------------
1 | package tests
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | // Spec is an access point to test Expections
8 | type Spec struct {
9 | t *testing.T
10 | }
11 |
12 | // S generates a spec. You will want to use it once in a test file, once in a test or once per each check
13 | func S(t *testing.T) *Spec {
14 | return &Spec{t: t}
15 | }
16 |
17 | // ExpectNil expects given value to be nil, or errors
18 | func (spec *Spec) ExpectNil(actual interface{}) {
19 | if actual == nil {
20 | return
21 | }
22 | spec.t.Errorf("Expected %+v to be nil", actual)
23 | }
24 |
25 | // ExpectNotNil expects given value to be not nil, or errors
26 | func (spec *Spec) ExpectNotNil(actual interface{}) {
27 | if actual != nil {
28 | return
29 | }
30 | spec.t.Errorf("Expected %+v to be not nil", actual)
31 | }
32 |
33 | // ExpectEquals expects given values to be equal (comparison via `==`), or errors
34 | func (spec *Spec) ExpectEquals(actual, value interface{}) {
35 | if actual == value {
36 | return
37 | }
38 | spec.t.Errorf("Expected %+v, got %+v", value, actual)
39 | }
40 |
41 | // ExpectNotEquals expects given values to be nonequal (comparison via `==`), or errors
42 | func (spec *Spec) ExpectNotEquals(actual, value interface{}) {
43 | if !(actual == value) {
44 | return
45 | }
46 | spec.t.Errorf("Expected not %+v", value)
47 | }
48 |
49 | // ExpectEqualsAny expects given actual to equal (comparison via `==`) at least one of given values, or errors
50 | func (spec *Spec) ExpectEqualsAny(actual interface{}, values ...interface{}) {
51 | for _, value := range values {
52 | if actual == value {
53 | return
54 | }
55 | }
56 | spec.t.Errorf("Expected %+v to equal any of given values", actual)
57 | }
58 |
59 | // ExpectNotEqualsAny expects given actual to be nonequal (comparison via `==`)tp any of given values, or errors
60 | func (spec *Spec) ExpectNotEqualsAny(actual interface{}, values ...interface{}) {
61 | for _, value := range values {
62 | if actual == value {
63 | spec.t.Errorf("Expected not %+v", value)
64 | }
65 | }
66 | }
67 |
68 | // ExpectFalse expects given values to be false, or errors
69 | func (spec *Spec) ExpectFalse(actual interface{}) {
70 | spec.ExpectEquals(actual, false)
71 | }
72 |
73 | // ExpectTrue expects given values to be true, or errors
74 | func (spec *Spec) ExpectTrue(actual interface{}) {
75 | spec.ExpectEquals(actual, true)
76 | }
77 |
--------------------------------------------------------------------------------
/vendor/github.com/outbrain/golib/util/text.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2015 Shlomi Noach.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | package util
18 |
19 | import (
20 | "errors"
21 | "fmt"
22 | "regexp"
23 | "strconv"
24 | )
25 |
26 | // ParseSimpleTime parses input in the format 7s, 55m, 3h, 31d, 4w (second, minute, hour, day, week)
27 | // The time.ParseDuration() function should have done this, but it does not support "d" and "w" extensions.
28 | func SimpleTimeToSeconds(simpleTime string) (int, error) {
29 | if matched, _ := regexp.MatchString("^[0-9]+s$", simpleTime); matched {
30 | i, _ := strconv.Atoi(simpleTime[0 : len(simpleTime)-1])
31 | return i, nil
32 | }
33 | if matched, _ := regexp.MatchString("^[0-9]+m$", simpleTime); matched {
34 | i, _ := strconv.Atoi(simpleTime[0 : len(simpleTime)-1])
35 | return i * 60, nil
36 | }
37 | if matched, _ := regexp.MatchString("^[0-9]+h$", simpleTime); matched {
38 | i, _ := strconv.Atoi(simpleTime[0 : len(simpleTime)-1])
39 | return i * 60 * 60, nil
40 | }
41 | if matched, _ := regexp.MatchString("^[0-9]+d$", simpleTime); matched {
42 | i, _ := strconv.Atoi(simpleTime[0 : len(simpleTime)-1])
43 | return i * 60 * 60 * 24, nil
44 | }
45 | if matched, _ := regexp.MatchString("^[0-9]+w$", simpleTime); matched {
46 | i, _ := strconv.Atoi(simpleTime[0 : len(simpleTime)-1])
47 | return i * 60 * 60 * 24 * 7, nil
48 | }
49 | return 0, errors.New(fmt.Sprintf("Cannot parse simple time: %s", simpleTime))
50 | }
51 |
--------------------------------------------------------------------------------
/vendor/github.com/oxtoacart/bpool/README.md:
--------------------------------------------------------------------------------
1 | # bpool [](https://godoc.org/github.com/oxtoacart/bpool)
2 |
3 | Package bpool implements leaky pools of byte arrays and Buffers as bounded channels.
4 | It is based on the leaky buffer example from the Effective Go documentation: http://golang.org/doc/effective_go.html#leaky_buffer
5 |
6 | bpool provides the following pool types:
7 |
8 | * [bpool.BufferPool](https://godoc.org/github.com/oxtoacart/bpool#BufferPool)
9 | which provides a fixed-size pool of
10 | [bytes.Buffers](http://golang.org/pkg/bytes/#Buffer).
11 | * [bpool.BytePool](https://godoc.org/github.com/oxtoacart/bpool#BytePool) which
12 | provides a fixed-size pool of `[]byte` slices with a pre-set width (length).
13 | * [bpool.SizedBufferPool](https://godoc.org/github.com/oxtoacart/bpool#SizedBufferPool),
14 | which is an alternative to `bpool.BufferPool` that pre-sizes the capacity of
15 | buffers issued from the pool and discards buffers that have grown too large
16 | upon return.
17 |
18 | A common use case for this package is to use buffers to execute HTML templates
19 | against (via ExecuteTemplate) or encode JSON into (via json.NewEncoder). This
20 | allows you to catch any rendering or marshalling errors prior to writing to a
21 | `http.ResponseWriter`, which helps to avoid writing incomplete or malformed data
22 | to the response.
23 |
24 | ## Install
25 |
26 | `go get github.com/oxtoacart/bpool`
27 |
28 | ## Documentation
29 |
30 | See [godoc.org](http://godoc.org/github.com/oxtoacart/bpool) or use `godoc github.com/oxtoacart/bpool`
31 |
32 | ## Example
33 |
34 | Here's a quick example for using `bpool.BufferPool`. We create a pool of the
35 | desired size, call the `Get()` method to obtain a buffer for use, and call
36 | `Put(buf)` to return the buffer to the pool.
37 |
38 | ```go
39 |
40 | var bufpool *bpool.BufferPool
41 |
42 | func main() {
43 |
44 | bufpool = bpool.NewBufferPool(48)
45 |
46 | }
47 |
48 | func someFunction() error {
49 |
50 | // Get a buffer from the pool
51 | buf := bufpool.Get()
52 | ...
53 | ...
54 | ...
55 | // Return the buffer to the pool
56 | bufpool.Put(buf)
57 |
58 | return nil
59 | }
60 | ```
61 |
62 | ## License
63 |
64 | Apache 2.0 Licensed. See the LICENSE file for details.
65 |
66 |
--------------------------------------------------------------------------------
/vendor/github.com/oxtoacart/bpool/bpool.go:
--------------------------------------------------------------------------------
1 | /*
2 | Package bpool implements leaky pools of byte arrays and Buffers as bounded
3 | channels. It is based on the leaky buffer example from the Effective Go
4 | documentation: http://golang.org/doc/effective_go.html#leaky_buffer
5 | */
6 | package bpool
7 |
--------------------------------------------------------------------------------
/vendor/github.com/oxtoacart/bpool/bufferpool.go:
--------------------------------------------------------------------------------
1 | package bpool
2 |
3 | import (
4 | "bytes"
5 | )
6 |
7 | // BufferPool implements a pool of bytes.Buffers in the form of a bounded
8 | // channel.
9 | type BufferPool struct {
10 | c chan *bytes.Buffer
11 | }
12 |
13 | // NewBufferPool creates a new BufferPool bounded to the given size.
14 | func NewBufferPool(size int) (bp *BufferPool) {
15 | return &BufferPool{
16 | c: make(chan *bytes.Buffer, size),
17 | }
18 | }
19 |
20 | // Get gets a Buffer from the BufferPool, or creates a new one if none are
21 | // available in the pool.
22 | func (bp *BufferPool) Get() (b *bytes.Buffer) {
23 | select {
24 | case b = <-bp.c:
25 | // reuse existing buffer
26 | default:
27 | // create new buffer
28 | b = bytes.NewBuffer([]byte{})
29 | }
30 | return
31 | }
32 |
33 | // Put returns the given Buffer to the BufferPool.
34 | func (bp *BufferPool) Put(b *bytes.Buffer) {
35 | b.Reset()
36 | select {
37 | case bp.c <- b:
38 | default: // Discard the buffer if the pool is full.
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/vendor/github.com/oxtoacart/bpool/bytepool.go:
--------------------------------------------------------------------------------
1 | package bpool
2 |
3 | // BytePool implements a leaky pool of []byte in the form of a bounded
4 | // channel.
5 | type BytePool struct {
6 | c chan []byte
7 | w int
8 | }
9 |
10 | // NewBytePool creates a new BytePool bounded to the given maxSize, with new
11 | // byte arrays sized based on width.
12 | func NewBytePool(maxSize int, width int) (bp *BytePool) {
13 | return &BytePool{
14 | c: make(chan []byte, maxSize),
15 | w: width,
16 | }
17 | }
18 |
19 | // Get gets a []byte from the BytePool, or creates a new one if none are
20 | // available in the pool.
21 | func (bp *BytePool) Get() (b []byte) {
22 | select {
23 | case b = <-bp.c:
24 | // reuse existing buffer
25 | default:
26 | // create new buffer
27 | b = make([]byte, bp.w)
28 | }
29 | return
30 | }
31 |
32 | // Put returns the given Buffer to the BytePool.
33 | func (bp *BytePool) Put(b []byte) {
34 | select {
35 | case bp.c <- b:
36 | // buffer went back into pool
37 | default:
38 | // buffer didn't go back into pool, just discard
39 | }
40 | }
41 |
42 | // Width returns the width of the byte arrays in this pool.
43 | func (bp *BytePool) Width() (n int) {
44 | return bp.w
45 | }
46 |
--------------------------------------------------------------------------------
/vendor/github.com/oxtoacart/bpool/sizedbufferpool.go:
--------------------------------------------------------------------------------
1 | package bpool
2 |
3 | import (
4 | "bytes"
5 | )
6 |
7 | // SizedBufferPool implements a pool of bytes.Buffers in the form of a bounded
8 | // channel. Buffers are pre-allocated to the requested size.
9 | type SizedBufferPool struct {
10 | c chan *bytes.Buffer
11 | a int
12 | }
13 |
14 | // SizedBufferPool creates a new BufferPool bounded to the given size.
15 | // size defines the number of buffers to be retained in the pool and alloc sets
16 | // the initial capacity of new buffers to minimize calls to make().
17 | //
18 | // The value of alloc should seek to provide a buffer that is representative of
19 | // most data written to the the buffer (i.e. 95th percentile) without being
20 | // overly large (which will increase static memory consumption). You may wish to
21 | // track the capacity of your last N buffers (i.e. using an []int) prior to
22 | // returning them to the pool as input into calculating a suitable alloc value.
23 | func NewSizedBufferPool(size int, alloc int) (bp *SizedBufferPool) {
24 | return &SizedBufferPool{
25 | c: make(chan *bytes.Buffer, size),
26 | a: alloc,
27 | }
28 | }
29 |
30 | // Get gets a Buffer from the SizedBufferPool, or creates a new one if none are
31 | // available in the pool. Buffers have a pre-allocated capacity.
32 | func (bp *SizedBufferPool) Get() (b *bytes.Buffer) {
33 | select {
34 | case b = <-bp.c:
35 | // reuse existing buffer
36 | default:
37 | // create new buffer
38 | b = bytes.NewBuffer(make([]byte, 0, bp.a))
39 | }
40 | return
41 | }
42 |
43 | // Put returns the given Buffer to the SizedBufferPool.
44 | func (bp *SizedBufferPool) Put(b *bytes.Buffer) {
45 | b.Reset()
46 |
47 | // Release buffers over our maximum capacity and re-create a pre-sized
48 | // buffer to replace it.
49 | // Note that the cap(b.Bytes()) provides the capacity from the read off-set
50 | // only, but as we've called b.Reset() the full capacity of the underlying
51 | // byte slice is returned.
52 | if cap(b.Bytes()) > bp.a {
53 | b = bytes.NewBuffer(make([]byte, 0, bp.a))
54 | }
55 |
56 | select {
57 | case bp.c <- b:
58 | default: // Discard the buffer if the pool is full.
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/vendor/github.com/patrickmn/go-cache/CONTRIBUTORS:
--------------------------------------------------------------------------------
1 | This is a list of people who have contributed code to go-cache. They, or their
2 | employers, are the copyright holders of the contributed code. Contributed code
3 | is subject to the license restrictions listed in LICENSE (as they were when the
4 | code was contributed.)
5 |
6 | Dustin Sallings
7 | Jason Mooberry
8 | Sergey Shepelev
9 |
--------------------------------------------------------------------------------
/vendor/github.com/patrickmn/go-cache/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2012-2015 Patrick Mylund Nielsen and the go-cache contributors
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in
11 | all copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
20 |
--------------------------------------------------------------------------------
/vendor/github.com/patrickmn/go-cache/sharded_test.go:
--------------------------------------------------------------------------------
1 | package cache
2 |
3 | import (
4 | "strconv"
5 | "sync"
6 | "testing"
7 | "time"
8 | )
9 |
10 | // func TestDjb33(t *testing.T) {
11 | // }
12 |
13 | var shardedKeys = []string{
14 | "f",
15 | "fo",
16 | "foo",
17 | "barf",
18 | "barfo",
19 | "foobar",
20 | "bazbarf",
21 | "bazbarfo",
22 | "bazbarfoo",
23 | "foobarbazq",
24 | "foobarbazqu",
25 | "foobarbazquu",
26 | "foobarbazquux",
27 | }
28 |
29 | func TestShardedCache(t *testing.T) {
30 | tc := unexportedNewSharded(DefaultExpiration, 0, 13)
31 | for _, v := range shardedKeys {
32 | tc.Set(v, "value", DefaultExpiration)
33 | }
34 | }
35 |
36 | func BenchmarkShardedCacheGetExpiring(b *testing.B) {
37 | benchmarkShardedCacheGet(b, 5*time.Minute)
38 | }
39 |
40 | func BenchmarkShardedCacheGetNotExpiring(b *testing.B) {
41 | benchmarkShardedCacheGet(b, NoExpiration)
42 | }
43 |
44 | func benchmarkShardedCacheGet(b *testing.B, exp time.Duration) {
45 | b.StopTimer()
46 | tc := unexportedNewSharded(exp, 0, 10)
47 | tc.Set("foobarba", "zquux", DefaultExpiration)
48 | b.StartTimer()
49 | for i := 0; i < b.N; i++ {
50 | tc.Get("foobarba")
51 | }
52 | }
53 |
54 | func BenchmarkShardedCacheGetManyConcurrentExpiring(b *testing.B) {
55 | benchmarkShardedCacheGetManyConcurrent(b, 5*time.Minute)
56 | }
57 |
58 | func BenchmarkShardedCacheGetManyConcurrentNotExpiring(b *testing.B) {
59 | benchmarkShardedCacheGetManyConcurrent(b, NoExpiration)
60 | }
61 |
62 | func benchmarkShardedCacheGetManyConcurrent(b *testing.B, exp time.Duration) {
63 | b.StopTimer()
64 | n := 10000
65 | tsc := unexportedNewSharded(exp, 0, 20)
66 | keys := make([]string, n)
67 | for i := 0; i < n; i++ {
68 | k := "foo" + strconv.Itoa(n)
69 | keys[i] = k
70 | tsc.Set(k, "bar", DefaultExpiration)
71 | }
72 | each := b.N / n
73 | wg := new(sync.WaitGroup)
74 | wg.Add(n)
75 | for _, v := range keys {
76 | go func() {
77 | for j := 0; j < each; j++ {
78 | tsc.Get(v)
79 | }
80 | wg.Done()
81 | }()
82 | }
83 | b.StartTimer()
84 | wg.Wait()
85 | }
86 |
--------------------------------------------------------------------------------
/vendor/github.com/rcrowley/go-metrics/.gitignore:
--------------------------------------------------------------------------------
1 | *.[68]
2 | *.a
3 | *.out
4 | *.swp
5 | _obj
6 | _testmain.go
7 | cmd/metrics-bench/metrics-bench
8 | cmd/metrics-example/metrics-example
9 | cmd/never-read/never-read
10 |
--------------------------------------------------------------------------------
/vendor/github.com/rcrowley/go-metrics/.travis.yml:
--------------------------------------------------------------------------------
1 | language: go
2 |
3 | go:
4 | - 1.2
5 | - 1.3
6 | - 1.4
7 | - 1.5
8 |
9 | script:
10 | - ./validate.sh
11 |
12 | # this should give us faster builds according to
13 | # http://docs.travis-ci.com/user/migrating-from-legacy/
14 | sudo: false
15 |
--------------------------------------------------------------------------------
/vendor/github.com/rcrowley/go-metrics/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright 2012 Richard Crowley. All rights reserved.
2 |
3 | Redistribution and use in source and binary forms, with or without
4 | modification, are permitted provided that the following conditions are
5 | met:
6 |
7 | 1. Redistributions of source code must retain the above copyright
8 | notice, this list of conditions and the following disclaimer.
9 |
10 | 2. Redistributions in binary form must reproduce the above
11 | copyright notice, this list of conditions and the following
12 | disclaimer in the documentation and/or other materials provided
13 | with the distribution.
14 |
15 | THIS SOFTWARE IS PROVIDED BY RICHARD CROWLEY ``AS IS'' AND ANY EXPRESS
16 | OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 | DISCLAIMED. IN NO EVENT SHALL RICHARD CROWLEY OR CONTRIBUTORS BE LIABLE
19 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
25 | THE POSSIBILITY OF SUCH DAMAGE.
26 |
27 | The views and conclusions contained in the software and documentation
28 | are those of the authors and should not be interpreted as representing
29 | official policies, either expressed or implied, of Richard Crowley.
30 |
--------------------------------------------------------------------------------
/vendor/github.com/rcrowley/go-metrics/cmd/metrics-bench/metrics-bench.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "github.com/rcrowley/go-metrics"
6 | "time"
7 | )
8 |
9 | func main() {
10 | r := metrics.NewRegistry()
11 | for i := 0; i < 10000; i++ {
12 | r.Register(fmt.Sprintf("counter-%d", i), metrics.NewCounter())
13 | r.Register(fmt.Sprintf("gauge-%d", i), metrics.NewGauge())
14 | r.Register(fmt.Sprintf("gaugefloat64-%d", i), metrics.NewGaugeFloat64())
15 | r.Register(fmt.Sprintf("histogram-uniform-%d", i), metrics.NewHistogram(metrics.NewUniformSample(1028)))
16 | r.Register(fmt.Sprintf("histogram-exp-%d", i), metrics.NewHistogram(metrics.NewExpDecaySample(1028, 0.015)))
17 | r.Register(fmt.Sprintf("meter-%d", i), metrics.NewMeter())
18 | }
19 | time.Sleep(600e9)
20 | }
21 |
--------------------------------------------------------------------------------
/vendor/github.com/rcrowley/go-metrics/cmd/never-read/never-read.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "log"
5 | "net"
6 | )
7 |
8 | func main() {
9 | addr, _ := net.ResolveTCPAddr("tcp", "127.0.0.1:2003")
10 | l, err := net.ListenTCP("tcp", addr)
11 | if nil != err {
12 | log.Fatalln(err)
13 | }
14 | log.Println("listening", l.Addr())
15 | for {
16 | c, err := l.AcceptTCP()
17 | if nil != err {
18 | log.Fatalln(err)
19 | }
20 | log.Println("accepted", c.RemoteAddr())
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/vendor/github.com/rcrowley/go-metrics/counter_test.go:
--------------------------------------------------------------------------------
1 | package metrics
2 |
3 | import "testing"
4 |
5 | func BenchmarkCounter(b *testing.B) {
6 | c := NewCounter()
7 | b.ResetTimer()
8 | for i := 0; i < b.N; i++ {
9 | c.Inc(1)
10 | }
11 | }
12 |
13 | func TestCounterClear(t *testing.T) {
14 | c := NewCounter()
15 | c.Inc(1)
16 | c.Clear()
17 | if count := c.Count(); 0 != count {
18 | t.Errorf("c.Count(): 0 != %v\n", count)
19 | }
20 | }
21 |
22 | func TestCounterDec1(t *testing.T) {
23 | c := NewCounter()
24 | c.Dec(1)
25 | if count := c.Count(); -1 != count {
26 | t.Errorf("c.Count(): -1 != %v\n", count)
27 | }
28 | }
29 |
30 | func TestCounterDec2(t *testing.T) {
31 | c := NewCounter()
32 | c.Dec(2)
33 | if count := c.Count(); -2 != count {
34 | t.Errorf("c.Count(): -2 != %v\n", count)
35 | }
36 | }
37 |
38 | func TestCounterInc1(t *testing.T) {
39 | c := NewCounter()
40 | c.Inc(1)
41 | if count := c.Count(); 1 != count {
42 | t.Errorf("c.Count(): 1 != %v\n", count)
43 | }
44 | }
45 |
46 | func TestCounterInc2(t *testing.T) {
47 | c := NewCounter()
48 | c.Inc(2)
49 | if count := c.Count(); 2 != count {
50 | t.Errorf("c.Count(): 2 != %v\n", count)
51 | }
52 | }
53 |
54 | func TestCounterSnapshot(t *testing.T) {
55 | c := NewCounter()
56 | c.Inc(1)
57 | snapshot := c.Snapshot()
58 | c.Inc(1)
59 | if count := snapshot.Count(); 1 != count {
60 | t.Errorf("c.Count(): 1 != %v\n", count)
61 | }
62 | }
63 |
64 | func TestCounterZero(t *testing.T) {
65 | c := NewCounter()
66 | if count := c.Count(); 0 != count {
67 | t.Errorf("c.Count(): 0 != %v\n", count)
68 | }
69 | }
70 |
71 | func TestGetOrRegisterCounter(t *testing.T) {
72 | r := NewRegistry()
73 | NewRegisteredCounter("foo", r).Inc(47)
74 | if c := GetOrRegisterCounter("foo", r); 47 != c.Count() {
75 | t.Fatal(c)
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/vendor/github.com/rcrowley/go-metrics/debug_test.go:
--------------------------------------------------------------------------------
1 | package metrics
2 |
3 | import (
4 | "runtime"
5 | "runtime/debug"
6 | "testing"
7 | "time"
8 | )
9 |
10 | func BenchmarkDebugGCStats(b *testing.B) {
11 | r := NewRegistry()
12 | RegisterDebugGCStats(r)
13 | b.ResetTimer()
14 | for i := 0; i < b.N; i++ {
15 | CaptureDebugGCStatsOnce(r)
16 | }
17 | }
18 |
19 | func TestDebugGCStatsBlocking(t *testing.T) {
20 | if g := runtime.GOMAXPROCS(0); g < 2 {
21 | t.Skipf("skipping TestDebugGCMemStatsBlocking with GOMAXPROCS=%d\n", g)
22 | return
23 | }
24 | ch := make(chan int)
25 | go testDebugGCStatsBlocking(ch)
26 | var gcStats debug.GCStats
27 | t0 := time.Now()
28 | debug.ReadGCStats(&gcStats)
29 | t1 := time.Now()
30 | t.Log("i++ during debug.ReadGCStats:", <-ch)
31 | go testDebugGCStatsBlocking(ch)
32 | d := t1.Sub(t0)
33 | t.Log(d)
34 | time.Sleep(d)
35 | t.Log("i++ during time.Sleep:", <-ch)
36 | }
37 |
38 | func testDebugGCStatsBlocking(ch chan int) {
39 | i := 0
40 | for {
41 | select {
42 | case ch <- i:
43 | return
44 | default:
45 | i++
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/vendor/github.com/rcrowley/go-metrics/gauge.go:
--------------------------------------------------------------------------------
1 | package metrics
2 |
3 | import "sync/atomic"
4 |
5 | // Gauges hold an int64 value that can be set arbitrarily.
6 | type Gauge interface {
7 | Snapshot() Gauge
8 | Update(int64)
9 | Value() int64
10 | }
11 |
12 | // GetOrRegisterGauge returns an existing Gauge or constructs and registers a
13 | // new StandardGauge.
14 | func GetOrRegisterGauge(name string, r Registry) Gauge {
15 | if nil == r {
16 | r = DefaultRegistry
17 | }
18 | return r.GetOrRegister(name, NewGauge).(Gauge)
19 | }
20 |
21 | // NewGauge constructs a new StandardGauge.
22 | func NewGauge() Gauge {
23 | if UseNilMetrics {
24 | return NilGauge{}
25 | }
26 | return &StandardGauge{0}
27 | }
28 |
29 | // NewRegisteredGauge constructs and registers a new StandardGauge.
30 | func NewRegisteredGauge(name string, r Registry) Gauge {
31 | c := NewGauge()
32 | if nil == r {
33 | r = DefaultRegistry
34 | }
35 | r.Register(name, c)
36 | return c
37 | }
38 |
39 | // GaugeSnapshot is a read-only copy of another Gauge.
40 | type GaugeSnapshot int64
41 |
42 | // Snapshot returns the snapshot.
43 | func (g GaugeSnapshot) Snapshot() Gauge { return g }
44 |
45 | // Update panics.
46 | func (GaugeSnapshot) Update(int64) {
47 | panic("Update called on a GaugeSnapshot")
48 | }
49 |
50 | // Value returns the value at the time the snapshot was taken.
51 | func (g GaugeSnapshot) Value() int64 { return int64(g) }
52 |
53 | // NilGauge is a no-op Gauge.
54 | type NilGauge struct{}
55 |
56 | // Snapshot is a no-op.
57 | func (NilGauge) Snapshot() Gauge { return NilGauge{} }
58 |
59 | // Update is a no-op.
60 | func (NilGauge) Update(v int64) {}
61 |
62 | // Value is a no-op.
63 | func (NilGauge) Value() int64 { return 0 }
64 |
65 | // StandardGauge is the standard implementation of a Gauge and uses the
66 | // sync/atomic package to manage a single int64 value.
67 | type StandardGauge struct {
68 | value int64
69 | }
70 |
71 | // Snapshot returns a read-only copy of the gauge.
72 | func (g *StandardGauge) Snapshot() Gauge {
73 | return GaugeSnapshot(g.Value())
74 | }
75 |
76 | // Update updates the gauge's value.
77 | func (g *StandardGauge) Update(v int64) {
78 | atomic.StoreInt64(&g.value, v)
79 | }
80 |
81 | // Value returns the gauge's current value.
82 | func (g *StandardGauge) Value() int64 {
83 | return atomic.LoadInt64(&g.value)
84 | }
85 |
--------------------------------------------------------------------------------
/vendor/github.com/rcrowley/go-metrics/gauge_float64.go:
--------------------------------------------------------------------------------
1 | package metrics
2 |
3 | import "sync"
4 |
5 | // GaugeFloat64s hold a float64 value that can be set arbitrarily.
6 | type GaugeFloat64 interface {
7 | Snapshot() GaugeFloat64
8 | Update(float64)
9 | Value() float64
10 | }
11 |
12 | // GetOrRegisterGaugeFloat64 returns an existing GaugeFloat64 or constructs and registers a
13 | // new StandardGaugeFloat64.
14 | func GetOrRegisterGaugeFloat64(name string, r Registry) GaugeFloat64 {
15 | if nil == r {
16 | r = DefaultRegistry
17 | }
18 | return r.GetOrRegister(name, NewGaugeFloat64()).(GaugeFloat64)
19 | }
20 |
21 | // NewGaugeFloat64 constructs a new StandardGaugeFloat64.
22 | func NewGaugeFloat64() GaugeFloat64 {
23 | if UseNilMetrics {
24 | return NilGaugeFloat64{}
25 | }
26 | return &StandardGaugeFloat64{
27 | value: 0.0,
28 | }
29 | }
30 |
31 | // NewRegisteredGaugeFloat64 constructs and registers a new StandardGaugeFloat64.
32 | func NewRegisteredGaugeFloat64(name string, r Registry) GaugeFloat64 {
33 | c := NewGaugeFloat64()
34 | if nil == r {
35 | r = DefaultRegistry
36 | }
37 | r.Register(name, c)
38 | return c
39 | }
40 |
41 | // GaugeFloat64Snapshot is a read-only copy of another GaugeFloat64.
42 | type GaugeFloat64Snapshot float64
43 |
44 | // Snapshot returns the snapshot.
45 | func (g GaugeFloat64Snapshot) Snapshot() GaugeFloat64 { return g }
46 |
47 | // Update panics.
48 | func (GaugeFloat64Snapshot) Update(float64) {
49 | panic("Update called on a GaugeFloat64Snapshot")
50 | }
51 |
52 | // Value returns the value at the time the snapshot was taken.
53 | func (g GaugeFloat64Snapshot) Value() float64 { return float64(g) }
54 |
55 | // NilGauge is a no-op Gauge.
56 | type NilGaugeFloat64 struct{}
57 |
58 | // Snapshot is a no-op.
59 | func (NilGaugeFloat64) Snapshot() GaugeFloat64 { return NilGaugeFloat64{} }
60 |
61 | // Update is a no-op.
62 | func (NilGaugeFloat64) Update(v float64) {}
63 |
64 | // Value is a no-op.
65 | func (NilGaugeFloat64) Value() float64 { return 0.0 }
66 |
67 | // StandardGaugeFloat64 is the standard implementation of a GaugeFloat64 and uses
68 | // sync.Mutex to manage a single float64 value.
69 | type StandardGaugeFloat64 struct {
70 | mutex sync.Mutex
71 | value float64
72 | }
73 |
74 | // Snapshot returns a read-only copy of the gauge.
75 | func (g *StandardGaugeFloat64) Snapshot() GaugeFloat64 {
76 | return GaugeFloat64Snapshot(g.Value())
77 | }
78 |
79 | // Update updates the gauge's value.
80 | func (g *StandardGaugeFloat64) Update(v float64) {
81 | g.mutex.Lock()
82 | defer g.mutex.Unlock()
83 | g.value = v
84 | }
85 |
86 | // Value returns the gauge's current value.
87 | func (g *StandardGaugeFloat64) Value() float64 {
88 | g.mutex.Lock()
89 | defer g.mutex.Unlock()
90 | return g.value
91 | }
92 |
--------------------------------------------------------------------------------
/vendor/github.com/rcrowley/go-metrics/gauge_float64_test.go:
--------------------------------------------------------------------------------
1 | package metrics
2 |
3 | import "testing"
4 |
5 | func BenchmarkGuageFloat64(b *testing.B) {
6 | g := NewGaugeFloat64()
7 | b.ResetTimer()
8 | for i := 0; i < b.N; i++ {
9 | g.Update(float64(i))
10 | }
11 | }
12 |
13 | func TestGaugeFloat64(t *testing.T) {
14 | g := NewGaugeFloat64()
15 | g.Update(float64(47.0))
16 | if v := g.Value(); float64(47.0) != v {
17 | t.Errorf("g.Value(): 47.0 != %v\n", v)
18 | }
19 | }
20 |
21 | func TestGaugeFloat64Snapshot(t *testing.T) {
22 | g := NewGaugeFloat64()
23 | g.Update(float64(47.0))
24 | snapshot := g.Snapshot()
25 | g.Update(float64(0))
26 | if v := snapshot.Value(); float64(47.0) != v {
27 | t.Errorf("g.Value(): 47.0 != %v\n", v)
28 | }
29 | }
30 |
31 | func TestGetOrRegisterGaugeFloat64(t *testing.T) {
32 | r := NewRegistry()
33 | NewRegisteredGaugeFloat64("foo", r).Update(float64(47.0))
34 | t.Logf("registry: %v", r)
35 | if g := GetOrRegisterGaugeFloat64("foo", r); float64(47.0) != g.Value() {
36 | t.Fatal(g)
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/vendor/github.com/rcrowley/go-metrics/gauge_test.go:
--------------------------------------------------------------------------------
1 | package metrics
2 |
3 | import "testing"
4 |
5 | func BenchmarkGuage(b *testing.B) {
6 | g := NewGauge()
7 | b.ResetTimer()
8 | for i := 0; i < b.N; i++ {
9 | g.Update(int64(i))
10 | }
11 | }
12 |
13 | func TestGauge(t *testing.T) {
14 | g := NewGauge()
15 | g.Update(int64(47))
16 | if v := g.Value(); 47 != v {
17 | t.Errorf("g.Value(): 47 != %v\n", v)
18 | }
19 | }
20 |
21 | func TestGaugeSnapshot(t *testing.T) {
22 | g := NewGauge()
23 | g.Update(int64(47))
24 | snapshot := g.Snapshot()
25 | g.Update(int64(0))
26 | if v := snapshot.Value(); 47 != v {
27 | t.Errorf("g.Value(): 47 != %v\n", v)
28 | }
29 | }
30 |
31 | func TestGetOrRegisterGauge(t *testing.T) {
32 | r := NewRegistry()
33 | NewRegisteredGauge("foo", r).Update(47)
34 | if g := GetOrRegisterGauge("foo", r); 47 != g.Value() {
35 | t.Fatal(g)
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/vendor/github.com/rcrowley/go-metrics/graphite_test.go:
--------------------------------------------------------------------------------
1 | package metrics
2 |
3 | import (
4 | "net"
5 | "time"
6 | )
7 |
8 | func ExampleGraphite() {
9 | addr, _ := net.ResolveTCPAddr("net", ":2003")
10 | go Graphite(DefaultRegistry, 1*time.Second, "some.prefix", addr)
11 | }
12 |
13 | func ExampleGraphiteWithConfig() {
14 | addr, _ := net.ResolveTCPAddr("net", ":2003")
15 | go GraphiteWithConfig(GraphiteConfig{
16 | Addr: addr,
17 | Registry: DefaultRegistry,
18 | FlushInterval: 1 * time.Second,
19 | DurationUnit: time.Millisecond,
20 | Percentiles: []float64{0.5, 0.75, 0.99, 0.999},
21 | })
22 | }
23 |
--------------------------------------------------------------------------------
/vendor/github.com/rcrowley/go-metrics/healthcheck.go:
--------------------------------------------------------------------------------
1 | package metrics
2 |
3 | // Healthchecks hold an error value describing an arbitrary up/down status.
4 | type Healthcheck interface {
5 | Check()
6 | Error() error
7 | Healthy()
8 | Unhealthy(error)
9 | }
10 |
11 | // NewHealthcheck constructs a new Healthcheck which will use the given
12 | // function to update its status.
13 | func NewHealthcheck(f func(Healthcheck)) Healthcheck {
14 | if UseNilMetrics {
15 | return NilHealthcheck{}
16 | }
17 | return &StandardHealthcheck{nil, f}
18 | }
19 |
20 | // NilHealthcheck is a no-op.
21 | type NilHealthcheck struct{}
22 |
23 | // Check is a no-op.
24 | func (NilHealthcheck) Check() {}
25 |
26 | // Error is a no-op.
27 | func (NilHealthcheck) Error() error { return nil }
28 |
29 | // Healthy is a no-op.
30 | func (NilHealthcheck) Healthy() {}
31 |
32 | // Unhealthy is a no-op.
33 | func (NilHealthcheck) Unhealthy(error) {}
34 |
35 | // StandardHealthcheck is the standard implementation of a Healthcheck and
36 | // stores the status and a function to call to update the status.
37 | type StandardHealthcheck struct {
38 | err error
39 | f func(Healthcheck)
40 | }
41 |
42 | // Check runs the healthcheck function to update the healthcheck's status.
43 | func (h *StandardHealthcheck) Check() {
44 | h.f(h)
45 | }
46 |
47 | // Error returns the healthcheck's status, which will be nil if it is healthy.
48 | func (h *StandardHealthcheck) Error() error {
49 | return h.err
50 | }
51 |
52 | // Healthy marks the healthcheck as healthy.
53 | func (h *StandardHealthcheck) Healthy() {
54 | h.err = nil
55 | }
56 |
57 | // Unhealthy marks the healthcheck as unhealthy. The error is stored and
58 | // may be retrieved by the Error method.
59 | func (h *StandardHealthcheck) Unhealthy(err error) {
60 | h.err = err
61 | }
62 |
--------------------------------------------------------------------------------
/vendor/github.com/rcrowley/go-metrics/histogram_test.go:
--------------------------------------------------------------------------------
1 | package metrics
2 |
3 | import "testing"
4 |
5 | func BenchmarkHistogram(b *testing.B) {
6 | h := NewHistogram(NewUniformSample(100))
7 | b.ResetTimer()
8 | for i := 0; i < b.N; i++ {
9 | h.Update(int64(i))
10 | }
11 | }
12 |
13 | func TestGetOrRegisterHistogram(t *testing.T) {
14 | r := NewRegistry()
15 | s := NewUniformSample(100)
16 | NewRegisteredHistogram("foo", r, s).Update(47)
17 | if h := GetOrRegisterHistogram("foo", r, s); 1 != h.Count() {
18 | t.Fatal(h)
19 | }
20 | }
21 |
22 | func TestHistogram10000(t *testing.T) {
23 | h := NewHistogram(NewUniformSample(100000))
24 | for i := 1; i <= 10000; i++ {
25 | h.Update(int64(i))
26 | }
27 | testHistogram10000(t, h)
28 | }
29 |
30 | func TestHistogramEmpty(t *testing.T) {
31 | h := NewHistogram(NewUniformSample(100))
32 | if count := h.Count(); 0 != count {
33 | t.Errorf("h.Count(): 0 != %v\n", count)
34 | }
35 | if min := h.Min(); 0 != min {
36 | t.Errorf("h.Min(): 0 != %v\n", min)
37 | }
38 | if max := h.Max(); 0 != max {
39 | t.Errorf("h.Max(): 0 != %v\n", max)
40 | }
41 | if mean := h.Mean(); 0.0 != mean {
42 | t.Errorf("h.Mean(): 0.0 != %v\n", mean)
43 | }
44 | if stdDev := h.StdDev(); 0.0 != stdDev {
45 | t.Errorf("h.StdDev(): 0.0 != %v\n", stdDev)
46 | }
47 | ps := h.Percentiles([]float64{0.5, 0.75, 0.99})
48 | if 0.0 != ps[0] {
49 | t.Errorf("median: 0.0 != %v\n", ps[0])
50 | }
51 | if 0.0 != ps[1] {
52 | t.Errorf("75th percentile: 0.0 != %v\n", ps[1])
53 | }
54 | if 0.0 != ps[2] {
55 | t.Errorf("99th percentile: 0.0 != %v\n", ps[2])
56 | }
57 | }
58 |
59 | func TestHistogramSnapshot(t *testing.T) {
60 | h := NewHistogram(NewUniformSample(100000))
61 | for i := 1; i <= 10000; i++ {
62 | h.Update(int64(i))
63 | }
64 | snapshot := h.Snapshot()
65 | h.Update(0)
66 | testHistogram10000(t, snapshot)
67 | }
68 |
69 | func testHistogram10000(t *testing.T, h Histogram) {
70 | if count := h.Count(); 10000 != count {
71 | t.Errorf("h.Count(): 10000 != %v\n", count)
72 | }
73 | if min := h.Min(); 1 != min {
74 | t.Errorf("h.Min(): 1 != %v\n", min)
75 | }
76 | if max := h.Max(); 10000 != max {
77 | t.Errorf("h.Max(): 10000 != %v\n", max)
78 | }
79 | if mean := h.Mean(); 5000.5 != mean {
80 | t.Errorf("h.Mean(): 5000.5 != %v\n", mean)
81 | }
82 | if stdDev := h.StdDev(); 2886.751331514372 != stdDev {
83 | t.Errorf("h.StdDev(): 2886.751331514372 != %v\n", stdDev)
84 | }
85 | ps := h.Percentiles([]float64{0.5, 0.75, 0.99})
86 | if 5000.5 != ps[0] {
87 | t.Errorf("median: 5000.5 != %v\n", ps[0])
88 | }
89 | if 7500.75 != ps[1] {
90 | t.Errorf("75th percentile: 7500.75 != %v\n", ps[1])
91 | }
92 | if 9900.99 != ps[2] {
93 | t.Errorf("99th percentile: 9900.99 != %v\n", ps[2])
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/vendor/github.com/rcrowley/go-metrics/json.go:
--------------------------------------------------------------------------------
1 | package metrics
2 |
3 | import (
4 | "encoding/json"
5 | "io"
6 | "time"
7 | )
8 |
9 | // MarshalJSON returns a byte slice containing a JSON representation of all
10 | // the metrics in the Registry.
11 | func (r *StandardRegistry) MarshalJSON() ([]byte, error) {
12 | data := make(map[string]map[string]interface{})
13 | r.Each(func(name string, i interface{}) {
14 | values := make(map[string]interface{})
15 | switch metric := i.(type) {
16 | case Counter:
17 | values["count"] = metric.Count()
18 | case Gauge:
19 | values["value"] = metric.Value()
20 | case GaugeFloat64:
21 | values["value"] = metric.Value()
22 | case Healthcheck:
23 | values["error"] = nil
24 | metric.Check()
25 | if err := metric.Error(); nil != err {
26 | values["error"] = metric.Error().Error()
27 | }
28 | case Histogram:
29 | h := metric.Snapshot()
30 | ps := h.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999})
31 | values["count"] = h.Count()
32 | values["min"] = h.Min()
33 | values["max"] = h.Max()
34 | values["mean"] = h.Mean()
35 | values["stddev"] = h.StdDev()
36 | values["median"] = ps[0]
37 | values["75%"] = ps[1]
38 | values["95%"] = ps[2]
39 | values["99%"] = ps[3]
40 | values["99.9%"] = ps[4]
41 | case Meter:
42 | m := metric.Snapshot()
43 | values["count"] = m.Count()
44 | values["1m.rate"] = m.Rate1()
45 | values["5m.rate"] = m.Rate5()
46 | values["15m.rate"] = m.Rate15()
47 | values["mean.rate"] = m.RateMean()
48 | case Timer:
49 | t := metric.Snapshot()
50 | ps := t.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999})
51 | values["count"] = t.Count()
52 | values["min"] = t.Min()
53 | values["max"] = t.Max()
54 | values["mean"] = t.Mean()
55 | values["stddev"] = t.StdDev()
56 | values["median"] = ps[0]
57 | values["75%"] = ps[1]
58 | values["95%"] = ps[2]
59 | values["99%"] = ps[3]
60 | values["99.9%"] = ps[4]
61 | values["1m.rate"] = t.Rate1()
62 | values["5m.rate"] = t.Rate5()
63 | values["15m.rate"] = t.Rate15()
64 | values["mean.rate"] = t.RateMean()
65 | }
66 | data[name] = values
67 | })
68 | return json.Marshal(data)
69 | }
70 |
71 | // WriteJSON writes metrics from the given registry periodically to the
72 | // specified io.Writer as JSON.
73 | func WriteJSON(r Registry, d time.Duration, w io.Writer) {
74 | for _ = range time.Tick(d) {
75 | WriteJSONOnce(r, w)
76 | }
77 | }
78 |
79 | // WriteJSONOnce writes metrics from the given registry to the specified
80 | // io.Writer as JSON.
81 | func WriteJSONOnce(r Registry, w io.Writer) {
82 | json.NewEncoder(w).Encode(r)
83 | }
84 |
--------------------------------------------------------------------------------
/vendor/github.com/rcrowley/go-metrics/json_test.go:
--------------------------------------------------------------------------------
1 | package metrics
2 |
3 | import (
4 | "bytes"
5 | "encoding/json"
6 | "testing"
7 | )
8 |
9 | func TestRegistryMarshallJSON(t *testing.T) {
10 | b := &bytes.Buffer{}
11 | enc := json.NewEncoder(b)
12 | r := NewRegistry()
13 | r.Register("counter", NewCounter())
14 | enc.Encode(r)
15 | if s := b.String(); "{\"counter\":{\"count\":0}}\n" != s {
16 | t.Fatalf(s)
17 | }
18 | }
19 |
20 | func TestRegistryWriteJSONOnce(t *testing.T) {
21 | r := NewRegistry()
22 | r.Register("counter", NewCounter())
23 | b := &bytes.Buffer{}
24 | WriteJSONOnce(r, b)
25 | if s := b.String(); s != "{\"counter\":{\"count\":0}}\n" {
26 | t.Fail()
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/vendor/github.com/rcrowley/go-metrics/librato/client.go:
--------------------------------------------------------------------------------
1 | package librato
2 |
3 | import (
4 | "bytes"
5 | "encoding/json"
6 | "fmt"
7 | "io/ioutil"
8 | "net/http"
9 | )
10 |
11 | const Operations = "operations"
12 | const OperationsShort = "ops"
13 |
14 | type LibratoClient struct {
15 | Email, Token string
16 | }
17 |
18 | // property strings
19 | const (
20 | // display attributes
21 | Color = "color"
22 | DisplayMax = "display_max"
23 | DisplayMin = "display_min"
24 | DisplayUnitsLong = "display_units_long"
25 | DisplayUnitsShort = "display_units_short"
26 | DisplayStacked = "display_stacked"
27 | DisplayTransform = "display_transform"
28 | // special gauge display attributes
29 | SummarizeFunction = "summarize_function"
30 | Aggregate = "aggregate"
31 |
32 | // metric keys
33 | Name = "name"
34 | Period = "period"
35 | Description = "description"
36 | DisplayName = "display_name"
37 | Attributes = "attributes"
38 |
39 | // measurement keys
40 | MeasureTime = "measure_time"
41 | Source = "source"
42 | Value = "value"
43 |
44 | // special gauge keys
45 | Count = "count"
46 | Sum = "sum"
47 | Max = "max"
48 | Min = "min"
49 | SumSquares = "sum_squares"
50 |
51 | // batch keys
52 | Counters = "counters"
53 | Gauges = "gauges"
54 |
55 | MetricsPostUrl = "https://metrics-api.librato.com/v1/metrics"
56 | )
57 |
58 | type Measurement map[string]interface{}
59 | type Metric map[string]interface{}
60 |
61 | type Batch struct {
62 | Gauges []Measurement `json:"gauges,omitempty"`
63 | Counters []Measurement `json:"counters,omitempty"`
64 | MeasureTime int64 `json:"measure_time"`
65 | Source string `json:"source"`
66 | }
67 |
68 | func (self *LibratoClient) PostMetrics(batch Batch) (err error) {
69 | var (
70 | js []byte
71 | req *http.Request
72 | resp *http.Response
73 | )
74 |
75 | if len(batch.Counters) == 0 && len(batch.Gauges) == 0 {
76 | return nil
77 | }
78 |
79 | if js, err = json.Marshal(batch); err != nil {
80 | return
81 | }
82 |
83 | if req, err = http.NewRequest("POST", MetricsPostUrl, bytes.NewBuffer(js)); err != nil {
84 | return
85 | }
86 |
87 | req.Header.Set("Content-Type", "application/json")
88 | req.SetBasicAuth(self.Email, self.Token)
89 |
90 | if resp, err = http.DefaultClient.Do(req); err != nil {
91 | return
92 | }
93 |
94 | if resp.StatusCode != http.StatusOK {
95 | var body []byte
96 | if body, err = ioutil.ReadAll(resp.Body); err != nil {
97 | body = []byte(fmt.Sprintf("(could not fetch response body for error: %s)", err))
98 | }
99 | err = fmt.Errorf("Unable to post to Librato: %d %s %s", resp.StatusCode, resp.Status, string(body))
100 | }
101 | return
102 | }
103 |
--------------------------------------------------------------------------------
/vendor/github.com/rcrowley/go-metrics/meter_test.go:
--------------------------------------------------------------------------------
1 | package metrics
2 |
3 | import (
4 | "testing"
5 | "time"
6 | )
7 |
8 | func BenchmarkMeter(b *testing.B) {
9 | m := NewMeter()
10 | b.ResetTimer()
11 | for i := 0; i < b.N; i++ {
12 | m.Mark(1)
13 | }
14 | }
15 |
16 | func TestGetOrRegisterMeter(t *testing.T) {
17 | r := NewRegistry()
18 | NewRegisteredMeter("foo", r).Mark(47)
19 | if m := GetOrRegisterMeter("foo", r); 47 != m.Count() {
20 | t.Fatal(m)
21 | }
22 | }
23 |
24 | func TestMeterDecay(t *testing.T) {
25 | ma := meterArbiter{
26 | ticker: time.NewTicker(time.Millisecond),
27 | }
28 | m := newStandardMeter()
29 | ma.meters = append(ma.meters, m)
30 | go ma.tick()
31 | m.Mark(1)
32 | rateMean := m.RateMean()
33 | time.Sleep(100 * time.Millisecond)
34 | if m.RateMean() >= rateMean {
35 | t.Error("m.RateMean() didn't decrease")
36 | }
37 | }
38 |
39 | func TestMeterNonzero(t *testing.T) {
40 | m := NewMeter()
41 | m.Mark(3)
42 | if count := m.Count(); 3 != count {
43 | t.Errorf("m.Count(): 3 != %v\n", count)
44 | }
45 | }
46 |
47 | func TestMeterSnapshot(t *testing.T) {
48 | m := NewMeter()
49 | m.Mark(1)
50 | if snapshot := m.Snapshot(); m.RateMean() != snapshot.RateMean() {
51 | t.Fatal(snapshot)
52 | }
53 | }
54 |
55 | func TestMeterZero(t *testing.T) {
56 | m := NewMeter()
57 | if count := m.Count(); 0 != count {
58 | t.Errorf("m.Count(): 0 != %v\n", count)
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/vendor/github.com/rcrowley/go-metrics/metrics.go:
--------------------------------------------------------------------------------
1 | // Go port of Coda Hale's Metrics library
2 | //
3 | //
4 | //
5 | // Coda Hale's original work:
6 | package metrics
7 |
8 | // UseNilMetrics is checked by the constructor functions for all of the
9 | // standard metrics. If it is true, the metric returned is a stub.
10 | //
11 | // This global kill-switch helps quantify the observer effect and makes
12 | // for less cluttered pprof profiles.
13 | var UseNilMetrics bool = false
14 |
--------------------------------------------------------------------------------
/vendor/github.com/rcrowley/go-metrics/metrics_test.go:
--------------------------------------------------------------------------------
1 | package metrics
2 |
3 | import (
4 | "io/ioutil"
5 | "log"
6 | "sync"
7 | "testing"
8 | )
9 |
10 | const FANOUT = 128
11 |
12 | // Stop the compiler from complaining during debugging.
13 | var (
14 | _ = ioutil.Discard
15 | _ = log.LstdFlags
16 | )
17 |
18 | func BenchmarkMetrics(b *testing.B) {
19 | r := NewRegistry()
20 | c := NewRegisteredCounter("counter", r)
21 | g := NewRegisteredGauge("gauge", r)
22 | gf := NewRegisteredGaugeFloat64("gaugefloat64", r)
23 | h := NewRegisteredHistogram("histogram", r, NewUniformSample(100))
24 | m := NewRegisteredMeter("meter", r)
25 | t := NewRegisteredTimer("timer", r)
26 | RegisterDebugGCStats(r)
27 | RegisterRuntimeMemStats(r)
28 | b.ResetTimer()
29 | ch := make(chan bool)
30 |
31 | wgD := &sync.WaitGroup{}
32 | /*
33 | wgD.Add(1)
34 | go func() {
35 | defer wgD.Done()
36 | //log.Println("go CaptureDebugGCStats")
37 | for {
38 | select {
39 | case <-ch:
40 | //log.Println("done CaptureDebugGCStats")
41 | return
42 | default:
43 | CaptureDebugGCStatsOnce(r)
44 | }
45 | }
46 | }()
47 | //*/
48 |
49 | wgR := &sync.WaitGroup{}
50 | //*
51 | wgR.Add(1)
52 | go func() {
53 | defer wgR.Done()
54 | //log.Println("go CaptureRuntimeMemStats")
55 | for {
56 | select {
57 | case <-ch:
58 | //log.Println("done CaptureRuntimeMemStats")
59 | return
60 | default:
61 | CaptureRuntimeMemStatsOnce(r)
62 | }
63 | }
64 | }()
65 | //*/
66 |
67 | wgW := &sync.WaitGroup{}
68 | /*
69 | wgW.Add(1)
70 | go func() {
71 | defer wgW.Done()
72 | //log.Println("go Write")
73 | for {
74 | select {
75 | case <-ch:
76 | //log.Println("done Write")
77 | return
78 | default:
79 | WriteOnce(r, ioutil.Discard)
80 | }
81 | }
82 | }()
83 | //*/
84 |
85 | wg := &sync.WaitGroup{}
86 | wg.Add(FANOUT)
87 | for i := 0; i < FANOUT; i++ {
88 | go func(i int) {
89 | defer wg.Done()
90 | //log.Println("go", i)
91 | for i := 0; i < b.N; i++ {
92 | c.Inc(1)
93 | g.Update(int64(i))
94 | gf.Update(float64(i))
95 | h.Update(int64(i))
96 | m.Mark(1)
97 | t.Update(1)
98 | }
99 | //log.Println("done", i)
100 | }(i)
101 | }
102 | wg.Wait()
103 | close(ch)
104 | wgD.Wait()
105 | wgR.Wait()
106 | wgW.Wait()
107 | }
108 |
--------------------------------------------------------------------------------
/vendor/github.com/rcrowley/go-metrics/opentsdb_test.go:
--------------------------------------------------------------------------------
1 | package metrics
2 |
3 | import (
4 | "net"
5 | "time"
6 | )
7 |
8 | func ExampleOpenTSDB() {
9 | addr, _ := net.ResolveTCPAddr("net", ":2003")
10 | go OpenTSDB(DefaultRegistry, 1*time.Second, "some.prefix", addr)
11 | }
12 |
13 | func ExampleOpenTSDBWithConfig() {
14 | addr, _ := net.ResolveTCPAddr("net", ":2003")
15 | go OpenTSDBWithConfig(OpenTSDBConfig{
16 | Addr: addr,
17 | Registry: DefaultRegistry,
18 | FlushInterval: 1 * time.Second,
19 | DurationUnit: time.Millisecond,
20 | })
21 | }
22 |
--------------------------------------------------------------------------------
/vendor/github.com/rcrowley/go-metrics/runtime_cgo.go:
--------------------------------------------------------------------------------
1 | // +build cgo
2 | // +build !appengine
3 |
4 | package metrics
5 |
6 | import "runtime"
7 |
8 | func numCgoCall() int64 {
9 | return runtime.NumCgoCall()
10 | }
11 |
--------------------------------------------------------------------------------
/vendor/github.com/rcrowley/go-metrics/runtime_gccpufraction.go:
--------------------------------------------------------------------------------
1 | // +build go1.5
2 |
3 | package metrics
4 |
5 | import "runtime"
6 |
7 | func gcCPUFraction(memStats *runtime.MemStats) float64 {
8 | return memStats.GCCPUFraction
9 | }
10 |
--------------------------------------------------------------------------------
/vendor/github.com/rcrowley/go-metrics/runtime_no_cgo.go:
--------------------------------------------------------------------------------
1 | // +build !cgo appengine
2 |
3 | package metrics
4 |
5 | func numCgoCall() int64 {
6 | return 0
7 | }
8 |
--------------------------------------------------------------------------------
/vendor/github.com/rcrowley/go-metrics/runtime_no_gccpufraction.go:
--------------------------------------------------------------------------------
1 | // +build !go1.5
2 |
3 | package metrics
4 |
5 | import "runtime"
6 |
7 | func gcCPUFraction(memStats *runtime.MemStats) float64 {
8 | return 0
9 | }
10 |
--------------------------------------------------------------------------------
/vendor/github.com/rcrowley/go-metrics/runtime_test.go:
--------------------------------------------------------------------------------
1 | package metrics
2 |
3 | import (
4 | "runtime"
5 | "testing"
6 | "time"
7 | )
8 |
9 | func BenchmarkRuntimeMemStats(b *testing.B) {
10 | r := NewRegistry()
11 | RegisterRuntimeMemStats(r)
12 | b.ResetTimer()
13 | for i := 0; i < b.N; i++ {
14 | CaptureRuntimeMemStatsOnce(r)
15 | }
16 | }
17 |
18 | func TestRuntimeMemStats(t *testing.T) {
19 | r := NewRegistry()
20 | RegisterRuntimeMemStats(r)
21 | CaptureRuntimeMemStatsOnce(r)
22 | zero := runtimeMetrics.MemStats.PauseNs.Count() // Get a "zero" since GC may have run before these tests.
23 | runtime.GC()
24 | CaptureRuntimeMemStatsOnce(r)
25 | if count := runtimeMetrics.MemStats.PauseNs.Count(); 1 != count-zero {
26 | t.Fatal(count - zero)
27 | }
28 | runtime.GC()
29 | runtime.GC()
30 | CaptureRuntimeMemStatsOnce(r)
31 | if count := runtimeMetrics.MemStats.PauseNs.Count(); 3 != count-zero {
32 | t.Fatal(count - zero)
33 | }
34 | for i := 0; i < 256; i++ {
35 | runtime.GC()
36 | }
37 | CaptureRuntimeMemStatsOnce(r)
38 | if count := runtimeMetrics.MemStats.PauseNs.Count(); 259 != count-zero {
39 | t.Fatal(count - zero)
40 | }
41 | for i := 0; i < 257; i++ {
42 | runtime.GC()
43 | }
44 | CaptureRuntimeMemStatsOnce(r)
45 | if count := runtimeMetrics.MemStats.PauseNs.Count(); 515 != count-zero { // We lost one because there were too many GCs between captures.
46 | t.Fatal(count - zero)
47 | }
48 | }
49 |
50 | func TestRuntimeMemStatsNumThread(t *testing.T) {
51 | r := NewRegistry()
52 | RegisterRuntimeMemStats(r)
53 | CaptureRuntimeMemStatsOnce(r)
54 |
55 | if value := runtimeMetrics.NumThread.Value(); value < 1 {
56 | t.Fatalf("got NumThread: %d, wanted at least 1", value)
57 | }
58 | }
59 |
60 | func TestRuntimeMemStatsBlocking(t *testing.T) {
61 | if g := runtime.GOMAXPROCS(0); g < 2 {
62 | t.Skipf("skipping TestRuntimeMemStatsBlocking with GOMAXPROCS=%d\n", g)
63 | }
64 | ch := make(chan int)
65 | go testRuntimeMemStatsBlocking(ch)
66 | var memStats runtime.MemStats
67 | t0 := time.Now()
68 | runtime.ReadMemStats(&memStats)
69 | t1 := time.Now()
70 | t.Log("i++ during runtime.ReadMemStats:", <-ch)
71 | go testRuntimeMemStatsBlocking(ch)
72 | d := t1.Sub(t0)
73 | t.Log(d)
74 | time.Sleep(d)
75 | t.Log("i++ during time.Sleep:", <-ch)
76 | }
77 |
78 | func testRuntimeMemStatsBlocking(ch chan int) {
79 | i := 0
80 | for {
81 | select {
82 | case ch <- i:
83 | return
84 | default:
85 | i++
86 | }
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/vendor/github.com/rcrowley/go-metrics/syslog.go:
--------------------------------------------------------------------------------
1 | // +build !windows
2 |
3 | package metrics
4 |
5 | import (
6 | "fmt"
7 | "log/syslog"
8 | "time"
9 | )
10 |
11 | // Output each metric in the given registry to syslog periodically using
12 | // the given syslogger.
13 | func Syslog(r Registry, d time.Duration, w *syslog.Writer) {
14 | for _ = range time.Tick(d) {
15 | r.Each(func(name string, i interface{}) {
16 | switch metric := i.(type) {
17 | case Counter:
18 | w.Info(fmt.Sprintf("counter %s: count: %d", name, metric.Count()))
19 | case Gauge:
20 | w.Info(fmt.Sprintf("gauge %s: value: %d", name, metric.Value()))
21 | case GaugeFloat64:
22 | w.Info(fmt.Sprintf("gauge %s: value: %f", name, metric.Value()))
23 | case Healthcheck:
24 | metric.Check()
25 | w.Info(fmt.Sprintf("healthcheck %s: error: %v", name, metric.Error()))
26 | case Histogram:
27 | h := metric.Snapshot()
28 | ps := h.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999})
29 | w.Info(fmt.Sprintf(
30 | "histogram %s: count: %d min: %d max: %d mean: %.2f stddev: %.2f median: %.2f 75%%: %.2f 95%%: %.2f 99%%: %.2f 99.9%%: %.2f",
31 | name,
32 | h.Count(),
33 | h.Min(),
34 | h.Max(),
35 | h.Mean(),
36 | h.StdDev(),
37 | ps[0],
38 | ps[1],
39 | ps[2],
40 | ps[3],
41 | ps[4],
42 | ))
43 | case Meter:
44 | m := metric.Snapshot()
45 | w.Info(fmt.Sprintf(
46 | "meter %s: count: %d 1-min: %.2f 5-min: %.2f 15-min: %.2f mean: %.2f",
47 | name,
48 | m.Count(),
49 | m.Rate1(),
50 | m.Rate5(),
51 | m.Rate15(),
52 | m.RateMean(),
53 | ))
54 | case Timer:
55 | t := metric.Snapshot()
56 | ps := t.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999})
57 | w.Info(fmt.Sprintf(
58 | "timer %s: count: %d min: %d max: %d mean: %.2f stddev: %.2f median: %.2f 75%%: %.2f 95%%: %.2f 99%%: %.2f 99.9%%: %.2f 1-min: %.2f 5-min: %.2f 15-min: %.2f mean-rate: %.2f",
59 | name,
60 | t.Count(),
61 | t.Min(),
62 | t.Max(),
63 | t.Mean(),
64 | t.StdDev(),
65 | ps[0],
66 | ps[1],
67 | ps[2],
68 | ps[3],
69 | ps[4],
70 | t.Rate1(),
71 | t.Rate5(),
72 | t.Rate15(),
73 | t.RateMean(),
74 | ))
75 | }
76 | })
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/vendor/github.com/rcrowley/go-metrics/timer_test.go:
--------------------------------------------------------------------------------
1 | package metrics
2 |
3 | import (
4 | "math"
5 | "testing"
6 | "time"
7 | )
8 |
9 | func BenchmarkTimer(b *testing.B) {
10 | tm := NewTimer()
11 | b.ResetTimer()
12 | for i := 0; i < b.N; i++ {
13 | tm.Update(1)
14 | }
15 | }
16 |
17 | func TestGetOrRegisterTimer(t *testing.T) {
18 | r := NewRegistry()
19 | NewRegisteredTimer("foo", r).Update(47)
20 | if tm := GetOrRegisterTimer("foo", r); 1 != tm.Count() {
21 | t.Fatal(tm)
22 | }
23 | }
24 |
25 | func TestTimerExtremes(t *testing.T) {
26 | tm := NewTimer()
27 | tm.Update(math.MaxInt64)
28 | tm.Update(0)
29 | if stdDev := tm.StdDev(); 4.611686018427388e+18 != stdDev {
30 | t.Errorf("tm.StdDev(): 4.611686018427388e+18 != %v\n", stdDev)
31 | }
32 | }
33 |
34 | func TestTimerFunc(t *testing.T) {
35 | tm := NewTimer()
36 | tm.Time(func() { time.Sleep(50e6) })
37 | if max := tm.Max(); 45e6 > max || max > 55e6 {
38 | t.Errorf("tm.Max(): 45e6 > %v || %v > 55e6\n", max, max)
39 | }
40 | }
41 |
42 | func TestTimerZero(t *testing.T) {
43 | tm := NewTimer()
44 | if count := tm.Count(); 0 != count {
45 | t.Errorf("tm.Count(): 0 != %v\n", count)
46 | }
47 | if min := tm.Min(); 0 != min {
48 | t.Errorf("tm.Min(): 0 != %v\n", min)
49 | }
50 | if max := tm.Max(); 0 != max {
51 | t.Errorf("tm.Max(): 0 != %v\n", max)
52 | }
53 | if mean := tm.Mean(); 0.0 != mean {
54 | t.Errorf("tm.Mean(): 0.0 != %v\n", mean)
55 | }
56 | if stdDev := tm.StdDev(); 0.0 != stdDev {
57 | t.Errorf("tm.StdDev(): 0.0 != %v\n", stdDev)
58 | }
59 | ps := tm.Percentiles([]float64{0.5, 0.75, 0.99})
60 | if 0.0 != ps[0] {
61 | t.Errorf("median: 0.0 != %v\n", ps[0])
62 | }
63 | if 0.0 != ps[1] {
64 | t.Errorf("75th percentile: 0.0 != %v\n", ps[1])
65 | }
66 | if 0.0 != ps[2] {
67 | t.Errorf("99th percentile: 0.0 != %v\n", ps[2])
68 | }
69 | if rate1 := tm.Rate1(); 0.0 != rate1 {
70 | t.Errorf("tm.Rate1(): 0.0 != %v\n", rate1)
71 | }
72 | if rate5 := tm.Rate5(); 0.0 != rate5 {
73 | t.Errorf("tm.Rate5(): 0.0 != %v\n", rate5)
74 | }
75 | if rate15 := tm.Rate15(); 0.0 != rate15 {
76 | t.Errorf("tm.Rate15(): 0.0 != %v\n", rate15)
77 | }
78 | if rateMean := tm.RateMean(); 0.0 != rateMean {
79 | t.Errorf("tm.RateMean(): 0.0 != %v\n", rateMean)
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/vendor/github.com/rcrowley/go-metrics/validate.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -e
4 |
5 | # check there are no formatting issues
6 | GOFMT_LINES=`gofmt -l . | wc -l | xargs`
7 | test $GOFMT_LINES -eq 0 || echo "gofmt needs to be run, ${GOFMT_LINES} files have issues"
8 |
9 | # run the tests for the root package
10 | go test .
11 |
--------------------------------------------------------------------------------
/vendor/github.com/rcrowley/go-metrics/writer_test.go:
--------------------------------------------------------------------------------
1 | package metrics
2 |
3 | import (
4 | "sort"
5 | "testing"
6 | )
7 |
8 | func TestMetricsSorting(t *testing.T) {
9 | var namedMetrics = namedMetricSlice{
10 | {name: "zzz"},
11 | {name: "bbb"},
12 | {name: "fff"},
13 | {name: "ggg"},
14 | }
15 |
16 | sort.Sort(namedMetrics)
17 | for i, name := range []string{"bbb", "fff", "ggg", "zzz"} {
18 | if namedMetrics[i].name != name {
19 | t.Fail()
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/vendor/golang.org/x/crypto/ssh/terminal/util_bsd.go:
--------------------------------------------------------------------------------
1 | // Copyright 2013 The Go Authors. All rights reserved.
2 | // Use of this source code is governed by a BSD-style
3 | // license that can be found in the LICENSE file.
4 |
5 | // +build darwin dragonfly freebsd netbsd openbsd
6 |
7 | package terminal
8 |
9 | import "syscall"
10 |
11 | const ioctlReadTermios = syscall.TIOCGETA
12 | const ioctlWriteTermios = syscall.TIOCSETA
13 |
--------------------------------------------------------------------------------
/vendor/golang.org/x/crypto/ssh/terminal/util_linux.go:
--------------------------------------------------------------------------------
1 | // Copyright 2013 The Go Authors. All rights reserved.
2 | // Use of this source code is governed by a BSD-style
3 | // license that can be found in the LICENSE file.
4 |
5 | package terminal
6 |
7 | // These constants are declared here, rather than importing
8 | // them from the syscall package as some syscall packages, even
9 | // on linux, for example gccgo, do not declare them.
10 | const ioctlReadTermios = 0x5401 // syscall.TCGETS
11 | const ioctlWriteTermios = 0x5402 // syscall.TCSETS
12 |
--------------------------------------------------------------------------------
/vendor/golang.org/x/crypto/ssh/terminal/util_plan9.go:
--------------------------------------------------------------------------------
1 | // Copyright 2016 The Go Authors. All rights reserved.
2 | // Use of this source code is governed by a BSD-style
3 | // license that can be found in the LICENSE file.
4 |
5 | // Package terminal provides support functions for dealing with terminals, as
6 | // commonly found on UNIX systems.
7 | //
8 | // Putting a terminal into raw mode is the most common requirement:
9 | //
10 | // oldState, err := terminal.MakeRaw(0)
11 | // if err != nil {
12 | // panic(err)
13 | // }
14 | // defer terminal.Restore(0, oldState)
15 | package terminal
16 |
17 | import (
18 | "fmt"
19 | "runtime"
20 | )
21 |
22 | type State struct{}
23 |
24 | // IsTerminal returns true if the given file descriptor is a terminal.
25 | func IsTerminal(fd int) bool {
26 | return false
27 | }
28 |
29 | // MakeRaw put the terminal connected to the given file descriptor into raw
30 | // mode and returns the previous state of the terminal so that it can be
31 | // restored.
32 | func MakeRaw(fd int) (*State, error) {
33 | return nil, fmt.Errorf("terminal: MakeRaw not implemented on %s/%s", runtime.GOOS, runtime.GOARCH)
34 | }
35 |
36 | // GetState returns the current state of a terminal which may be useful to
37 | // restore the terminal after a signal.
38 | func GetState(fd int) (*State, error) {
39 | return nil, fmt.Errorf("terminal: GetState not implemented on %s/%s", runtime.GOOS, runtime.GOARCH)
40 | }
41 |
42 | // Restore restores the terminal connected to the given file descriptor to a
43 | // previous state.
44 | func Restore(fd int, state *State) error {
45 | return fmt.Errorf("terminal: Restore not implemented on %s/%s", runtime.GOOS, runtime.GOARCH)
46 | }
47 |
48 | // GetSize returns the dimensions of the given terminal.
49 | func GetSize(fd int) (width, height int, err error) {
50 | return 0, 0, fmt.Errorf("terminal: GetSize not implemented on %s/%s", runtime.GOOS, runtime.GOARCH)
51 | }
52 |
53 | // ReadPassword reads a line of input from a terminal without local echo. This
54 | // is commonly used for inputting passwords and other sensitive data. The slice
55 | // returned does not include the \n.
56 | func ReadPassword(fd int) ([]byte, error) {
57 | return nil, fmt.Errorf("terminal: ReadPassword not implemented on %s/%s", runtime.GOOS, runtime.GOARCH)
58 | }
59 |
--------------------------------------------------------------------------------
/vendor/gopkg.in/gcfg.v1/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2012 Péter Surányi. Portions Copyright (c) 2009 The Go
2 | Authors. All rights reserved.
3 |
4 | Redistribution and use in source and binary forms, with or without
5 | modification, are permitted provided that the following conditions are
6 | met:
7 |
8 | * Redistributions of source code must retain the above copyright
9 | notice, this list of conditions and the following disclaimer.
10 | * Redistributions in binary form must reproduce the above
11 | copyright notice, this list of conditions and the following disclaimer
12 | in the documentation and/or other materials provided with the
13 | distribution.
14 | * Neither the name of Google Inc. nor the names of its
15 | contributors may be used to endorse or promote products derived from
16 | this software without specific prior written permission.
17 |
18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 |
--------------------------------------------------------------------------------
/vendor/gopkg.in/gcfg.v1/README:
--------------------------------------------------------------------------------
1 | Gcfg reads INI-style configuration files into Go structs;
2 | supports user-defined types and subsections.
3 |
4 | Package docs: https://godoc.org/gopkg.in/gcfg.v1
5 |
--------------------------------------------------------------------------------
/vendor/gopkg.in/gcfg.v1/go1_0.go:
--------------------------------------------------------------------------------
1 | // +build !go1.2
2 |
3 | package gcfg
4 |
5 | type textUnmarshaler interface {
6 | UnmarshalText(text []byte) error
7 | }
8 |
--------------------------------------------------------------------------------
/vendor/gopkg.in/gcfg.v1/go1_2.go:
--------------------------------------------------------------------------------
1 | // +build go1.2
2 |
3 | package gcfg
4 |
5 | import (
6 | "encoding"
7 | )
8 |
9 | type textUnmarshaler encoding.TextUnmarshaler
10 |
--------------------------------------------------------------------------------
/vendor/gopkg.in/gcfg.v1/issues_test.go:
--------------------------------------------------------------------------------
1 | package gcfg
2 |
3 | import (
4 | "fmt"
5 | "math/big"
6 | "strings"
7 | "testing"
8 | )
9 |
10 | type Config1 struct {
11 | Section struct {
12 | Int int
13 | BigInt big.Int
14 | }
15 | }
16 |
17 | var testsIssue1 = []struct {
18 | cfg string
19 | typename string
20 | }{
21 | {"[section]\nint=X", "int"},
22 | {"[section]\nint=", "int"},
23 | {"[section]\nint=1A", "int"},
24 | {"[section]\nbigint=X", "big.Int"},
25 | {"[section]\nbigint=", "big.Int"},
26 | {"[section]\nbigint=1A", "big.Int"},
27 | }
28 |
29 | // Value parse error should:
30 | // - include plain type name
31 | // - not include reflect internals
32 | func TestIssue1(t *testing.T) {
33 | for i, tt := range testsIssue1 {
34 | var c Config1
35 | err := ReadStringInto(&c, tt.cfg)
36 | switch {
37 | case err == nil:
38 | t.Errorf("%d fail: got ok; wanted error", i)
39 | case !strings.Contains(err.Error(), tt.typename):
40 | t.Errorf("%d fail: error message doesn't contain type name %q: %v",
41 | i, tt.typename, err)
42 | case strings.Contains(err.Error(), "reflect"):
43 | t.Errorf("%d fail: error message includes reflect internals: %v",
44 | i, err)
45 | default:
46 | t.Logf("%d pass: %v", i, err)
47 | }
48 | }
49 | }
50 |
51 | type confIssue2 struct{ Main struct{ Foo string } }
52 |
53 | var testsIssue2 = []readtest{
54 | {"[main]\n;\nfoo = bar\n", &confIssue2{struct{ Foo string }{"bar"}}, true},
55 | {"[main]\r\n;\r\nfoo = bar\r\n", &confIssue2{struct{ Foo string }{"bar"}}, true},
56 | }
57 |
58 | func TestIssue2(t *testing.T) {
59 | for i, tt := range testsIssue2 {
60 | id := fmt.Sprintf("issue2:%d", i)
61 | testRead(t, id, tt)
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/vendor/gopkg.in/gcfg.v1/scanner/example_test.go:
--------------------------------------------------------------------------------
1 | // Copyright 2012 The Go Authors. All rights reserved.
2 | // Use of this source code is governed by a BSD-style
3 | // license that can be found in the LICENSE file.
4 |
5 | package scanner_test
6 |
7 | import (
8 | "fmt"
9 | )
10 |
11 | import (
12 | "gopkg.in/gcfg.v1/scanner"
13 | "gopkg.in/gcfg.v1/token"
14 | )
15 |
16 | func ExampleScanner_Scan() {
17 | // src is the input that we want to tokenize.
18 | src := []byte(`[profile "A"]
19 | color = blue ; Comment`)
20 |
21 | // Initialize the scanner.
22 | var s scanner.Scanner
23 | fset := token.NewFileSet() // positions are relative to fset
24 | file := fset.AddFile("", fset.Base(), len(src)) // register input "file"
25 | s.Init(file, src, nil /* no error handler */, scanner.ScanComments)
26 |
27 | // Repeated calls to Scan yield the token sequence found in the input.
28 | for {
29 | pos, tok, lit := s.Scan()
30 | if tok == token.EOF {
31 | break
32 | }
33 | fmt.Printf("%s\t%q\t%q\n", fset.Position(pos), tok, lit)
34 | }
35 |
36 | // output:
37 | // 1:1 "[" ""
38 | // 1:2 "IDENT" "profile"
39 | // 1:10 "STRING" "\"A\""
40 | // 1:13 "]" ""
41 | // 1:14 "\n" ""
42 | // 2:1 "IDENT" "color"
43 | // 2:7 "=" ""
44 | // 2:9 "STRING" "blue"
45 | // 2:14 "COMMENT" "; Comment"
46 | }
47 |
--------------------------------------------------------------------------------
/vendor/gopkg.in/gcfg.v1/testdata/gcfg_test.gcfg:
--------------------------------------------------------------------------------
1 | ; Comment line
2 | [section]
3 | name=value # comment
4 |
--------------------------------------------------------------------------------
/vendor/gopkg.in/gcfg.v1/testdata/gcfg_unicode_test.gcfg:
--------------------------------------------------------------------------------
1 | ; Comment line
2 | [甲]
3 | 乙=丙 # comment
4 |
--------------------------------------------------------------------------------
/vendor/gopkg.in/gcfg.v1/token/serialize.go:
--------------------------------------------------------------------------------
1 | // Copyright 2011 The Go Authors. All rights reserved.
2 | // Use of this source code is governed by a BSD-style
3 | // license that can be found in the LICENSE file.
4 |
5 | package token
6 |
7 | type serializedFile struct {
8 | // fields correspond 1:1 to fields with same (lower-case) name in File
9 | Name string
10 | Base int
11 | Size int
12 | Lines []int
13 | Infos []lineInfo
14 | }
15 |
16 | type serializedFileSet struct {
17 | Base int
18 | Files []serializedFile
19 | }
20 |
21 | // Read calls decode to deserialize a file set into s; s must not be nil.
22 | func (s *FileSet) Read(decode func(interface{}) error) error {
23 | var ss serializedFileSet
24 | if err := decode(&ss); err != nil {
25 | return err
26 | }
27 |
28 | s.mutex.Lock()
29 | s.base = ss.Base
30 | files := make([]*File, len(ss.Files))
31 | for i := 0; i < len(ss.Files); i++ {
32 | f := &ss.Files[i]
33 | files[i] = &File{s, f.Name, f.Base, f.Size, f.Lines, f.Infos}
34 | }
35 | s.files = files
36 | s.last = nil
37 | s.mutex.Unlock()
38 |
39 | return nil
40 | }
41 |
42 | // Write calls encode to serialize the file set s.
43 | func (s *FileSet) Write(encode func(interface{}) error) error {
44 | var ss serializedFileSet
45 |
46 | s.mutex.Lock()
47 | ss.Base = s.base
48 | files := make([]serializedFile, len(s.files))
49 | for i, f := range s.files {
50 | files[i] = serializedFile{f.name, f.base, f.size, f.lines, f.infos}
51 | }
52 | ss.Files = files
53 | s.mutex.Unlock()
54 |
55 | return encode(ss)
56 | }
57 |
--------------------------------------------------------------------------------
/vendor/gopkg.in/gcfg.v1/token/token.go:
--------------------------------------------------------------------------------
1 | // Copyright 2009 The Go Authors. All rights reserved.
2 | // Use of this source code is governed by a BSD-style
3 | // license that can be found in the LICENSE file.
4 |
5 | // Package token defines constants representing the lexical tokens of the gcfg
6 | // configuration syntax and basic operations on tokens (printing, predicates).
7 | //
8 | // Note that the API for the token package may change to accommodate new
9 | // features or implementation changes in gcfg.
10 | //
11 | package token
12 |
13 | import "strconv"
14 |
15 | // Token is the set of lexical tokens of the gcfg configuration syntax.
16 | type Token int
17 |
18 | // The list of tokens.
19 | const (
20 | // Special tokens
21 | ILLEGAL Token = iota
22 | EOF
23 | COMMENT
24 |
25 | literal_beg
26 | // Identifiers and basic type literals
27 | // (these tokens stand for classes of literals)
28 | IDENT // section-name, variable-name
29 | STRING // "subsection-name", variable value
30 | literal_end
31 |
32 | operator_beg
33 | // Operators and delimiters
34 | ASSIGN // =
35 | LBRACK // [
36 | RBRACK // ]
37 | EOL // \n
38 | operator_end
39 | )
40 |
41 | var tokens = [...]string{
42 | ILLEGAL: "ILLEGAL",
43 |
44 | EOF: "EOF",
45 | COMMENT: "COMMENT",
46 |
47 | IDENT: "IDENT",
48 | STRING: "STRING",
49 |
50 | ASSIGN: "=",
51 | LBRACK: "[",
52 | RBRACK: "]",
53 | EOL: "\n",
54 | }
55 |
56 | // String returns the string corresponding to the token tok.
57 | // For operators and delimiters, the string is the actual token character
58 | // sequence (e.g., for the token ASSIGN, the string is "="). For all other
59 | // tokens the string corresponds to the token constant name (e.g. for the
60 | // token IDENT, the string is "IDENT").
61 | //
62 | func (tok Token) String() string {
63 | s := ""
64 | if 0 <= tok && tok < Token(len(tokens)) {
65 | s = tokens[tok]
66 | }
67 | if s == "" {
68 | s = "token(" + strconv.Itoa(int(tok)) + ")"
69 | }
70 | return s
71 | }
72 |
73 | // Predicates
74 |
75 | // IsLiteral returns true for tokens corresponding to identifiers
76 | // and basic type literals; it returns false otherwise.
77 | //
78 | func (tok Token) IsLiteral() bool { return literal_beg < tok && tok < literal_end }
79 |
80 | // IsOperator returns true for tokens corresponding to operators and
81 | // delimiters; it returns false otherwise.
82 | //
83 | func (tok Token) IsOperator() bool { return operator_beg < tok && tok < operator_end }
84 |
--------------------------------------------------------------------------------
/vendor/gopkg.in/gcfg.v1/types/bool.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | // BoolValues defines the name and value mappings for ParseBool.
4 | var BoolValues = map[string]interface{}{
5 | "true": true, "yes": true, "on": true, "1": true,
6 | "false": false, "no": false, "off": false, "0": false,
7 | }
8 |
9 | var boolParser = func() *EnumParser {
10 | ep := &EnumParser{}
11 | ep.AddVals(BoolValues)
12 | return ep
13 | }()
14 |
15 | // ParseBool parses bool values according to the definitions in BoolValues.
16 | // Parsing is case-insensitive.
17 | func ParseBool(s string) (bool, error) {
18 | v, err := boolParser.Parse(s)
19 | if err != nil {
20 | return false, err
21 | }
22 | return v.(bool), nil
23 | }
24 |
--------------------------------------------------------------------------------
/vendor/gopkg.in/gcfg.v1/types/doc.go:
--------------------------------------------------------------------------------
1 | // Package types defines helpers for type conversions.
2 | //
3 | // The API for this package is not finalized yet.
4 | package types
5 |
--------------------------------------------------------------------------------
/vendor/gopkg.in/gcfg.v1/types/enum.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | import (
4 | "fmt"
5 | "reflect"
6 | "strings"
7 | )
8 |
9 | // EnumParser parses "enum" values; i.e. a predefined set of strings to
10 | // predefined values.
11 | type EnumParser struct {
12 | Type string // type name; if not set, use type of first value added
13 | CaseMatch bool // if true, matching of strings is case-sensitive
14 | // PrefixMatch bool
15 | vals map[string]interface{}
16 | }
17 |
18 | // AddVals adds strings and values to an EnumParser.
19 | func (ep *EnumParser) AddVals(vals map[string]interface{}) {
20 | if ep.vals == nil {
21 | ep.vals = make(map[string]interface{})
22 | }
23 | for k, v := range vals {
24 | if ep.Type == "" {
25 | ep.Type = reflect.TypeOf(v).Name()
26 | }
27 | if !ep.CaseMatch {
28 | k = strings.ToLower(k)
29 | }
30 | ep.vals[k] = v
31 | }
32 | }
33 |
34 | // Parse parses the string and returns the value or an error.
35 | func (ep EnumParser) Parse(s string) (interface{}, error) {
36 | if !ep.CaseMatch {
37 | s = strings.ToLower(s)
38 | }
39 | v, ok := ep.vals[s]
40 | if !ok {
41 | return false, fmt.Errorf("failed to parse %s %#q", ep.Type, s)
42 | }
43 | return v, nil
44 | }
45 |
--------------------------------------------------------------------------------
/vendor/gopkg.in/gcfg.v1/types/enum_test.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | func TestEnumParserBool(t *testing.T) {
8 | for _, tt := range []struct {
9 | val string
10 | res bool
11 | ok bool
12 | }{
13 | {val: "tRuE", res: true, ok: true},
14 | {val: "False", res: false, ok: true},
15 | {val: "t", ok: false},
16 | } {
17 | b, err := ParseBool(tt.val)
18 | switch {
19 | case tt.ok && err != nil:
20 | t.Errorf("%q: got error %v, want %v", tt.val, err, tt.res)
21 | case !tt.ok && err == nil:
22 | t.Errorf("%q: got %v, want error", tt.val, b)
23 | case tt.ok && b != tt.res:
24 | t.Errorf("%q: got %v, want %v", tt.val, b, tt.res)
25 | default:
26 | t.Logf("%q: got %v, %v", tt.val, b, err)
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/vendor/gopkg.in/gcfg.v1/types/int.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | import (
4 | "fmt"
5 | "strings"
6 | )
7 |
8 | // An IntMode is a mode for parsing integer values, representing a set of
9 | // accepted bases.
10 | type IntMode uint8
11 |
12 | // IntMode values for ParseInt; can be combined using binary or.
13 | const (
14 | Dec IntMode = 1 << iota
15 | Hex
16 | Oct
17 | )
18 |
19 | // String returns a string representation of IntMode; e.g. `IntMode(Dec|Hex)`.
20 | func (m IntMode) String() string {
21 | var modes []string
22 | if m&Dec != 0 {
23 | modes = append(modes, "Dec")
24 | }
25 | if m&Hex != 0 {
26 | modes = append(modes, "Hex")
27 | }
28 | if m&Oct != 0 {
29 | modes = append(modes, "Oct")
30 | }
31 | return "IntMode(" + strings.Join(modes, "|") + ")"
32 | }
33 |
34 | var errIntAmbig = fmt.Errorf("ambiguous integer value; must include '0' prefix")
35 |
36 | func prefix0(val string) bool {
37 | return strings.HasPrefix(val, "0") || strings.HasPrefix(val, "-0")
38 | }
39 |
40 | func prefix0x(val string) bool {
41 | return strings.HasPrefix(val, "0x") || strings.HasPrefix(val, "-0x")
42 | }
43 |
44 | // ParseInt parses val using mode into intptr, which must be a pointer to an
45 | // integer kind type. Non-decimal value require prefix `0` or `0x` in the cases
46 | // when mode permits ambiguity of base; otherwise the prefix can be omitted.
47 | func ParseInt(intptr interface{}, val string, mode IntMode) error {
48 | val = strings.TrimSpace(val)
49 | verb := byte(0)
50 | switch mode {
51 | case Dec:
52 | verb = 'd'
53 | case Dec + Hex:
54 | if prefix0x(val) {
55 | verb = 'v'
56 | } else {
57 | verb = 'd'
58 | }
59 | case Dec + Oct:
60 | if prefix0(val) && !prefix0x(val) {
61 | verb = 'v'
62 | } else {
63 | verb = 'd'
64 | }
65 | case Dec + Hex + Oct:
66 | verb = 'v'
67 | case Hex:
68 | if prefix0x(val) {
69 | verb = 'v'
70 | } else {
71 | verb = 'x'
72 | }
73 | case Oct:
74 | verb = 'o'
75 | case Hex + Oct:
76 | if prefix0(val) {
77 | verb = 'v'
78 | } else {
79 | return errIntAmbig
80 | }
81 | }
82 | if verb == 0 {
83 | panic("unsupported mode")
84 | }
85 | return ScanFully(intptr, val, verb)
86 | }
87 |
--------------------------------------------------------------------------------
/vendor/gopkg.in/gcfg.v1/types/int_test.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | import (
4 | "reflect"
5 | "testing"
6 | )
7 |
8 | func elem(p interface{}) interface{} {
9 | return reflect.ValueOf(p).Elem().Interface()
10 | }
11 |
12 | func TestParseInt(t *testing.T) {
13 | for _, tt := range []struct {
14 | val string
15 | mode IntMode
16 | exp interface{}
17 | ok bool
18 | }{
19 | {"0", Dec, int(0), true},
20 | {"10", Dec, int(10), true},
21 | {"-10", Dec, int(-10), true},
22 | {"x", Dec, int(0), false},
23 | {"0xa", Hex, int(0xa), true},
24 | {"a", Hex, int(0xa), true},
25 | {"10", Hex, int(0x10), true},
26 | {"-0xa", Hex, int(-0xa), true},
27 | {"0x", Hex, int(0x0), true}, // Scanf doesn't require digit behind 0x
28 | {"-0x", Hex, int(0x0), true}, // Scanf doesn't require digit behind 0x
29 | {"-a", Hex, int(-0xa), true},
30 | {"-10", Hex, int(-0x10), true},
31 | {"x", Hex, int(0), false},
32 | {"10", Oct, int(010), true},
33 | {"010", Oct, int(010), true},
34 | {"-10", Oct, int(-010), true},
35 | {"-010", Oct, int(-010), true},
36 | {"10", Dec | Hex, int(10), true},
37 | {"010", Dec | Hex, int(10), true},
38 | {"0x10", Dec | Hex, int(0x10), true},
39 | {"10", Dec | Oct, int(10), true},
40 | {"010", Dec | Oct, int(010), true},
41 | {"0x10", Dec | Oct, int(0), false},
42 | {"10", Hex | Oct, int(0), false}, // need prefix to distinguish Hex/Oct
43 | {"010", Hex | Oct, int(010), true},
44 | {"0x10", Hex | Oct, int(0x10), true},
45 | {"10", Dec | Hex | Oct, int(10), true},
46 | {"010", Dec | Hex | Oct, int(010), true},
47 | {"0x10", Dec | Hex | Oct, int(0x10), true},
48 | } {
49 | typ := reflect.TypeOf(tt.exp)
50 | res := reflect.New(typ).Interface()
51 | err := ParseInt(res, tt.val, tt.mode)
52 | switch {
53 | case tt.ok && err != nil:
54 | t.Errorf("ParseInt(%v, %#v, %v): fail; got error %v, want ok",
55 | typ, tt.val, tt.mode, err)
56 | case !tt.ok && err == nil:
57 | t.Errorf("ParseInt(%v, %#v, %v): fail; got %v, want error",
58 | typ, tt.val, tt.mode, elem(res))
59 | case tt.ok && !reflect.DeepEqual(elem(res), tt.exp):
60 | t.Errorf("ParseInt(%v, %#v, %v): fail; got %v, want %v",
61 | typ, tt.val, tt.mode, elem(res), tt.exp)
62 | default:
63 | t.Logf("ParseInt(%v, %#v, %s): pass; got %v, error %v",
64 | typ, tt.val, tt.mode, elem(res), err)
65 | }
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/vendor/gopkg.in/gcfg.v1/types/scan.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | import (
4 | "fmt"
5 | "io"
6 | "reflect"
7 | )
8 |
9 | // ScanFully uses fmt.Sscanf with verb to fully scan val into ptr.
10 | func ScanFully(ptr interface{}, val string, verb byte) error {
11 | t := reflect.ValueOf(ptr).Elem().Type()
12 | // attempt to read extra bytes to make sure the value is consumed
13 | var b []byte
14 | n, err := fmt.Sscanf(val, "%"+string(verb)+"%s", ptr, &b)
15 | switch {
16 | case n < 1 || n == 1 && err != io.EOF:
17 | return fmt.Errorf("failed to parse %q as %v: %v", val, t, err)
18 | case n > 1:
19 | return fmt.Errorf("failed to parse %q as %v: extra characters %q", val, t, string(b))
20 | }
21 | // n == 1 && err == io.EOF
22 | return nil
23 | }
24 |
--------------------------------------------------------------------------------
/vendor/gopkg.in/gcfg.v1/types/scan_test.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | import (
4 | "reflect"
5 | "testing"
6 | )
7 |
8 | func TestScanFully(t *testing.T) {
9 | for _, tt := range []struct {
10 | val string
11 | verb byte
12 | res interface{}
13 | ok bool
14 | }{
15 | {"a", 'v', int(0), false},
16 | {"0x", 'v', int(0), true},
17 | {"0x", 'd', int(0), false},
18 | } {
19 | d := reflect.New(reflect.TypeOf(tt.res)).Interface()
20 | err := ScanFully(d, tt.val, tt.verb)
21 | switch {
22 | case tt.ok && err != nil:
23 | t.Errorf("ScanFully(%T, %q, '%c'): want ok, got error %v",
24 | d, tt.val, tt.verb, err)
25 | case !tt.ok && err == nil:
26 | t.Errorf("ScanFully(%T, %q, '%c'): want error, got %v",
27 | d, tt.val, tt.verb, elem(d))
28 | case tt.ok && err == nil && !reflect.DeepEqual(tt.res, elem(d)):
29 | t.Errorf("ScanFully(%T, %q, '%c'): want %v, got %v",
30 | d, tt.val, tt.verb, tt.res, elem(d))
31 | default:
32 | t.Logf("ScanFully(%T, %q, '%c') = %v; *ptr==%v",
33 | d, tt.val, tt.verb, err, elem(d))
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/vendor/vendor.json:
--------------------------------------------------------------------------------
1 | {
2 | "comment": "",
3 | "ignore": "",
4 | "package": [
5 | {
6 | "path": "appengine/cloudsql",
7 | "revision": ""
8 | },
9 | {
10 | "checksumSHA1": "3xVanMXn/lblhNfZYORorpd8N6E=",
11 | "path": "github.com/go-sql-driver/mysql",
12 | "revision": "0b58b37b664c21f3010e836f1b931e1d0b0b0685",
13 | "revisionTime": "2016-08-02T11:38:42Z"
14 | },
15 | {
16 | "checksumSHA1": "Em+idtZv9NvuTvzwBnkcCjv/j40=",
17 | "path": "github.com/patrickmn/go-cache",
18 | "revision": "1881a9bccb818787f68c52bfba648c6cf34c34fa",
19 | "revisionTime": "2016-01-27T17:00:04Z"
20 | }
21 | ],
22 | "rootPath": "github.com/outbrain/orchestrator"
23 | }
24 |
--------------------------------------------------------------------------------