示例#1
0
class CertConnect(object):
    """
    Demonstrates how to Connect to vCenter vAPI service with
    with Valid Cert
    """
    def __init__(self):
        self.server = None
        self.username = None
        self.password = None
        self.stub_config = None
        self.cleardata = None
        self.skip_verification = False
        self.cert_path = None
        self.category_svc = None
        self.category_id = None

    def setup(self):
        parser = build_arg_parser()
        parser.add_argument(
            '-cpath',
            '--cert_path',
            action='store',
            help=
            'path to a CA_BUNDLE file or directory with certificates of trusted CAs'
        )
        args = parser.parse_args()

        self.server, self.username, self.password, self.cleardata, self.skip_verification = \
            process_cli_args(args)

        if args.cert_path:
            self.cert_path = args.cert_path

    def run(self):
        print('\n\n#### Example: Login to vCenter server with '
              'Valid Cert Verification')
        # Connect to VAPI
        self.stub_config = vapiconnect.connect(self.server,
                                               self.username,
                                               self.password,
                                               self.skip_verification,
                                               cert_path=self.cert_path)
        atexit.register(vapiconnect.logout, self.stub_config)

        # Create and Delete TagCategory to Verify connection is successful
        print('\nStep 3: Creating and Deleting Tag Category...\n')
        self.category_svc = Category(self.stub_config)

        self.category_id = self.create_tag_category(
            'TestTagCat', 'TestTagDesc', CategoryModel.Cardinality.MULTIPLE)
        assert self.category_id is not None
        print('Tag category created; Id: {0}\n'.format(self.category_id))

        # Delete TagCategory
        self.category_svc.delete(self.category_id)

        print('VAPI session disconnected successfully...')

    def create_tag_category(self, name, description, cardinality):
        """create a category. User who invokes this needs create category privilege."""
        create_spec = self.category_svc.CreateSpec()
        create_spec.name = name
        create_spec.description = description
        create_spec.cardinality = cardinality
        associableTypes = set()
        create_spec.associable_types = associableTypes
        return self.category_svc.create(create_spec)
示例#2
0
class EmbeddedPscSsoWorkflow(object):
    """
    Demonstrates how to Login to vCenter vAPI service with
    embedded Platform Services Controller.
    """

    def __init__(self):
        self.server = None
        self.username = None
        self.password = None
        self.session = None
        self.session_id = None
        self.skip_verification = False
        self.category_svc = None
        self.category_id = None

    def setup(self):
        self.server, self.username, self.password, _, self.skip_verification = \
            parse_cli_args()

    def run(self):
        print('\n\n#### Example: Login to vCenter server with '
              'embedded Platform Services Controller')

        # Since the platform services controller is embedded, the sso server
        # is the same as the vCenter server.
        ssoUrl = 'https://{}/sts/STSService'.format(self.server)

        print('\nStep 1: Connect to the Single Sign-On URL and '
              'retrieve the SAML bearer token.')

        authenticator = sso.SsoAuthenticator(ssoUrl)
        context = None
        if self.skip_verification:
            context = get_unverified_context()
        bearer_token = authenticator.get_bearer_saml_assertion(
            self.username,
            self.password,
            delegatable=True,
            ssl_context=context)

        # Creating SAML Bearer Security Context
        sec_ctx = create_saml_bearer_security_context(bearer_token)

        print('\nStep 2. Login to vAPI services using the SAML bearer token.')

        # The URL for the stub requests are made against the /api HTTP endpoint
        # of the vCenter system.
        vapi_url = 'https://{}/api'.format(self.server)

        # Create an authenticated stub configuration object that can be used to
        # issue requests against vCenter.
        session = requests.Session()
        if self.skip_verification:
            session = create_unverified_session(session)
        connector = get_requests_connector(session=session, url=vapi_url)
        connector.set_security_context(sec_ctx)
        stub_config = StubConfigurationFactory.new_std_configuration(
            connector)
        self.session = Session(stub_config)

        # Login to VAPI endpoint and get the session_id
        self.session_id = self.session.create()

        # Update the VAPI connection with session_id
        session_sec_ctx = create_session_security_context(self.session_id)
        connector.set_security_context(session_sec_ctx)

        # Create and Delete TagCategory to Verify connection is successful
        print('\nStep 3: Creating and Deleting Tag Category...\n')
        self.category_svc = Category(stub_config)

        self.category_id = self.create_tag_category('TestTagCat', 'TestTagDesc',
                                                    CategoryModel.Cardinality.MULTIPLE)
        assert self.category_id is not None
        print('Tag category created; Id: {0}\n'.format(self.category_id))

        # Delete TagCategory
        self.category_svc.delete(self.category_id)

        self.session.delete()
        print('VAPI session disconnected successfully...')

    def create_tag_category(self, name, description, cardinality):
        """create a category. User who invokes this needs create category privilege."""
        create_spec = self.category_svc.CreateSpec()
        create_spec.name = name
        create_spec.description = description
        create_spec.cardinality = cardinality
        associableTypes = set()
        create_spec.associable_types = associableTypes
        return self.category_svc.create(create_spec)
class TaggingWorkflow(SampleBase):
    """
    Demonstrates tagging CRUD operations
    Step 1: Create a Tag category.
    Step 2: Create a Tag under the category.
    Step 3: Retrieve the managed object id of an existing cluster from its name.
    Step 4: Assign the tag to the cluster.
    Additional steps when clearData flag is set to TRUE:
    Step 5: Detach the tag from the cluster.
    Step 6: Delete the tag.
    Step 7: Delete the tag category.
    Note: the sample needs an existing cluster
    """
    def __init__(self):
        SampleBase.__init__(self, self.__doc__)
        self.servicemanager = None

        self.category_svc = None
        self.tag_svc = None
        self.tag_association = None

        self.category_name = None
        self.category_desc = None
        self.tag_name = None
        self.tag_desc = None

        self.cluster_name = None
        self.cluster_moid = None
        self.category_id = None
        self.tag_id = None
        self.tag_attached = False
        self.dynamic_id = None

    def _options(self):
        self.argparser.add_argument('-clustername',
                                    '--clustername',
                                    help='Name of the cluster to be tagged')
        self.argparser.add_argument('-categoryname',
                                    '--categoryname',
                                    help='Name of the Category to be created')
        self.argparser.add_argument(
            '-categorydesc',
            '--categorydesc',
            help='Description of the Category to be created')
        self.argparser.add_argument('-tagname',
                                    '--tagname',
                                    help='Name of the tag to be created')
        self.argparser.add_argument(
            '-tagdesc',
            '--tagdesc',
            help='Description of the tag to be created')

    def _setup(self):
        if self.cluster_name is None:  # for testing
            self.cluster_name = self.args.clustername
        assert self.cluster_name is not None
        print('Cluster Name: {0}'.format(self.cluster_name))

        if self.category_name is None:
            self.category_name = self.args.categoryname
        assert self.category_name is not None
        print('Category Name: {0}'.format(self.category_name))

        if self.category_desc is None:
            self.category_desc = self.args.categorydesc
        assert self.category_desc is not None
        print('Category Description: {0}'.format(self.category_desc))

        if self.tag_name is None:
            self.tag_name = self.args.tagname
        assert self.tag_name is not None
        print('Tag Name: {0}'.format(self.tag_name))

        if self.tag_desc is None:
            self.tag_desc = self.args.tagdesc
        assert self.tag_desc is not None
        print('Tag Description: {0}'.format(self.tag_desc))

        if self.servicemanager is None:
            self.servicemanager = self.get_service_manager()

        self.category_svc = Category(self.servicemanager.stub_config)
        self.tag_svc = Tag(self.servicemanager.stub_config)
        self.tag_association = TagAssociation(self.servicemanager.stub_config)

    def _execute(self):
        print('List all the existing categories user has access to...')
        categories = self.category_svc.list()
        if len(categories) > 0:
            for category in categories:
                print('Found Category: {0}'.format(category))
        else:
            print('No Tag Category Found...')

        print('List all the existing tags user has access to...')
        tags = self.tag_svc.list()
        if len(tags) > 0:
            for tag in tags:
                print('Found Tag: {0}'.format(tag))
        else:
            print('No Tag Found...')

        print('creating a new tag category...')
        self.category_id = self.create_tag_category(
            self.category_name, self.category_desc,
            CategoryModel.Cardinality.MULTIPLE)
        assert self.category_id is not None
        print('Tag category created; Id: {0}'.format(self.category_id))

        print("creating a new Tag...")
        self.tag_id = self.create_tag(self.tag_name, self.tag_desc,
                                      self.category_id)
        assert self.tag_id is not None
        print('Tag created; Id: {0}'.format(self.tag_id))

        print('updating the tag...')
        date_time = time.strftime('%d/%m/%Y %H:%M:%S')
        self.update_tag(self.tag_id, 'Server Tag updated at ' + date_time)
        print('Tag updated; Id: {0}'.format(self.tag_id))

        print('finding the cluster {0}'.format(self.cluster_name))
        self.cluster_moid = get_cluster_id(service_manager=self.servicemanager,
                                           cluster_name=self.cluster_name)
        assert self.cluster_moid is not None
        print('Found cluster:{0} mo_id:{1}'.format('vAPISDKCluster',
                                                   self.cluster_moid))

        print('Tagging the cluster {0}...'.format(self.cluster_name))
        self.dynamic_id = DynamicID(type='ClusterComputeResource',
                                    id=self.cluster_moid)
        self.tag_association.attach(tag_id=self.tag_id,
                                    object_id=self.dynamic_id)
        for tag_id in self.tag_association.list_attached_tags(self.dynamic_id):
            if tag_id == self.tag_id:
                self.tag_attached = True
                break
        assert self.tag_attached
        print('Tagged cluster: {0}'.format(self.cluster_moid))

    def _cleanup(self):
        try:
            if self.tag_attached:
                self.tag_association.detach(self.tag_id, self.dynamic_id)
                print('Removed tag from cluster: {0}'.format(
                    self.cluster_moid))

            if self.tag_id is not None:
                self.delete_tag(self.tag_id)
                print('Tag deleted; Id: {0}'.format(self.tag_id))

            if self.category_id is not None:
                self.delete_tag_category(self.category_id)
                print('Tag category deleted; Id: {0}'.format(self.category_id))
        except Exception as e:
            raise Exception(e)

    def create_tag_category(self, name, description, cardinality):
        """create a category. User who invokes this needs create category privilege."""
        create_spec = self.category_svc.CreateSpec()
        create_spec.name = name
        create_spec.description = description
        create_spec.cardinality = cardinality
        associableTypes = set()
        create_spec.associable_types = associableTypes
        return self.category_svc.create(create_spec)

    def delete_tag_category(self, category_id):
        """Deletes an existing tag category; User who invokes this API needs
        delete privilege on the tag category.
        """
        self.category_svc.delete(category_id)

    def create_tag(self, name, description, category_id):
        """Creates a Tag"""
        create_spec = self.tag_svc.CreateSpec()
        create_spec.name = name
        create_spec.description = description
        create_spec.category_id = category_id
        return self.tag_svc.create(create_spec)

    def update_tag(self, tag_id, description):
        """Update the description of an existing tag.
        User who invokes this API needs edit privilege on the tag.
        """
        update_spec = self.tag_svc.UpdateSpec()
        update_spec.setDescription = description
        self.tag_svc.update(tag_id, update_spec)

    def delete_tag(self, tag_id):
        """Delete an existing tag.
        User who invokes this API needs delete privilege on the tag."""
        self.tag_svc.delete(tag_id)
示例#4
0
class VmwareCategory(VmwareRestClient):
    def __init__(self, module):
        super(VmwareCategory, self).__init__(module)
        self.category_service = Category(self.connect)
        self.global_categories = dict()
        self.category_name = self.params.get('category_name')
        self.get_all_categories()

    def ensure_state(self):
        """Manage internal states of categories. """
        desired_state = self.params.get('state')
        states = {
            'present': {
                'present': self.state_update_category,
                'absent': self.state_create_category,
            },
            'absent': {
                'present': self.state_delete_category,
                'absent': self.state_unchanged,
            }
        }
        states[desired_state][self.check_category_status()]()

    def state_create_category(self):
        """Create category."""
        category_spec = self.category_service.CreateSpec()
        category_spec.name = self.category_name
        category_spec.description = self.params.get('category_description')

        if self.params.get('category_cardinality') == 'single':
            category_spec.cardinality = CategoryModel.Cardinality.SINGLE
        else:
            category_spec.cardinality = CategoryModel.Cardinality.MULTIPLE

        category_spec.associable_types = set()

        category_id = self.category_service.create(category_spec)
        if category_id:
            self.module.exit_json(
                changed=True,
                category_results=dict(msg="Category '%s' created." %
                                      category_spec.name,
                                      category_id=category_id))
        self.module.exit_json(changed=False,
                              category_results=dict(msg="No category created",
                                                    category_id=''))

    def state_unchanged(self):
        """Return unchanged state."""
        self.module.exit_json(changed=False)

    def state_update_category(self):
        """Update category."""
        category_id = self.global_categories[self.category_name]['category_id']
        changed = False
        results = dict(msg="Category %s is unchanged." % self.category_name,
                       category_id=category_id)

        category_update_spec = self.category_service.UpdateSpec()
        change_list = []
        old_cat_desc = self.global_categories[
            self.category_name]['category_description']
        new_cat_desc = self.params.get('category_description')
        if new_cat_desc and new_cat_desc != old_cat_desc:
            category_update_spec.description = new_cat_desc
            results['msg'] = 'Category %s updated.' % self.category_name
            change_list.append(True)

        new_cat_name = self.params.get('new_category_name')
        if new_cat_name in self.global_categories:
            self.module.fail_json(msg="Unable to rename %s as %s already"
                                  " exists in configuration." %
                                  (self.category_name, new_cat_name))
        old_cat_name = self.global_categories[
            self.category_name]['category_name']

        if new_cat_name and new_cat_name != old_cat_name:
            category_update_spec.name = new_cat_name
            results['msg'] = 'Category %s updated.' % self.category_name
            change_list.append(True)

        if any(change_list):
            self.category_service.update(category_id, category_update_spec)
            changed = True

        self.module.exit_json(changed=changed, category_results=results)

    def state_delete_category(self):
        """Delete category."""
        category_id = self.global_categories[self.category_name]['category_id']
        self.category_service.delete(category_id=category_id)
        self.module.exit_json(
            changed=True,
            category_results=dict(msg="Category '%s' deleted." %
                                  self.category_name,
                                  category_id=category_id))

    def check_category_status(self):
        """
        Check if category exists or not
        Returns: 'present' if category found, else 'absent'

        """
        if self.category_name in self.global_categories:
            return 'present'
        else:
            return 'absent'

    def get_all_categories(self):
        """Retrieve all category information."""
        for category in self.category_service.list():
            category_obj = self.category_service.get(category)
            self.global_categories[category_obj.name] = dict(
                category_description=category_obj.description,
                category_used_by=category_obj.used_by,
                category_cardinality=str(category_obj.cardinality),
                category_associable_types=category_obj.associable_types,
                category_id=category_obj.id,
                category_name=category_obj.name,
            )
class ExternalPscSsoWorkflow(object):
    """
    Demonstrates how to Login to vCenter vAPI service with
    external Platform Services Controller.
    """
    def __init__(self):
        self.lswsdl = None
        self.lsurl = None
        self.mgmtinstancename = None
        self.username = None
        self.password = None
        self.session = None
        self.session_id = None
        self.args = None
        self.argparser = None
        self.mgmtinstancename = None
        self.skip_verification = False
        self.category_svc = None
        self.category_id = None

    def options(self):
        self.argparser = argparse.ArgumentParser(description=self.__doc__)
        # setup the argument parser
        self.argparser.add_argument('-w',
                                    '--lswsdl',
                                    help='Path to the Lookup Service WSDL. '
                                    'By default, lookupservice.wsdl in '
                                    '../wsdl will be used if the parameter'
                                    ' is absent')
        self.argparser.add_argument('-s', '--lsurl', help='Lookup service URL')
        self.argparser.add_argument('-m',
                                    '--mgmtinstancename',
                                    help='Instance name of the vCenter Server '
                                    'management node. '
                                    'When only one node is registered, '
                                    'it is selected by default; otherwise,'
                                    ' omit the parameter to get a list of '
                                    'available nodes.')
        self.argparser.add_argument('-u', '--username', help='SSO user name')
        self.argparser.add_argument('-p',
                                    '--password',
                                    help='SSO user password')
        self.argparser.add_argument('-v',
                                    '--skipverification',
                                    action='store_true',
                                    help='Do not verify server certificate')
        self.args = self.argparser.parse_args()

    def setup(self):
        if self.args.lswsdl:
            self.lswsdl = os.path.abspath(self.args.lswsdl)
        else:
            self.lswsdl = os.path.join(
                os.path.dirname(os.path.abspath(__file__)), 'wsdl',
                'lookupservice.wsdl')
        assert self.lswsdl is not None
        print('lswsdl: {0}'.format(self.lswsdl))

        self.lsurl = self.args.lsurl
        assert self.lsurl is not None
        print('lsurl: {0}'.format(self.lsurl))

        self.username = self.args.username
        assert self.username is not None

        self.password = self.args.password
        assert self.password is not None

        self.mgmtinstancename = self.args.mgmtinstancename
        self.skip_verification = self.args.skipverification

    def run(self):
        print('\n\n#### Example: Login to vCenter server with '
              'external Platform Services Controller')

        print('\nStep 1: Connect to the lookup service on the '
              'Platform Services Controller node: {0}'.format(self.lsurl))

        # Convert wsdl path to url
        self.lswsdl = parse.urljoin('file:', request.pathname2url(self.lswsdl))
        lookupservicehelper = LookupServiceHelper(
            wsdl_url=self.lswsdl,
            soap_url=self.lsurl,
            skip_verification=self.skip_verification)
        lookupservicehelper.connect()

        if self.mgmtinstancename is None:
            self.mgmtinstancename, self.mgmtnodeid = lookupservicehelper.get_default_mgmt_node(
            )
        elif self.mgmtnodeid is None:
            self.mgmtnodeid = lookupservicehelper.get_mgmt_node_id(
                self.mgmtinstancename)
        assert self.mgmtnodeid is not None

        print('\nStep 2: Discover the Single Sign-On service URL'
              ' from lookup service.')
        sso_url = lookupservicehelper.find_sso_url()
        print('Sso URL: {0}'.format(sso_url))

        print('\nStep 3: Connect to the Single Sign-On URL and '
              'retrieve the SAML bearer token.')
        authenticator = sso.SsoAuthenticator(sso_url)
        context = None
        if self.skip_verification:
            context = get_unverified_context()
        bearer_token = authenticator.get_bearer_saml_assertion(
            self.username,
            self.password,
            delegatable=True,
            ssl_context=context)

        # Creating SAML Bearer Security Context
        sec_ctx = create_saml_bearer_security_context(bearer_token)

        print('\nStep 4. Discover the vAPI service URL from lookup service.')
        vapi_url = lookupservicehelper.find_vapi_url(self.mgmtnodeid)
        print('vAPI URL: {0}'.format(vapi_url))

        print('\nStep 5. Login to vAPI service using the SAML bearer token.')

        # Create an authenticated stub configuration object that can be used to
        # issue requests against vCenter.
        session = requests.Session()
        if self.skip_verification:
            session = create_unverified_session(session)
        connector = get_requests_connector(session=session, url=vapi_url)
        connector.set_security_context(sec_ctx)
        stub_config = StubConfigurationFactory.new_std_configuration(connector)
        self.session = Session(stub_config)

        # Login to VAPI endpoint and get the session_id
        self.session_id = self.session.create()

        # Update the VAPI connection with session_id
        session_sec_ctx = create_session_security_context(self.session_id)
        connector.set_security_context(session_sec_ctx)

        # Create and Delete TagCategory to Verify connection is successful
        print('\nStep 6: Creating and Deleting Tag Category...\n')
        self.category_svc = Category(stub_config)

        self.category_id = self.create_tag_category(
            'TestTagCat', 'TestTagDesc', CategoryModel.Cardinality.MULTIPLE)
        assert self.category_id is not None
        print('Tag category created; Id: {0}\n'.format(self.category_id))

        # Delete TagCategory
        self.category_svc.delete(self.category_id)

        self.session.delete()
        print('VAPI session disconnected successfully...')

    def create_tag_category(self, name, description, cardinality):
        """create a category. User who invokes this needs create category privilege."""
        create_spec = self.category_svc.CreateSpec()
        create_spec.name = name
        create_spec.description = description
        create_spec.cardinality = cardinality
        associableTypes = set()
        create_spec.associable_types = associableTypes
        return self.category_svc.create(create_spec)

        self.session.delete()
        print('VAPI session disconnected successfully...')
示例#6
0
class TaggingWorkflow(SampleBase):
    """
    Demonstrates tagging CRUD operations
    Step 1: Create a Tag category.
    Step 2: Create a Tag under the category.
    Step 3: Retrieve the managed object id of an existing cluster from its name.
    Step 4: Assign the tag to the cluster.
    Additional steps when clearData flag is set to TRUE:
    Step 5: Detach the tag from the cluster.
    Step 6: Delete the tag.
    Step 7: Delete the tag category.
    Note: the sample needs an existing cluster
    """

    def __init__(self, platformservicecontroller):
        SampleBase.__init__(self, self.__doc__, platformservicecontroller)
        self.servicemanager = None

        self.category_svc = None
        self.tag_svc = None
        self.tag_association = None

        self.category_name = None
        self.category_desc = None
        self.tag_name = None
        self.tag_desc = None

        self.cluster_name = None
        self.cluster_moid = None
        self.category_id = None
        self.tag_id = None
        self.tag_attached = False
        self.dynamic_id = None

    def _options(self):
        self.argparser.add_argument('-clustername', '--clustername', help='Name of the cluster to be tagged')
        self.argparser.add_argument('-categoryname', '--categoryname', help='Name of the Category to be created')
        self.argparser.add_argument('-categorydesc', '--categorydesc', help='Description of the Category to be created')
        self.argparser.add_argument('-tagname', '--tagname', help='Name of the tag to be created')
        self.argparser.add_argument('-tagdesc', '--tagdesc', help='Description of the tag to be created')

    def _setup(self):
        if self.cluster_name is None:  # for testing
            self.cluster_name = self.args.clustername
        assert self.cluster_name is not None
        logger.info('Cluster Name: {0}'.format(self.cluster_name))

        if self.category_name is None:
            self.category_name = self.args.categoryname
        assert self.category_name is not None
        logger.info('Category Name: {0}'.format(self.category_name))

        if self.category_desc is None:
            self.category_desc = self.args.categorydesc
        assert self.category_desc is not None
        logger.info('Category Description: {0}'.format(self.category_desc))

        if self.tag_name is None:
            self.tag_name = self.args.tagname
        assert self.tag_name is not None
        logger.info('Tag Name: {0}'.format(self.tag_name))

        if self.tag_desc is None:
            self.tag_desc = self.args.tagdesc
        assert self.tag_desc is not None
        logger.info('Tag Description: {0}'.format(self.tag_desc))

        if self.servicemanager is None:
            self.servicemanager = self.get_service_manager()

        self.category_svc = Category(self.servicemanager.stub_config)
        self.tag_svc = Tag(self.servicemanager.stub_config)
        self.tag_association = TagAssociation(self.servicemanager.stub_config)

    def _execute(self):
        logger.info('List all the existing categories user has access to...')
        categories = self.category_svc.list()
        if len(categories) > 0:
            for category in categories:
                logger.info('Found Category: {0}'.format(category))
        else:
            logger.info('No Tag Category Found...')

        logger.info('List all the existing tags user has access to...')
        tags = self.tag_svc.list()
        if len(tags) > 0:
            for tag in tags:
                logger.info('Found Tag: {0}'.format(tag))
        else:
            logger.info('No Tag Found...')

        logger.info('creating a new tag category...')
        self.category_id = self.create_tag_category(self.category_name, self.category_desc, CategoryModel.Cardinality.MULTIPLE)
        assert self.category_id is not None
        logger.info('Tag category created; Id: {0}'.format(self.category_id))

        logger.info("creating a new Tag...")
        self.tag_id = self.create_tag(self.tag_name, self.tag_desc, self.category_id)
        assert self.tag_id is not None
        logger.info('Tag created; Id: {0}'.format(self.tag_id))

        logger.info('updating the tag...')
        date_time = time.strftime('%d/%m/%Y %H:%M:%S')
        self.update_tag(self.tag_id, 'Server Tag updated at ' + date_time)
        logger.info('Tag updated; Id: {0}'.format(self.tag_id))

        logger.info('finding the cluster {0}'.format(self.cluster_name))
        self.cluster_moid = get_cluster_id(service_manager=self.servicemanager, cluster_name=self.cluster_name)
        assert self.cluster_moid is not None
        logger.info('Found cluster:{0} mo_id:{1}'.format('vAPISDKCluster', self.cluster_moid))

        logger.info('Tagging the cluster {0}...'.format(self.cluster_name))
        self.dynamic_id = DynamicID(type='ClusterComputeResource', id=self.cluster_moid)
        self.tag_association.attach(tag_id=self.tag_id, object_id=self.dynamic_id)
        for tag_id in self.tag_association.list_attached_tags(self.dynamic_id):
            if tag_id == self.tag_id:
                self.tag_attached = True
                break
        assert self.tag_attached
        logger.info('Tagged cluster: {0}'.format(self.cluster_moid))

    def _cleanup(self):
        try:
            if self.tag_attached:
                self.tag_association.detach(self.tag_id, self.dynamic_id)
                logger.info('Removed tag from cluster: {0}'.format(self.cluster_moid))

            if self.tag_id is not None:
                self.delete_tag(self.tag_id)
                logger.info('Tag deleted; Id: {0}'.format(self.tag_id))

            if self.category_id is not None:
                self.delete_tag_category(self.category_id)
                logger.info('Tag category deleted; Id: {0}'.format(self.category_id))
        except Exception as e:
            raise Exception(e)

    def create_tag_category(self, name, description, cardinality):
        """create a category. User who invokes this needs create category privilege."""
        create_spec = self.category_svc.CreateSpec()
        create_spec.name = name
        create_spec.description = description
        create_spec.cardinality = cardinality
        associableTypes = set()
        create_spec.associable_types = associableTypes
        return self.category_svc.create(create_spec)

    def delete_tag_category(self, category_id):
        """Deletes an existing tag category; User who invokes this API needs
        delete privilege on the tag category.
        """
        self.category_svc.delete(category_id)

    def create_tag(self, name, description, category_id):
        """Creates a Tag"""
        create_spec = self.tag_svc.CreateSpec()
        create_spec.name = name
        create_spec.description = description
        create_spec.category_id = category_id
        return self.tag_svc.create(create_spec)

    def update_tag(self, tag_id, description):
        """Update the description of an existing tag.
        User who invokes this API needs edit privilege on the tag.
        """
        update_spec = self.tag_svc.UpdateSpec()
        update_spec.setDescription = description
        self.tag_svc.update(tag_id, update_spec)

    def delete_tag(self, tag_id):
        """Delete an existing tag.
        User who invokes this API needs delete privilege on the tag."""
        self.tag_svc.delete(tag_id)