text: """Module provider for Netcup"""
  from __future__ import absolute_import
  
  import json
  import logging
  
  import requests
  
  from lexicon.providers.base import Provider as BaseProvider
  
  LOGGER = logging.getLogger(__name__)
  
  NAMESERVER_DOMAINS = ["netcup.de"]
  
  
  def provider_parser(subparser):
      """Configure provider parser for Netcup"""
      subparser.add_argument(
          "--auth-customer-id", help="specify customer number for authentication"
      )
      subparser.add_argument("--auth-api-key", help="specify API key for authentication")
      subparser.add_argument(
          "--auth-api-password", help="specify API password for authentication"
      )
  
  
  class Provider(BaseProvider):
      """Provider class for Netcup"""
  
      def __init__(self, config):
          super(Provider, self).__init__(config)
          self.domain_id = 0
          self.zone_ttl = None
          self.api_session_id = None
          self.api_endpoint = (
              self._get_provider_option("api_endpoint")
              or "https://ccp.netcup.net/run/webservice/servers/endpoint.php?JSON"
          )
  
      # lexicon.provider.Provider overrides:
  
      def _authenticate(self):
          """Authenticate with netcup server. Must be called first."""
          login_info = self._apicall("login")
          self.api_session_id = login_info["apisessionid"]
          if not self.api_session_id:
              raise Exception("Login failed")
          # query ttl and verify access to self.domain:
          zone_info = self._apicall("infoDnsZone", domainname=self.domain)
          self.zone_ttl = zone_info["ttl"]
  
      def _create_record(self, rtype, name, content):
          """Create record. If it already exists, do nothing."""
          if not self._list_records(rtype, name, content):
              self._update_records(
                  [{}],
                  {
                      "type": rtype,
                      "hostname": self._relative_name(name),
                      "destination": content,
                      "priority": self._get_lexicon_option("priority"),
                  },
              )
          LOGGER.debug("create_record: %s", True)
          return True
  
      def _list_records(self, rtype=None, name=None, content=None):
          """List all records. Return an empty list if no records found.
          ``rtype``, ``name`` and ``content`` are used to filter records."""
          records = [
              {
                  "id": record["id"],
                  "type": record["type"],
                  "name": self._full_name(record["hostname"]),
                  "content": record["destination"],
                  "priority": record["priority"],
                  "ttl": self.zone_ttl,
              }
              for record in self._raw_records(None, rtype, name, content)
          ]
          LOGGER.debug("list_records: %s", records)
          return records
  
      def _update_record(self, identifier, rtype=None, name=None, content=None):
          """Create or update a record."""
          records = self._raw_records(identifier, rtype, name, content)
          self._update_records(
              records,
              {
                  "type": rtype,
                  "hostname": self._relative_name(name),
                  "destination": content,
                  "priority": self._get_lexicon_option("priority"),
              },
          )
          LOGGER.debug("update_record: %s", True)
          return True
  
      def _delete_record(self, identifier=None, rtype=None, name=None, content=None):
          """Delete an existing record. If record does not exist, do nothing."""
          records = self._raw_records(identifier, rtype, name, content)
          LOGGER.debug("delete_records: %s", [rec["id"] for rec in records])
          self._update_records(
              records,
              {
                  "deleterecord": True,
                  "type": rtype,
                  "hostname": name,
                  "destination": content,
              },
          )
          LOGGER.debug("delete_record: %s", True)
          return True
  
      # Helpers
  
      def _raw_records(self, identifier=None, rtype=None, name=None, content=None):
          """Return list of record dicts in the netcup API convention."""
          record_fields = {
              "id": identifier,
              "type": rtype,
              "hostname": name and self._relative_name(name),
              "destination": content,
          }
          # type/hostname/destination of the dnsrecord type are mandatory (even
          # when deleting), and must be queried if not all were specified:
          if all(record_fields.values()):
              return [record_fields]
          data = self._apicall("infoDnsRecords", domainname=self.domain)
          records = data.get("dnsrecords", [])
          return [
              record
              for record in records
              if all(record[k] == v for k, v in record_fields.items() if v)
          ]
  
      def _update_records(self, records, data):
          """Insert or update a list of DNS records, specified in the netcup API
          convention.
  
          The fields ``hostname``, ``type``, and ``destination`` are mandatory
          and must be provided either in the record dict or through ``data``!
          """
          data = {k: v for k, v in data.items() if v}
          records = [dict(record, **data) for record in records]
          return self._apicall(
              "updateDnsRecords",
              domainname=self.domain,
              dnsrecordset={"dnsrecords": records},
          ).get("dnsrecords", [])
  
      def _apicall(self, method, **params):
          """Call an API method and return response data. For more info, see:
          https://ccp.netcup.net/run/webservice/servers/endpoint"""
          LOGGER.debug("%s(%r)", method, params)
          auth = {
              "customernumber": self._get_provider_option("auth_customer_id"),
              "apikey": self._get_provider_option("auth_api_key"),
          }
          if method == "login":
              auth["apipassword"] = self._get_provider_option("auth_api_password")
          else:
              auth["apisessionid"] = self.api_session_id
          if not all(auth.values()):
              raise Exception("No valid authentication mechanism found")
          data = self._request(
              "POST", url="", data={"action": method, "param": dict(params, **auth)}
          )
          if data["status"] != "success":
              raise Exception("{} ({})".format(data["longmessage"], data["statuscode"]))
          return data.get("responsedata", {})
  
      def _request(self, action="GET", url="/", data=None, query_params=None):
          """Perform network request to configured JSON endpoint."""
          if data is None:
              data = {}
          if query_params is None:
              query_params = {}
          default_headers = {
              "Accept": "application/json",
              "Content-Type": "application/json",
          }
          response = requests.request(
              action,
              self.api_endpoint + url,
              data=json.dumps(data),
              params=query_params,
              headers=default_headers,
          )
          response.raise_for_status()
          return response.json()
  