vagrant-rancher 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +19 -0
- data/.rubocop.yml +11 -0
- data/Gemfile +10 -0
- data/LICENSE.txt +21 -0
- data/README.md +60 -0
- data/Rakefile +17 -0
- data/examples/Vagrantfile +50 -0
- data/examples/Vagrantfile.rancheros +42 -0
- data/examples/vagrant_rancheros_guest_plugin.rb +74 -0
- data/lib/vagrant-rancher.rb +12 -0
- data/lib/vagrant-rancher/config.rb +67 -0
- data/lib/vagrant-rancher/errors.rb +49 -0
- data/lib/vagrant-rancher/plugin.rb +34 -0
- data/lib/vagrant-rancher/provisioner.rb +148 -0
- data/lib/vagrant-rancher/rancher.rb +168 -0
- data/lib/vagrant-rancher/version.rb +5 -0
- data/locales/en.yml +44 -0
- data/vagrant-rancher.gemspec +24 -0
- metadata +92 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 07fc0ab4dffdade295fb36426c3e1a7b6979763c
|
4
|
+
data.tar.gz: 7f8c27bd89e8c65c707282b8a28b10e9d4f8bd4b
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 0b7d6c32011364096681eced5929074fa3d7dcf03e856066a7d2dc09e5c2673f4b57c92660a8f18c286cae0802c6ad5bca51e5e3ca579a2f7e6e9691a7de05e2
|
7
|
+
data.tar.gz: d01d57d525a84e44a34e519090a6d6f64b26692fe3c95f2c970d24e5f75b2dfd485ad190207c8f2676c57027204c9743e1831f42f695665231bd67ceaf8abdd4
|
data/.gitignore
ADDED
data/.rubocop.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2016 nextrevision
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
# vagrant-rancher
|
2
|
+
|
3
|
+
Vagrant plugin to install a Rancher server and agents on all vagrant guests.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
```
|
8
|
+
vagrant plugin install vagrant-rancher
|
9
|
+
```
|
10
|
+
|
11
|
+
## Requirements
|
12
|
+
|
13
|
+
* Docker to be intalled and running on the guest (ideally via unix socket)
|
14
|
+
* Guest to have an IP reachable by the host running the `vagrant` command (for VirtualBox and VMWare, see [private_network](https://www.vagrantup.com/docs/networking/private_network.html))
|
15
|
+
|
16
|
+
## Usage
|
17
|
+
|
18
|
+
```
|
19
|
+
Vagrant.configure("2") do |config|
|
20
|
+
config.vm.box = "ubuntu/trusty64"
|
21
|
+
config.vm.network "private_network", ip: "192.168.33.100"
|
22
|
+
config.vm.provider "virtualbox" do |vb|
|
23
|
+
vb.memory = "1024"
|
24
|
+
end
|
25
|
+
|
26
|
+
config.vm.provision :docker
|
27
|
+
config.vm.provision "rancher" do |rancher|
|
28
|
+
rancher.hostname = "192.168.33.100"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
```
|
32
|
+
|
33
|
+
The `vagrant-rancher` plugin requires the hostname being set to either a DNS name or IP that is reachable by the host running the `vagrant` command.
|
34
|
+
|
35
|
+
### Options
|
36
|
+
|
37
|
+
* `hostname` (**required**): the DNS name or IP of the rancher server (must be reachable by the host running the `vagrant` command)
|
38
|
+
* `role` (*optional*, default: `'server'`): either 'server' (to run the Rancher server) or 'agent' to only run the Rancher agent
|
39
|
+
* `version` (*optional*, default: `'latest'`): version (tag) of the Rancher server container to run
|
40
|
+
* `port` (*optional*, default: `8080`): port to run the rancher server on in the case of the server, and communicate with in the case of the agent
|
41
|
+
* `server_args` (*optional*, default: `''`): additional args to pass to the Docker run command when starting the Rancher server
|
42
|
+
* `labels` (*optional*, default: `[]`): array of key=value pairs of labels to assign to the agent (ex. ["role=server","env=local"])
|
43
|
+
* `deactivate` (*optional*, default: `false`): deactivate the host in Rancher to prevent it from being scheduled on
|
44
|
+
|
45
|
+
## Examples
|
46
|
+
|
47
|
+
See examples directory. For a quick setup of a Rancher environment running on RancherOS, see [https://github.com/nextrevision/rancheros-vagrant](https://github.com/nextrevision/rancheros-vagrant).
|
48
|
+
|
49
|
+
## Providers Tested
|
50
|
+
|
51
|
+
* VirtualBox
|
52
|
+
|
53
|
+
## Contributing
|
54
|
+
|
55
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/nextrevision/vagrant-rancher.
|
56
|
+
|
57
|
+
## License
|
58
|
+
|
59
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
60
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler/setup'
|
3
|
+
require 'rubocop/rake_task'
|
4
|
+
|
5
|
+
# Immediately sync all stdout so that tools like buildbot can
|
6
|
+
# immediately load in the output.
|
7
|
+
$stdout.sync = true
|
8
|
+
$stderr.sync = true
|
9
|
+
|
10
|
+
# Change to the directory of this file.
|
11
|
+
Dir.chdir(File.expand_path('../', __FILE__))
|
12
|
+
|
13
|
+
# This installs the tasks that help with gem creation and
|
14
|
+
# publishing.
|
15
|
+
Bundler::GemHelper.install_tasks
|
16
|
+
|
17
|
+
RuboCop::RakeTask.new
|
@@ -0,0 +1,50 @@
|
|
1
|
+
Vagrant.configure(2) do |config|
|
2
|
+
# start with a standard box
|
3
|
+
config.vm.box = "ubuntu/trusty64"
|
4
|
+
|
5
|
+
# in order to communicate with the api, we need to set
|
6
|
+
# a static, private ip address. this also allows for
|
7
|
+
# other vagrant guests to run agents and connect to the
|
8
|
+
# rancher server.
|
9
|
+
config.vm.network "private_network", ip: "192.168.33.100"
|
10
|
+
|
11
|
+
# increase the ram allotment to accomodate rancher
|
12
|
+
config.vm.provider "virtualbox" do |vb|
|
13
|
+
vb.memory = "1024"
|
14
|
+
end
|
15
|
+
|
16
|
+
# install docker on the guest
|
17
|
+
config.vm.provision :docker
|
18
|
+
|
19
|
+
# start the rancher server and agent
|
20
|
+
config.vm.provision :rancher do |rancher|
|
21
|
+
# the role to assign to the guest. can be either
|
22
|
+
# 'server' or 'agent', and 'server' implies 'agent'
|
23
|
+
# as well
|
24
|
+
rancher.role = "server"
|
25
|
+
|
26
|
+
# required parameter that instructs the provisioner
|
27
|
+
# how to reach the rancher server api endpoint
|
28
|
+
rancher.hostname = "192.168.33.100"
|
29
|
+
|
30
|
+
# port to run rancher server on and also connect over
|
31
|
+
# for agent communication
|
32
|
+
rancher.port = 8080
|
33
|
+
|
34
|
+
# version (tag) of the rancher server to deploy
|
35
|
+
rancher.version = "v0.63.1"
|
36
|
+
|
37
|
+
# do not deactivate the host, resulting in it not
|
38
|
+
# being scheduled upon (useful when you want the server
|
39
|
+
# to be the only container running on a guest)
|
40
|
+
rancher.deactivate = false
|
41
|
+
|
42
|
+
# additional args to pass to docker when starting
|
43
|
+
# the server
|
44
|
+
rancher.server_args = "--restart always"
|
45
|
+
|
46
|
+
# labels to assign to the agent and resulting host
|
47
|
+
# in rancher
|
48
|
+
rancher.labels = ["environment=local"]
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# -*- mode: ruby -*-
|
2
|
+
# vi: set ft=ruby :
|
3
|
+
|
4
|
+
# required for setting the guest capabilities
|
5
|
+
require_relative 'vagrant_rancheros_guest_plugin.rb'
|
6
|
+
|
7
|
+
Vagrant.configure(2) do |config|
|
8
|
+
# global config settings
|
9
|
+
config.vm.box = "rancherio/rancheros"
|
10
|
+
config.vm.box_version = ">=0.4.1"
|
11
|
+
config.vm.synced_folder ".", "/vagrant", disabled: true
|
12
|
+
|
13
|
+
# define the rancher-server guest
|
14
|
+
config.vm.define "rancher-server" do |node|
|
15
|
+
node.vm.hostname = "rancher-server"
|
16
|
+
node.vm.network "private_network", ip: "192.168.33.100"
|
17
|
+
node.vm.provider "virtualbox" do |vb|
|
18
|
+
vb.memory = 1536
|
19
|
+
end
|
20
|
+
|
21
|
+
node.vm.provision :rancher do |rancher|
|
22
|
+
rancher.hostname = "192.168.33.100"
|
23
|
+
rancher.deactivate = true
|
24
|
+
rancher.labels = ["role=server"]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# define the rancher-agent guest
|
29
|
+
config.vm.define "rancher-agent" do |node|
|
30
|
+
node.vm.hostname = "rancher-agent"
|
31
|
+
node.vm.network "private_network", ip: "192.168.33.101"
|
32
|
+
node.vm.provider "virtualbox" do |vb|
|
33
|
+
vb.memory = 512
|
34
|
+
end
|
35
|
+
|
36
|
+
node.vm.provision :rancher do |rancher|
|
37
|
+
rancher.role = "agent"
|
38
|
+
rancher.hostname = "192.168.33.100"
|
39
|
+
rancher.labels = ["role=agent"]
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'ipaddr'
|
2
|
+
|
3
|
+
## Hacking this until we get a real plugin
|
4
|
+
|
5
|
+
# Borrowing from http://stackoverflow.com/questions/1825928/netmask-to-cidr-in-ruby
|
6
|
+
IPAddr.class_eval do
|
7
|
+
def to_cidr
|
8
|
+
self.to_i.to_s(2).count("1")
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
module VagrantPlugins
|
13
|
+
module GuestLinux
|
14
|
+
class Plugin < Vagrant.plugin("2")
|
15
|
+
guest_capability("linux", "change_host_name") do
|
16
|
+
Cap::ChangeHostName
|
17
|
+
end
|
18
|
+
|
19
|
+
guest_capability("linux", "configure_networks") do
|
20
|
+
Cap::ConfigureNetworks
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
module VagrantPlugins
|
27
|
+
module GuestLinux
|
28
|
+
module Cap
|
29
|
+
class ConfigureNetworks
|
30
|
+
def self.configure_networks(machine, networks)
|
31
|
+
machine.communicate.tap do |comm|
|
32
|
+
interfaces = []
|
33
|
+
comm.sudo("ip link show|grep eth[1-9]|awk '{print $2}'|sed -e 's/:$//'") do |_, result|
|
34
|
+
interfaces = result.split("\n")
|
35
|
+
end
|
36
|
+
|
37
|
+
networks.each do |network|
|
38
|
+
dhcp = "true"
|
39
|
+
iface = interfaces[network[:interface].to_i - 1]
|
40
|
+
|
41
|
+
if network[:type] == :static
|
42
|
+
cidr = IPAddr.new(network[:netmask]).to_cidr
|
43
|
+
comm.sudo("ros config set rancher.network.interfaces.#{iface}.address #{network[:ip]}/#{cidr}")
|
44
|
+
comm.sudo("ros config set rancher.network.interfaces.#{iface}.match #{iface}")
|
45
|
+
|
46
|
+
dhcp = "false"
|
47
|
+
end
|
48
|
+
comm.sudo("ros config set rancher.network.interfaces.#{iface}.dhcp #{dhcp}")
|
49
|
+
end
|
50
|
+
|
51
|
+
comm.sudo("system-docker restart network")
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
module VagrantPlugins
|
60
|
+
module GuestLinux
|
61
|
+
module Cap
|
62
|
+
class ChangeHostName
|
63
|
+
def self.change_host_name(machine, name)
|
64
|
+
machine.communicate.tap do |comm|
|
65
|
+
if !comm.test("sudo hostname --fqdn | grep '#{name}'")
|
66
|
+
comm.sudo("hostname #{name.split('.')[0]}")
|
67
|
+
comm.sudo("echo '#{name.split('.')[0]}' > /etc/hostname")
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module VagrantPlugins
|
2
|
+
module Rancher
|
3
|
+
lib_path = Pathname.new(File.expand_path('../vagrant-rancher', __FILE__))
|
4
|
+
autoload :Errors, lib_path.join('errors')
|
5
|
+
|
6
|
+
def self.source_root
|
7
|
+
@source_root ||= Pathname.new(File.expand_path("../../", __FILE__))
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
require 'vagrant-rancher/plugin'
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module VagrantPlugins
|
2
|
+
module Rancher
|
3
|
+
class Config < Vagrant.plugin('2', :config)
|
4
|
+
attr_accessor :role
|
5
|
+
attr_accessor :version
|
6
|
+
attr_accessor :hostname
|
7
|
+
attr_accessor :port
|
8
|
+
attr_accessor :deactivate
|
9
|
+
attr_accessor :server_args
|
10
|
+
attr_accessor :labels
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
@role = UNSET_VALUE
|
14
|
+
@version = UNSET_VALUE
|
15
|
+
@hostname = UNSET_VALUE
|
16
|
+
@port = UNSET_VALUE
|
17
|
+
@server_args = UNSET_VALUE
|
18
|
+
@labels = UNSET_VALUE
|
19
|
+
@deactivate = UNSET_VALUE
|
20
|
+
end
|
21
|
+
|
22
|
+
def finalize!
|
23
|
+
@role = 'server' if @role == UNSET_VALUE
|
24
|
+
@version = 'latest' if @version == UNSET_VALUE
|
25
|
+
@hostname = nil if @hostname == UNSET_VALUE
|
26
|
+
@port = 8080 if @port == UNSET_VALUE
|
27
|
+
@server_args = nil if @server_args == UNSET_VALUE
|
28
|
+
@labels = nil if @labels == UNSET_VALUE
|
29
|
+
@deactivate = false if @deactivate == UNSET_VALUE
|
30
|
+
end
|
31
|
+
|
32
|
+
def validate(_machine)
|
33
|
+
errors = _detected_errors
|
34
|
+
|
35
|
+
unless role == 'server' || role == 'agent'
|
36
|
+
errors << ':rancher provisioner requires role to either be "server" or "agent"'
|
37
|
+
end
|
38
|
+
|
39
|
+
unless version.is_a?(String) || version.nil?
|
40
|
+
errors << ':rancher provisioner requires version to be a string'
|
41
|
+
end
|
42
|
+
|
43
|
+
unless hostname.is_a?(String)
|
44
|
+
errors << ':rancher provisioner requires hostname to be set to a string'
|
45
|
+
end
|
46
|
+
|
47
|
+
unless port.is_a?(Fixnum) || port.is_a?(Fixnum)
|
48
|
+
errors << ':rancher provisioner requires port to be a number'
|
49
|
+
end
|
50
|
+
|
51
|
+
unless server_args.is_a?(String) || server_args.nil?
|
52
|
+
errors << ':rancher provisioner requires server_args to be a string'
|
53
|
+
end
|
54
|
+
|
55
|
+
unless labels.is_a?(Array) || labels.nil?
|
56
|
+
errors << ':rancher provisioner requires labels to be an array'
|
57
|
+
end
|
58
|
+
|
59
|
+
unless deactivate.is_a?(TrueClass) || deactivate.is_a?(FalseClass)
|
60
|
+
errors << ':rancher provisioner requires deactivate to be a bool'
|
61
|
+
end
|
62
|
+
|
63
|
+
{ 'rancher provisioner' => errors }
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module VagrantPlugins
|
2
|
+
module Rancher
|
3
|
+
module Errors
|
4
|
+
class VagrantRancherError < Vagrant::Errors::VagrantError
|
5
|
+
error_namespace("vagrant_rancher.errors")
|
6
|
+
end
|
7
|
+
|
8
|
+
class DockerConnection < VagrantRancherError
|
9
|
+
error_key(:docker_connection)
|
10
|
+
end
|
11
|
+
|
12
|
+
class RancherServerContainer < VagrantRancherError
|
13
|
+
error_key(:rancher_server_container)
|
14
|
+
end
|
15
|
+
|
16
|
+
class RancherAgentContainer < VagrantRancherError
|
17
|
+
error_key(:rancher_agent_container)
|
18
|
+
end
|
19
|
+
|
20
|
+
class RegistrationTokenMissing < VagrantRancherError
|
21
|
+
error_key(:registration_token_missing)
|
22
|
+
end
|
23
|
+
|
24
|
+
class ApiConnectionError < VagrantRancherError
|
25
|
+
error_key(:api_connection_error)
|
26
|
+
end
|
27
|
+
|
28
|
+
class ApiConnectionTimeout < VagrantRancherError
|
29
|
+
error_key(:api_connection_timeout)
|
30
|
+
end
|
31
|
+
|
32
|
+
class AgentRegistrationTimeout < VagrantRancherError
|
33
|
+
error_key(:agent_registration_timeout)
|
34
|
+
end
|
35
|
+
|
36
|
+
class HttpResponseCode < VagrantRancherError
|
37
|
+
error_key(:http_response_code)
|
38
|
+
end
|
39
|
+
|
40
|
+
class ProjectNotFound < VagrantRancherError
|
41
|
+
error_key(:project_not_found)
|
42
|
+
end
|
43
|
+
|
44
|
+
class HostNotFound < VagrantRancherError
|
45
|
+
error_key(:host_not_found)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
begin
|
2
|
+
require 'vagrant'
|
3
|
+
rescue LoadError
|
4
|
+
raise 'The vagrant-rancher plugin must be run within Vagrant.'
|
5
|
+
end
|
6
|
+
|
7
|
+
module VagrantPlugins
|
8
|
+
module Rancher
|
9
|
+
class Plugin < Vagrant.plugin('2')
|
10
|
+
name 'vagrant-rancher'
|
11
|
+
description <<-DESC.gsub(/^ +/, '')
|
12
|
+
Vagrant plugin to install a Rancher server
|
13
|
+
and agents on all Vagrant guests.
|
14
|
+
DESC
|
15
|
+
|
16
|
+
action_hook(:init_i18n, :environment_load) { init_i18n }
|
17
|
+
|
18
|
+
config(:rancher, :provisioner) do
|
19
|
+
require_relative 'config'
|
20
|
+
Config
|
21
|
+
end
|
22
|
+
|
23
|
+
provisioner(:rancher) do
|
24
|
+
require_relative 'provisioner'
|
25
|
+
Provisioner
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.init_i18n
|
29
|
+
I18n.load_path << File.expand_path("locales/en.yml", Rancher.source_root)
|
30
|
+
I18n.reload!
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,148 @@
|
|
1
|
+
require_relative 'rancher'
|
2
|
+
require_relative 'errors'
|
3
|
+
|
4
|
+
module VagrantPlugins
|
5
|
+
module Rancher
|
6
|
+
class Provisioner < Vagrant.plugin('2', :provisioner)
|
7
|
+
def initialize(machine, config, rancher = nil)
|
8
|
+
super(machine, config)
|
9
|
+
@rancher = rancher || RancherClient.new(@config.hostname, @config.port)
|
10
|
+
end
|
11
|
+
|
12
|
+
def provision
|
13
|
+
self.check_docker
|
14
|
+
|
15
|
+
if config.role == 'server'
|
16
|
+
self.install_server
|
17
|
+
self.configure_server
|
18
|
+
end
|
19
|
+
|
20
|
+
if config.role == 'server' || config.role == 'agent'
|
21
|
+
self.install_agent
|
22
|
+
self.configure_agent
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# determines if we can reach the docker daemon
|
27
|
+
def check_docker
|
28
|
+
unless @machine.communicate.test('sh -c sleep 3; sudo docker info')
|
29
|
+
@machine.ui.error 'Could not connect to docker daemon'
|
30
|
+
raise Errors::DockerConnection
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# installs the rancher server at the supplied version
|
35
|
+
def install_server
|
36
|
+
# check to see if the rancher server is already running
|
37
|
+
unless @machine.communicate.test('sudo docker inspect rancher-server')
|
38
|
+
@machine.ui.info "Starting server container: rancher/server:#{config.version}..."
|
39
|
+
|
40
|
+
docker_cmd = "docker run -d -t --name rancher-server -p #{@config.port}:8080"
|
41
|
+
|
42
|
+
# add any user supplied args to the docker command
|
43
|
+
unless config.server_args.nil?
|
44
|
+
docker_cmd = "#{docker_cmd} #{config.server_args}"
|
45
|
+
end
|
46
|
+
|
47
|
+
# start the server and error if there is a failure
|
48
|
+
unless @machine.communicate.sudo("#{docker_cmd} rancher/server:#{config.version}")
|
49
|
+
@machine.ui.error 'Could not start Rancher server container'
|
50
|
+
raise Errors::RancherServerContainer
|
51
|
+
end
|
52
|
+
|
53
|
+
# wait for the server api to come online
|
54
|
+
@machine.ui.detail 'Waiting for server API to become available...'
|
55
|
+
unless @rancher.wait_for_api
|
56
|
+
raise Errors::ApiConnectionTimeout,
|
57
|
+
:host => @config.hostname,
|
58
|
+
:port => @config.port
|
59
|
+
end
|
60
|
+
|
61
|
+
# gratuitous pause for the server api
|
62
|
+
sleep 5
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# configures a running server with the required settings
|
67
|
+
def configure_server
|
68
|
+
# retrieve the default project id
|
69
|
+
project_id = @rancher.get_project_id
|
70
|
+
raise Errors::ProjectNotFound if project_id.nil?
|
71
|
+
|
72
|
+
# attempt to retrieve a registration token, otherwise create one
|
73
|
+
unless @rancher.get_registration_token project_id
|
74
|
+
@machine.ui.detail "Registration tokens have not been created, creating now..."
|
75
|
+
@rancher.create_registration_token project_id
|
76
|
+
|
77
|
+
# set the api.host setting required for agents
|
78
|
+
@rancher.configure_setting 'api.host', "http://#{@config.hostname}:#{@config.port}"
|
79
|
+
sleep(2)
|
80
|
+
|
81
|
+
# verify that the registration token was created
|
82
|
+
raise Errors::RegistrationTokenMissing unless @rancher.get_registration_token project_id
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
# runs the agent container on the guest
|
87
|
+
def install_agent
|
88
|
+
# if the agent container is not running, start it
|
89
|
+
unless @machine.communicate.test('sudo docker inspect rancher-agent')
|
90
|
+
# retrieve the default project id
|
91
|
+
project_id = @rancher.get_project_id
|
92
|
+
raise Errors::ProjectNotFound if project_id.nil?
|
93
|
+
|
94
|
+
# retrieve the registration token
|
95
|
+
@machine.ui.detail 'Retrieving agent registration command...'
|
96
|
+
registration_token = @rancher.get_registration_token project_id
|
97
|
+
raise Errors::RegistrationTokenMissing if registration_token.nil?
|
98
|
+
|
99
|
+
docker_cmd = registration_token['command']
|
100
|
+
|
101
|
+
# apply a default label with the machine id used for
|
102
|
+
# checking that the agent has indeed registered the host
|
103
|
+
labels = "id=#{@machine.id}"
|
104
|
+
# apply and additional host labels
|
105
|
+
unless config.labels.nil?
|
106
|
+
labels = "#{labels}&#{config.labels.join('&')}"
|
107
|
+
end
|
108
|
+
|
109
|
+
extra_args = "-e 'CATTLE_HOST_LABELS=#{labels}' --name rancher-agent-bootstrap"
|
110
|
+
docker_cmd = docker_cmd.sub('docker run', "docker run #{extra_args}")
|
111
|
+
|
112
|
+
# start the agent container
|
113
|
+
@machine.ui.info "Starting agent container: #{registration_token['image']}..."
|
114
|
+
unless @machine.communicate.sudo(docker_cmd)
|
115
|
+
@machine.ui.error 'Could not start Rancher agent container'
|
116
|
+
raise Errors::RancherAgentContainer
|
117
|
+
end
|
118
|
+
|
119
|
+
# wait for the agent to register the host in rancher (checks
|
120
|
+
# for the @machine.id in the host labels)
|
121
|
+
@machine.ui.detail 'Waiting for agent to register...'
|
122
|
+
unless @rancher.wait_for_agent @machine.id
|
123
|
+
raise Errors::AgentRegistrationTimeout,
|
124
|
+
:host => @config.hostname,
|
125
|
+
:port => @config.port
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
# configure the agent in rancher
|
131
|
+
def configure_agent
|
132
|
+
# retrieve the project id
|
133
|
+
project_id = @rancher.get_project_id
|
134
|
+
raise Errors::ProjectNotFound if project_id.nil?
|
135
|
+
|
136
|
+
# retrieve the host by the @machine.id label
|
137
|
+
host = @rancher.get_host project_id, @machine.id
|
138
|
+
raise Errors::HostNotFound, :project_id => project_id if host.nil?
|
139
|
+
|
140
|
+
# when deactivate is set and the host is active, deactivate it
|
141
|
+
if @config.deactivate and host['state'] == 'active'
|
142
|
+
@machine.ui.info "Deactivating agent..."
|
143
|
+
@rancher.deactivate_host project_id, host['id']
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
@@ -0,0 +1,168 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
module VagrantPlugins
|
5
|
+
module Rancher
|
6
|
+
class RancherClient
|
7
|
+
def initialize(hostname, port)
|
8
|
+
@hostname = hostname
|
9
|
+
@port = port
|
10
|
+
end
|
11
|
+
|
12
|
+
# waits for the rancher api to come online
|
13
|
+
def wait_for_api
|
14
|
+
uri = URI "http://#{@hostname}:#{@port}/v1"
|
15
|
+
|
16
|
+
15.times do |i|
|
17
|
+
begin
|
18
|
+
Net::HTTP.get_response uri
|
19
|
+
break
|
20
|
+
rescue
|
21
|
+
return false if i == 15
|
22
|
+
sleep 10
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
true
|
27
|
+
end
|
28
|
+
|
29
|
+
# waits for the agent to register the host
|
30
|
+
def wait_for_agent(machine_id)
|
31
|
+
project_id = self.get_project_id
|
32
|
+
raise Errors::ProjectNotFound if project_id.nil?
|
33
|
+
|
34
|
+
15.times do |i|
|
35
|
+
host = self.get_host project_id, machine_id
|
36
|
+
break unless host.nil?
|
37
|
+
return false if i == 15
|
38
|
+
sleep 10
|
39
|
+
end
|
40
|
+
|
41
|
+
true
|
42
|
+
end
|
43
|
+
|
44
|
+
# retrieves the Default project id
|
45
|
+
def get_project_id
|
46
|
+
project_id = nil
|
47
|
+
|
48
|
+
response = self.api '/v1/projects'
|
49
|
+
|
50
|
+
unless response.nil? or response['data'].empty?
|
51
|
+
response['data'].each do |project|
|
52
|
+
if project['name'] == 'Default'
|
53
|
+
project_id = project['id']
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
project_id
|
59
|
+
end
|
60
|
+
|
61
|
+
# retrieves a rancher host object
|
62
|
+
def get_host(project_id, machine_id)
|
63
|
+
host = nil
|
64
|
+
|
65
|
+
response = self.api "/v1/projects/#{project_id}/hosts"
|
66
|
+
|
67
|
+
unless response.nil? or response['data'].empty?
|
68
|
+
response['data'].each do |h|
|
69
|
+
host = h if h['labels'].values.include? machine_id
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
host
|
74
|
+
end
|
75
|
+
|
76
|
+
# retrieves a registration token for a project
|
77
|
+
def get_registration_token(project_id)
|
78
|
+
headers = { 'x-api-project-id' => project_id }
|
79
|
+
response = self.api '/v1/registrationtokens/', 'GET', headers
|
80
|
+
|
81
|
+
return response['data'][0] unless response['data'].empty?
|
82
|
+
nil
|
83
|
+
end
|
84
|
+
|
85
|
+
# creates a registration token for a project
|
86
|
+
def create_registration_token(project_id)
|
87
|
+
headers = { 'x-api-project-id' => project_id }
|
88
|
+
self.api '/v1/registrationtokens/', 'POST', headers
|
89
|
+
end
|
90
|
+
|
91
|
+
# configures rancher settings
|
92
|
+
def configure_setting(setting, value)
|
93
|
+
self.api "/v1/activesettings/#{setting}", 'PUT', nil, 'value' => value
|
94
|
+
end
|
95
|
+
|
96
|
+
# deactivates a host in rancher to avoid being scheduled on
|
97
|
+
def deactivate_host(project_id, host_id)
|
98
|
+
headers = { 'x-api-project-id' => project_id }
|
99
|
+
self.api "/v1/projects/#{project_id}/hosts/#{host_id}/?action=deactivate", 'POST'
|
100
|
+
end
|
101
|
+
|
102
|
+
protected
|
103
|
+
|
104
|
+
def api(path, type = 'GET', headers = nil, data = nil)
|
105
|
+
# define the connection uri to the rancher server
|
106
|
+
uri = URI("http://#{@hostname}:#{@port}#{path}")
|
107
|
+
|
108
|
+
# cheap throttle to avoid connection errors due
|
109
|
+
# to too many requests in a short time
|
110
|
+
sleep 0.1
|
111
|
+
|
112
|
+
# attempt to start the http connection
|
113
|
+
begin
|
114
|
+
Net::HTTP.start(uri.host, uri.port) do |http|
|
115
|
+
case type
|
116
|
+
when 'GET'
|
117
|
+
request = Net::HTTP::Get.new uri.request_uri
|
118
|
+
when 'POST'
|
119
|
+
request = Net::HTTP::Post.new uri.request_uri
|
120
|
+
request['Accept'] = 'application/json'
|
121
|
+
request['Content-Type'] = 'application/json'
|
122
|
+
data = {} if data.nil?
|
123
|
+
when 'PUT'
|
124
|
+
request = Net::HTTP::Put.new uri.request_uri
|
125
|
+
request['Accept'] = 'application/json'
|
126
|
+
request['Content-Type'] = 'application/json'
|
127
|
+
data = {} if data.nil?
|
128
|
+
end
|
129
|
+
|
130
|
+
# set any supplied headers
|
131
|
+
unless headers.nil?
|
132
|
+
headers.each do |key, value|
|
133
|
+
request.add_field key, value
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
# set data for the request
|
138
|
+
unless data.nil?
|
139
|
+
request.set_form_data data
|
140
|
+
end
|
141
|
+
|
142
|
+
# make the request
|
143
|
+
response = http.request request
|
144
|
+
|
145
|
+
# if the response code is not 2xx, then errror
|
146
|
+
unless response.code =~ /20[0-9]/
|
147
|
+
raise Errors::HttpResponseCode,
|
148
|
+
:method => type,
|
149
|
+
:host => @hostname,
|
150
|
+
:port => @port,
|
151
|
+
:path => path,
|
152
|
+
:code => response.code,
|
153
|
+
:error => response.body
|
154
|
+
end
|
155
|
+
|
156
|
+
# parse the JSON response and return an object
|
157
|
+
return JSON.parse response.body
|
158
|
+
end
|
159
|
+
rescue Exception => e
|
160
|
+
raise Errors::ApiConnectionError,
|
161
|
+
:host => @hostname,
|
162
|
+
:port => @port,
|
163
|
+
:error => e.message
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
data/locales/en.yml
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
en:
|
2
|
+
vagrant_rancher:
|
3
|
+
errors:
|
4
|
+
generic_error: |-
|
5
|
+
The vagrant-rancher plugin encountered an error.
|
6
|
+
docker_connection: |-
|
7
|
+
Could not connect to Docker daemon.
|
8
|
+
rancher_server_container: |-
|
9
|
+
Could not start the rancher server container. For more details,
|
10
|
+
please check the logs of the failed container by running the
|
11
|
+
following command on the Docker host.
|
12
|
+
|
13
|
+
docker logs rancher-server
|
14
|
+
rancher_agent_container: |-
|
15
|
+
Could not start the rancher agent bootstrap container. For more
|
16
|
+
details, please check the logs of the failed container by running
|
17
|
+
the following command on the Docker host.
|
18
|
+
|
19
|
+
docker logs rancher-agent-bootstrap
|
20
|
+
api_connection_timeout: |-
|
21
|
+
Error waiting for API to become available for
|
22
|
+
endpoint http://%{host}:%{port}.
|
23
|
+
api_connection_error: |-
|
24
|
+
There was an error connecting to the Rancher API endpoint at
|
25
|
+
http://%{host}:%{port}
|
26
|
+
|
27
|
+
The error returned was
|
28
|
+
|
29
|
+
%{error}
|
30
|
+
agent_registration_timeout: |-
|
31
|
+
Timeout waiting for agent to register to the Default project.
|
32
|
+
http_response_code: |-
|
33
|
+
Received a status code of %{code} when calling '%{method}' on
|
34
|
+
the Rancher API.
|
35
|
+
|
36
|
+
http://%{host}:%{port}%{path}
|
37
|
+
|
38
|
+
The error returned was
|
39
|
+
|
40
|
+
%{error}
|
41
|
+
project_not_found: |-
|
42
|
+
Unable to find project 'Default' in Rancher
|
43
|
+
host_not_found: |-
|
44
|
+
The Vagrant guest was not found in project %{project_id}
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'vagrant-rancher/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'vagrant-rancher'
|
8
|
+
spec.version = VagrantPlugins::Rancher::VERSION
|
9
|
+
spec.authors = ['nextrevision']
|
10
|
+
spec.email = ['notarobot@nextrevision.net']
|
11
|
+
|
12
|
+
spec.summary = 'Vagrant plugin to bootstrap a Rancher environment.'
|
13
|
+
spec.description = 'Vagrant plugin to install a Rancher server and agents on all Vagrant guests.'
|
14
|
+
spec.homepage = 'https://github.com/nextrevision/vagrant-rancher'
|
15
|
+
spec.license = 'MIT'
|
16
|
+
|
17
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
18
|
+
spec.bindir = 'exe'
|
19
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
20
|
+
spec.require_paths = ['lib', 'locales']
|
21
|
+
|
22
|
+
spec.add_development_dependency 'bundler', '~> 1.11'
|
23
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
24
|
+
end
|
metadata
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: vagrant-rancher
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- nextrevision
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-03-18 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.11'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.11'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ~>
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
description: Vagrant plugin to install a Rancher server and agents on all Vagrant
|
42
|
+
guests.
|
43
|
+
email:
|
44
|
+
- notarobot@nextrevision.net
|
45
|
+
executables: []
|
46
|
+
extensions: []
|
47
|
+
extra_rdoc_files: []
|
48
|
+
files:
|
49
|
+
- .gitignore
|
50
|
+
- .rubocop.yml
|
51
|
+
- Gemfile
|
52
|
+
- LICENSE.txt
|
53
|
+
- README.md
|
54
|
+
- Rakefile
|
55
|
+
- examples/Vagrantfile
|
56
|
+
- examples/Vagrantfile.rancheros
|
57
|
+
- examples/vagrant_rancheros_guest_plugin.rb
|
58
|
+
- lib/vagrant-rancher.rb
|
59
|
+
- lib/vagrant-rancher/config.rb
|
60
|
+
- lib/vagrant-rancher/errors.rb
|
61
|
+
- lib/vagrant-rancher/plugin.rb
|
62
|
+
- lib/vagrant-rancher/provisioner.rb
|
63
|
+
- lib/vagrant-rancher/rancher.rb
|
64
|
+
- lib/vagrant-rancher/version.rb
|
65
|
+
- locales/en.yml
|
66
|
+
- vagrant-rancher.gemspec
|
67
|
+
homepage: https://github.com/nextrevision/vagrant-rancher
|
68
|
+
licenses:
|
69
|
+
- MIT
|
70
|
+
metadata: {}
|
71
|
+
post_install_message:
|
72
|
+
rdoc_options: []
|
73
|
+
require_paths:
|
74
|
+
- lib
|
75
|
+
- locales
|
76
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
77
|
+
requirements:
|
78
|
+
- - '>='
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: '0'
|
81
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
82
|
+
requirements:
|
83
|
+
- - '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
requirements: []
|
87
|
+
rubyforge_project:
|
88
|
+
rubygems_version: 2.0.14
|
89
|
+
signing_key:
|
90
|
+
specification_version: 4
|
91
|
+
summary: Vagrant plugin to bootstrap a Rancher environment.
|
92
|
+
test_files: []
|