1#!/usr/local/bin/python3.8 2# -*- coding: utf-8 -*- 3# (c) 2018, Sean O'Keeffe <seanokeeffe797@gmail.com> 4# 5# This program is free software: you can redistribute it and/or modify 6# it under the terms of the GNU General Public License as published by 7# the Free Software Foundation, either version 3 of the License, or 8# (at your option) any later version. 9# 10# This program is distributed in the hope that it will be useful, 11# but WITHOUT ANY WARRANTY; without even the implied warranty of 12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13# GNU General Public License for more details. 14# 15# You should have received a copy of the GNU General Public License 16# along with this program. If not, see <http://www.gnu.org/licenses/>. 17 18from __future__ import absolute_import, division, print_function 19__metaclass__ = type 20 21 22DOCUMENTATION = ''' 23--- 24module: content_view_filter 25version_added: 1.0.0 26short_description: Manage Content View Filters 27description: 28 - Create and manage content View filters 29author: "Sean O'Keeffe (@sean797)" 30options: 31 architecture: 32 description: 33 - package architecture 34 type: str 35 name: 36 description: 37 - Name of the Content View Filter 38 type: str 39 required: true 40 description: 41 description: 42 - Description of the Content View Filter 43 type: str 44 content_view: 45 description: 46 - Name of the content view 47 required: true 48 type: str 49 filter_state: 50 description: 51 - State of the content view filter 52 default: present 53 choices: 54 - present 55 - absent 56 type: str 57 repositories: 58 description: 59 - List of repositories that include name and product 60 - An empty Array means all current and future repositories 61 default: [] 62 type: list 63 elements: dict 64 rule_state: 65 description: 66 - State of the content view filter rule 67 default: present 68 choices: 69 - present 70 - absent 71 type: str 72 filter_type: 73 description: 74 - Content view filter type 75 required: true 76 choices: 77 - rpm 78 - package_group 79 - erratum 80 - docker 81 type: str 82 rule_name: 83 description: 84 - Content view filter rule name or package name 85 - If omitted, the value of I(name) will be used if necessary 86 aliases: 87 - package_name 88 - package_group 89 - tag 90 type: str 91 date_type: 92 description: 93 - Search using the 'Issued On' or 'Updated On' 94 - Only valid on I(filter_type=erratum). 95 default: updated 96 choices: 97 - issued 98 - updated 99 type: str 100 end_date: 101 description: 102 - erratum end date (YYYY-MM-DD) 103 type: str 104 start_date: 105 description: 106 - erratum start date (YYYY-MM-DD) 107 type: str 108 errata_id: 109 description: 110 - erratum id 111 type: str 112 max_version: 113 description: 114 - package maximum version 115 type: str 116 min_version: 117 description: 118 - package minimum version 119 type: str 120 types: 121 description: 122 - erratum types (enhancement, bugfix, security) 123 default: ["bugfix", "enhancement", "security"] 124 type: list 125 elements: str 126 version: 127 description: 128 - package version 129 type: str 130 inclusion: 131 description: 132 - Create an include filter 133 default: False 134 type: bool 135 original_packages: 136 description: 137 - Include all RPMs with no errata 138 type: bool 139extends_documentation_fragment: 140 - theforeman.foreman.foreman 141 - theforeman.foreman.foreman.organization 142''' 143 144EXAMPLES = ''' 145- name: Exclude csh 146 theforeman.foreman.content_view_filter: 147 username: "admin" 148 password: "changeme" 149 server_url: "https://foreman.example.com" 150 name: "package filter 1" 151 organization: "Default Organization" 152 content_view: Web Servers 153 filter_type: "rpm" 154 package_name: tcsh 155 156- name: Include newer csh versions 157 theforeman.foreman.content_view_filter: 158 username: "admin" 159 password: "changeme" 160 server_url: "https://foreman.example.com" 161 name: "package filter 1" 162 organization: "Default Organization" 163 content_view: Web Servers 164 filter_type: "rpm" 165 package_name: tcsh 166 min_version: 6.20.00 167 inclusion: True 168''' 169 170RETURN = ''' 171entity: 172 description: Final state of the affected entities grouped by their type. 173 returned: success 174 type: dict 175 contains: 176 content_view_filters: 177 description: List of content view filters. 178 type: list 179 elements: dict 180''' 181 182from ansible_collections.theforeman.foreman.plugins.module_utils.foreman_helper import KatelloMixin, ForemanStatelessEntityAnsibleModule 183 184content_filter_spec = { 185 'id': {}, 186 'name': {}, 187 'description': {}, 188 'repositories': {'type': 'entity_list'}, 189 'inclusion': {}, 190 'content_view': {'type': 'entity'}, 191 'filter_type': {'flat_name': 'type'}, 192 'original_packages': {}, 193} 194 195content_filter_rule_erratum_spec = { 196 'id': {}, 197 'date_type': {}, 198 'end_date': {}, 199 'start_date': {}, 200 'types': {'type': 'list'}, 201} 202 203content_filter_rule_erratum_id_spec = { 204 'id': {}, 205 'errata_id': {}, 206 'date_type': {}, 207} 208 209content_filter_rule_rpm_spec = { 210 'id': {}, 211 'rule_name': {'flat_name': 'name'}, 212 'end_date': {}, 213 'max_version': {}, 214 'min_version': {}, 215 'version': {}, 216 'architecture': {}, 217} 218 219content_filter_rule_package_group_spec = { 220 'id': {}, 221 'rule_name': {'flat_name': 'name'}, 222 'uuid': {}, 223} 224 225content_filter_rule_docker_spec = { 226 'id': {}, 227 'rule_name': {'flat_name': 'name'}, 228} 229 230 231class KatelloContentViewFilterModule(KatelloMixin, ForemanStatelessEntityAnsibleModule): 232 pass 233 234 235def main(): 236 module = KatelloContentViewFilterModule( 237 foreman_spec=dict( 238 name=dict(required=True), 239 description=dict(), 240 repositories=dict(type='list', default=[], elements='dict'), 241 inclusion=dict(type='bool', default=False), 242 original_packages=dict(type='bool'), 243 content_view=dict(type='entity', scope=['organization'], required=True), 244 filter_type=dict(required=True, choices=['rpm', 'package_group', 'erratum', 'docker']), 245 filter_state=dict(default='present', choices=['present', 'absent']), 246 rule_state=dict(default='present', choices=['present', 'absent']), 247 rule_name=dict(aliases=['package_name', 'package_group', 'tag']), 248 date_type=dict(default='updated', choices=['issued', 'updated']), 249 end_date=dict(), 250 errata_id=dict(), 251 max_version=dict(), 252 min_version=dict(), 253 start_date=dict(), 254 types=dict(default=["bugfix", "enhancement", "security"], type='list', elements='str'), 255 version=dict(), 256 architecture=dict(), 257 ), 258 entity_opts=dict(scope=['content_view']), 259 ) 260 261 filter_state = module.foreman_params.pop('filter_state') 262 rule_state = module.foreman_params.pop('rule_state') 263 264 if module.foreman_params['filter_type'] == 'erratum': 265 module.foreman_params['rule_name'] = None 266 elif 'rule_name' not in module.foreman_params: 267 module.foreman_params['rule_name'] = module.foreman_params['name'] 268 269 with module.api_connection(): 270 scope = module.scope_for('organization') 271 272 cv_scope = module.scope_for('content_view') 273 if module.foreman_params['repositories']: 274 repositories = [] 275 for repo in module.foreman_params['repositories']: 276 product = module.find_resource_by_name('products', repo['product'], params=scope, thin=True) 277 product_scope = {'product_id': product['id']} 278 repositories.append(module.find_resource_by_name('repositories', repo['name'], params=product_scope, thin=True)) 279 module.foreman_params['repositories'] = repositories 280 281 entity = module.lookup_entity('entity') 282 content_view_filter = module.ensure_entity( 283 'content_view_filters', 284 module.foreman_params, 285 entity, 286 params=cv_scope, 287 state=filter_state, 288 foreman_spec=content_filter_spec, 289 ) 290 291 if content_view_filter is not None: 292 cv_filter_scope = {'content_view_filter_id': content_view_filter['id']} 293 if 'errata_id' in module.foreman_params: 294 # should we try to find the errata the user is asking for? or just pass it blindly? 295 # errata = module.find_resource('errata', 'id={0}'.format(module.foreman_params['errata_id']), params=scope) 296 rule_spec = content_filter_rule_erratum_id_spec 297 search_scope = {'errata_id': module.foreman_params['errata_id']} 298 search_scope.update(cv_filter_scope) 299 search = None 300 else: 301 rule_spec = globals()['content_filter_rule_%s_spec' % (module.foreman_params['filter_type'])] 302 search_scope = cv_filter_scope 303 if module.foreman_params['rule_name'] is not None: 304 search = 'name="{0}"'.format(module.foreman_params['rule_name']) 305 else: 306 search = None 307 # not using find_resource_by_name here, because not all filters (errata) have names 308 content_view_filter_rule = module.find_resource('content_view_filter_rules', search, params=search_scope, failsafe=True) if entity else None 309 310 if module.foreman_params['filter_type'] == 'package_group': 311 package_group = module.find_resource_by_name('package_groups', module.foreman_params['rule_name'], params=scope) 312 module.foreman_params['uuid'] = package_group['uuid'] 313 314 # drop 'name' from the dict, as otherwise it might override 'rule_name' 315 rule_dict = module.foreman_params.copy() 316 rule_dict.pop('name', None) 317 318 module.ensure_entity( 319 'content_view_filter_rules', 320 rule_dict, 321 content_view_filter_rule, 322 params=cv_filter_scope, 323 state=rule_state, 324 foreman_spec=rule_spec, 325 ) 326 327 328if __name__ == '__main__': 329 main() 330