Repository: ansible/ansible-modules-extras

Issue:
openvswitch_port cannot set port property on the 'openvswitch' port
##### ISSUE TYPE
 - Bug Report

##### COMPONENT NAME
network/openvswitch_port.py

##### ANSIBLE VERSION
```
$ ansible --version
ansible 2.0.0.2
  config file = /etc/ansible/ansible.cfg
  configured module search path = Default w/o overrides
```

##### CONFIGURATION
N/A

##### OS / ENVIRONMENT
Managing Open vSwitch running on Ubuntu 14.04/16.04.

##### SUMMARY
For each Open vSwitch instance (such as those created by using the network/openvswitch_bridge module), an implicit 'openvswitch' port that has the same name with the bridge itself is created.  For example,
```
# ovs-vsctl add-br br0
# ovs-vsctl list port br0
_uuid               : d32b978e-e828-4c5d-a368-877b2bc676a1
bond_active_slave   : []
bond_downdelay      : 0
bond_fake_iface     : false
bond_mode           : []
bond_updelay        : 0
external_ids        : {}
fake_bridge         : false
interfaces          : [0a67c10e-e341-484a-9af2-3feb2f7539d5]
lacp                : []
mac                 : []
name                : "br0"
other_config        : {}
qos                 : []
rstp_statistics     : {}
rstp_status         : {}
statistics          : {}
status              : {}
tag                 : []
trunks              : []
vlan_mode           : []
# ovs-vsctl list interface br0
_uuid               : 0a67c10e-e341-484a-9af2-3feb2f7539d5
admin_state         : down
bfd                 : {}
bfd_status          : {}
cfm_fault           : []
cfm_fault_status    : []
cfm_flap_count      : []
cfm_health          : []
cfm_mpid            : []
cfm_remote_mpids    : []
cfm_remote_opstate  : []
duplex              : []
error               : []
external_ids        : {}
ifindex             : 1220
ingress_policing_burst: 0
ingress_policing_rate: 0
lacp_current        : []
link_resets         : 0
link_speed          : []
link_state          : down
lldp                : {}
mac                 : []
mac_in_use          : "1a:16:94:02:c9:42"
mtu                 : 1500
name                : "br0"
ofport              : 65534
ofport_request      : []
options             : {}
other_config        : {}
statistics          : {collisions=0, rx_bytes=0, rx_crc_err=0, rx_dropped=0, rx_errors=0, rx_frame_err=0, rx_over_err=0, rx_packets=0, tx_bytes=0, tx_dropped=0, tx_errors=0, tx_packets=0}
status              : {driver_name=openvswitch}
type                : internal
```

However, the 'list-ports' commands do not return this port.  For example,

```
# ovs-vsctl list-ports br0
<returns nothing>
```

Therefore, if one uses the openvswitch_port module to set properties on this port, the module would try to create this port first and result in failure (because the port already exists.)

This can be easily fixed by taking into account that a port that has the same name with the bridge itself always exists.  This is a one-line change in OVSPort.exists(), such as:

```
--- openvswitch_port.py.orig	2016-11-09 13:46:57.957148377 -0800
+++ openvswitch_port.py	2016-11-09 13:47:27.641029747 -0800
@@ -136,7 +136,7 @@
         if rtc != 0:
             self.module.fail_json(msg=err)

-        return any(port.rstrip() == self.port for port in out.split('\n'))
+        return any(port.rstrip() == self.port for port in out.split('\n')) or (self.port == self.bridge)

     def set(self, set_opt):
         """ Set attributes on a port. """
```

##### STEPS TO REPRODUCE
```
$ ansible all -m openvswitch_bridge -a 'bridge=br0'
$ ansible all -m openvswitch_port -a 'bridge=br0 port=br0 set="Port br0 tag=0"'
```

##### EXPECTED RESULTS
```
# ansible all -m openvswitch_bridge -a 'bridge=br0'
localhost | SUCCESS => {
    "changed": true
}
root@xenial:~# ansible -vvvv all -m openvswitch_port -a 'bridge=br0 port=br0 set="Port br0 tag=0"'
localhost | SUCCESS => {
    "changed": true,
    "invocation": {
        "module_args": {
            "bridge": "br0",
            "external_ids": {},
            "port": "br0",
            "set": "Port br0 tag=0",
            "state": "present",
            "timeout": 5
        },
        "module_name": "openvswitch_port"
    }
}
```

##### ACTUAL RESULTS
```
$ ansible all -m openvswitch_bridge -a 'bridge=br0'
localhost | SUCCESS => {
    "changed": true
}
$ ansible all -m openvswitch_port -a 'bridge=br0 port=br0 set="Port br0 tag=0"'
localhost | FAILED! => {
    "changed": false,
    "cmd": "ovs-vsctl -t 5 add-port br0 br0 -- set Port br0 tag=0",
    "failed": true,
    "msg": "ovs-vsctl: cannot create a port named br0 because a bridge named br0 already exists",
    "rc": 1,
    "stderr": "ovs-vsctl: cannot create a port named br0 because a bridge named br0 already exists\n",
    "stdout": "",
    "stdout_lines": []
}
```
The 'add-port br0 br0' part shouldn't be part of the command to be run.
openvswitch_port cannot set port property on the 'openvswitch' port
##### ISSUE TYPE
 - Bug Report

##### COMPONENT NAME
network/openvswitch_port.py

##### ANSIBLE VERSION
```
$ ansible --version
ansible 2.0.0.2
  config file = /etc/ansible/ansible.cfg
  configured module search path = Default w/o overrides
```

##### CONFIGURATION
N/A

##### OS / ENVIRONMENT
Managing Open vSwitch running on Ubuntu 14.04/16.04.

##### SUMMARY
For each Open vSwitch instance (such as those created by using the network/openvswitch_bridge module), an implicit 'openvswitch' port that has the same name with the bridge itself is created.  For example,
```
# ovs-vsctl add-br br0
# ovs-vsctl list port br0
_uuid               : d32b978e-e828-4c5d-a368-877b2bc676a1
bond_active_slave   : []
bond_downdelay      : 0
bond_fake_iface     : false
bond_mode           : []
bond_updelay        : 0
external_ids        : {}
fake_bridge         : false
interfaces          : [0a67c10e-e341-484a-9af2-3feb2f7539d5]
lacp                : []
mac                 : []
name                : "br0"
other_config        : {}
qos                 : []
rstp_statistics     : {}
rstp_status         : {}
statistics          : {}
status              : {}
tag                 : []
trunks              : []
vlan_mode           : []
# ovs-vsctl list interface br0
_uuid               : 0a67c10e-e341-484a-9af2-3feb2f7539d5
admin_state         : down
bfd                 : {}
bfd_status          : {}
cfm_fault           : []
cfm_fault_status    : []
cfm_flap_count      : []
cfm_health          : []
cfm_mpid            : []
cfm_remote_mpids    : []
cfm_remote_opstate  : []
duplex              : []
error               : []
external_ids        : {}
ifindex             : 1220
ingress_policing_burst: 0
ingress_policing_rate: 0
lacp_current        : []
link_resets         : 0
link_speed          : []
link_state          : down
lldp                : {}
mac                 : []
mac_in_use          : "1a:16:94:02:c9:42"
mtu                 : 1500
name                : "br0"
ofport              : 65534
ofport_request      : []
options             : {}
other_config        : {}
statistics          : {collisions=0, rx_bytes=0, rx_crc_err=0, rx_dropped=0, rx_errors=0, rx_frame_err=0, rx_over_err=0, rx_packets=0, tx_bytes=0, tx_dropped=0, tx_errors=0, tx_packets=0}
status              : {driver_name=openvswitch}
type                : internal
```

However, the 'list-ports' commands do not return this port.  For example,

```
# ovs-vsctl list-ports br0
<returns nothing>
```

Therefore, if one uses the openvswitch_port module to set properties on this port, the module would try to create this port first and result in failure (because the port already exists.)

This can be easily fixed by taking into account that a port that has the same name with the bridge itself always exists.  This is a one-line change in OVSPort.exists(), such as:

```
--- openvswitch_port.py.orig	2016-11-09 13:46:57.957148377 -0800
+++ openvswitch_port.py	2016-11-09 13:47:27.641029747 -0800
@@ -136,7 +136,7 @@
         if rtc != 0:
             self.module.fail_json(msg=err)

-        return any(port.rstrip() == self.port for port in out.split('\n'))
+        return any(port.rstrip() == self.port for port in out.split('\n')) or (self.port == self.bridge)

     def set(self, set_opt):
         """ Set attributes on a port. """
```

##### STEPS TO REPRODUCE
```
$ ansible all -m openvswitch_bridge -a 'bridge=br0'
$ ansible all -m openvswitch_port -a 'bridge=br0 port=br0 set="Port br0 tag=0"'
```

##### EXPECTED RESULTS
```
# ansible all -m openvswitch_bridge -a 'bridge=br0'
localhost | SUCCESS => {
    "changed": true
}
root@xenial:~# ansible -vvvv all -m openvswitch_port -a 'bridge=br0 port=br0 set="Port br0 tag=0"'
localhost | SUCCESS => {
    "changed": true,
    "invocation": {
        "module_args": {
            "bridge": "br0",
            "external_ids": {},
            "port": "br0",
            "set": "Port br0 tag=0",
            "state": "present",
            "timeout": 5
        },
        "module_name": "openvswitch_port"
    }
}
```

##### ACTUAL RESULTS
```
$ ansible all -m openvswitch_bridge -a 'bridge=br0'
localhost | SUCCESS => {
    "changed": true
}
$ ansible all -m openvswitch_port -a 'bridge=br0 port=br0 set="Port br0 tag=0"'
localhost | FAILED! => {
    "changed": false,
    "cmd": "ovs-vsctl -t 5 add-port br0 br0 -- set Port br0 tag=0",
    "failed": true,
    "msg": "ovs-vsctl: cannot create a port named br0 because a bridge named br0 already exists",
    "rc": 1,
    "stderr": "ovs-vsctl: cannot create a port named br0 because a bridge named br0 already exists\n",
    "stdout": "",
    "stdout_lines": []
}
```
The 'add-port br0 br0' part shouldn't be part of the command to be run.


Discussion:
<!-- @howardtsai: Thanks for filing this bug report! -->

@stygstra ping, this issue is waiting for your response.
[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)

<!--- boilerplate: issue_bug_new --->

<!-- @howardtsai: Thanks for filing this bug report! -->

@stygstra ping, this issue is waiting for your response.
[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)

<!--- boilerplate: issue_bug_new --->


Resolving patch:
diff --git a/network/openvswitch_port.py b/network/openvswitch_port.py
--- a/network/openvswitch_port.py
+++ b/network/openvswitch_port.py
@@ -146,7 +146,7 @@ def exists(self):
         if rtc != 0:
             self.module.fail_json(msg=err)
 
-        return any(port.rstrip() == self.port for port in out.split('\n'))
+        return any(port.rstrip() == self.port for port in out.split('\n')) or self.port == self.bridge
 
     def set(self, set_opt):
         """ Set attributes on a port. """


Test patch: