File: ovs.rb

package info (click to toggle)
puppet-module-vswitch 23.0.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 612 kB
  • sloc: ruby: 2,195; python: 33; makefile: 10; sh: 10
file content (164 lines) | stat: -rw-r--r-- 4,563 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
require File.join(File.dirname(__FILE__), '..','..','..', 'puppet/provider/ovs')

Puppet::Type.type(:vs_port).provide(
  :ovs,
  :parent => Puppet::Provider::Ovs
) do

  UUID_RE ||= /[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[89aAbB][a-f0-9]{3}-[a-f0-9]{12}/

  commands :vsctl => 'ovs-vsctl'

  has_feature :bonding
  has_feature :vlan
  has_feature :interface_type

  def exists?
    vsctl('list-ports', @resource[:bridge]).split("\n").include? @resource[:port]
  rescue Puppet::ExecutionFailure => e
    return false
  end

  def create
    if ! bridge.exists?
      raise Puppet::Error, "Bridge #{@resource[:bridge]} does not exist"
    end

    # create with first interface, other interfaces will be added later when synchronizing properties
    if @resource[:interface_type] == :internal
       vsctl('add-port', @resource[:bridge], @resource[:port], '--', 'set', 'Interface', @resource[:port], 'type=internal')
    else
      vsctl('--', '--id=@iface0', 'create', 'Interface', "name=#{@resource[:interface][0]}", '--', 'add-port', @resource[:bridge], @resource[:port], 'interfaces=@iface0')
    end

    # synchronize properties
    # Only sync those properties actually supported by the provider. This
    # allows this provider to be used as a base class for providers not
    # supporting all properties.
    sync_properties = []
    if @resource.provider.class.feature?(:bonding)
      sync_properties += [:interface,
                          :bond_mode,
                          :lacp,
                          :lacp_time,
                         ]
    end
    if @resource.provider.class.feature?(:vlan)
      sync_properties += [:vlan_mode,
                          :vlan_tag,
                          :vlan_trunks,
                         ]
    end
    if @resource.provider.class.feature?(:interface_type)
      sync_properties += [:interface_type,
                         ]
    end
    for prop_name in sync_properties
      property = @resource.property(prop_name)
      property.sync unless property.safe_insync?(property.retrieve)
    end
  end

  def destroy
    vsctl('del-port', @resource[:bridge], @resource[:port])
  end

  def interface
    get_port_interface_property('name')
  end

  def interface=(value)
    # find interfaces we want to keep on the port
    keep = @resource.property(:interface).retrieve() & value
    keep_uids = keep.map { |iface| vsctl('get', 'Interface', iface, '_uuid').strip }
    new = value - keep
    args = ['--'] + new.each_with_index.map { |iface, i| ["--id=@#{i+1}", 'create', 'Interface', "name=#{iface}", '--'] }
    ifaces = (1..new.length).map { |i| "@#{i}" } + keep_uids
    args += ['set', 'Port', @resource[:port], "interfaces=#{ifaces.join(',')}"]
    vsctl(*args)
  end

  def interface_type
    types = get_port_interface_property('type').uniq
    types != nil ? types.join(' ') : :system
  end

  def interface_type=(value)
    @resource.property(:interface).retrieve.each do |iface|
      vsctl('set', 'Interface', iface, "type=#{value}")
    end
  end

  def bond_mode
    get_port_property('bond_mode')
  end

  def bond_mode=(value)
    set_port_property('bond_mode', value)
  end

  def lacp
    get_port_property('lacp')
  end

  def lacp=(value)
    set_port_property('lacp', value)
  end

  def lacp_time
    val = self.class.get_other_config('Port', @resource[:port], 'lacp-time')
    if val.nil? then '' else val.gsub(/^"|"$/, '') end
  end

  def lacp_time=(value)
    self.class.set_other_config('Port', @resource[:port], 'lacp-time', value)
  end

  def vlan_mode
    get_port_property('vlan_mode')
  end

  def vlan_mode=(value)
    set_port_property('vlan_mode', value)
  end

  def vlan_tag
    get_port_property('tag')
  end

  def vlan_tag=(value)
    set_port_property('tag', value)
  end

  def vlan_trunks
    get_port_property('trunks').scan(/\d+/)
  end

  def vlan_trunks=(value)
    set_port_property('trunks', value.join(' '))
  end

  protected

  def bridge
    @bridge ||= Puppet::Type.type(:vs_bridge).provider(:ovs).new(
      Puppet::Type::Vs_bridge.new(:title => @resource[:bridge])
    )
  end

  private

  def get_port_property(key)
    value = self.class.get_property('Port', @resource[:port], key)
    if value == '[]' then '' else value end
  end

  def set_port_property(key, value)
    self.class.set_property('Port', @resource[:port], key, value)
  end

  def get_port_interface_property(key)
    uuids = get_port_property('interfaces').scan(UUID_RE)
    uuids.map!{|id| self.class.get_property('Interface', id, key).gsub(/^"|"$/, '')}
  end
end