Repository: ansible/ansible

Issue:
Can't register a client to Katello/Satellite using subscription manager without activation key parameter
<!---
Verify first that your issue/request is not already reported on GitHub.
Also test if the latest release, and master branch are affected too.
-->

##### ISSUE TYPE
<!--- Pick one below and delete the rest: -->
 - Bug Report

##### COMPONENT NAME
<!--- Name of the module/plugin/task/feature -->
Red hat subscription module

##### ANSIBLE VERSION
<!--- Paste verbatim output from “ansible --version” between quotes below -->
```
ansible 2.3.1.0
  config file = /home/jomitsch/forklift/ansible.cfg
  configured module search path = Default w/o overrides
  python version = 2.7.13 (default, Jan 12 2017, 17:59:37) [GCC 6.3.1 20161221 (Red Hat 6.3.1-1)]

```

##### CONFIGURATION
<!---
Mention any settings you have changed/added/removed in ansible.cfg
(or using the ANSIBLE_* environment variables).
-->
```
[defaults]
callback_plugins = $PWD/playbooks/callback_plugins/
callback_whitelist = profile_tasks
nocows = 1
inventory = $PWD/playbooks/inventory/vagrant.py
roles_path = $PWD/playbooks/galaxy_roles:$PWD/user_playbooks/roles:$PWD/roles
retry_files_save_path = $HOME/.ansible/retry-files
private_key_file = $HOME/.vagrant.d/insecure_private_key
remote_user = vagrant
host_key_checking = False
```
##### OS / ENVIRONMENT
<!---
Mention the OS you are running Ansible from, and the OS you are
managing, or say “N/A” for anything that is not platform-specific.
Also mention the specific version of what you are trying to control,
e.g. if this is a network bug the version of firmware on the network device.
-->
I'm running ansible from Fedora 25 and managing a Centos 7 box

##### SUMMARY
<!--- Explain the problem briefly -->

It is impossible to register to a default organization in Katello or Satellite without an activation key.
The [docs](http://docs.ansible.com/ansible/latest/redhat_subscription_module.html) say that org_id is to be used with activation key id	

> Organization ID to use in conjunction with activationkey

I know this makes sense for the portal, but Katello/Satellite supports just registering to a specific organization without an activation key.

It looks like [this hasn't changed](https://github.com/ansible/ansible/blob/devel/lib/ansible/modules/packaging/os/redhat_subscription.py#L81) in the devel branch as well.
##### STEPS TO REPRODUCE
<!---
For bugs, show exactly how to reproduce the problem, using a minimal test-case.
For new features, show how the feature would be used.
-->
This used to work for registering a client with katello
<!--- Paste example playbooks or commands between quotes below -->
```yaml
- name: 'Install bootstrap rpm'
  yum:
    name: "http://{{ katello_client_server }}/pub/katello-ca-consumer-latest.noarch.rpm"
    state: "present"

- name: 'Register client with subscription-manager'
  redhat_subscription:
    state: "present"
    org_id: "Default_Organization"
    environment: "Library"
    username: "admin"
    password: "changeme"
```

<!--- You can also paste gist.github.com links for larger files -->

##### EXPECTED RESULTS
<!--- What did you expect to happen when running the steps above? -->
Client is succesfully registered to katello

##### ACTUAL RESULTS
<!--- What actually happened? If possible run with extra verbosity (-vvvv) -->
The playbook task fails
<!--- Paste verbatim command output between quotes below -->
```
TASK [katello_client : Register client with subscription-manager] **************
task path: /home/jomitsch/forklift/roles/katello_client/tasks/main.yml:7
Tuesday 25 July 2017  10:17:12 -0400 (0:00:30.399)       0:00:36.166 ********** 
Using module file /usr/lib/python2.7/site-packages/ansible/modules/packaging/os/redhat_subscription.py
<192.168.121.14> ESTABLISH SSH CONNECTION FOR USER: vagrant
<192.168.121.14> SSH: EXEC ssh -vvv -o UserKnownHostsFile=/dev/null -o IdentitiesOnly=yes -o ControlMaster=auto -o ControlPersist=60s -o StrictHostKeyChecking=no -o Port=22 -o 'IdentityFile="/home/jomitsch/.vagrant.d/insecure_private_key"' -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o User=vagrant -o ConnectTimeout=30 -o ControlPath=/home/jomitsch/.ansible/cp/70cce52674 192.168.121.14 '/bin/sh -c '"'"'echo ~ && sleep 0'"'"''
<192.168.121.14> (0, '/home/vagrant\n', 'OpenSSH_7.3p1, OpenSSL 1.0.2k-fips  26 Jan 2017\r\ndebug1: Reading configuration data /etc/ssh/ssh_config\r\ndebug3: /etc/ssh/ssh_config line 56: Including file /etc/ssh/ssh_config.d/05-redhat.conf depth 0\r\ndebug1: Reading configuration data /etc/ssh/ssh_config.d/05-redhat.conf\r\ndebug1: /etc/ssh/ssh_config.d/05-redhat.conf line 2: include /etc/crypto-policies/back-ends/openssh.txt matched no files\r\ndebug1: /etc/ssh/ssh_config.d/05-redhat.conf line 8: Applying options for *\r\ndebug1: auto-mux: Trying existing master\r\ndebug2: fd 3 setting O_NONBLOCK\r\ndebug2: mux_client_hello_exchange: master version 4\r\ndebug3: mux_client_forwards: request forwardings: 0 local, 0 remote\r\ndebug3: mux_client_request_session: entering\r\ndebug3: mux_client_request_alive: entering\r\ndebug3: mux_client_request_alive: done pid = 2553\r\ndebug3: mux_client_request_session: session request sent\r\ndebug1: mux_client_request_session: master session id: 2\r\ndebug3: mux_client_read_packet: read header failed: Broken pipe\r\ndebug2: Received exit status from master 0\r\n')
<192.168.121.14> ESTABLISH SSH CONNECTION FOR USER: vagrant
<192.168.121.14> SSH: EXEC ssh -vvv -o UserKnownHostsFile=/dev/null -o IdentitiesOnly=yes -o ControlMaster=auto -o ControlPersist=60s -o StrictHostKeyChecking=no -o Port=22 -o 'IdentityFile="/home/jomitsch/.vagrant.d/insecure_private_key"' -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o User=vagrant -o ConnectTimeout=30 -o ControlPath=/home/jomitsch/.ansible/cp/70cce52674 192.168.121.14 '/bin/sh -c '"'"'( umask 77 && mkdir -p "` echo /home/vagrant/.ansible/tmp/ansible-tmp-1500992232.31-244540377155956 `" && echo ansible-tmp-1500992232.31-244540377155956="` echo /home/vagrant/.ansible/tmp/ansible-tmp-1500992232.31-244540377155956 `" ) && sleep 0'"'"''
<192.168.121.14> (0, 'ansible-tmp-1500992232.31-244540377155956=/home/vagrant/.ansible/tmp/ansible-tmp-1500992232.31-244540377155956\n', 'OpenSSH_7.3p1, OpenSSL 1.0.2k-fips  26 Jan 2017\r\ndebug1: Reading configuration data /etc/ssh/ssh_config\r\ndebug3: /etc/ssh/ssh_config line 56: Including file /etc/ssh/ssh_config.d/05-redhat.conf depth 0\r\ndebug1: Reading configuration data /etc/ssh/ssh_config.d/05-redhat.conf\r\ndebug1: /etc/ssh/ssh_config.d/05-redhat.conf line 2: include /etc/crypto-policies/back-ends/openssh.txt matched no files\r\ndebug1: /etc/ssh/ssh_config.d/05-redhat.conf line 8: Applying options for *\r\ndebug1: auto-mux: Trying existing master\r\ndebug2: fd 3 setting O_NONBLOCK\r\ndebug2: mux_client_hello_exchange: master version 4\r\ndebug3: mux_client_forwards: request forwardings: 0 local, 0 remote\r\ndebug3: mux_client_request_session: entering\r\ndebug3: mux_client_request_alive: entering\r\ndebug3: mux_client_request_alive: done pid = 2553\r\ndebug3: mux_client_request_session: session request sent\r\ndebug1: mux_client_request_session: master session id: 2\r\ndebug3: mux_client_read_packet: read header failed: Broken pipe\r\ndebug2: Received exit status from master 0\r\n')
<192.168.121.14> PUT /tmp/tmpFa_r0i TO /home/vagrant/.ansible/tmp/ansible-tmp-1500992232.31-244540377155956/redhat_subscription.py
<192.168.121.14> SSH: EXEC sftp -b - -vvv -o UserKnownHostsFile=/dev/null -o IdentitiesOnly=yes -o ControlMaster=auto -o ControlPersist=60s -o StrictHostKeyChecking=no -o Port=22 -o 'IdentityFile="/home/jomitsch/.vagrant.d/insecure_private_key"' -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o User=vagrant -o ConnectTimeout=30 -o ControlPath=/home/jomitsch/.ansible/cp/70cce52674 '[192.168.121.14]'
<192.168.121.14> (0, 'sftp> put /tmp/tmpFa_r0i /home/vagrant/.ansible/tmp/ansible-tmp-1500992232.31-244540377155956/redhat_subscription.py\n', 'OpenSSH_7.3p1, OpenSSL 1.0.2k-fips  26 Jan 2017\r\ndebug1: Reading configuration data /etc/ssh/ssh_config\r\ndebug3: /etc/ssh/ssh_config line 56: Including file /etc/ssh/ssh_config.d/05-redhat.conf depth 0\r\ndebug1: Reading configuration data /etc/ssh/ssh_config.d/05-redhat.conf\r\ndebug1: /etc/ssh/ssh_config.d/05-redhat.conf line 2: include /etc/crypto-policies/back-ends/openssh.txt matched no files\r\ndebug1: /etc/ssh/ssh_config.d/05-redhat.conf line 8: Applying options for *\r\ndebug1: auto-mux: Trying existing master\r\ndebug2: fd 3 setting O_NONBLOCK\r\ndebug2: mux_client_hello_exchange: master version 4\r\ndebug3: mux_client_forwards: request forwardings: 0 local, 0 remote\r\ndebug3: mux_client_request_session: entering\r\ndebug3: mux_client_request_alive: entering\r\ndebug3: mux_client_request_alive: done pid = 2553\r\ndebug3: mux_client_request_session: session request sent\r\ndebug1: mux_client_request_session: master session id: 2\r\ndebug2: Remote version: 3\r\ndebug2: Server supports extension "posix-rename@openssh.com" revision 1\r\ndebug2: Server supports extension "statvfs@openssh.com" revision 2\r\ndebug2: Server supports extension "fstatvfs@openssh.com" revision 2\r\ndebug2: Server supports extension "hardlink@openssh.com" revision 1\r\ndebug2: Server supports extension "fsync@openssh.com" revision 1\r\ndebug3: Sent message fd 5 T:16 I:1\r\ndebug3: SSH_FXP_REALPATH . -> /home/vagrant size 0\r\ndebug3: Looking up /tmp/tmpFa_r0i\r\ndebug3: Sent message fd 5 T:17 I:2\r\ndebug3: Received stat reply T:101 I:2\r\ndebug1: Couldn\'t stat remote file: No such file or directory\r\ndebug3: Sent message SSH2_FXP_OPEN I:3 P:/home/vagrant/.ansible/tmp/ansible-tmp-1500992232.31-244540377155956/redhat_subscription.py\r\ndebug3: Sent message SSH2_FXP_WRITE I:4 O:0 S:32768\r\ndebug3: SSH2_FXP_STATUS 0\r\ndebug3: In write loop, ack for 4 32768 bytes at 0\r\ndebug3: Sent message SSH2_FXP_WRITE I:5 O:32768 S:29675\r\ndebug3: SSH2_FXP_STATUS 0\r\ndebug3: In write loop, ack for 5 29675 bytes at 32768\r\ndebug3: Sent message SSH2_FXP_CLOSE I:4\r\ndebug3: SSH2_FXP_STATUS 0\r\ndebug3: mux_client_read_packet: read header failed: Broken pipe\r\ndebug2: Received exit status from master 0\r\n')
<192.168.121.14> ESTABLISH SSH CONNECTION FOR USER: vagrant
<192.168.121.14> SSH: EXEC ssh -vvv -o UserKnownHostsFile=/dev/null -o IdentitiesOnly=yes -o ControlMaster=auto -o ControlPersist=60s -o StrictHostKeyChecking=no -o Port=22 -o 'IdentityFile="/home/jomitsch/.vagrant.d/insecure_private_key"' -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o User=vagrant -o ConnectTimeout=30 -o ControlPath=/home/jomitsch/.ansible/cp/70cce52674 192.168.121.14 '/bin/sh -c '"'"'chmod u+x /home/vagrant/.ansible/tmp/ansible-tmp-1500992232.31-244540377155956/ /home/vagrant/.ansible/tmp/ansible-tmp-1500992232.31-244540377155956/redhat_subscription.py && sleep 0'"'"''
<192.168.121.14> (0, '', 'OpenSSH_7.3p1, OpenSSL 1.0.2k-fips  26 Jan 2017\r\ndebug1: Reading configuration data /etc/ssh/ssh_config\r\ndebug3: /etc/ssh/ssh_config line 56: Including file /etc/ssh/ssh_config.d/05-redhat.conf depth 0\r\ndebug1: Reading configuration data /etc/ssh/ssh_config.d/05-redhat.conf\r\ndebug1: /etc/ssh/ssh_config.d/05-redhat.conf line 2: include /etc/crypto-policies/back-ends/openssh.txt matched no files\r\ndebug1: /etc/ssh/ssh_config.d/05-redhat.conf line 8: Applying options for *\r\ndebug1: auto-mux: Trying existing master\r\ndebug2: fd 3 setting O_NONBLOCK\r\ndebug2: mux_client_hello_exchange: master version 4\r\ndebug3: mux_client_forwards: request forwardings: 0 local, 0 remote\r\ndebug3: mux_client_request_session: entering\r\ndebug3: mux_client_request_alive: entering\r\ndebug3: mux_client_request_alive: done pid = 2553\r\ndebug3: mux_client_request_session: session request sent\r\ndebug1: mux_client_request_session: master session id: 2\r\ndebug3: mux_client_read_packet: read header failed: Broken pipe\r\ndebug2: Received exit status from master 0\r\n')
<192.168.121.14> ESTABLISH SSH CONNECTION FOR USER: vagrant
<192.168.121.14> SSH: EXEC ssh -vvv -o UserKnownHostsFile=/dev/null -o IdentitiesOnly=yes -o ControlMaster=auto -o ControlPersist=60s -o StrictHostKeyChecking=no -o Port=22 -o 'IdentityFile="/home/jomitsch/.vagrant.d/insecure_private_key"' -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o User=vagrant -o ConnectTimeout=30 -o ControlPath=/home/jomitsch/.ansible/cp/70cce52674 -tt 192.168.121.14 '/bin/sh -c '"'"'sudo -H -S -n -u root /bin/sh -c '"'"'"'"'"'"'"'"'echo BECOME-SUCCESS-xgfbdqqkftzcfrvuokynwbvinltloyyl; /usr/bin/python /home/vagrant/.ansible/tmp/ansible-tmp-1500992232.31-244540377155956/redhat_subscription.py; rm -rf "/home/vagrant/.ansible/tmp/ansible-tmp-1500992232.31-244540377155956/" > /dev/null 2>&1'"'"'"'"'"'"'"'"' && sleep 0'"'"''
<192.168.121.14> (0, '\r\n{"msg": "parameters are required together: [\'activationkey\', \'org_id\']", "failed": true, "invocation": {"module_args": {"username": "admin", "server_hostname": "almond.example.com", "org_id": "Default_Organization", "environment": "Library", "force_register": false, "state": "present", "pool": "^$", "server_insecure": "0", "password": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER", "rhsm_baseurl": "https://almond.example.com/pulp/repos", "autosubscribe": false}}}\r\n', 'OpenSSH_7.3p1, OpenSSL 1.0.2k-fips  26 Jan 2017\r\ndebug1: Reading configuration data /etc/ssh/ssh_config\r\ndebug3: /etc/ssh/ssh_config line 56: Including file /etc/ssh/ssh_config.d/05-redhat.conf depth 0\r\ndebug1: Reading configuration data /etc/ssh/ssh_config.d/05-redhat.conf\r\ndebug1: /etc/ssh/ssh_config.d/05-redhat.conf line 2: include /etc/crypto-policies/back-ends/openssh.txt matched no files\r\ndebug1: /etc/ssh/ssh_config.d/05-redhat.conf line 8: Applying options for *\r\ndebug1: auto-mux: Trying existing master\r\ndebug2: fd 3 setting O_NONBLOCK\r\ndebug2: mux_client_hello_exchange: master version 4\r\ndebug3: mux_client_forwards: request forwardings: 0 local, 0 remote\r\ndebug3: mux_client_request_session: entering\r\ndebug3: mux_client_request_alive: entering\r\ndebug3: mux_client_request_alive: done pid = 2553\r\ndebug3: mux_client_request_session: session request sent\r\ndebug1: mux_client_request_session: master session id: 2\r\ndebug3: mux_client_read_packet: read header failed: Broken pipe\r\ndebug2: Received exit status from master 0\r\nShared connection to 192.168.121.14 closed.\r\n')
fatal: [almond-client]: FAILED! => {
    "changed": false, 
    "failed": true, 
    "invocation": {
        "module_args": {
            "autosubscribe": false, 
            "environment": "Library", 
            "force_register": false, 
            "org_id": "Default_Organization", 
            "password": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER", 
            "pool": "^$", 
            "rhsm_baseurl": "https://almond.example.com/pulp/repos", 
            "server_hostname": "almond.example.com", 
            "server_insecure": "0", 
            "state": "present", 
            "username": "admin"
        }
    }, 
    "msg": "parameters are required together: ['activationkey', 'org_id']"
}


```



Discussion:
In katello/satellite context, you  need an organization when registering, but you don't need an activation key. the activation key will also provide the environnment i.e.

with activation key:
```
[root@almond-client ~]# subscription-manager register --activationkey="ack1"
Error: Must provide --org with activation keys.
```
the above will fail, but this will work:
```
[root@almond-client ~]# subscription-manager register --org="Default_Organization" --activationkey="ack1"
The system has been registered with ID: f2ddd12b-e2cd-4e5e-87cb-a5bc2f74f183 

No products installed.
```

without activation key:
```
[root@almond-client ~]# subscription-manager register --org="Default_Organization" --environment="Library" --username admin --password changeme
Registering to: almond.example.com:443/rhsm
The system has been registered with ID: foo
```

Resolving patch:
diff --git a/lib/ansible/modules/packaging/os/redhat_subscription.py b/lib/ansible/modules/packaging/os/redhat_subscription.py
--- a/lib/ansible/modules/packaging/os/redhat_subscription.py
+++ b/lib/ansible/modules/packaging/os/redhat_subscription.py
@@ -381,9 +381,11 @@ def register(self, username, password, autosubscribe, activationkey, org_id,
         if server_hostname:
             args.extend(['--serverurl', server_hostname])
 
+        if org_id:
+            args.extend(['--org', org_id])
+
         if activationkey:
             args.extend(['--activationkey', activationkey])
-            args.extend(['--org', org_id])
         else:
             if autosubscribe:
                 args.append('--autosubscribe')
@@ -701,9 +703,17 @@ def main():
                                        required=False,
                                        no_log=True),
         ),
-        required_together=[['username', 'password'], ['activationkey', 'org_id'],
-                           ['server_proxy_hostname', 'server_proxy_port'], ['server_proxy_user', 'server_proxy_password']],
-        mutually_exclusive=[['username', 'activationkey'], ['pool', 'pool_ids']],
+        required_together=[['username', 'password'],
+                           ['server_proxy_hostname', 'server_proxy_port'],
+                           ['server_proxy_user', 'server_proxy_password']],
+
+        mutually_exclusive=[['activationkey', 'username'],
+                            ['activationkey', 'consumer_id'],
+                            ['activationkey', 'environment'],
+                            ['activationkey', 'autosubscribe'],
+                            ['force', 'consumer_id'],
+                            ['pool', 'pool_ids']],
+
         required_if=[['state', 'present', ['username', 'activationkey'], True]],
     )
 
@@ -717,6 +727,8 @@ def main():
     autosubscribe = module.params['autosubscribe']
     activationkey = module.params['activationkey']
     org_id = module.params['org_id']
+    if activationkey and not org_id:
+        module.fail_json(msg='org_id is required when using activationkey')
     environment = module.params['environment']
     pool = module.params['pool']
     pool_ids = {}


Test patch: