# # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import six from heat.common.i18n import _ from heat.engine import constraints from heat.engine import properties from heat.engine import resource from heat.engine import support class DesignateRecord(resource.Resource): """Heat Template Resource for Designate Record. Designate provides DNS-as-a-Service services for OpenStack. Record is storage unit in DNS. So, DNS name server is a server that stores the DNS records for a domain. Each record has a type and type-specific data. """ support_status = support.SupportStatus( version='5.0.0') entity = 'records' PROPERTIES = ( NAME, TTL, DESCRIPTION, TYPE, DATA, PRIORITY, DOMAIN ) = ( 'name', 'ttl', 'description', 'type', 'data', 'priority', 'domain' ) _ALLOWED_TYPES = ( A, AAAA, CNAME, MX, SRV, TXT, SPF, NS, PTR, SSHFP, SOA ) = ( 'A', 'AAAA', 'CNAME', 'MX', 'SRV', 'TXT', 'SPF', 'NS', 'PTR', 'SSHFP', 'SOA' ) properties_schema = { # Based on RFC 1035, length of name is set to max of 255 NAME: properties.Schema( properties.Schema.STRING, _('Record name.'), required=True, constraints=[constraints.Length(max=255)] ), # Based on RFC 1035, range for ttl is set to 1 to signed 32 bit number TTL: properties.Schema( properties.Schema.INTEGER, _('Time To Live (Seconds).'), update_allowed=True, constraints=[constraints.Range(min=1, max=2147483647)] ), # designate mandates to the max length of 160 for description DESCRIPTION: properties.Schema( properties.Schema.STRING, _('Description of record.'), update_allowed=True, constraints=[constraints.Length(max=160)] ), TYPE: properties.Schema( properties.Schema.STRING, _('DNS Record type.'), update_allowed=True, required=True, constraints=[constraints.AllowedValues( _ALLOWED_TYPES )] ), DATA: properties.Schema( properties.Schema.STRING, _('DNS record data, varies based on the type of record. For more ' 'details, please refer rfc 1035.'), update_allowed=True, required=True ), # Based on RFC 1035, range for priority is set to 0 to signed 16 bit # number PRIORITY: properties.Schema( properties.Schema.INTEGER, _('DNS record priority. It is considered only for MX and SRV ' 'types, otherwise, it is ignored.'), update_allowed=True, constraints=[constraints.Range(min=0, max=65536)] ), DOMAIN: properties.Schema( properties.Schema.STRING, _('DNS Domain id or name.'), required=True, constraints=[constraints.CustomConstraint('designate.domain')] ), } default_client_name = 'designate' def handle_create(self): args = dict( name=self.properties[self.NAME], type=self.properties[self.TYPE], description=self.properties[self.DESCRIPTION], ttl=self.properties[self.TTL], data=self.properties[self.DATA], # priority is considered only for MX and SRV record. priority=(self.properties[self.PRIORITY] if self.properties[self.TYPE] in (self.MX, self.SRV) else None), domain=self.properties[self.DOMAIN] ) domain = self.client_plugin().record_create(**args) self.resource_id_set(domain.id) def handle_update(self, json_snippet, tmpl_diff, prop_diff): args = dict() if prop_diff.get(self.TTL): args['ttl'] = prop_diff.get(self.TTL) if prop_diff.get(self.DESCRIPTION): args['description'] = prop_diff.get(self.DESCRIPTION) if prop_diff.get(self.TYPE): args['type'] = prop_diff.get(self.TYPE) # priority is considered only for MX and SRV record. if prop_diff.get(self.PRIORITY): args['priority'] = (prop_diff.get(self.PRIORITY) if (prop_diff.get(self.TYPE) or self.properties[self.TYPE]) in (self.MX, self.SRV) else None) if prop_diff.get(self.DATA): args['data'] = prop_diff.get(self.DATA) if len(args.keys()) > 0: args['id'] = self.resource_id args['domain'] = self.properties[self.DOMAIN] self.client_plugin().record_update(**args) def handle_delete(self): if self.resource_id is not None: with self.client_plugin().ignore_not_found: self.client_plugin().record_delete( id=self.resource_id, domain=self.properties[self.DOMAIN] ) # FIXME(kanagaraj-manickam) Remove this method once designate defect # 1485552 is fixed. def _show_resource(self): kwargs = dict(domain=self.properties[self.DOMAIN], id=self.resource_id) return dict(six.iteritems(self.client_plugin().record_show(**kwargs))) def resource_mapping(): return { 'OS::Designate::Record': DesignateRecord }