def update(self, campaign_id, data):
        """
        Set the content for a campaign.

        :param campaign_id: The unique id for the campaign.
        :type campaign_id: :py:class:`str`
        :param data: The request body parameters
        :type data: :py:class:`dict`
        """
        self.campaign_id = campaign_id
        return self._mc_client._put(url=self._build_path(campaign_id, 'content'), data=data)

def update ( self , campaign_id , data ) : self . campaign_id = campaign_id return self . _mc_client . _put ( url = self . _build_path ( campaign_id , 'content' ) , data = data )


def get(self, conversation_id, **queryparams):
        """
        Get details about an individual conversation.

        :param conversation_id: The unique id for the conversation.
        :type conversation_id: :py:class:`str`
        :param queryparams: The query string parameters
        queryparams['fields'] = []
        queryparams['exclude_fields'] = []
        """
        self.conversation_id = conversation_id
        return self._mc_client._get(url=self._build_path(conversation_id), **queryparams)

def get ( self , conversation_id , * * queryparams ) : self . conversation_id = conversation_id return self . _mc_client . _get ( url = self . _build_path ( conversation_id ) , * * queryparams )

Get details about an individual conversation .


def all(self, campaign_id, get_all=False, **queryparams):
        """
        Get information about members who have unsubscribed from a specific
        campaign.

        :param campaign_id: The unique id for the campaign.
        :type campaign_id: :py:class:`str`
        :param get_all: Should the query get all results
        :type get_all: :py:class:`bool`
        :param queryparams: The query string parameters
        queryparams['fields'] = []
        queryparams['exclude_fields'] = []
        queryparams['count'] = integer
        queryparams['offset'] = integer
        """
        self.campaign_id = campaign_id
        self.subscriber_hash = None
        if get_all:
            return self._iterate(url=self._build_path(campaign_id, 'unsubscribed'), **queryparams)
        else:
            return self._mc_client._get(url=self._build_path(campaign_id, 'unsubscribed'), **queryparams)

def all ( self , campaign_id , get_all = False , * * queryparams ) : self . campaign_id = campaign_id self . subscriber_hash = None if get_all : return self . _iterate ( url = self . _build_path ( campaign_id , 'unsubscribed' ) , * * queryparams ) else : return self . _mc_client . _get ( url = self . _build_path ( campaign_id , 'unsubscribed' ) , * * queryparams )

Get information about members who have unsubscribed from a specific campaign .


def create(self, workflow_id, email_id, data):
        """
        Manually add a subscriber to a workflow, bypassing the default trigger
        settings. You can also use this endpoint to trigger a series of
        automated emails in an API 3.0 workflow type or add subscribers to an
        automated email queue that uses the API request delay type.

        :param workflow_id: The unique id for the Automation workflow.
        :type workflow_id: :py:class:`str`
        :param email_id: The unique id for the Automation workflow email.
        :type email_id: :py:class:`str`
        :param data: The request body parameters
        :type data: :py:class:`dict`
        data = {
            "email_address": string*
        }
        """
        self.workflow_id = workflow_id
        self.email_id = email_id
        if 'email_address' not in data:
            raise KeyError('The automation email queue must have an email_address')
        check_email(data['email_address'])
        response = self._mc_client._post(
            url=self._build_path(workflow_id, 'emails', email_id, 'queue'),
            data=data
        )
        if response is not None:
            self.subscriber_hash = response['id']
        else:
            self.subscriber_hash = None
        return response

Manually add a subscriber to a workflow bypassing the default trigger settings . You can also use this endpoint to trigger a series of automated emails in an API 3 . 0 workflow type or add subscribers to an automated email queue that uses the API request delay type .


def all(self, workflow_id, email_id):
        """
        Get information about an Automation email queue.

        :param workflow_id: The unique id for the Automation workflow.
        :type workflow_id: :py:class:`str`
        :param email_id: The unique id for the Automation workflow email.
        :type email_id: :py:class:`str`
        """
        self.workflow_id = workflow_id
        self.email_id = email_id
        self.subscriber_hash = None
        return self._mc_client._get(url=self._build_path(workflow_id, 'emails', email_id, 'queue'))

def all ( self , workflow_id , email_id ) : self . workflow_id = workflow_id self . email_id = email_id self . subscriber_hash = None return self . _mc_client . _get ( url = self . _build_path ( workflow_id , 'emails' , email_id , 'queue' ) )

Get information about an Automation email queue .


def get(self, workflow_id, email_id, subscriber_hash):
        """
        Get information about a specific subscriber in an Automation email
        queue.

        :param workflow_id: The unique id for the Automation workflow.
        :type workflow_id: :py:class:`str`
        :param email_id: The unique id for the Automation workflow email.
        :type email_id: :py:class:`str`
        :param subscriber_hash: The MD5 hash of the lowercase version of the
          list member’s email address.
        :type subscriber_hash: :py:class:`str`
        """
        subscriber_hash = check_subscriber_hash(subscriber_hash)
        self.workflow_id = workflow_id
        self.email_id = email_id
        self.subscriber_hash = subscriber_hash
        return self._mc_client._get(url=self._build_path(workflow_id, 'emails', email_id, 'queue', subscriber_hash))

def get ( self , workflow_id , email_id , subscriber_hash ) : subscriber_hash = check_subscriber_hash ( subscriber_hash ) self . workflow_id = workflow_id self . email_id = email_id self . subscriber_hash = subscriber_hash return self . _mc_client . _get ( url = self . _build_path ( workflow_id , 'emails' , email_id , 'queue' , subscriber_hash ) )

Get information about a specific subscriber in an Automation email queue .


def cancel(self, campaign_id):
        """
        Cancel a Regular or Plain-Text Campaign after you send, before all of
        your recipients receive it. This feature is included with MailChimp
        Pro.

        :param campaign_id: The unique id for the campaign.
        :type campaign_id: :py:class:`str`
        """
        self.campaign_id = campaign_id
        return self._mc_client._post(url=self._build_path(campaign_id, 'actions/cancel-send'))

def cancel ( self , campaign_id ) : self . campaign_id = campaign_id return self . _mc_client . _post ( url = self . _build_path ( campaign_id , 'actions/cancel-send' ) )

Cancel a Regular or Plain - Text Campaign after you send before all of your recipients receive it . This feature is included with MailChimp Pro .


def pause(self, campaign_id):
        """
        Pause an RSS-Driven campaign.

        :param campaign_id: The unique id for the campaign.
        :type campaign_id: :py:class:`str`
        """
        self.campaign_id = campaign_id
        return self._mc_client._post(url=self._build_path(campaign_id, 'actions/pause'))

def pause ( self , campaign_id ) : self . campaign_id = campaign_id return self . _mc_client . _post ( url = self . _build_path ( campaign_id , 'actions/pause' ) )


def replicate(self, campaign_id):
        """
        Replicate a campaign in saved or send status.

        :param campaign_id: The unique id for the campaign.
        :type campaign_id: :py:class:`str`
        """
        self.campaign_id = campaign_id
        return self._mc_client._post(url=self._build_path(campaign_id, 'actions/replicate'))

def replicate ( self , campaign_id ) : self . campaign_id = campaign_id return self . _mc_client . _post ( url = self . _build_path ( campaign_id , 'actions/replicate' ) )

Replicate a campaign in saved or send status .


def resume(self, campaign_id):
        """
        Resume an RSS-Driven campaign.

        :param campaign_id: The unique id for the campaign.
        :type campaign_id: :py:class:`str`
        """
        self.campaign_id = campaign_id
        return self._mc_client._post(url=self._build_path(campaign_id, 'actions/resume'))

def resume ( self , campaign_id ) : self . campaign_id = campaign_id return self . _mc_client . _post ( url = self . _build_path ( campaign_id , 'actions/resume' ) )


def send(self, campaign_id):
        """
        Send a MailChimp campaign. For RSS Campaigns, the campaign will send
        according to its schedule. All other campaigns will send immediately.

        :param campaign_id: The unique id for the campaign.
        :type campaign_id: :py:class:`str`
        """
        self.campaign_id = campaign_id
        return self._mc_client._post(url=self._build_path(campaign_id, 'actions/send'))

def send ( self , campaign_id ) : self . campaign_id = campaign_id return self . _mc_client . _post ( url = self . _build_path ( campaign_id , 'actions/send' ) )

Send a MailChimp campaign . For RSS Campaigns the campaign will send according to its schedule . All other campaigns will send immediately .


def create(self, store_id, data):
        """
        Add a new customer to a store.

        :param store_id: The store id.
        :type store_id: :py:class:`str`
        :param data: The request body parameters
        :type data: :py:class:`dict`
        data = {
            "id": string*,
            "email_address": string*,
            "opt_in_status": boolean*
        }
        """
        self.store_id = store_id
        if 'id' not in data:
            raise KeyError('The store customer must have an id')
        if 'email_address' not in data:
            raise KeyError('The store customer must have an email_address')
        check_email(data['email_address'])
        if 'opt_in_status' not in data:
            raise KeyError('The store customer must have an opt_in_status')
        if data['opt_in_status'] not in [True, False]:
            raise TypeError('The opt_in_status must be True or False')
        response = self._mc_client._post(url=self._build_path(store_id, 'customers'), data=data)
        if response is not None:
            self.customer_id = response['id']
        else:
            self.customer_id = None
        return response


def get(self, store_id, customer_id, **queryparams):
        """
        Get information about a specific customer.

        :param store_id: The store id.
        :type store_id: :py:class:`str`
        :param customer_id: The id for the customer of a store.
        :type customer_id: :py:class:`str`
        :param queryparams: The query string parameters
        queryparams['fields'] = []
        queryparams['exclude_fields'] = []
        """
        self.store_id = store_id
        self.customer_id = customer_id
        return self._mc_client._get(url=self._build_path(store_id, 'customers', customer_id), **queryparams)

def get ( self , store_id , customer_id , * * queryparams ) : self . store_id = store_id self . customer_id = customer_id return self . _mc_client . _get ( url = self . _build_path ( store_id , 'customers' , customer_id ) , * * queryparams )

Get information about a specific customer .


def create_or_update(self, store_id, customer_id, data):
        """
        Add or update a customer.

        :param store_id: The store id.
        :type store_id: :py:class:`str`
        :param customer_id: The id for the customer of a store.
        :type customer_id: :py:class:`str`
        :param data: The request body parameters
        :type data: :py:class:`dict`
        data = {
            "id": string*,
            "email_address": string*,
            "opt_in_status": boolean
        }
        """
        self.store_id = store_id
        self.customer_id = customer_id
        if 'id' not in data:
            raise KeyError('The store customer must have an id')
        if 'email_address' not in data:
            raise KeyError('Each store customer must have an email_address')
        check_email(data['email_address'])
        if 'opt_in_status' not in data:
            raise KeyError('The store customer must have an opt_in_status')
        if data['opt_in_status'] not in [True, False]:
            raise TypeError('The opt_in_status must be True or False')
        return self._mc_client._put(url=self._build_path(store_id, 'customers', customer_id), data=data)


def create_or_update(self, store_id, product_id, variant_id, data):
        """
        Add or update a product variant.

        :param store_id: The store id.
        :type store_id: :py:class:`str`
        :param product_id: The id for the product of a store.
        :type product_id: :py:class:`str`
        :param variant_id: The id for the product variant.
        :type variant_id: :py:class:`str`
        :param data: The request body parameters
        :type data: :py:class:`dict`
        data = {
            "id": string*,
            "title": string*
        }
        """
        self.store_id = store_id
        self.product_id = product_id
        self.variant_id = variant_id
        if 'id' not in data:
             raise KeyError('The product variant must have an id')
        if 'title' not in data:
            raise KeyError('The product variant must have a title')
        return self._mc_client._put(
            url=self._build_path(store_id, 'products', product_id, 'variants', variant_id),
            data=data
        )

def
create_or_update
(
self
,
store_id
,
product_id
,
variant_id
,
data
)
:
self
.
store_id
=
store_id
self
.
product_id
=
product_id
self
.
variant_id
=
variant_id
if
'id'
not
in
data
:
raise
KeyError
(
'The product variant must have an id'
)
if
'title'
not
in
data
:
raise
KeyError
(
'The product variant must have a title'
)
return
self
.
_mc_client
.
_put
(
url
=
self
.
_build_path
(
store_id
,
'products'
,
product_id
,
'variants'
,
variant_id
)
,
data
=
data
)


def create(self, campaign_id, data, **queryparams):
        """
        Add feedback on a specific campaign.

        :param campaign_id: The unique id for the campaign.
        :type campaign_id: :py:class:`str`
        :param data: The request body parameters
        :type data: :py:class:`dict`
        data = {
            "message": string*
        }
        :param queryparams: The query string parameters
        queryparams['fields'] = []
        queryparams['exclude_fields'] = []
        """
        self.campaign_id = campaign_id
        if 'message' not in data:
            raise KeyError('The campaign feedback must have a message')
        response = self._mc_client._post(url=self._build_path(campaign_id, 'feedback'), data=data, **queryparams)
        if response is not None:
            self.feedback_id = response['feedback_id']
        else:
            self.feedback_id = None
        return response


def update(self, campaign_id, feedback_id, data):
        """
        Update a specific feedback message for a campaign.

        :param campaign_id: The unique id for the campaign.
        :type campaign_id: :py:class:`str`
        :param feedback_id: The unique id for the feedback message.
        :type feedback_id: :py:class:`str`
        :param data: The request body parameters
        :type data: :py:class:`dict`
        data = {
            "message": string*
        }
        """
        self.campaign_id = campaign_id
        self.feedback_id = feedback_id
        if 'message' not in data:
            raise KeyError('The campaign feedback must have a message')
        return self._mc_client._patch(url=self._build_path(campaign_id, 'feedback', feedback_id), data=data)

Update a specific feedback message for a campaign .


def create(self, list_id, data):
        """
        Add a new merge field for a specific list.

        :param list_id: The unique id for the list.
        :type list_id: :py:class:`str`
        :param data: The request body parameters
        :type data: :py:class:`dict`
        data = {
            "name": string*,
            "type": string*
        }
        """
        self.list_id = list_id
        if 'name' not in data:
            raise KeyError('The list merge field must have a name')
        if 'type' not in data:
            raise KeyError('The list merge field must have a type')
        response = self._mc_client._post(url=self._build_path(list_id, 'merge-fields'), data=data)
        if response is not None:
            self.merge_id = response['merge_id']
        else:
            self.merge_id = None
        return response

def
create
(
self
,
list_id
,
data
)
:
self
.
list_id
=
list_id
if
'name'
not
in
data
:
raise
KeyError
(
'The list merge field must have a name'
)
if
'type'
not
in
data
:
raise
KeyError
(
'The list merge field must have a type'
)
response
=
self
.
_mc_client
.
_post
(
url
=
self
.
_build_path
(
list_id
,
'merge-fields'
)
,
data
=
data
)
if
response
is
not
:
self
.
merge_id
=
response
[
'merge_id'
]
else
:
self
.
merge_id
=
return
response

Add a new merge field for a specific list .


def get(self, list_id, merge_id):
        """
        Get information about a specific merge field in a list.

        :param list_id: The unique id for the list.
        :type list_id: :py:class:`str`
        :param merge_id: The id for the merge field.
        :type merge_id: :py:class:`str`
        """
        self.list_id = list_id
        self.merge_id = merge_id
        return self._mc_client._get(url=self._build_path(list_id, 'merge-fields', merge_id))

def get ( self , list_id , merge_id ) : self . list_id = list_id self . merge_id = merge_id return self . _mc_client . _get ( url = self . _build_path ( list_id , 'merge-fields' , merge_id ) )

Get information about a specific merge field in a list .


def get(self, batch_webhook_id, **queryparams):
        """
        Get information about a specific batch webhook.

        :param batch_webhook_id: The unique id for the batch webhook.
        :type batch_webhook_id: :py:class:`str`
        :param queryparams: The query string parameters
        queryparams['fields'] = []
        queryparams['exclude_fields'] = []
        """
        self.batch_webhook_id = batch_webhook_id
        return self._mc_client._get(url=self._build_path(batch_webhook_id), **queryparams)

def get ( self , batch_webhook_id , * * queryparams ) : self . batch_webhook_id = batch_webhook_id return self . _mc_client . _get ( url = self . _build_path ( batch_webhook_id ) , * * queryparams )

Get information about a specific batch webhook .


def update(self, batch_webhook_id, data):
        """
        Update a webhook that will fire whenever any batch request completes
        processing.

        :param batch_webhook_id: The unique id for the batch webhook.
        :type batch_webhook_id: :py:class:`str`
        :param data: The request body parameters
        :type data: :py:class:`dict`
        data = {
            "url": string*
        }
        """
        self.batch_webhook_id = batch_webhook_id
        if 'url' not in data:
            raise KeyError('The batch webhook must have a valid url')
        return self._mc_client._patch(url=self._build_path(batch_webhook_id), data=data)

Update a webhook that will fire whenever any batch request completes processing .


def delete(self, batch_webhook_id):
        """
        Remove a batch webhook. Webhooks will no longer be sent to the given
        URL.

        :param batch_webhook_id: The unique id for the batch webhook.
        :type batch_webhook_id: :py:class:`str`
        """
        self.batch_webhook_id = batch_webhook_id
        return self._mc_client._delete(url=self._build_path(batch_webhook_id))

def delete ( self , batch_webhook_id ) : self . batch_webhook_id = batch_webhook_id return self . _mc_client . _delete ( url = self . _build_path ( batch_webhook_id ) )

Remove a batch webhook . Webhooks will no longer be sent to the given URL .


def create(self, data):
        """
        Add a new store to your MailChimp account.

        Error checking on the currency code verifies that it is in the correct
        three-letter, all-caps format as specified by ISO 4217 but does not
        check that it is a valid code as the list of valid codes changes over
        time.

        :param data: The request body parameters
        :type data: :py:class:`dict`
        data = {
            "id": string*,
            "list_id": string*,
            "name": string*,
            "currency_code": string*
        }
        """
        if 'id' not in data:
            raise KeyError('The store must have an id')
        if 'list_id' not in data:
            raise KeyError('The store must have a list_id')
        if 'name' not in data:
            raise KeyError('The store must have a name')
        if 'currency_code' not in data:
            raise KeyError('The store must have a currency_code')
        if not re.match(r"^[A-Z]{3}$", data['currency_code']):
            raise ValueError('The currency_code must be a valid 3-letter ISO 4217 currency code')
        response = self._mc_client._post(url=self._build_path(), data=data)
        if response is not None:
            self.store_id = response['id']
        else:
            self.store_id = None
        return response

Add a new store to your MailChimp account .


def update(self, store_id, data):
        """
        Update a store.

        :param store_id: The store id.
        :type store_id: :py:class:`str`
        :param data: The request body parameters
        :type data: :py:class:`dict`
        """
        self.store_id = store_id
        return self._mc_client._patch(url=self._build_path(store_id), data=data)

def update ( self , store_id , data ) : self . store_id = store_id return self . _mc_client . _patch ( url = self . _build_path ( store_id ) , data = data )


def create(self, store_id, product_id, data):
        """
        Add a new image to the product.

        :param store_id: The store id.
        :type store_id: :py:class:`str`
        :param product_id: The id for the product of a store.
        :type product_id: :py:class:`str`
        :param data: The request body parameters
        :type data: :py:class:`dict`
        data = {
            "id": string*,
            "url": string*
        }
        """
        self.store_id = store_id
        self.product_id = product_id
        if 'id' not in data:
            raise KeyError('The product image must have an id')
        if 'title' not in data:
            raise KeyError('The product image must have a url')
        response = self._mc_client._post(url=self._build_path(store_id, 'products', product_id, 'images'), data=data)
        if response is not None:
            self.image_id = response['id']
        else:
            self.image_id = None
        return response

def
create
(
self
,
store_id
,
product_id
,
data
)
:
self
.
store_id
=
store_id
self
.
product_id
=
product_id
if
'id'
not
in
data
:
raise
KeyError
(
'The product image must have an id'
)
if
'title'
not
in
data
:
raise
KeyError
(
'The product image must have a url'
)
response
=
self
.
_mc_client
.
_post
(
url
=
self
.
_build_path
(
store_id
,
'products'
,
product_id
,
'images'
)
,
data
=
data
)
if
response
is
not
:
self
.
image_id
=
response
[
'id'
]
else
:
self
.
image_id
=
return
response


def get(self, store_id, product_id, image_id, **queryparams):
        """
        Get information about a specific product image.

        :param store_id: The store id.
        :type store_id: :py:class:`str`
        :param product_id: The id for the product of a store.
        :type product_id: :py:class:`str`
        :param image_id: The id for the product image.
        :type image_id: :py:class:`str`
        :param queryparams: The query string parameters
        queryparams['fields'] = []
        queryparams['exclude_fields'] = []
        """
        self.store_id = store_id
        self.product_id = product_id
        self.image_id = image_id
        return self._mc_client._post(
            url=self._build_path(store_id, 'products', product_id, 'images', image_id),
            **queryparams
        )

def get ( self , store_id , product_id , image_id , * * queryparams ) : self . store_id = store_id self . product_id = product_id self . image_id = image_id return self . _mc_client . _post ( url = self . _build_path ( store_id , 'products' , product_id , 'images' , image_id ) , * * queryparams )

Get information about a specific product image .


def create(self, conversation_id, data):
        """
        Post a new message to a conversation.

        :param conversation_id: The unique id for the conversation.
        :type conversation_id: :py:class:`str`
        :param data: The request body parameters
        :type data: :py:class:`dict`
        data = {
            "from_email": string*,
            "read": boolean*
        }
        """
        self.conversation_id = conversation_id
        if 'from_email' not in data:
            raise KeyError('The conversation message must have a from_email')
        check_email(data['from_email'])
        if 'read' not in data:
            raise KeyError('The conversation message must have a read')
        if data['read'] not in [True, False]:
            raise TypeError('The conversation message read must be True or False')
        response =  self._mc_client._post(url=self._build_path(conversation_id, 'messages'), data=data)
        if response is not None:
            self.message_id = response['id']
        else:
            self.message_id = None
        return response


def create(self, store_id, data):
        """
        Add a new order to a store.

        :param store_id: The store id.
        :type store_id: :py:class:`str`
        :param data: The request body parameters
        :type data: :py:class:`dict`
        data = {
            "id": string*,
            "customer": object*
            {
                "'id": string*
            },
            "curency_code": string*,
            "order_total": number*,
            "lines": array*
            [
                {
                    "id": string*,
                    "product_id": string*,
                    "product_variant_id": string*,
                    "quantity": integer*,
                    "price": number*
                }
            ]
        }
        """
        self.store_id = store_id
        if 'id' not in data:
            raise KeyError('The order must have an id')
        if 'customer' not in data:
            raise KeyError('The order must have a customer')
        if 'id' not in data['customer']:
            raise KeyError('The order customer must have an id')
        if 'currency_code' not in data:
            raise KeyError('The order must have a currency_code')
        if not re.match(r"^[A-Z]{3}$", data['currency_code']):
            raise ValueError('The currency_code must be a valid 3-letter ISO 4217 currency code')
        if 'order_total' not in data:
            raise KeyError('The order must have an order_total')
        if 'lines' not in data:
            raise KeyError('The order must have at least one order line')
        for line in data['lines']:
            if 'id' not in line:
                raise KeyError('Each order line must have an id')
            if 'product_id' not in line:
                raise KeyError('Each order line must have a product_id')
            if 'product_variant_id' not in line:
                raise KeyError('Each order line must have a product_variant_id')
            if 'quantity' not in line:
                raise KeyError('Each order line must have a quantity')
            if 'price' not in line:
                raise KeyError('Each order line must have a price')
        response = self._mc_client._post(url=self._build_path(store_id, 'orders'), data=data)
        if response is not None:
            self.order_id = response['id']
        else:
            self.order_id = None
        return response


def create(self, list_id, subscriber_hash, data):
        """
        Add a new note for a specific subscriber.

        The documentation lists only the note request body parameter so it is
        being documented and error-checked as if it were required based on the
        description of the method.

        :param list_id: The unique id for the list.
        :type list_id: :py:class:`str`
        :param subscriber_hash: The MD5 hash of the lowercase version of the
          list member’s email address.
        :type subscriber_hash: :py:class:`str`
        :param data: The request body parameters
        :type data: :py:class:`dict`
        data = {
            "note": string*
        }
        """
        subscriber_hash = check_subscriber_hash(subscriber_hash)
        self.list_id = list_id
        self.subscriber_hash = subscriber_hash
        if 'note' not in data:
            raise KeyError('The list member note must have a note')
        response = self._mc_client._post(url=self._build_path(list_id, 'members', subscriber_hash, 'notes'), data=data)
        if response is not None:
            self.note_id = response['id']
        else:
            self.note_id = None
        return response

def
create
(
self
,
list_id
,
subscriber_hash
,
data
)
:
subscriber_hash
=
check_subscriber_hash
(
subscriber_hash
)
self
.
list_id
=
list_id
self
.
subscriber_hash
=
subscriber_hash
if
'note'
not
in
data
:
raise
KeyError
(
'The list member note must have a note'
)
response
=
self
.
_mc_client
.
_post
(
url
=
self
.
_build_path
(
list_id
,
'members'
,
subscriber_hash
,
'notes'
)
,
data
=
data
)
if
response
is
not
:
self
.
note_id
=
response
[
'id'
]
else
:
self
.
note_id
=
return
response

Add a new note for a specific subscriber .


def update(self, list_id, subscriber_hash, data):
        """
        Update tags for a specific subscriber.

        The documentation lists only the tags request body parameter so it is
        being documented and error-checked as if it were required based on the
        description of the method.

        The data list needs to include a "status" key. This determines if the
        tag should be added or removed from the user:

        data = {
            'tags': [
                {'name': 'foo', 'status': 'active'},
                {'name': 'bar', 'status': 'inactive'}
            ]
        }

        :param list_id: The unique id for the list.
        :type list_id: :py:class:`str`
        :param subscriber_hash: The MD5 hash of the lowercase version of the
          list member’s email address.
        :type subscriber_hash: :py:class:`str`
        :param data: The request body parameters
        :type data: :py:class:`dict`
        data = {
            "tags": list*
        }
        """
        subscriber_hash = check_subscriber_hash(subscriber_hash)
        self.list_id = list_id
        self.subscriber_hash = subscriber_hash
        if 'tags' not in data:
            raise KeyError('The list member tags must have a tag')
        response = self._mc_client._post(url=self._build_path(list_id, 'members', subscriber_hash, 'tags'), data=data)
        return response

def
update
(
self
,
list_id
,
subscriber_hash
,
data
)
:
subscriber_hash
=
check_subscriber_hash
(
subscriber_hash
)
self
.
list_id
=
list_id
self
.
subscriber_hash
=
subscriber_hash
if
'tags'
not
in
data
:
raise
KeyError
(
'The list member tags must have a tag'
)
response
=
self
.
_mc_client
.
_post
(
url
=
self
.
_build_path
(
list_id
,
'members'
,
subscriber_hash
,
'tags'
)
,
data
=
data
)
return
response


def update(self, list_id, segment_id, data):
        """
        Update a specific segment in a list.

        :param list_id: The unique id for the list.
        :type list_id: :py:class:`str`
        :param segment_id: The unique id for the segment.
        :type segment_id: :py:class:`str`
        :param data: The request body parameters
        :type data: :py:class:`dict`
        data = {
            "name": string*
        }
        """
        self.list_id = list_id
        self.segment_id = segment_id
        if 'name' not in data:
            raise KeyError('The list segment must have a name')
        return self._mc_client._patch(url=self._build_path(list_id, 'segments', segment_id), data=data)

def
update
(
self
,
list_id
,
segment_id
,
data
)
:
self
.
list_id
=
list_id
self
.
segment_id
=
segment_id
if
'name'
not
in
data
:
raise
KeyError
(
'The list segment must have a name'
)
return
self
.
_mc_client
.
_patch
(
url
=
self
.
_build_path
(
list_id
,
'segments'
,
segment_id
)
,
data
=
data
)


def update(self, folder_id, data):
        """
        Update a specific folder used to organize templates.

        :param folder_id: The unique id for the File Manager folder.
        :type folder_id: :py:class:`str`
        :param data: The request body parameters
        :type data: :py:class:`dict`
        data = {
            "name": string*
        }
        """
        if 'name' not in data:
            raise KeyError('The template folder must have a name')
        self.folder_id = folder_id
        return self._mc_client._patch(url=self._build_path(folder_id), data=data)

def
update
(
self
,
folder_id
,
data
)
:
if
'name'
not
in
data
:
raise
KeyError
(
'The template folder must have a name'
)
self
.
folder_id
=
folder_id
return
self
.
_mc_client
.
_patch
(
url
=
self
.
_build_path
(
folder_id
)
,
data
=
data
)

Update a specific folder used to organize templates .


def create(self, list_id, data):
        """
        Add a new member to the list.

        :param list_id: The unique id for the list.
        :type list_id: :py:class:`str`
        :param data: The request body parameters
        :type data: :py:class:`dict`
        data = {
            "status": string*, (Must be one of 'subscribed', 'unsubscribed', 'cleaned',
                'pending', or 'transactional')
            "email_address": string*
        }
        """
        self.list_id = list_id
        if 'status' not in data:
            raise KeyError('The list member must have a status')
        if data['status'] not in ['subscribed', 'unsubscribed', 'cleaned', 'pending', 'transactional']:
            raise ValueError('The list member status must be one of "subscribed", "unsubscribed", "cleaned", '
                             '"pending", or "transactional"')
        if 'email_address' not in data:
            raise KeyError('The list member must have an email_address')
        check_email(data['email_address'])
        response = self._mc_client._post(url=self._build_path(list_id, 'members'), data=data)
        if response is not None:
            self.subscriber_hash = response['id']
        else:
            self.subscriber_hash = None
        return response


def update(self, list_id, subscriber_hash, data):
        """
        Update information for a specific list member.

        :param list_id: The unique id for the list.
        :type list_id: :py:class:`str`
        :param subscriber_hash: The MD5 hash of the lowercase version of the
            list member’s email address.
        :type subscriber_hash: :py:class:`str`
        :param data: The request body parameters
        :type data: :py:class:`dict`
        """
        subscriber_hash = check_subscriber_hash(subscriber_hash)
        self.list_id = list_id
        self.subscriber_hash = subscriber_hash
        return self._mc_client._patch(url=self._build_path(list_id, 'members', subscriber_hash), data=data)

def update ( self , list_id , subscriber_hash , data ) : subscriber_hash = check_subscriber_hash ( subscriber_hash ) self . list_id = list_id self . subscriber_hash = subscriber_hash return self . _mc_client . _patch ( url = self . _build_path ( list_id , 'members' , subscriber_hash ) , data = data )

Update information for a specific list member .


def create_or_update(self, list_id, subscriber_hash, data):
        """
        Add or update a list member.

        :param list_id: The unique id for the list.
        :type list_id: :py:class:`str`
        :param subscriber_hash: The MD5 hash of the lowercase version of the
            list member’s email address.
        :type subscriber_hash: :py:class:`str`
        :param data: The request body parameters
        :type data: :py:class:`dict`
        data = {
            "email_address": string*,
            "status_if_new": string* (Must be one of 'subscribed',
                'unsubscribed', 'cleaned', 'pending', or 'transactional')
        }
        """
        subscriber_hash = check_subscriber_hash(subscriber_hash)
        self.list_id = list_id
        self.subscriber_hash = subscriber_hash
        if 'email_address' not in data:
            raise KeyError('The list member must have an email_address')
        check_email(data['email_address'])
        if 'status_if_new' not in data:
            raise KeyError('The list member must have a status_if_new')
        if data['status_if_new'] not in ['subscribed', 'unsubscribed', 'cleaned', 'pending', 'transactional']:
            raise ValueError('The list member status_if_new must be one of "subscribed", "unsubscribed", "cleaned", '
                             '"pending", or "transactional"')
        return self._mc_client._put(url=self._build_path(list_id, 'members', subscriber_hash), data=data)


def delete(self, list_id, subscriber_hash):
        """
        Delete a member from a list.

        :param list_id: The unique id for the list.
        :type list_id: :py:class:`str`
        :param subscriber_hash: The MD5 hash of the lowercase version of the
          list member’s email address.
        :type subscriber_hash: :py:class:`str`
        """
        subscriber_hash = check_subscriber_hash(subscriber_hash)
        self.list_id = list_id
        self.subscriber_hash = subscriber_hash
        return self._mc_client._delete(url=self._build_path(list_id, 'members', subscriber_hash))

def delete ( self , list_id , subscriber_hash ) : subscriber_hash = check_subscriber_hash ( subscriber_hash ) self . list_id = list_id self . subscriber_hash = subscriber_hash return self . _mc_client . _delete ( url = self . _build_path ( list_id , 'members' , subscriber_hash ) )


def delete_permanent(self, list_id, subscriber_hash):
        """
        Delete permanently a member from a list.

        :param list_id: The unique id for the list.
        :type list_id: :py:class:`str`
        :param subscriber_hash: The MD5 hash of the lowercase version of the
          list member’s email address.
        :type subscriber_hash: :py:class:`str`
        """
        subscriber_hash = check_subscriber_hash(subscriber_hash)
        self.list_id = list_id
        self.subscriber_hash = subscriber_hash
        return self._mc_client._post(url=self._build_path(list_id, 'members', subscriber_hash, 'actions', 'delete-permanent'))

def delete_permanent ( self , list_id , subscriber_hash ) : subscriber_hash = check_subscriber_hash ( subscriber_hash ) self . list_id = list_id self . subscriber_hash = subscriber_hash return self . _mc_client . _post ( url = self . _build_path ( list_id , 'members' , subscriber_hash , 'actions' , 'delete-permanent' ) )

Delete permanently a member from a list .


def pause(self, workflow_id, email_id):
        """
        Pause an automated email.

        :param workflow_id: The unique id for the Automation workflow.
        :type workflow_id: :py:class:`str`
        :param email_id: The unique id for the Automation workflow email.
        :type email_id: :py:class:`str`
        """
        self.workflow_id = workflow_id
        self.email_id = email_id
        return self._mc_client._post(url=self._build_path(workflow_id, 'emails', email_id, 'actions/pause'))

def pause ( self , workflow_id , email_id ) : self . workflow_id = workflow_id self . email_id = email_id return self . _mc_client . _post ( url = self . _build_path ( workflow_id , 'emails' , email_id , 'actions/pause' ) )


def start(self, workflow_id, email_id):
        """
        Start an automated email.

        :param workflow_id: The unique id for the Automation workflow.
        :type workflow_id: :py:class:`str`
        :param email_id: The unique id for the Automation workflow email.
        :type email_id: :py:class:`str`
        """
        self.workflow_id = workflow_id
        self.email_id = email_id
        return self._mc_client._post(url=self._build_path(workflow_id, 'emails', email_id, 'actions/start'))

def start ( self , workflow_id , email_id ) : self . workflow_id = workflow_id self . email_id = email_id return self . _mc_client . _post ( url = self . _build_path ( workflow_id , 'emails' , email_id , 'actions/start' ) )


def delete(self, workflow_id, email_id):
        """
        Removes an individual Automation workflow email.

        :param workflow_id: The unique id for the Automation workflow.
        :type workflow_id: :py:class:`str`
        :param email_id: The unique id for the Automation workflow email.
        :type email_id: :py:class:`str`
        """

        self.workflow_id = workflow_id
        self.email_id = email_id
        return self._mc_client._delete(url=self._build_path(workflow_id, 'emails', email_id))

def delete ( self , workflow_id , email_id ) : self . workflow_id = workflow_id self . email_id = email_id return self . _mc_client . _delete ( url = self . _build_path ( workflow_id , 'emails' , email_id ) )

Removes an individual Automation workflow email .


def create(self, data):
        """
        Create a new MailChimp campaign.

        The ValueError raised by an invalid type in data does not mention
        'absplit' as a potential value because the documentation indicates
        that the absplit type has been deprecated.

        :param data: The request body parameters
        :type data: :py:class:`dict`
        data = {
            "recipients": object*
            {
                "list_id": string*
            },
            "settings": object*
            {
                "subject_line": string*,
                "from_name": string*,
                "reply_to": string*
            },
            "variate_settings": object* (Required if type is "variate")
            {
                "winner_criteria": string* (Must be one of "opens", "clicks", "total_revenue", or "manual")
            },
            "rss_opts": object* (Required if type is "rss")
            {
                "feed_url": string*,
                "frequency": string* (Must be one of "daily", "weekly", or "monthly")
            },
            "type": string* (Must be one of "regular", "plaintext", "rss", "variate", or "absplit")
        }
        """
        if 'recipients' not in data:
            raise KeyError('The campaign must have recipients')
        if 'list_id' not in data['recipients']:
            raise KeyError('The campaign recipients must have a list_id')
        if 'settings' not in data:
            raise KeyError('The campaign must have settings')
        if 'subject_line' not in data['settings']:
            raise KeyError('The campaign settings must have a subject_line')
        if 'from_name' not in data['settings']:
            raise KeyError('The campaign settings must have a from_name')
        if 'reply_to' not in data['settings']:
            raise KeyError('The campaign settings must have a reply_to')
        check_email(data['settings']['reply_to'])
        if 'type' not in data:
            raise KeyError('The campaign must have a type')
        if not data['type'] in ['regular', 'plaintext', 'rss', 'variate', 'abspilt']:
            raise ValueError('The campaign type must be one of "regular", "plaintext", "rss", or "variate"')
        if data['type'] == 'variate':
            if 'variate_settings' not in data:
                raise KeyError('The variate campaign must have variate_settings')
            if 'winner_criteria' not in data['variate_settings']:
                raise KeyError('The campaign variate_settings must have a winner_criteria')
            if data['variate_settings']['winner_criteria'] not in ['opens', 'clicks', 'total_revenue', 'manual']:
                raise ValueError('The campaign variate_settings '
                                 'winner_criteria must be one of "opens", "clicks", "total_revenue", or "manual"')
        if data['type'] == 'rss':
            if 'rss_opts' not in data:
                raise KeyError('The rss campaign must have rss_opts')
            if 'feed_url' not in data['rss_opts']:
                raise KeyError('The campaign rss_opts must have a feed_url')
            if not data['rss_opts']['frequency'] in ['daily', 'weekly', 'monthly']:
                raise ValueError('The rss_opts frequency must be one of "daily", "weekly", or "monthly"')
        response = self._mc_client._post(url=self._build_path(), data=data)
        if response is not None:
            self.campaign_id = response['id']
        else:
            self.campaign_id = None
        return response


def update(self, campaign_id, data):
        """
        Update some or all of the settings for a specific campaign.

        :param campaign_id: The unique id for the campaign.
        :type campaign_id: :py:class:`str`
        :param data: The request body parameters
        :type data: :py:class:`dict`
        data = {
            "settings": object*
            {
                "subject_line": string*,
                "from_name": string*,
                "reply_to": string*
            },
        }
        """
        self.campaign_id = campaign_id
        if 'settings' not in data:
            raise KeyError('The campaign must have settings')
        if 'subject_line' not in data['settings']:
            raise KeyError('The campaign settings must have a subject_line')
        if 'from_name' not in data['settings']:
            raise KeyError('The campaign settings must have a from_name')
        if 'reply_to' not in data['settings']:
            raise KeyError('The campaign settings must have a reply_to')
        check_email(data['settings']['reply_to'])
        return self._mc_client._patch(url=self._build_path(campaign_id), data=data)

Update some or all of the settings for a specific campaign .


def delete(self, campaign_id):
        """
        Remove a campaign from your MailChimp account.

        :param campaign_id: The unique id for the campaign.
        :type campaign_id: :py:class:`str`
        """
        self.campaign_id = campaign_id
        return self._mc_client._delete(url=self._build_path(campaign_id))

def delete ( self , campaign_id ) : self . campaign_id = campaign_id return self . _mc_client . _delete ( url = self . _build_path ( campaign_id ) )

Remove a campaign from your MailChimp account .


def delete(self, store_id, cart_id, line_id):
        """
        Delete a cart.

        :param store_id: The store id.
        :type store_id: :py:class:`str`
        :param cart_id: The id for the cart.
        :type cart_id: :py:class:`str`
        :param line_id: The id for the line item of a cart.
        :type line_id: :py:class:`str`
        """
        self.store_id = store_id
        self.cart_id = cart_id
        self.line_id = line_id
        return self._mc_client._delete(url=self._build_path(store_id, 'carts', cart_id, 'lines', line_id))

def delete ( self , store_id , cart_id , line_id ) : self . store_id = store_id self . cart_id = cart_id self . line_id = line_id return self . _mc_client . _delete ( url = self . _build_path ( store_id , 'carts' , cart_id , 'lines' , line_id ) )


def create(self, data):
        """
        Begin processing a batch operations request.

        :param data: The request body parameters
        :type data: :py:class:`dict`
        data = {
            "operations": array*
            [
                {
                    "method": string* (Must be one of "GET", "POST", "PUT", "PATCH", or "DELETE")
                    "path": string*,
                }
            ]
        }
        """
        if 'operations' not in data:
            raise KeyError('The batch must have operations')
        for op in data['operations']:
            if 'method' not in op:
                raise KeyError('The batch operation must have a method')
            if op['method'] not in ['GET', 'POST', 'PUT', 'PATCH', 'DELETE']:
                raise ValueError('The batch operation method must be one of "GET", "POST", "PUT", "PATCH", '
                                 'or "DELETE", not {0}'.format(op['method']))
            if 'path' not in op:
                raise KeyError('The batch operation must have a path')
        return self._mc_client._post(url=self._build_path(), data=data)

Begin processing a batch operations request .


def all(self, get_all=False, **queryparams):
        """
        Get a summary of batch requests that have been made.

        :param get_all: Should the query get all results
        :type get_all: :py:class:`bool`
        :param queryparams: The query string parameters
        queryparams['fields'] = []
        queryparams['exclude_fields'] = []
        queryparams['count'] = integer
        queryparams['offset'] = integer
        """
        self.batch_id = None
        self.operation_status = None
        if get_all:
            return self._iterate(url=self._build_path(), **queryparams)
        else:
            return self._mc_client._get(url=self._build_path(), **queryparams)

def all ( self , get_all = False , * * queryparams ) : self . batch_id = None self . operation_status = None if get_all : return self . _iterate ( url = self . _build_path ( ) , * * queryparams ) else : return self . _mc_client . _get ( url = self . _build_path ( ) , * * queryparams )

Get a summary of batch requests that have been made .


def get(self, batch_id, **queryparams):
        """
        Get the status of a batch request.

        :param batch_id: The unique id for the batch operation.
        :type batch_id: :py:class:`str`
        :param queryparams: The query string parameters
        queryparams['fields'] = []
        queryparams['exclude_fields'] = []
        """
        self.batch_id = batch_id
        self.operation_status = None
        return self._mc_client._get(url=self._build_path(batch_id), **queryparams)

def get ( self , batch_id , * * queryparams ) : self . batch_id = batch_id self . operation_status = None return self . _mc_client . _get ( url = self . _build_path ( batch_id ) , * * queryparams )


def delete(self, batch_id):
        """
        Stops a batch request from running. Since only one batch request is
        run at a time, this can be used to cancel a long running request. The
        results of any completed operations will not be available after this
        call.

        :param batch_id: The unique id for the batch operation.
        :type batch_id: :py:class:`str`
        """
        self.batch_id = batch_id
        self.operation_status = None
        return self._mc_client._delete(url=self._build_path(batch_id))

def delete ( self , batch_id ) : self . batch_id = batch_id self . operation_status = None return self . _mc_client . _delete ( url = self . _build_path ( batch_id ) )

Stops a batch request from running . Since only one batch request is run at a time this can be used to cancel a long running request . The results of any completed operations will not be available after this call .


def _reformat_policy(policy):
    """
    Policies returned from boto3 are massive, ugly, and difficult to read.
    This method flattens and reformats the policy.

    :param policy: Result from invoking describe_load_balancer_policies(...)
    :return: Returns a tuple containing policy_name and the reformatted policy dict.
    """
    policy_name = policy['PolicyName']
    ret = {}
    ret['type'] = policy['PolicyTypeName']
    attrs = policy['PolicyAttributeDescriptions']

    if ret['type'] != 'SSLNegotiationPolicyType':
        return policy_name, ret

    attributes = dict()
    for attr in attrs:
        attributes[attr['AttributeName']] = attr['AttributeValue']

    ret['protocols'] = dict()
    ret['protocols']['sslv2'] = bool(attributes.get('Protocol-SSLv2'))
    ret['protocols']['sslv3'] = bool(attributes.get('Protocol-SSLv3'))
    ret['protocols']['tlsv1'] = bool(attributes.get('Protocol-TLSv1'))
    ret['protocols']['tlsv1_1'] = bool(attributes.get('Protocol-TLSv1.1'))
    ret['protocols']['tlsv1_2'] = bool(attributes.get('Protocol-TLSv1.2'))
    ret['server_defined_cipher_order'] = bool(attributes.get('Server-Defined-Cipher-Order'))
    ret['reference_security_policy'] = attributes.get('Reference-Security-Policy', None)

    non_ciphers = [
        'Server-Defined-Cipher-Order',
        'Protocol-SSLv2',
        'Protocol-SSLv3',
        'Protocol-TLSv1',
        'Protocol-TLSv1.1',
        'Protocol-TLSv1.2',
        'Reference-Security-Policy'
    ]

    ciphers = []
    for cipher in attributes:
        if attributes[cipher] == 'true' and cipher not in non_ciphers:
            ciphers.append(cipher)

    ciphers.sort()
    ret['supported_ciphers'] = ciphers

    return policy_name, ret

def _reformat_policy ( policy ) : policy_name = policy [ 'PolicyName' ] ret = { } ret [ 'type' ] = policy [ 'PolicyTypeName' ] attrs = policy [ 'PolicyAttributeDescriptions' ] if ret [ 'type' ] != 'SSLNegotiationPolicyType' : return policy_name , ret attributes = dict ( ) for attr in attrs : attributes [ attr [ 'AttributeName' ] ] = attr [ 'AttributeValue' ] ret [ 'protocols' ] = dict ( ) ret [ 'protocols' ] [ 'sslv2' ] = bool ( attributes . get ( 'Protocol-SSLv2' ) ) ret [ 'protocols' ] [ 'sslv3' ] = bool ( attributes . get ( 'Protocol-SSLv3' ) ) ret [ 'protocols' ] [ 'tlsv1' ] = bool ( attributes . get ( 'Protocol-TLSv1' ) ) ret [ 'protocols' ] [ 'tlsv1_1' ] = bool ( attributes . get ( 'Protocol-TLSv1.1' ) ) ret [ 'protocols' ] [ 'tlsv1_2' ] = bool ( attributes . get ( 'Protocol-TLSv1.2' ) ) ret [ 'server_defined_cipher_order' ] = bool ( attributes . get ( 'Server-Defined-Cipher-Order' ) ) ret [ 'reference_security_policy' ] = attributes . get ( 'Reference-Security-Policy' , None ) non_ciphers = [ 'Server-Defined-Cipher-Order' , 'Protocol-SSLv2' , 'Protocol-SSLv3' , 'Protocol-TLSv1' , 'Protocol-TLSv1.1' , 'Protocol-TLSv1.2' , 'Reference-Security-Policy' ] ciphers = [ ] for cipher in attributes : if attributes [ cipher ] == 'true' and cipher not in non_ciphers : ciphers . append ( cipher ) ciphers . sort ( ) ret [ 'supported_ciphers' ] = ciphers return policy_name , ret

Policies returned from boto3 are massive ugly and difficult to read . This method flattens and reformats the policy .


def get_load_balancer(load_balancer, flags=FLAGS.ALL ^ FLAGS.POLICY_TYPES, **conn):
    """
    Fully describes an ELB.

    :param loadbalancer: Could be an ELB Name or a dictionary. Likely the return value from a previous call to describe_load_balancers. At a minimum, must contain a key titled 'LoadBalancerName'.
    :param flags: Flags describing which sections should be included in the return value. Default is FLAGS.ALL minus FLAGS.POLICY_TYPES.
    :return: Returns a dictionary describing the ELB with the fields described in the flags parameter.
    """
    # Python 2 and 3 support:
    try:
        basestring
    except NameError as _:
        basestring = str

    if isinstance(load_balancer, basestring):
        load_balancer = dict(LoadBalancerName=load_balancer)

    return registry.build_out(flags, start_with=load_balancer, pass_datastructure=True, **conn)

def
get_load_balancer
(
load_balancer
,
flags
=
FLAGS
.
ALL
^
FLAGS
.
POLICY_TYPES
,
*
*
conn
)
:
# Python 2 and 3 support:
try
:
basestring
except
NameError
as
_
:
basestring
=
str
if
isinstance
(
load_balancer
,
basestring
)
:
load_balancer
=
dict
(
LoadBalancerName
=
load_balancer
)
return
registry
.
build_out
(
flags
,
start_with
=
load_balancer
,
pass_datastructure
=
True
,
*
*
conn
)


def get(self, key, delete_if_expired=True):
        """
        Retrieve key from Cache.

        :param key: key to look up in cache.
        :type key: ``object``

        :param delete_if_expired: remove value from cache if it is expired.
                                  Default is True.
        :type delete_if_expired: ``bool``

        :returns: value from cache or None
        :rtype: varies or None
        """
        self._update_cache_stats(key, None)

        if key in self._CACHE:
            (expiration, obj) = self._CACHE[key]
            if expiration > self._now():
                self._update_cache_stats(key, 'hit')
                return obj
            else:
                if delete_if_expired:
                    self.delete(key)
                    self._update_cache_stats(key, 'expired')
                    return None

        self._update_cache_stats(key, 'miss')
        return None

def get ( self , key , delete_if_expired = True ) : self . _update_cache_stats ( key , None ) if key in self . _CACHE : ( expiration , obj ) = self . _CACHE [ key ] if expiration > self . _now ( ) : self . _update_cache_stats ( key , 'hit' ) return obj else : if delete_if_expired : self . delete ( key ) self . _update_cache_stats ( key , 'expired' ) return None self . _update_cache_stats ( key , 'miss' ) return None


def insert(self, key, obj, future_expiration_minutes=15):
        """
        Insert item into cache.

        :param key: key to look up in cache.
        :type key: ``object``

        :param obj: item to store in cache.
        :type obj: varies

        :param future_expiration_minutes: number of minutes item is valid
        :type param: ``int``

        :returns: True
        :rtype: ``bool``
        """
        expiration_time = self._calculate_expiration(future_expiration_minutes)
        self._CACHE[key] = (expiration_time, obj)
        return True

def insert ( self , key , obj , future_expiration_minutes = 15 ) : expiration_time = self . _calculate_expiration ( future_expiration_minutes ) self . _CACHE [ key ] = ( expiration_time , obj ) return True


def _update_cache_stats(self, key, result):
        """
        Update the cache stats.

        If no cache-result is specified, we iniitialize the key.
        Otherwise, we increment the correct cache-result.

        Note the behavior for expired.  A client can be expired and the key
        still exists.
        """
        if result is None:
            self._CACHE_STATS['access_stats'].setdefault(key,
                                         {'hit': 0, 'miss': 0, 'expired': 0})
        else:
            self._CACHE_STATS['access_stats'][key][result] +=1

def _update_cache_stats ( self , key , result ) : if result is None : self . _CACHE_STATS [ 'access_stats' ] . setdefault ( key , { 'hit' : 0 , 'miss' : 0 , 'expired' : 0 } ) else : self . _CACHE_STATS [ 'access_stats' ] [ key ] [ result ] += 1

Update the cache stats . If no cache - result is specified we iniitialize the key . Otherwise we increment the correct cache - result .


def get_access_details(self, key=None):
        """Get access details in cache."""
        if key in self._CACHE_STATS:
            return self._CACHE_STATS['access_stats'][key]
        else:
            return self._CACHE_STATS['access_stats']

def get_access_details ( self , key = None ) : if key in self . _CACHE_STATS : return self . _CACHE_STATS [ 'access_stats' ] [ key ] else : return self . _CACHE_STATS [ 'access_stats' ]


def get_stats(self):
        """Get general stats for the cache."""
        expired = sum([x['expired'] for _, x in
                       self._CACHE_STATS['access_stats'].items()])
        miss = sum([x['miss'] for _, x in
                    self._CACHE_STATS['access_stats'].items()])

        hit = sum([x['hit'] for _, x in
                       self._CACHE_STATS['access_stats'].items()])
        return {
            'totals': {
                'keys': len(self._CACHE_STATS['access_stats']),
                'expired': expired,
                'miss': miss,
                'hit': hit,
                }
        }

def get_stats ( self ) : expired = sum ( [ x [ 'expired' ] for _ , x in self . _CACHE_STATS [ 'access_stats' ] . items ( ) ] ) miss = sum ( [ x [ 'miss' ] for _ , x in self . _CACHE_STATS [ 'access_stats' ] . items ( ) ] ) hit = sum ( [ x [ 'hit' ] for _ , x in self . _CACHE_STATS [ 'access_stats' ] . items ( ) ] ) return { 'totals' : { 'keys' : len ( self . _CACHE_STATS [ 'access_stats' ] ) , 'expired' : expired , 'miss' : miss , 'hit' : hit , } }


def get_vpc_flow_logs(vpc, **conn):
    """Gets the VPC Flow Logs for a VPC"""
    fl_result = describe_flow_logs(Filters=[{"Name": "resource-id", "Values": [vpc["id"]]}], **conn)

    fl_ids = []
    for fl in fl_result:
        fl_ids.append(fl["FlowLogId"])

    return fl_ids

def get_vpc_flow_logs ( vpc , * * conn ) : fl_result = describe_flow_logs ( Filters = [ { "Name" : "resource-id" , "Values" : [ vpc [ "id" ] ] } ] , * * conn ) fl_ids = [ ] for fl in fl_result : fl_ids . append ( fl [ "FlowLogId" ] ) return fl_ids


def get_classic_link(vpc, **conn):
    """Gets the Classic Link details about a VPC"""
    result = {}

    try:
        cl_result = describe_vpc_classic_link(VpcIds=[vpc["id"]], **conn)[0]
        result["Enabled"] = cl_result["ClassicLinkEnabled"]

        # Check for DNS as well:
        dns_result = describe_vpc_classic_link_dns_support(VpcIds=[vpc["id"]], **conn)[0]
        result["DnsEnabled"] = dns_result["ClassicLinkDnsSupported"]
    except ClientError as e:
        # This is not supported for all regions.
        if 'UnsupportedOperation' not in str(e):
            raise e

    return result


def get_subnets(vpc, **conn):
    """Gets the VPC Subnets"""
    subnets = describe_subnets(Filters=[{"Name": "vpc-id", "Values": [vpc["id"]]}], **conn)

    s_ids = []
    for s in subnets:
        s_ids.append(s["SubnetId"])

    return s_ids

def get_subnets ( vpc , * * conn ) : subnets = describe_subnets ( Filters = [ { "Name" : "vpc-id" , "Values" : [ vpc [ "id" ] ] } ] , * * conn ) s_ids = [ ] for s in subnets : s_ids . append ( s [ "SubnetId" ] ) return s_ids


def get_route_tables(vpc, **conn):
    """Gets the VPC Route Tables"""
    route_tables = describe_route_tables(Filters=[{"Name": "vpc-id", "Values": [vpc["id"]]}], **conn)

    rt_ids = []
    for r in route_tables:
        rt_ids.append(r["RouteTableId"])

    return rt_ids

def get_route_tables ( vpc , * * conn ) : route_tables = describe_route_tables ( Filters = [ { "Name" : "vpc-id" , "Values" : [ vpc [ "id" ] ] } ] , * * conn ) rt_ids = [ ] for r in route_tables : rt_ids . append ( r [ "RouteTableId" ] ) return rt_ids


def get_network_acls(vpc, **conn):
    """Gets the VPC Network ACLs"""
    route_tables = describe_network_acls(Filters=[{"Name": "vpc-id", "Values": [vpc["id"]]}], **conn)

    nacl_ids = []
    for r in route_tables:
        nacl_ids.append(r["NetworkAclId"])

    return nacl_ids

def get_network_acls ( vpc , * * conn ) : route_tables = describe_network_acls ( Filters = [ { "Name" : "vpc-id" , "Values" : [ vpc [ "id" ] ] } ] , * * conn ) nacl_ids = [ ] for r in route_tables : nacl_ids . append ( r [ "NetworkAclId" ] ) return nacl_ids


def get_client(service, service_type='client', **conn_args):
    """
    User function to get the correct client.

    Based on the GOOGLE_CLIENT_MAP dictionary, the return will be a cloud or general
    client that can interact with the desired service.

    :param service: GCP service to connect to. E.g. 'gce', 'iam'
    :type service: ``str``

    :param conn_args: Dictionary of connection arguments.  'project' is required.
                      'user_agent' can be specified and will be set in the client
                       returned.
    :type conn_args: ``dict``

    :return: client_details, client
    :rtype: ``tuple`` of ``dict``, ``object``
    """
    client_details = choose_client(service)
    user_agent = get_user_agent(**conn_args)
    if client_details:
        if client_details['client_type'] == 'cloud':
            client = get_gcp_client(
                mod_name=client_details['module_name'],
                pkg_name=conn_args.get('pkg_name', 'google.cloud'),
                key_file=conn_args.get('key_file', None),
                project=conn_args['project'], user_agent=user_agent)
        else:
            client = get_google_client(
                mod_name=client_details['module_name'],
                key_file=conn_args.get('key_file', None),
                user_agent=user_agent, api_version=conn_args.get('api_version', 'v1'))
    else:
        # There is no client known for this service. We can try the standard API.
        try:
            client = get_google_client(
                mod_name=service, key_file=conn_args.get('key_file', None),
                user_agent=user_agent, api_version=conn_args.get('api_version', 'v1'))
        except Exception as e:
            raise e

    return client_details, client

User function to get the correct client .


def get_gcp_client(**kwargs):
    """Public GCP client builder."""
    return _gcp_client(project=kwargs['project'], mod_name=kwargs['mod_name'],
                       pkg_name=kwargs.get('pkg_name', 'google.cloud'),
                       key_file=kwargs.get('key_file', None),
                       http_auth=kwargs.get('http', None),
                       user_agent=kwargs.get('user_agent', None))

def get_gcp_client ( * * kwargs ) : return _gcp_client ( project = kwargs [ 'project' ] , mod_name = kwargs [ 'mod_name' ] , pkg_name = kwargs . get ( 'pkg_name' , 'google.cloud' ) , key_file = kwargs . get ( 'key_file' , None ) , http_auth = kwargs . get ( 'http' , None ) , user_agent = kwargs . get ( 'user_agent' , None ) )


def _gcp_client(project, mod_name, pkg_name, key_file=None, http_auth=None,
                user_agent=None):
    """
    Private GCP client builder.

    :param project: Google Cloud project string.
    :type project: ``str``

    :param mod_name: Module name to load.  Should be found in sys.path.
    :type mod_name: ``str``

    :param pkg_name: package name that mod_name is part of.  Default is 'google.cloud' .
    :type pkg_name: ``str``

    :param key_file: Default is None.
    :type key_file: ``str`` or None

    :param http_auth: httplib2 authorized client. Default is None.
    :type http_auth: :class: `HTTPLib2`

    :param user_agent: User Agent string to use in requests. Default is None.
    :type http_auth: ``str`` or None

    :return: GCP client
    :rtype: ``object``
    """
    client = None
    if http_auth is None:
        http_auth = _googleauth(key_file=key_file, user_agent=user_agent)
    try:
        # Using a relative path, so we prefix with a dot (.)
        google_module = importlib.import_module('.' + mod_name,
                                                package=pkg_name)
        client = google_module.Client(use_GAX=USE_GAX, project=project,
                                      http=http_auth)
    except ImportError as ie:
        import_err = 'Unable to import %s.%s' % (pkg_name, mod_name)
        raise ImportError(import_err)
    except TypeError:
        # Not all clients use gRPC
        client = google_module.Client(project=project, http=http_auth)
    if user_agent and hasattr(client, 'user_agent'):
        client.user_agent = user_agent
    return client


def _googleauth(key_file=None, scopes=[], user_agent=None):
    """
    Google http_auth helper.

    If key_file is not specified, default credentials will be used.

    If scopes is specified (and key_file), will be used instead of DEFAULT_SCOPES

    :param key_file: path to key file to use. Default is None
    :type key_file: ``str``

    :param scopes: scopes to set.  Default is DEFAUL_SCOPES
    :type scopes: ``list``

    :param user_agent: User Agent string to use in requests. Default is None.
    :type http_auth: ``str`` or None

    :return: HTTPLib2 authorized client.
    :rtype: :class: `HTTPLib2`
    """
    if key_file:
        if not scopes:
            scopes = DEFAULT_SCOPES
        creds = ServiceAccountCredentials.from_json_keyfile_name(key_file,
                                                                 scopes=scopes)
    else:
        creds = GoogleCredentials.get_application_default()
    http = Http()
    if user_agent:
        http = set_user_agent(http, user_agent)
    http_auth = creds.authorize(http)
    return http_auth

def _googleauth ( key_file = None , scopes = [ ] , user_agent = None ) : if key_file : if not scopes : scopes = DEFAULT_SCOPES creds = ServiceAccountCredentials . from_json_keyfile_name ( key_file , scopes = scopes ) else : creds = GoogleCredentials . get_application_default ( ) http = Http ( ) if user_agent : http = set_user_agent ( http , user_agent ) http_auth = creds . authorize ( http ) return http_auth


def _build_google_client(service, api_version, http_auth):
    """
    Google build client helper.

    :param service: service to build client for
    :type service: ``str``

    :param api_version: API version to use.
    :type api_version: ``str``

    :param http_auth: Initialized HTTP client to use.
    :type http_auth: ``object``

    :return: google-python-api client initialized to use 'service'
    :rtype: ``object``
    """
    client = build(service, api_version, http=http_auth)
    return client

def _build_google_client ( service , api_version , http_auth ) : client = build ( service , api_version , http = http_auth ) return client


def iter_project(projects, key_file=None):
    """
    Call decorated function for each item in project list.

    Note: the function 'decorated' is expected to return a value plus a dictionary of exceptions.

    If item in list is a dictionary, we look for a 'project' and 'key_file' entry, respectively.
    If item in list is of type string_types, we assume it is the project string. Default credentials
    will be used by the underlying client library.

    :param projects: list of project strings or list of dictionaries
                     Example: {'project':..., 'keyfile':...}. Required.
    :type projects: ``list`` of ``str`` or ``list`` of ``dict``

    :param key_file: path on disk to keyfile, for use with all projects
    :type key_file: ``str``

    :returns: tuple containing a list of function output and an exceptions map
    :rtype: ``tuple of ``list``, ``dict``
    """

    def decorator(func):
        @wraps(func)
        def decorated_function(*args, **kwargs):
            item_list = []
            exception_map = {}
            for project in projects:
                if isinstance(project, string_types):
                    kwargs['project'] = project
                    if key_file:
                        kwargs['key_file'] = key_file
                elif isinstance(project, dict):
                    kwargs['project'] = project['project']
                    kwargs['key_file'] = project['key_file']
                itm, exc = func(*args, **kwargs)
                item_list.extend(itm)
                exception_map.update(exc)
            return (item_list, exception_map)

        return decorated_function

    return decorator

def iter_project ( projects , key_file = None ) : def decorator ( func ) : @ wraps ( func ) def decorated_function ( * args , * * kwargs ) : item_list = [ ] exception_map = { } for project in projects : if isinstance ( project , string_types ) : kwargs [ 'project' ] = project if key_file : kwargs [ 'key_file' ] = key_file elif isinstance ( project , dict ) : kwargs [ 'project' ] = project [ 'project' ] kwargs [ 'key_file' ] = project [ 'key_file' ] itm , exc = func ( * args , * * kwargs ) item_list . extend ( itm ) exception_map . update ( exc ) return ( item_list , exception_map ) return decorated_function return decorator

Call decorated function for each item in project list .


def get_creds_from_kwargs(kwargs):
    """Helper to get creds out of kwargs."""
    creds = {
        'key_file': kwargs.pop('key_file', None),
        'http_auth': kwargs.pop('http_auth', None),
        'project': kwargs.get('project', None),
        'user_agent': kwargs.pop('user_agent', None),
        'api_version': kwargs.pop('api_version', 'v1')
    }
    return (creds, kwargs)

def get_creds_from_kwargs ( kwargs ) : creds = { 'key_file' : kwargs . pop ( 'key_file' , None ) , 'http_auth' : kwargs . pop ( 'http_auth' , None ) , 'project' : kwargs . get ( 'project' , None ) , 'user_agent' : kwargs . pop ( 'user_agent' , None ) , 'api_version' : kwargs . pop ( 'api_version' , 'v1' ) } return ( creds , kwargs )


def rewrite_kwargs(conn_type, kwargs, module_name=None):
    """
    Manipulate connection keywords.

    Modifieds keywords based on connection type.

    There is an assumption here that the client has
    already been created and that these keywords are being
    passed into methods for interacting with various services.

    Current modifications:
    - if conn_type is not cloud and module is 'compute',
      then rewrite project as name.
    - if conn_type is cloud and module is 'storage',
      then remove 'project' from dict.

    :param conn_type: E.g. 'cloud' or 'general'
    :type conn_type: ``str``

    :param kwargs: Dictionary of keywords sent in by user.
    :type kwargs: ``dict``

    :param module_name: Name of specific module that will be loaded.
                        Default is None.
    :type conn_type: ``str`` or None

    :returns kwargs with client and module specific changes
    :rtype: ``dict``
    """
    if conn_type != 'cloud' and module_name != 'compute':
        if 'project' in kwargs:
            kwargs['name'] = 'projects/%s' % kwargs.pop('project')
    if conn_type == 'cloud' and module_name == 'storage':
        if 'project' in kwargs:
            del kwargs['project']
    return kwargs

def rewrite_kwargs ( conn_type , kwargs , module_name = None ) : if conn_type != 'cloud' and module_name != 'compute' : if 'project' in kwargs : kwargs [ 'name' ] = 'projects/%s' % kwargs . pop ( 'project' ) if conn_type == 'cloud' and module_name == 'storage' : if 'project' in kwargs : del kwargs [ 'project' ] return kwargs

Manipulate connection keywords . Modifieds keywords based on connection type .


def gce_list_aggregated(service=None, key_name='name', **kwargs):
    """General aggregated list function for the GCE service."""
    resp_list = []
    req = service.aggregatedList(**kwargs)

    while req is not None:
        resp = req.execute()
        for location, item in resp['items'].items():
            if key_name in item:
                resp_list.extend(item[key_name])

        req = service.aggregatedList_next(previous_request=req,
                                          previous_response=resp)
    return resp_list

def gce_list_aggregated ( service = None , key_name = 'name' , * * kwargs ) : resp_list = [ ] req = service . aggregatedList ( * * kwargs ) while req is not None : resp = req . execute ( ) for location , item in resp [ 'items' ] . items ( ) : if key_name in item : resp_list . extend ( item [ key_name ] ) req = service . aggregatedList_next ( previous_request = req , previous_response = resp ) return resp_list

General aggregated list function for the GCE service .


def gce_list(service=None, **kwargs):
    """General list function for the GCE service."""
    resp_list = []
    req = service.list(**kwargs)

    while req is not None:
        resp = req.execute()
        for item in resp.get('items', []):
            resp_list.append(item)
        req = service.list_next(previous_request=req, previous_response=resp)
    return resp_list

def gce_list ( service = None , * * kwargs ) : resp_list = [ ] req = service . list ( * * kwargs ) while req is not None : resp = req . execute ( ) for item in resp . get ( 'items' , [ ] ) : resp_list . append ( item ) req = service . list_next ( previous_request = req , previous_response = resp ) return resp_list

General list function for the GCE service .


def service_list(service=None, key_name=None, **kwargs):
    """General list function for Google APIs."""
    resp_list = []
    req = service.list(**kwargs)

    while req is not None:
        resp = req.execute()
        if key_name and key_name in resp:
            resp_list.extend(resp[key_name])
        else:
            resp_list.append(resp)
        # Not all list calls have a list_next
        if hasattr(service, 'list_next'):
            req = service.list_next(previous_request=req,
                                    previous_response=resp)
        else:
            req = None
    return resp_list

def
service_list
(
service
=
,
key_name
=
,
*
*
kwargs
)
:
resp_list
=
[
]
req
=
service
.
list
(
*
*
kwargs
)
while
req
is
not
:
resp
=
req
.
execute
(
)
if
key_name
and
key_name
in
resp
:
resp_list
.
extend
(
resp
[
key_name
]
)
else
:
resp_list
.
append
(
resp
)
# Not all list calls have a list_next
if
hasattr
(
service
,
'list_next'
)
:
req
=
service
.
list_next
(
previous_request
=
req
,
previous_response
=
resp
)
else
:
req
=
return
resp_list


def get_cache_access_details(key=None):
    """Retrieve detailed cache information."""
    from cloudaux.gcp.decorators import _GCP_CACHE
    return _GCP_CACHE.get_access_details(key=key)

def get_cache_access_details ( key = None ) : from cloudaux . gcp . decorators import _GCP_CACHE return _GCP_CACHE . get_access_details ( key = key )


def get_user_agent_default(pkg_name='cloudaux'):
    """
    Get default User Agent String.

    Try to import pkg_name to get an accurate version number.

    return: string
    """
    version = '0.0.1'
    try:
        import pkg_resources
        version = pkg_resources.get_distribution(pkg_name).version
    except pkg_resources.DistributionNotFound:
        pass
    except ImportError:
        pass

    return 'cloudaux/%s' % (version)

def get_user_agent_default ( pkg_name = 'cloudaux' ) : version = '0.0.1' try : import pkg_resources version = pkg_resources . get_distribution ( pkg_name ) . version except pkg_resources . DistributionNotFound : pass except ImportError : pass return 'cloudaux/%s' % ( version )


def list_rules(client=None, **kwargs):
    """
    NamePrefix='string'
    """
    result = client.list_rules(**kwargs)
    if not result.get("Rules"):
        result.update({"Rules": []})

    return result

def list_rules ( client = None , * * kwargs ) : result = client . list_rules ( * * kwargs ) if not result . get ( "Rules" ) : result . update ( { "Rules" : [ ] } ) return result


def list_targets_by_rule(client=None, **kwargs):
    """
    Rule='string'
    """
    result = client.list_targets_by_rule(**kwargs)
    if not result.get("Targets"):
        result.update({"Targets": []})

    return result

def list_targets_by_rule ( client = None , * * kwargs ) : result = client . list_targets_by_rule ( * * kwargs ) if not result . get ( "Targets" ) : result . update ( { "Targets" : [ ] } ) return result


def list_buckets(client=None, **kwargs):
    """
    List buckets for a project.

    :param client: client object to use.
    :type client: Google Cloud Storage client

    :returns: list of dictionary reprsentation of Bucket
    :rtype: ``list`` of ``dict``
    """
    buckets = client.list_buckets(**kwargs)
    return [b.__dict__ for b in buckets]

def list_buckets ( client = None , * * kwargs ) : buckets = client . list_buckets ( * * kwargs ) return [ b . __dict__ for b in buckets ]


def list_objects_in_bucket(**kwargs):
    """
    List objects in bucket.

    :param Bucket: name of bucket
    :type Bucket: ``str``

    :returns list of objects in bucket
    :rtype: ``list``
    """
    bucket = get_bucket(**kwargs)
    if bucket:
        return [o for o in bucket.list_blobs()]
    else:
        return None

def list_objects_in_bucket ( * * kwargs ) : bucket = get_bucket ( * * kwargs ) if bucket : return [ o for o in bucket . list_blobs ( ) ] else : return None


def modify(item, output='camelized'):
    """
    Calls _modify and either passes the inflection.camelize method or the inflection.underscore method.

    :param item: dictionary representing item to be modified
    :param output: string 'camelized' or 'underscored'
    :return:
    """
    if output == 'camelized':
        return _modify(item, camelize)
    elif output == 'underscored':
        return _modify(item, underscore)

def modify ( item , output = 'camelized' ) : if output == 'camelized' : return _modify ( item , camelize ) elif output == 'underscored' : return _modify ( item , underscore )

Calls _modify and either passes the inflection . camelize method or the inflection . underscore method .


def get_role_managed_policy_documents(role, client=None, **kwargs):
    """Retrieve the currently active policy version document for every managed policy that is attached to the role."""
    policies = get_role_managed_policies(role, force_client=client)

    policy_names = (policy['name'] for policy in policies)
    delayed_gmpd_calls = (delayed(get_managed_policy_document)(policy['arn'], force_client=client) for policy
                          in policies)
    policy_documents = Parallel(n_jobs=20, backend="threading")(delayed_gmpd_calls)

    return dict(zip(policy_names, policy_documents))

def get_role_managed_policy_documents ( role , client = None , * * kwargs ) : policies = get_role_managed_policies ( role , force_client = client ) policy_names = ( policy [ 'name' ] for policy in policies ) delayed_gmpd_calls = ( delayed ( get_managed_policy_document ) ( policy [ 'arn' ] , force_client = client ) for policy in policies ) policy_documents = Parallel ( n_jobs = 20 , backend = "threading" ) ( delayed_gmpd_calls ) return dict ( zip ( policy_names , policy_documents ) )

Retrieve the currently active policy version document for every managed policy that is attached to the role .


def get_group(group_name, users=True, client=None, **kwargs):
    """Get's the IAM Group details.

    :param group_name:
    :param users: Optional -- will return the IAM users that the group is attached to if desired (paginated).
    :param client:
    :param kwargs:
    :return:
    """
    # First, make the initial call to get the details for the group:
    result = client.get_group(GroupName=group_name, **kwargs)

    # If we care about the user details, then fetch them:
    if users:
        if result.get('IsTruncated'):
            kwargs_to_send = {'GroupName': group_name}
            kwargs_to_send.update(kwargs)

            user_list = result['Users']
            kwargs_to_send['Marker'] = result['Marker']

            result['Users'] = user_list + _get_users_for_group(client, **kwargs_to_send)

    else:
        result.pop('Users', None)
        result.pop('IsTruncated', None)
        result.pop('Marker', None)

    return result


def get_group_policy_document(group_name, policy_name, client=None, **kwargs):
    """Fetches the specific IAM group inline-policy document."""
    return client.get_group_policy(GroupName=group_name, PolicyName=policy_name, **kwargs)['PolicyDocument']

def get_group_policy_document ( group_name , policy_name , client = None , * * kwargs ) : return client . get_group_policy ( GroupName = group_name , PolicyName = policy_name , * * kwargs ) [ 'PolicyDocument' ]

Fetches the specific IAM group inline - policy document .


def _get_base(server_certificate, **conn):
    """Fetch the base IAM Server Certificate."""
    server_certificate['_version'] = 1

    # Get the initial cert details:
    cert_details = get_server_certificate_api(server_certificate['ServerCertificateName'], **conn)

    if cert_details:
        server_certificate.update(cert_details['ServerCertificateMetadata'])
        server_certificate['CertificateBody'] = cert_details['CertificateBody']
        server_certificate['CertificateChain'] = cert_details.get('CertificateChain', None)

        # Cast dates from a datetime to something JSON serializable.
        server_certificate['UploadDate'] = get_iso_string(server_certificate['UploadDate'])
        server_certificate['Expiration'] = get_iso_string(server_certificate['Expiration'])

    return server_certificate


def boto3_cached_conn(service, service_type='client', future_expiration_minutes=15, account_number=None,
                      assume_role=None, session_name='cloudaux', region='us-east-1', return_credentials=False,
                      external_id=None, arn_partition='aws'):
    """
    Used to obtain a boto3 client or resource connection.
    For cross account, provide both account_number and assume_role.

    :usage:

    # Same Account:
    client = boto3_cached_conn('iam')
    resource = boto3_cached_conn('iam', service_type='resource')

    # Cross Account Client:
    client = boto3_cached_conn('iam', account_number='000000000000', assume_role='role_name')

    # Cross Account Resource:
    resource = boto3_cached_conn('iam', service_type='resource', account_number='000000000000', assume_role='role_name')

    :param service: AWS service (i.e. 'iam', 'ec2', 'kms')
    :param service_type: 'client' or 'resource'
    :param future_expiration_minutes: Connections will expire from the cache
        when their expiration is within this many minutes of the present time. [Default 15]
    :param account_number: Required if assume_role is provided.
    :param assume_role:  Name of the role to assume into for account described by account_number.
    :param session_name: Session name to attach to requests. [Default 'cloudaux']
    :param region: Region name for connection. [Default us-east-1]
    :param return_credentials: Indicates if the STS credentials should be returned with the client [Default False]
    :param external_id: Optional external id to pass to sts:AssumeRole.
        See https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_create_for-user_externalid.html
    :param arn_partition: Optional parameter to specify other aws partitions such as aws-us-gov for aws govcloud
    :return: boto3 client or resource connection
    """
    key = (
        account_number,
        assume_role,
        session_name,
        external_id,
        region,
        service_type,
        service,
        arn_partition
    )

    if key in CACHE:
        retval = _get_cached_creds(key, service, service_type, region, future_expiration_minutes, return_credentials)
        if retval:
            return retval

    role = None
    if assume_role:
        sts = boto3.session.Session().client('sts')

        # prevent malformed ARN
        if not all([account_number, assume_role]):
            raise ValueError("Account number and role to assume are both required")

        arn = 'arn:{partition}:iam::{0}:role/{1}'.format(
            account_number,
            assume_role,
            partition=arn_partition
        )

        assume_role_kwargs = {
            'RoleArn': arn,
            'RoleSessionName': session_name
        }

        if external_id:
            assume_role_kwargs['ExternalId'] = external_id

        role = sts.assume_role(**assume_role_kwargs)

    if service_type == 'client':
        conn = _client(service, region, role)
    elif service_type == 'resource':
        conn = _resource(service, region, role)

    if role:
        CACHE[key] = role

    if return_credentials:
        return conn, role['Credentials']

    return conn

Used to obtain a boto3 client or resource connection . For cross account provide both account_number and assume_role .


def get_rules(security_group, **kwargs):
    """ format the rule fields to match AWS to support auditor reuse,
        will need to remap back if we want to orchestrate from our stored items """
    rules = security_group.pop('security_group_rules',[])
    for rule in rules:
        rule['ip_protocol'] = rule.pop('protocol')
        rule['from_port'] = rule.pop('port_range_max')
        rule['to_port'] = rule.pop('port_range_min')
        rule['cidr_ip'] = rule.pop('remote_ip_prefix')
        rule['rule_type'] = rule.pop('direction')
    security_group['rules'] = sorted(rules)
    return security_group

def get_rules ( security_group , * * kwargs ) : rules = security_group . pop ( 'security_group_rules' , [ ] ) for rule in rules : rule [ 'ip_protocol' ] = rule . pop ( 'protocol' ) rule [ 'from_port' ] = rule . pop ( 'port_range_max' ) rule [ 'to_port' ] = rule . pop ( 'port_range_min' ) rule [ 'cidr_ip' ] = rule . pop ( 'remote_ip_prefix' ) rule [ 'rule_type' ] = rule . pop ( 'direction' ) security_group [ 'rules' ] = sorted ( rules ) return security_group

format the rule fields to match AWS to support auditor reuse will need to remap back if we want to orchestrate from our stored items


def get_security_group(security_group, flags=FLAGS.ALL, **kwargs):
    result = registry.build_out(flags, start_with=security_group,  pass_datastructure=True, **kwargs)
    """ just store the AWS formatted rules """
    result.pop('security_group_rules', [])
    return result

def get_security_group ( security_group , flags = FLAGS . ALL , * * kwargs ) : result = registry . build_out ( flags , start_with = security_group , pass_datastructure = True , * * kwargs ) result . pop ( 'security_group_rules' , [ ] ) return result


def get_inline_policies(group, **conn):
    """Get the inline policies for the group."""
    policy_list = list_group_policies(group['GroupName'])

    policy_documents = {}

    for policy in policy_list:
        policy_documents[policy] = get_group_policy_document(group['GroupName'], policy, **conn)

    return policy_documents

def get_inline_policies ( group , * * conn ) : policy_list = list_group_policies ( group [ 'GroupName' ] ) policy_documents = { } for policy in policy_list : policy_documents [ policy ] = get_group_policy_document ( group [ 'GroupName' ] , policy , * * conn ) return policy_documents


def get_managed_policies(group, **conn):
    """Get a list of the managed policy names that are attached to the group."""
    managed_policies = list_attached_group_managed_policies(group['GroupName'], **conn)

    managed_policy_names = []

    for policy in managed_policies:
        managed_policy_names.append(policy['PolicyName'])

    return managed_policy_names

def get_managed_policies ( group , * * conn ) : managed_policies = list_attached_group_managed_policies ( group [ 'GroupName' ] , * * conn ) managed_policy_names = [ ] for policy in managed_policies : managed_policy_names . append ( policy [ 'PolicyName' ] ) return managed_policy_names

Get a list of the managed policy names that are attached to the group .


def get_users(group, **conn):
    """Gets a list of the usernames that are a part of this group."""
    group_details = get_group_api(group['GroupName'], **conn)

    user_list = []
    for user in group_details.get('Users', []):
        user_list.append(user['UserName'])

    return user_list

def get_users ( group , * * conn ) : group_details = get_group_api ( group [ 'GroupName' ] , * * conn ) user_list = [ ] for user in group_details . get ( 'Users' , [ ] ) : user_list . append ( user [ 'UserName' ] ) return user_list

Gets a list of the usernames that are a part of this group .


def _get_base(group, **conn):
    """Fetch the base IAM Group."""
    group['_version'] = 1

    # Get the initial group details (only needed if we didn't grab the users):
    group.update(get_group_api(group['GroupName'], users=False, **conn)['Group'])

    # Cast CreateDate from a datetime to something JSON serializable.
    group['CreateDate'] = get_iso_string(group['CreateDate'])
    return group


def get_base(managed_policy, **conn):
    """Fetch the base Managed Policy.

    This includes the base policy and the latest version document.

    :param managed_policy:
    :param conn:
    :return:
    """
    managed_policy['_version'] = 1

    arn = _get_name_from_structure(managed_policy, 'Arn')
    policy = get_policy(arn, **conn)
    document = get_managed_policy_document(arn, policy_metadata=policy, **conn)

    managed_policy.update(policy['Policy'])
    managed_policy['Document'] = document

    # Fix the dates:
    managed_policy['CreateDate'] = get_iso_string(managed_policy['CreateDate'])
    managed_policy['UpdateDate'] = get_iso_string(managed_policy['UpdateDate'])

    return managed_policy

def
get_base
(
managed_policy
,
*
*
conn
)
:
managed_policy
[
'_version'
]
=
1
arn
=
_get_name_from_structure
(
managed_policy
,
'Arn'
)
policy
=
get_policy
(
arn
,
*
*
conn
)
document
=
get_managed_policy_document
(
arn
,
policy_metadata
=
policy
,
*
*
conn
)
managed_policy
.
update
(
policy
[
'Policy'
]
)
managed_policy
[
'Document'
]
=
document
# Fix the dates:
managed_policy
[
'CreateDate'
]
=
get_iso_string
(
managed_policy
[
'CreateDate'
]
)
managed_policy
[
'UpdateDate'
]
=
get_iso_string
(
managed_policy
[
'UpdateDate'
]
)
return
managed_policy


def get_short_version(self):
        '''obtain the shory geoserver version
        '''
        gs_version = self.get_version()
        match = re.compile(r'[^\d.]+')
        return match.sub('', gs_version).strip('.')

def get_short_version ( self ) : gs_version = self . get_version ( ) match = re . compile ( r'[^\d.]+' ) return match . sub ( '' , gs_version ) . strip ( '.' )


def save(self, obj, content_type="application/xml"):
        """
        saves an object to the REST service
        gets the object's REST location and the data from the object,
        then POSTS the request.
        """
        rest_url = obj.href
        data = obj.message()

        headers = {
            "Content-type": content_type,
            "Accept": content_type
        }

        logger.debug("{} {}".format(obj.save_method, obj.href))
        resp = self.http_request(rest_url, method=obj.save_method.lower(), data=data, headers=headers)

        if resp.status_code not in (200, 201):
            raise FailedRequestError('Failed to save to Geoserver catalog: {}, {}'.format(resp.status_code, resp.text))

        self._cache.clear()
        return resp

saves an object to the REST service gets the object s REST location and the data from the object then POSTS the request .


def get_stores(self, names=None, workspaces=None):
        '''
          Returns a list of stores in the catalog. If workspaces is specified will only return stores in those workspaces.
          If names is specified, will only return stores that match.
          names can either be a comma delimited string or an array.
          Will return an empty list if no stores are found.
        '''

        if isinstance(workspaces, Workspace):
            workspaces = [workspaces]
        elif isinstance(workspaces, list) and [w for w in workspaces if isinstance(w, Workspace)]:
            # nothing
            pass
        else:
            workspaces = self.get_workspaces(names=workspaces)

        stores = []
        for ws in workspaces:
            ds_list = self.get_xml(ws.datastore_url)
            cs_list = self.get_xml(ws.coveragestore_url)
            wms_list = self.get_xml(ws.wmsstore_url)
            stores.extend([datastore_from_index(self, ws, n) for n in ds_list.findall("dataStore")])
            stores.extend([coveragestore_from_index(self, ws, n) for n in cs_list.findall("coverageStore")])
            stores.extend([wmsstore_from_index(self, ws, n) for n in wms_list.findall("wmsStore")])

        if names is None:
            names = []
        elif isinstance(names, basestring):
            names = [s.strip() for s in names.split(',') if s.strip()]

        if stores and names:
            return ([store for store in stores if store.name in names])

        return stores

def
get_stores
(
self
,
names
=
,
workspaces
=
)
:
if
isinstance
(
workspaces
,
Workspace
)
:
workspaces
=
[
workspaces
]
elif
isinstance
(
workspaces
,
list
)
and
[
w
for
w
in
workspaces
if
isinstance
(
w
,
Workspace
)
]
:
# nothing
pass
else
:
workspaces
=
self
.
get_workspaces
(
names
=
workspaces
)
stores
=
[
]
for
ws
in
workspaces
:
ds_list
=
self
.
get_xml
(
ws
.
datastore_url
)
cs_list
=
self
.
get_xml
(
ws
.
coveragestore_url
)
wms_list
=
self
.
get_xml
(
ws
.
wmsstore_url
)
stores
.
extend
(
[
datastore_from_index
(
self
,
ws
,
n
)
for
n
in
ds_list
.
findall
(
"dataStore"
)
]
)
stores
.
extend
(
[
coveragestore_from_index
(
self
,
ws
,
n
)
for
n
in
cs_list
.
findall
(
"coverageStore"
)
]
)
stores
.
extend
(
[
wmsstore_from_index
(
self
,
ws
,
n
)
for
n
in
wms_list
.
findall
(
"wmsStore"
)
]
)
if
names
is
:
names
=
[
]
elif
isinstance
(
names
,
basestring
)
:
names
=
[
s
.
strip
(
)
for
s
in
names
.
split
(
','
)
if
s
.
strip
(
)
]
if
stores
and
names
:
return
(
[
store
for
store
in
stores
if
store
.
name
in
names
]
)
return
stores

Returns a list of stores in the catalog . If workspaces is specified will only return stores in those workspaces . If names is specified will only return stores that match . names can either be a comma delimited string or an array . Will return an empty list if no stores are found .


def get_store(self, name, workspace=None):
        '''
          Returns a single store object.
          Will return None if no store is found.
          Will raise an error if more than one store with the same name is found.
        '''

        stores = self.get_stores(workspaces=workspace, names=name)
        return self._return_first_item(stores)

def get_store ( self , name , workspace = None ) : stores = self . get_stores ( workspaces = workspace , names = name ) return self . _return_first_item ( stores )

Returns a single store object . Will return None if no store is found . Will raise an error if more than one store with the same name is found .


def delete_granule(self, coverage, store, granule_id, workspace=None):
        '''Deletes a granule of an existing imagemosaic'''
        params = dict()

        workspace_name = workspace
        if isinstance(store, basestring):
            store_name = store
        else:
            store_name = store.name
            workspace_name = store.workspace.name

        if workspace_name is None:
            raise ValueError("Must specify workspace")

        url = build_url(
            self.service_url,
            [
                "workspaces",
                workspace_name,
                "coveragestores",
                store_name,
                "coverages",
                coverage,
                "index/granules",
                granule_id,
                ".json"
            ],
            params
        )

        # DELETE /workspaces/<ws>/coveragestores/<name>/coverages/<coverage>/index/granules/<granule_id>.json
        headers = {
            "Content-type": "application/json",
            "Accept": "application/json"
        }

        resp = self.http_request(url, method='delete', headers=headers)
        if resp.status_code != 200:
            FailedRequestError('Failed to delete granule from mosaic {} : {}, {}'.format(store, resp.status_code, resp.text))
        self._cache.clear()

        # maybe return a list of all granules?
        return None