drbd 0.1.0 → 0.1.1
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.
- 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
|