iface 0.1.3 → 0.1.4
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 +4 -4
- data/lib/iface.rb +1 -0
- data/lib/iface/config_file.rb +70 -23
- data/lib/iface/ip_address.rb +89 -4
- data/lib/iface/value_set.rb +34 -19
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fc2fdecabc038ea8a83b38920c8dff34d60a7f4d
|
4
|
+
data.tar.gz: afa9611dacfb1807fe1415d9ce3233a143a934db
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7dab1b175a9bd0e556529562aa060daabd8e56c3e830bfbade0c858ef99d9f0605650ba3879556b03b6c9240df4b8f9fb5a9cdeab502b1bb8e34c7b4cf8de2d8
|
7
|
+
data.tar.gz: 5bc90e93bfe86c604d6aadd650bed52a774056788ff5f94ba66a69403f1a9545beab65bc4b9128968b46a7b186a0abd4a5676ce244af7a80a138cd03a26ec50f
|
data/lib/iface.rb
CHANGED
data/lib/iface/config_file.rb
CHANGED
@@ -22,11 +22,10 @@ module Iface
|
|
22
22
|
def self.create(filename, io)
|
23
23
|
fname = File.split(filename).last
|
24
24
|
device, range_num, clone_num = parse_filename(fname)
|
25
|
-
vars = ValueSet.new(io)
|
26
25
|
|
27
26
|
FILE_TYPES.each do |klass|
|
28
|
-
if klass.recognize?(device, range_num, clone_num
|
29
|
-
return klass.new(filename, device, range_num, clone_num,
|
27
|
+
if klass.recognize?(device, range_num, clone_num)
|
28
|
+
return klass.new(filename, device, range_num, clone_num, io)
|
30
29
|
end
|
31
30
|
end
|
32
31
|
|
@@ -40,7 +39,7 @@ module Iface
|
|
40
39
|
[device, range_num&.to_i, clone_num&.to_i]
|
41
40
|
end
|
42
41
|
|
43
|
-
def self.recognize?(_device, _range_num, _clone_num
|
42
|
+
def self.recognize?(_device, _range_num, _clone_num)
|
44
43
|
false
|
45
44
|
end
|
46
45
|
|
@@ -48,10 +47,10 @@ module Iface
|
|
48
47
|
name.split('::').last[0..-5].decamelize.to_sym if name.match?(/File\Z/)
|
49
48
|
end
|
50
49
|
|
51
|
-
def initialize(filename, device, _range_num, _clone_num,
|
50
|
+
def initialize(filename, device, _range_num, _clone_num, io)
|
52
51
|
@filename = filename
|
53
52
|
@device = device
|
54
|
-
@vars =
|
53
|
+
@vars = value_set_class.new(io)
|
55
54
|
end
|
56
55
|
|
57
56
|
def static?
|
@@ -61,32 +60,80 @@ module Iface
|
|
61
60
|
def include?(_ip)
|
62
61
|
raise NotImplementedError
|
63
62
|
end
|
63
|
+
|
64
|
+
def value_set_class
|
65
|
+
ValueSet
|
66
|
+
end
|
67
|
+
|
68
|
+
def to_s
|
69
|
+
@vars.to_s
|
70
|
+
end
|
64
71
|
end
|
65
72
|
|
66
73
|
# Represents a primary config file (not loopback, range or clone file)
|
67
74
|
#
|
68
75
|
# These are files named like "ifcfg-eth0".
|
69
76
|
class PrimaryFile < ConfigFile
|
70
|
-
|
71
|
-
|
72
|
-
def self.recognize?(device, range_num, clone_num, _vars)
|
77
|
+
def self.recognize?(device, range_num, clone_num)
|
73
78
|
device != 'lo' && range_num.nil? && clone_num.nil?
|
74
79
|
end
|
75
80
|
|
76
|
-
def
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
@
|
81
|
+
def ip_address
|
82
|
+
@vars['ipaddr']
|
83
|
+
end
|
84
|
+
|
85
|
+
def ip_address=(new_ip)
|
86
|
+
@vars['ipaddr'] = new_ip
|
87
|
+
make_static
|
88
|
+
disable_nm
|
89
|
+
end
|
90
|
+
|
91
|
+
def ipv6_address
|
92
|
+
@vars['ipv6addr']
|
93
|
+
end
|
94
|
+
|
95
|
+
def ipv6_address=(new_ip)
|
96
|
+
@vars['ipv6addr'] = new_ip
|
97
|
+
make_static
|
98
|
+
disable_nm
|
99
|
+
end
|
100
|
+
|
101
|
+
def ipv6_secondaries
|
102
|
+
@vars['ipv6addr_secondaries']&.split(/\s+/)
|
103
|
+
end
|
104
|
+
|
105
|
+
def ipv6_secondaries=(new_ips)
|
106
|
+
@vars['ipv6addr_secondaries'] = new_ips
|
107
|
+
make_static
|
108
|
+
disable_nm
|
109
|
+
end
|
110
|
+
|
111
|
+
def value_set_class
|
112
|
+
PrimaryInterface
|
113
|
+
end
|
114
|
+
|
115
|
+
def make_static
|
116
|
+
@vars.make_static unless static?
|
117
|
+
end
|
118
|
+
|
119
|
+
def disable_nm
|
120
|
+
@vars.disable_nm
|
121
|
+
end
|
122
|
+
|
123
|
+
def nm_controlled?
|
124
|
+
@vars['nm_controlled'] == 'yes'
|
125
|
+
end
|
126
|
+
|
127
|
+
def use_ipv6
|
128
|
+
@vars.use_ipv6
|
82
129
|
end
|
83
130
|
|
84
131
|
def static?
|
85
|
-
|
132
|
+
@vars['bootproto'] == 'none'
|
86
133
|
end
|
87
134
|
|
88
135
|
def include?(ip)
|
89
|
-
|
136
|
+
ip_address == ip
|
90
137
|
end
|
91
138
|
end
|
92
139
|
|
@@ -96,11 +143,11 @@ module Iface
|
|
96
143
|
class CloneFile < ConfigFile
|
97
144
|
attr_reader :ip_address, :clone_num
|
98
145
|
|
99
|
-
def self.recognize?(_device, _range_num, clone_num
|
146
|
+
def self.recognize?(_device, _range_num, clone_num)
|
100
147
|
!clone_num.nil?
|
101
148
|
end
|
102
149
|
|
103
|
-
def initialize(filename, device, _range_num, clone_num,
|
150
|
+
def initialize(filename, device, _range_num, clone_num, io)
|
104
151
|
super
|
105
152
|
@ip_address = vars['ipaddr']
|
106
153
|
@clone_num = clone_num
|
@@ -121,11 +168,11 @@ module Iface
|
|
121
168
|
class RangeFile < ConfigFile
|
122
169
|
attr_reader :start_clone_num
|
123
170
|
|
124
|
-
def self.recognize?(_device, range_num, _clone_num
|
171
|
+
def self.recognize?(_device, range_num, _clone_num)
|
125
172
|
!range_num.nil?
|
126
173
|
end
|
127
174
|
|
128
|
-
def initialize(filename, device, range_num, clone_num,
|
175
|
+
def initialize(filename, device, range_num, clone_num, io)
|
129
176
|
super
|
130
177
|
@start_ip_num = string_to_ip_num(vars['ipaddr_start'])
|
131
178
|
@end_ip_num = string_to_ip_num(vars['ipaddr_end'])
|
@@ -156,11 +203,11 @@ module Iface
|
|
156
203
|
|
157
204
|
# Represents a loopback file (device "lo")
|
158
205
|
class LoopbackFile < ConfigFile
|
159
|
-
def self.recognize?(device, _range_num, _clone_num
|
206
|
+
def self.recognize?(device, _range_num, _clone_num)
|
160
207
|
device == 'lo'
|
161
208
|
end
|
162
209
|
|
163
|
-
def initialize(filename, device, range_num, _clone_num,
|
210
|
+
def initialize(filename, device, range_num, _clone_num, io)
|
164
211
|
super
|
165
212
|
@ip_address = vars['ipaddr']
|
166
213
|
end
|
data/lib/iface/ip_address.rb
CHANGED
@@ -3,12 +3,97 @@
|
|
3
3
|
require 'ipaddr'
|
4
4
|
|
5
5
|
module Iface
|
6
|
-
# Represents an IP address including
|
6
|
+
# Represents an IP address including prefix length
|
7
7
|
class IpAddress
|
8
|
-
def
|
9
|
-
|
10
|
-
|
8
|
+
def self.create(str)
|
9
|
+
ipaddr = IPAddr.new(str)
|
10
|
+
(ipaddr.ipv4? ? IpV4Address : IpV6Address).new(ipaddr)
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize(ip_address)
|
14
|
+
@ipaddr = ip_address.is_a?(IPAddr) ? ip_address : IPAddr.new(ip_address)
|
15
|
+
@mask_addr = @ipaddr.instance_eval { @mask_addr }
|
16
|
+
@_bitmask = @mask_addr.to_s(2)
|
11
17
|
@inverse_mask_addr = @_bitmask.tr('01', '10').to_i(2)
|
12
18
|
end
|
19
|
+
|
20
|
+
def cidr_mask
|
21
|
+
case diff = full_mask - @mask_addr
|
22
|
+
when 0
|
23
|
+
full_cidr_mask
|
24
|
+
when 1
|
25
|
+
full_cidr_mask - 1
|
26
|
+
else
|
27
|
+
full_cidr_mask - Math.log2(diff).ceil
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def to_i
|
32
|
+
@ipaddr.to_i
|
33
|
+
end
|
34
|
+
|
35
|
+
def to_s
|
36
|
+
@ipaddr.to_s
|
37
|
+
end
|
38
|
+
|
39
|
+
def full_mask
|
40
|
+
raise NotImplementedError
|
41
|
+
end
|
42
|
+
|
43
|
+
def full_cidr_mask
|
44
|
+
raise NotImplementedError
|
45
|
+
end
|
46
|
+
|
47
|
+
def ==(other)
|
48
|
+
self.class == other.class && __state__ == other.__state__
|
49
|
+
end
|
50
|
+
|
51
|
+
protected
|
52
|
+
|
53
|
+
def __state__
|
54
|
+
@ipaddr
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# Represents an IPv4 address
|
59
|
+
class IpV4Address < IpAddress
|
60
|
+
def self.from_numeric(numeric)
|
61
|
+
new(IPAddr.new_ntoh([numeric].pack('N')))
|
62
|
+
end
|
63
|
+
|
64
|
+
def initialize(ip_address)
|
65
|
+
super
|
66
|
+
raise ArgumentError, "Expected IPv4, got IPv6: #{ip_address}" unless @ipaddr.ipv4?
|
67
|
+
end
|
68
|
+
|
69
|
+
def full_mask
|
70
|
+
IPAddr::IN4MASK
|
71
|
+
end
|
72
|
+
|
73
|
+
def full_cidr_mask
|
74
|
+
32
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
# Represents an IPv6 address
|
79
|
+
class IpV6Address < IpAddress
|
80
|
+
MASK_32 = 0xffffffffffffffff
|
81
|
+
|
82
|
+
def self.from_numeric(numeric)
|
83
|
+
new(IPAddr.new_ntoh([(numeric >> 96), (numeric >> 64) & MASK_32, (numeric >> 32) & MASK_32, numeric & MASK_32].pack('N*')))
|
84
|
+
end
|
85
|
+
|
86
|
+
def initialize(ip_address)
|
87
|
+
super
|
88
|
+
raise ArgumentError, "Expected IPv6, got IPv4: #{ip_address}" unless @ipaddr.ipv6?
|
89
|
+
end
|
90
|
+
|
91
|
+
def full_mask
|
92
|
+
IPAddr::IN6MASK
|
93
|
+
end
|
94
|
+
|
95
|
+
def full_cidr_mask
|
96
|
+
128
|
97
|
+
end
|
13
98
|
end
|
14
99
|
end
|
data/lib/iface/value_set.rb
CHANGED
@@ -1,30 +1,16 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative 'value_set/pair'
|
4
|
+
|
3
5
|
module Iface
|
4
|
-
# Represents a set of NAME=value pairs
|
6
|
+
# Represents a generic set of NAME=value pairs
|
5
7
|
class ValueSet
|
6
|
-
# Represents a NAME=value pair
|
7
|
-
class Pair
|
8
|
-
attr_reader :name, :value
|
9
|
-
|
10
|
-
def initialize(line)
|
11
|
-
match = line.match(/(^[A-Z0-9_]+)="?(.*?)"?$/)
|
12
|
-
raise ArgumentError, "Expected pattern NAME=value; got #{line.inspect}" unless match
|
13
|
-
@name = match[1]
|
14
|
-
@value = match[2]&.sub(/^"/, '')&.sub(/"$/, '')
|
15
|
-
end
|
16
|
-
|
17
|
-
def to_s
|
18
|
-
"#{@name}=\"#{@value}\""
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
8
|
def initialize(io)
|
23
9
|
@vars = {}
|
24
10
|
io.each_line do |line|
|
25
11
|
edited_line = line.sub(/#.*$/, '').strip
|
26
12
|
next if edited_line.empty?
|
27
|
-
pair = Pair.
|
13
|
+
pair = Pair.create(edited_line, value_set: self)
|
28
14
|
@vars[pair.name] = pair
|
29
15
|
end
|
30
16
|
end
|
@@ -33,13 +19,42 @@ module Iface
|
|
33
19
|
@vars[name.upcase]&.value
|
34
20
|
end
|
35
21
|
|
22
|
+
def []=(name, value)
|
23
|
+
key = name.upcase
|
24
|
+
if @vars.key?(key)
|
25
|
+
@vars[key].value = value
|
26
|
+
else
|
27
|
+
@vars[key] = Pair.create(key, value, value_set: self)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def fetch_raw(name)
|
32
|
+
@vars[name.upcase]&.raw_value
|
33
|
+
end
|
34
|
+
|
36
35
|
def key?(name)
|
37
36
|
@vars.key?(name.upcase)
|
38
37
|
end
|
39
38
|
alias has_key? key?
|
40
39
|
|
41
40
|
def to_s
|
42
|
-
@vars.values.map(&:to_s).join("\n")
|
41
|
+
"#{@vars.values.map(&:to_s).join("\n")}\n"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# Represents a set of NAME=value pairs that would appear in a primary
|
46
|
+
# interface file, e.g. one named "ifcfg-eth0"
|
47
|
+
class PrimaryInterface < ValueSet
|
48
|
+
def make_static
|
49
|
+
self['BOOTPROTO'] = 'none'
|
50
|
+
end
|
51
|
+
|
52
|
+
def disable_nm
|
53
|
+
self['NM_CONTROLLED'] = 'no'
|
54
|
+
end
|
55
|
+
|
56
|
+
def use_ipv6
|
57
|
+
self['IPV6INIT'] = 'yes'
|
43
58
|
end
|
44
59
|
end
|
45
60
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: iface
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jim Cain
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-09-
|
11
|
+
date: 2017-09-28 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description:
|
14
14
|
email: camelotjim@jcain.net
|