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 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265
|
#
# Copyright (C) 2016 FreeIPA Contributors see COPYING for license
#
from __future__ import (
absolute_import,
division,
)
from ipalib import (
_,
ngettext,
api,
Str,
DNSNameParam,
output,
messages
)
from ipalib.errors import DependentEntry
from ipalib.plugable import Registry
from ipaserver.dns_data_management import IPASystemRecords
from ipaserver.plugins.baseldap import (
LDAPCreate,
LDAPSearch,
LDAPRetrieve,
LDAPDelete,
LDAPObject,
LDAPUpdate,
)
from ipapython.dn import DN
from ipapython.dnsutil import DNSName
__doc__ = _("""
IPA locations
""") + _("""
Manipulate DNS locations
""") + _("""
EXAMPLES:
""") + _("""
Find all locations:
ipa location-find
""") + _("""
Show specific location:
ipa location-show location
""") + _("""
Add location:
ipa location-add location --description 'My location'
""") + _("""
Delete location:
ipa location-del location
""")
register = Registry()
@register()
class location(LDAPObject):
"""
IPA locations
"""
container_dn = api.env.container_locations
object_name = _('location')
object_name_plural = _('locations')
object_class = ['top', 'ipaLocationObject']
search_attributes = ['idnsName']
default_attributes = [
'idnsname', 'description'
]
label = _('IPA Locations')
label_singular = _('IPA Location')
permission_filter_objectclasses = ['ipaLocationObject']
managed_permissions = {
'System: Read IPA Locations': {
'ipapermright': {'read', 'search', 'compare'},
'ipapermdefaultattr': {
'objectclass', 'idnsname', 'description',
},
'default_privileges': {'DNS Administrators'},
},
'System: Add IPA Locations': {
'ipapermright': {'add'},
'default_privileges': {'DNS Administrators'},
},
'System: Remove IPA Locations': {
'ipapermright': {'delete'},
'default_privileges': {'DNS Administrators'},
},
'System: Modify IPA Locations': {
'ipapermright': {'write'},
'ipapermdefaultattr': {
'description',
},
'default_privileges': {'DNS Administrators'},
},
}
takes_params = (
DNSNameParam(
'idnsname',
cli_name='name',
primary_key=True,
label=_('Location name'),
doc=_('IPA location name'),
# dns name must be relative, we will put it into middle of
# location domain name for location records
only_relative=True,
),
Str(
'description?',
label=_('Description'),
doc=_('IPA Location description'),
),
Str(
'servers_server*',
label=_('Servers'),
doc=_('Servers that belongs to the IPA location'),
flags={'virtual_attribute', 'no_create', 'no_update', 'no_search'},
),
Str(
'dns_server*',
label=_('Advertised by servers'),
doc=_('List of servers which advertise the given location'),
flags={'virtual_attribute', 'no_create', 'no_update', 'no_search'},
),
)
def get_dn(self, *keys, **options):
loc = keys[0]
assert isinstance(loc, DNSName)
loc_a = loc.ToASCII()
return super(location, self).get_dn(loc_a, **options)
@register()
class location_add(LDAPCreate):
__doc__ = _('Add a new IPA location.')
msg_summary = _('Added IPA location "%(value)s"')
@register()
class location_del(LDAPDelete):
__doc__ = _('Delete an IPA location.')
msg_summary = _('Deleted IPA location "%(value)s"')
def pre_callback(self, ldap, dn, *keys, **options):
assert isinstance(dn, DN)
if not options.get('force'):
servers = self.api.Command.server_find(
in_location=keys[-1])['result']
location_member = servers[0]['cn'][0] if servers else None
if location_member:
raise DependentEntry(
label=_('IPA Server'),
key=keys[-1],
dependent=location_member
)
system_records =IPASystemRecords(self.api)
_success, failed = system_records.remove_location_records(keys[-1])
if failed:
self.add_message(messages.AutomaticDNSRecordsUpdateFailed())
return dn
@register()
class location_mod(LDAPUpdate):
__doc__ = _('Modify information about an IPA location.')
msg_summary = _('Modified IPA location "%(value)s"')
@register()
class location_find(LDAPSearch):
__doc__ = _('Search for IPA locations.')
msg_summary = ngettext(
'%(count)d IPA location matched',
'%(count)d IPA locations matched', 0
)
@register()
class location_show(LDAPRetrieve):
__doc__ = _('Display information about an IPA location.')
has_output = LDAPRetrieve.has_output + (
output.Output(
'servers',
type=dict,
doc=_('Servers in location'),
flags={'no_display'}, # we use customized print to CLI
),
)
def execute(self, *keys, **options):
result = super(location_show, self).execute(*keys, **options)
servers_additional_info = {}
if not options.get('raw'):
servers_name = []
dns_servers = []
weight_sum = 0
servers = self.api.Command.server_find(
in_location=keys[0], no_members=False)['result']
for server in servers:
s_name = server['cn'][0]
servers_name.append(s_name)
weight = int(server.get('ipaserviceweight', [100])[0])
weight_sum += weight
servers_additional_info[s_name] = {
'cn': server['cn'],
'ipaserviceweight': server.get(
'ipaserviceweight', [u'100']),
}
s_roles = server.get('enabled_role_servrole', ())
if s_roles:
servers_additional_info[s_name][
'enabled_role_servrole'] = s_roles
if 'DNS server' in s_roles:
dns_servers.append(s_name)
# 1. If all masters have weight == 0 then all are equally
# weighted.
# 2. If any masters have weight == 0 then they have an
# extremely small chance of being chosen, percentage is
# 0.1.
# 3. Otherwise it's percentage change is based on the sum of
# the weights of non-zero masters.
dividend = 100.0
if weight_sum != 0:
for server in servers_additional_info.values():
if int(server['ipaserviceweight'][0]) == 0:
dividend = dividend - 0.1
for server in servers_additional_info.values():
if weight_sum == 0:
val = 100 / len(servers)
elif int(server['ipaserviceweight'][0]) == 0:
val = 0.1
else:
val = (
int(server['ipaserviceweight'][0]) *
dividend / weight_sum
)
server['service_relative_weight'] = [
u'{:.1f}%'.format(val)
]
if servers_name:
result['result']['servers_server'] = servers_name
if dns_servers:
result['result']['dns_server'] = dns_servers
if not dns_servers and servers_additional_info:
self.add_message(messages.LocationWithoutDNSServer(
location=keys[0]
))
result['servers'] = servers_additional_info
return result
|