drbd 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +53 -5
- data/VERSION +1 -1
- data/lib/drbd.rb +73 -20
- metadata +4 -4
data/README.rdoc
CHANGED
@@ -10,34 +10,82 @@ Ruby wrapper for DRBD
|
|
10
10
|
|
11
11
|
== Limitations
|
12
12
|
|
13
|
-
* Just one-morning prototype
|
14
13
|
* Best with drbd version > 8.3.7
|
14
|
+
* Hostname used for connection must be one of hostnames in drbd.conf (FQDN ideally)
|
15
|
+
* It'sJust one-morning's prototype, take patience
|
15
16
|
* No tests
|
16
17
|
* No documentation
|
17
18
|
* Absolutely no warranty, use it at your own risk
|
18
19
|
|
20
|
+
== Installation
|
21
|
+
|
22
|
+
<code>gem install drbd</code>
|
19
23
|
|
20
|
-
== How it works
|
21
24
|
|
25
|
+
== How it works
|
26
|
+
# simply fetch data from remote host
|
22
27
|
d = Drbd.new("fqdn.domain.tld")
|
23
28
|
|
29
|
+
# you can specify command to be executed
|
30
|
+
|
31
|
+
d = Drbd.new("fqdn.domain.tld", :command => 'sudo /sbin/drbdadm')
|
32
|
+
|
33
|
+
# obtain array of configured resources
|
24
34
|
r = d.resources.first
|
25
35
|
|
36
|
+
# get resource name
|
26
37
|
r.name
|
27
38
|
|
39
|
+
# get resource protocol
|
40
|
+
r.protocol
|
41
|
+
|
42
|
+
# get hosts for resource
|
43
|
+
r.hosts
|
44
|
+
|
45
|
+
# get status for resource
|
46
|
+
r.status
|
47
|
+
|
48
|
+
# get node addresses
|
28
49
|
r.hosts.map{|h| h.address }
|
29
50
|
|
51
|
+
# get status
|
52
|
+
# resource status is hash with keys:
|
53
|
+
# [:cs, :resynced_percent, :minor, :ro1, :ds1, :ro2, :ds2, :name]
|
30
54
|
r.status
|
31
55
|
|
56
|
+
# find resource by name
|
32
57
|
r = d.find_resource_by_name("r0")
|
33
58
|
|
34
|
-
|
35
|
-
|
59
|
+
# find resource by backing disk
|
36
60
|
r = d.find_resource_by_disk("/dev/volgroup-logvolume--name")
|
37
61
|
|
62
|
+
# true if both of devices are UpToDate
|
63
|
+
r.consinstent?
|
64
|
+
|
65
|
+
# true if resynced_percent is present in status
|
38
66
|
r.resync_running?
|
39
67
|
|
40
|
-
|
68
|
+
# true if resource status is "Connected"
|
69
|
+
r.up?
|
70
|
+
|
71
|
+
# true if resource status is "Unconfigured"
|
72
|
+
r.down?
|
73
|
+
|
74
|
+
# perform drbdadm up on resource (use at your own risk!)
|
75
|
+
r.up!
|
76
|
+
|
77
|
+
# perform drbdadm down on resource (use at your own risk!)
|
78
|
+
r.down!
|
79
|
+
|
80
|
+
# perform forced drbdadm create-md on resource (use at your own risk!)
|
81
|
+
r.init_metadata
|
82
|
+
|
83
|
+
|
84
|
+
== TODO
|
85
|
+
|
86
|
+
* Replace IO.popen("ssh ...") with native ruby net/ssh
|
87
|
+
* Add states to actions (analyze exit status)
|
88
|
+
* Test suite
|
41
89
|
|
42
90
|
|
43
91
|
== Copyright
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.1.
|
1
|
+
0.1.1
|
data/lib/drbd.rb
CHANGED
@@ -1,24 +1,29 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'nokogiri'
|
3
3
|
class DRBD
|
4
|
-
attr_reader :resources
|
4
|
+
attr_reader :resources, :host, :command
|
5
5
|
|
6
|
-
def initialize host
|
6
|
+
def initialize host, opts = {}
|
7
|
+
parse_opts opts
|
7
8
|
@host = host
|
8
9
|
load!
|
9
10
|
end
|
10
11
|
|
12
|
+
def parse_opts opts
|
13
|
+
opts[:command].nil? ? @command = "sudo /sbin/drbdadm" : @command = opts[:command]
|
14
|
+
end
|
15
|
+
|
11
16
|
def load!
|
12
17
|
load_resources!
|
13
18
|
load_status!
|
14
19
|
end
|
15
20
|
|
16
21
|
def load_resources!
|
17
|
-
@resources =
|
22
|
+
@resources = Resource.load_config(IO.popen("ssh #{@host} \"#{@command} dump-xml\""), self)
|
18
23
|
end
|
19
24
|
|
20
25
|
def load_status!
|
21
|
-
raw_xml = IO.popen("ssh #{@host} \"
|
26
|
+
raw_xml = IO.popen("ssh #{@host} \"#{@command} status\"")
|
22
27
|
statuses = Status.new(raw_xml).resources
|
23
28
|
set_resources_status statuses
|
24
29
|
end
|
@@ -37,35 +42,33 @@ class DRBD
|
|
37
42
|
def find_resource_by_disk disk_name
|
38
43
|
@resources.select{|r| r.hosts.inject(false){|sum,h| (h.disk == disk_name && sum == false) ? true : sum}}.first
|
39
44
|
end
|
40
|
-
|
41
|
-
class Config
|
42
|
-
attr_reader :xml
|
43
|
-
|
44
|
-
def initialize xml
|
45
|
-
@xml = Nokogiri::XML(xml)
|
46
|
-
end
|
47
|
-
|
48
|
-
def resources
|
49
|
-
@xml.xpath("//config/resource").map{|r| Resource.new r }
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
45
|
+
|
53
46
|
class Host
|
54
|
-
attr_reader :name, :device, :disk, :address, :meta_disk
|
47
|
+
attr_reader :name, :device, :disk, :address, :meta_disk, :minor
|
55
48
|
def initialize host
|
56
49
|
@name = host['name']
|
57
50
|
@device = host.xpath(".//device").text
|
51
|
+
@minor = host.xpath(".//device").attr("minor").value
|
58
52
|
@disk = host.xpath(".//disk").text
|
59
53
|
@address = host.xpath(".//address").text
|
54
|
+
@family = host.xpath(".//address").attr("family").value
|
55
|
+
@port = host.xpath(".//address").attr("port").value
|
60
56
|
@meta_disk = host.xpath(".//meta-disk").text
|
61
57
|
end
|
62
58
|
end
|
63
59
|
|
64
60
|
class Resource
|
65
|
-
attr_reader :name, :
|
61
|
+
attr_reader :name, :protocol, :hosts, :drbd
|
66
62
|
attr_accessor :status
|
67
|
-
|
63
|
+
|
64
|
+
def self.load_config raw, drbd
|
65
|
+
xml = Nokogiri::XML(raw)
|
66
|
+
xml.xpath("//config/resource").map{|r| Resource.new r, drbd }
|
67
|
+
end
|
68
|
+
|
69
|
+
def initialize nokogiri_resource, drbd
|
68
70
|
xml = nokogiri_resource
|
71
|
+
@drbd = drbd
|
69
72
|
@name = xml['name']
|
70
73
|
@protocol = xml['protocol']
|
71
74
|
@hosts = xml.xpath(".//host").to_a.map do |host_xml|
|
@@ -80,6 +83,53 @@ class DRBD
|
|
80
83
|
def consistent?
|
81
84
|
status[:ds1] == "UpToDate" && status[:ds2] == "UpToDate" && status[:resynced_percent] == nil
|
82
85
|
end
|
86
|
+
|
87
|
+
def up?
|
88
|
+
status[:cs] == "Connected" || status[:cs] == "SyncTarget"
|
89
|
+
end
|
90
|
+
|
91
|
+
def down?
|
92
|
+
status[:cs] == "Unconfigured"
|
93
|
+
end
|
94
|
+
|
95
|
+
def up!
|
96
|
+
args = "up #{self.name}"
|
97
|
+
command = "ssh #{drbd.host} \"#{drbd.command} #{args}\""
|
98
|
+
system(command)
|
99
|
+
drbd.load_status!
|
100
|
+
end
|
101
|
+
|
102
|
+
def down!
|
103
|
+
args = "down #{self.name}"
|
104
|
+
command = "ssh #{drbd.host} \"#{drbd.command} #{args}\""
|
105
|
+
system(command)
|
106
|
+
drbd.load_status!
|
107
|
+
end
|
108
|
+
|
109
|
+
def init_metadata!
|
110
|
+
if self.down?
|
111
|
+
#drbdmeta 0 v08 /dev/mapper/dikobraz-www--emailmaster--cz_root_meta 0 create-md
|
112
|
+
command = "ssh #{drbd.host} \"sudo /sbin/drbdmeta --force #{local_minor} v08 #{local_host.meta_disk} 0 create-md\""
|
113
|
+
system(command)
|
114
|
+
return true
|
115
|
+
else
|
116
|
+
return false
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
|
121
|
+
def local_host
|
122
|
+
hosts.select{|h| h.name == drbd.host}.first
|
123
|
+
end
|
124
|
+
|
125
|
+
def local_minor
|
126
|
+
retrurn nil if local_host == nil
|
127
|
+
local_host.minor
|
128
|
+
end
|
129
|
+
|
130
|
+
def state
|
131
|
+
status[:cs]
|
132
|
+
end
|
83
133
|
end
|
84
134
|
|
85
135
|
class Status
|
@@ -105,3 +155,6 @@ class DRBD
|
|
105
155
|
end
|
106
156
|
end
|
107
157
|
|
158
|
+
D = DRBD.new("dikobraz.vmin.cz")
|
159
|
+
require 'irb'
|
160
|
+
IRB.start
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: drbd
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 25
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 1
|
9
|
-
-
|
10
|
-
version: 0.1.
|
9
|
+
- 1
|
10
|
+
version: 0.1.1
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Adam Kliment
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-01-
|
18
|
+
date: 2011-01-18 00:00:00 +01:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|