Ejemplo n.º 1
0
    def run(self, options, arguments):
        """Executes command.

    Args:
      options: Command-line options.
      arguments: Command-line positional arguments

    Returns:
      True if successful. False, otherwise.
    """
        log.debug('broker machines list %(options)s %(arguments)s',
                  dict(options=options, arguments=arguments))

        if arguments:
            log.error('Unexpected arguments. See --help for more options.')
            return False

        deployment_name = options.deployment or options.project
        cam = camapi.CloudAccessManager(project=options.project,
                                        scope=camapi.Scope.DEPLOYMENT)
        deployment = cam.deployments.get(deployment_name)
        users = camapi.RequestIterator(cam.machines.entitlements.adusers.get,
                                       deployment)
        visitor = UserPrinter()
        for user in users:
            visitor.visit(user)
def test_users(local_backend):
    """Test user endpoints.

  Args:
    local_backend: Backend that intercepts requests and returns predictable
      test data.
  """
    with local_backend.activate() as backend:
        backend.expect(LocalBackend.GET,
                       camapi.Deployments.url,
                       params=dict(deploymentName='deployment1',
                                   showactive='true'),
                       result=dict(total=1, data=[backend.deployments[0]]))
        backend.expect(LocalBackend.GET,
                       camapi.MachinesEntitlementsADUsers.url,
                       params=dict(deploymentId='d1', userName='******'),
                       result=dict(total=1, data=[backend.users[0]]))
        backend.expect(LocalBackend.GET,
                       camapi.MachinesEntitlementsADUsers.url,
                       params=dict(deploymentId='d1',
                                   userName='******'),
                       result=dict(total=0, data=[]))
        backend.expect(LocalBackend.GET,
                       camapi.MachinesEntitlementsADUsers.url,
                       params=dict(deploymentId='d1'),
                       result=dict(total=2, data=backend.users))

        cam = camapi.CloudAccessManager(token=backend.token)
        deployment = cam.deployments.get('deployment1')

        users = cam.machines.entitlements.adusers.get(deployment,
                                                      userName='******')
        assert len(users) == 1
        assert users[0]['deploymentId'] == 'd1'
        assert users[0]['userGuid'] == 'guid1'
        assert users[0]['name'] == 'User One'
        assert users[0]['userName'] == 'user1'

        users = cam.machines.entitlements.adusers.get(
            deployment, userName='******')
        assert not users

        users = cam.machines.entitlements.adusers.get(deployment)
        assert len(users) == 2
        assert users[0]['deploymentId'] == 'd1'
        assert users[0]['userGuid'] == 'guid1'
        assert users[0]['name'] == 'User One'
        assert users[0]['userName'] == 'user1'
        assert users[1]['deploymentId'] == 'd1'
        assert users[1]['userGuid'] == 'guid2'
        assert users[1]['name'] == 'User Two'
        assert users[1]['userName'] == 'user2'
def test_deployments(local_backend):
    """Test deployments endpoints.

  Args:
    local_backend: Backend that intercepts requests and returns predictable
      test data.
  """
    with local_backend.activate() as backend:
        backend.expect(LocalBackend.GET,
                       camapi.Deployments.url,
                       params=dict(deploymentName='deployment1',
                                   showactive='true'),
                       result=dict(total=1, data=[backend.deployments[0]]))
        backend.expect(LocalBackend.GET,
                       camapi.Deployments.url,
                       params=dict(deploymentName='non-existent-deployment',
                                   showactive='true'),
                       result=dict(total=0, data=[]))
        backend.expect(LocalBackend.POST,
                       camapi.Deployments.url,
                       data=['deploymentName', 'registrationCode'],
                       result=backend.deployments_post)

        cam = camapi.CloudAccessManager(token=backend.token)
        deployment = cam.deployments.get('deployment1')
        assert deployment['deploymentId'] == 'd1'
        assert deployment['deploymentName'] == 'deployment1'
        assert deployment['registrationCode'] == '111AAA'
        assert deployment['status'] == 'active'

        deployment = cam.deployments.get('non-existent-deployment')
        assert not deployment

        deployment = cam.deployments.post('deployment2', '222BBB')
        assert deployment['deploymentId'] == 'd2'
        assert deployment['deploymentName'] == 'deployment2'
        assert deployment['registrationCode'] == '222BBB'
        assert deployment['status'] == 'active'

        backend.expect(LocalBackend.GET,
                       camapi.Deployments.url,
                       params=dict(deploymentName='deployment2',
                                   showactive='true'),
                       result=dict(total=1, data=[backend.deployments[1]]))

        deployment = cam.deployments.get('deployment2')
        assert deployment['deploymentId'] == 'd2'
        assert deployment['deploymentName'] == 'deployment2'
        assert deployment['registrationCode'] == '222BBB'
        assert deployment['status'] == 'active'
def test_connection_with_scope_autodetect():
    """Verify client can gracefully connect and adapt to scope discrepancies.

  Dynamically changes the scope if the provided credentials have a different
  scope, e.g. requested CAM-level but the credentials in fact belong to a
  Deployment-level account.
  """
    with mock.patch('orchestrate.systems.teradici.camapi.open') as mock_open:
        # Provide in-memory credentials for a Deployment-level account
        credentials = dict(
            keyId='deployment_keyId',
            username='******',
            apiKey='deployment_apiKey',
            keyName='deployment_keyName',
            deploymentId='deployment_deploymentId',
            tenantId='deployment_tenantId',
        )
        mock_open_read = mock.MagicMock()
        mock_open_read.return_value = json.dumps(credentials)
        mock_open.return_value.__enter__.return_value.read = mock_open_read

        with mock.patch('requests.post') as requests_post:
            # Return mock authentication token based on credentials
            payload = dict(data=dict(token='deployment_token', ))
            requests_post.return_value.json.return_value = payload

            # Connect
            # IMPORTANT difference here: We are requesting a CAM-level connection,
            # but the actual credentials stored in the file are for a Deployment-level
            # account. It will connect but update the scope to DEPLOYMENT instead of
            # CAM.
            cam = camapi.CloudAccessManager(project='test_connection',
                                            scope=camapi.Scope.CAM)

            # Verify it "loaded" file from the right location
            path = os.path.abspath(
                os.path.expanduser(
                    '~/.config/teradici/test_connection-cam.json'))
            mock_open.assert_called_once_with(path, 'r')

            # Verify it requested a token from the backend
            requests_post.assert_called_once()
            assert requests_post.call_args[0] == (camapi.AuthSignin.url, )

            # Verify we got a token that matches the actual credentials from disk
            # which in this test are different on purpose.
            assert cam.scope == camapi.Scope.DEPLOYMENT
            assert cam.headers == dict(Authorization='deployment_token')
def test_computers(local_backend):
    """Test computers endpoints.

  Args:
    local_backend: Backend that intercepts requests and returns predictable
      test data.
  """
    with local_backend.activate() as backend:
        backend.expect(LocalBackend.GET,
                       camapi.Deployments.url,
                       params=dict(deploymentName='deployment1',
                                   showactive='true'),
                       result=dict(total=1, data=[backend.deployments[0]]))
        backend.expect(LocalBackend.GET,
                       camapi.MachinesEntitlementsADComputers.url,
                       params=dict(deploymentId='d1',
                                   computerName='computer1'),
                       result=dict(total=1, data=[backend.computers[0]]))
        backend.expect(LocalBackend.GET,
                       camapi.MachinesEntitlementsADComputers.url,
                       params=dict(deploymentId='d1',
                                   computerName='non-existent-computer'),
                       result=dict(total=0, data=[]))
        backend.expect(LocalBackend.GET,
                       camapi.MachinesEntitlementsADComputers.url,
                       params=dict(deploymentId='d1'),
                       result=dict(total=2, data=backend.computers))

        cam = camapi.CloudAccessManager(token=backend.token)
        deployment = cam.deployments.get('deployment1')

        computers = cam.machines.entitlements.adcomputers.get(
            deployment, computerName='computer1')
        assert len(computers) == 1
        assert computers[0]['deploymentId'] == 'd1'
        assert computers[0]['computerName'] == 'COMPUTER1'

        computers = cam.machines.entitlements.adcomputers.get(
            deployment, computerName='non-existent-computer')
        assert not computers

        computers = cam.machines.entitlements.adcomputers.get(deployment)
        assert len(computers) == 2
        assert computers[0]['deploymentId'] == 'd1'
        assert computers[0]['computerName'] == 'COMPUTER1'
        assert computers[1]['deploymentId'] == 'd1'
        assert computers[1]['computerName'] == 'COMPUTER2'
  def unassign(self, project, deployment_name, machine_names):
    """Unassign all users from given machines.

    Args:
      project: GCP project.
      deployment_name: Deployment.
      machine_names: Machine names.

    Returns:
      True if it succeeded. False otherwise.
    """
    log.debug('Locating deployment: %s', deployment_name)
    cam = camapi.CloudAccessManager(project=project,
                                    scope=camapi.Scope.DEPLOYMENT)
    deployment = cam.deployments.get(deployment_name)

    # Get machine ids
    all_machines = []
    for machine_name in machine_names:
      log.debug('Locating machine in CAM: %s', machine_name)
      machines = cam.machines.get(deployment, machineName=machine_name)
      if machines:
        machine = machines[0]
        log.debug('Found machine %s with ID %s', machine_name,
                  machine['machineId'])
        all_machines.append(machine)
      else:
        message = (
            'Could not locate machine {machine_name}. Check whether it exists'
            ' and that it was assigned to users. Skipping for now.'
            ).format(machine_name=machine_name)
        log.warning(message)

    # Find all entitlements for all machine ids collected and remove them
    for machine in all_machines:
      log.info(
          'Locating entitlements for machine %(machineName)s %(machineId)s',
          machine)
      entitlements = cam.machines.entitlements.get(
          deployment, machineName=machine['machineName'])
      for entitlement in entitlements:
        log.info('Removing entitlement %(entitlementId)s', entitlement)
        cam.machines.entitlements.delete(entitlement)

    return True
def test_request_iterator(local_backend):
    """Test RequestIterator.

  Args:
    local_backend: Backend that intercepts requests and returns predictable
      test data.
  """
    with local_backend.activate() as backend:
        backend.expect(LocalBackend.GET,
                       camapi.Deployments.url,
                       params=dict(deploymentName='deployment1',
                                   showactive='true'),
                       result=dict(total=1, data=[backend.deployments[0]]))
        backend.expect(LocalBackend.GET,
                       camapi.MachinesEntitlementsADUsers.url,
                       params=dict(deploymentId='d1', offset=0, limit=1),
                       result=dict(total=1, data=[backend.users[0]]))
        backend.expect(LocalBackend.GET,
                       camapi.MachinesEntitlementsADUsers.url,
                       params=dict(deploymentId='d1', offset=1, limit=1),
                       result=dict(total=1, data=[backend.users[1]]))
        backend.expect(LocalBackend.GET,
                       camapi.MachinesEntitlementsADUsers.url,
                       params=dict(deploymentId='d1', offset=2, limit=1),
                       result=dict(total=0, data=[]))

        cam = camapi.CloudAccessManager(token=backend.token)
        deployment = cam.deployments.get('deployment1')
        assert deployment['deploymentId'] == 'd1'
        assert deployment['deploymentName'] == 'deployment1'
        assert deployment['registrationCode'] == '111AAA'
        assert deployment['status'] == 'active'

        users = camapi.RequestIterator(cam.machines.entitlements.adusers.get,
                                       deployment,
                                       limit=1)
        index = 0
        for user in users:
            index += 1
            guid = 'guid{}'.format(index)
            assert user['userGuid'] == guid
def test_connection_with_deployment_service_account():
    """Verify client can connect with CAM Deployment-level service account.
  """
    with mock.patch('orchestrate.systems.teradici.camapi.open') as mock_open:
        # Provide in-memory credentials
        credentials = dict(
            keyId='deployment_keyId',
            username='******',
            apiKey='deployment_apiKey',
            keyName='deployment_keyName',
            deploymentId='deployment_deploymentId',
            tenantId='deployment_tenantId',
        )
        mock_open_read = mock.MagicMock()
        mock_open_read.return_value = json.dumps(credentials)
        mock_open.return_value.__enter__.return_value.read = mock_open_read

        with mock.patch('requests.post') as requests_post:
            # Return mock authentication token based on credentials
            payload = dict(data=dict(token='deployment_token', ))
            requests_post.return_value.json.return_value = payload

            # Connect
            cam = camapi.CloudAccessManager(project='test_connection',
                                            scope=camapi.Scope.DEPLOYMENT)

            # Verify it "loaded" file from the right location
            path = os.path.abspath(
                os.path.expanduser(
                    '~/.config/teradici/test_connection-deployment.json'))
            mock_open.assert_called_once_with(path, 'r')

            # Verify it requested a token from the backend
            requests_post.assert_called_once()
            assert requests_post.call_args[0] == (camapi.AuthSignin.url, )

            # Verify we got a token for the requested scope
            assert cam.scope == camapi.Scope.DEPLOYMENT
            assert cam.headers == dict(Authorization='deployment_token')
  def assign(self, project, zone, deployment_name, machine_name, user_names):
    """Assign machine to list of users.

    Args:
      project: GCP project.
      zone: GCP zone.
      deployment_name: Deployment.
      machine_name: Machine.
      user_names: List of user names. Currently requires full user name.

    Returns:
      True if it succeeded. False otherwise.
    """
    log.debug('Locating deployment: %s', deployment_name)
    cam = camapi.CloudAccessManager(project=project,
                                    scope=camapi.Scope.DEPLOYMENT)
    deployment = cam.deployments.get(deployment_name)

    # Get or create machine
    # https://github.com/GoogleCloudPlatform/solutions-cloud-orchestrate/issues/35
    # Use the right case when locating machines by name, otherwise CAM API
    # requests will fail with 400 errors. Feels like this should be handled by
    # CAM itself in the backend. But, for the time being guidelines are:
    # - CAM machines: lowercase
    # - AD computers: uppercase
    cam_machine_name = machine_name.lower()
    ad_computer_name = machine_name.upper()
    log.debug('Locating machine in CAM: %s', cam_machine_name)
    machines = cam.machines.get(deployment, machineName=cam_machine_name)
    if machines:
      machine = machines[0]
    else:
      log.debug('Locating machine in AD: %s', ad_computer_name)
      computers = cam.machines.entitlements.adcomputers.get(
          deployment, computerName=ad_computer_name)
      if computers:
        log.debug('Creating machine in CAM: %s', cam_machine_name)
        machine = cam.machines.post(deployment, cam_machine_name, project, zone)
      else:
        message = (
            'Could not locate computer {machine_name}. Check whether it exists'
            ' and that it joined the AD domain.'
            ).format(machine_name=machine_name)
        log.error(message)
        return False

    # Create entitlement for every user
    for user_name in user_names:
      log.debug('Locating user %s', user_name)
      users = cam.machines.entitlements.adusers.get(deployment, name=user_name)
      if users:
        user = users[0]
        log.info('Assigning %s to %s (%s)', machine_name, user['name'],
                 user['userName'])
        try:
          entitlement = cam.machines.entitlements.post(machine, user)
        except requests.exceptions.HTTPError as exception:
          if exception.response.status_code == 409:
            log.info('Machine %s was already assigned to %s. Skipping',
                     machine_name, user_name)
            continue
          else:
            raise
        message = 'Assigned {machine} to {user} ({user_name}) with id {id}'.format(
            machine=machine_name,
            user=user_name,
            user_name=user['userName'],
            id=entitlement['entitlementId'],
            )
        log.info(message)
      else:
        message = (
            'Could not locate user {user_name}. Check whether it exists in the'
            ' AD domain. Skipping for now.'
            ).format(user_name=user_name)
        log.warning(message)

    return True
def test_entitlements(local_backend):
    """Test entitlement endpoints.

  Args:
    local_backend: Backend that intercepts requests and returns predictable
      test data.
  """
    with local_backend.activate() as backend:
        backend.expect(LocalBackend.GET,
                       camapi.Deployments.url,
                       params=dict(deploymentName='deployment1',
                                   showactive='true'),
                       result=dict(total=1, data=[backend.deployments[0]]))
        backend.expect(LocalBackend.GET,
                       camapi.MachinesEntitlements.url,
                       params=dict(deploymentId='d1', machineName='computer1'),
                       result=dict(total=1, data=[backend.entitlements[0]]))
        backend.expect(LocalBackend.GET,
                       camapi.MachinesEntitlements.url,
                       params=dict(deploymentId='d1',
                                   machineName='non-existent-computer'),
                       result=dict(total=0, data=[]))
        backend.expect(LocalBackend.GET,
                       camapi.MachinesEntitlements.url,
                       params=dict(deploymentId='d1'),
                       result=dict(total=2, data=backend.entitlements))

        cam = camapi.CloudAccessManager(token=backend.token)
        deployment = cam.deployments.get('deployment1')

        entitlements = cam.machines.entitlements.get(deployment,
                                                     machineName='computer1')
        assert len(entitlements) == 1
        assert entitlements[0]['entitlementId'] == 'e1'
        assert entitlements[0]['deploymentId'] == 'd1'
        assert entitlements[0]['machineId'] == 'm1'
        assert entitlements[0]['userGuid'] == 'guid1'
        assert entitlements[0]['machine']['machineId'] == 'm1'
        assert entitlements[0]['machine']['machineName'] == 'computer1'

        entitlements = cam.machines.entitlements.get(
            deployment, machineName='non-existent-computer')
        assert not entitlements

        entitlements = cam.machines.entitlements.get(deployment)
        assert len(entitlements) == 2
        assert entitlements[0]['entitlementId'] == 'e1'
        assert entitlements[0]['deploymentId'] == 'd1'
        assert entitlements[0]['machineId'] == 'm1'
        assert entitlements[0]['userGuid'] == 'guid1'
        assert entitlements[0]['machine']['machineId'] == 'm1'
        assert entitlements[0]['machine']['machineName'] == 'computer1'
        assert entitlements[1]['entitlementId'] == 'e2'
        assert entitlements[1]['deploymentId'] == 'd1'
        assert entitlements[1]['machineId'] == 'm2'
        assert entitlements[1]['userGuid'] == 'guid2'
        assert entitlements[1]['machine']['machineId'] == 'm2'
        assert entitlements[1]['machine']['machineName'] == 'computer2'

        backend.expect(LocalBackend.POST,
                       camapi.MachinesEntitlements.url,
                       data=['deploymentId', 'machineId', 'userGuid'],
                       result=backend.entitlements_post)
        backend.expect(LocalBackend.POST,
                       camapi.Machines.url,
                       data=[
                           'provider',
                           'machineName',
                           'deploymentId',
                           'projectId',
                           'zone',
                           'active',
                           'managed',
                       ],
                       result=backend.machines_post)
        backend.expect(LocalBackend.GET,
                       camapi.MachinesEntitlementsADUsers.url,
                       params=dict(deploymentId='d1', userName='******'),
                       result=dict(total=1, data=[backend.users[0]]))

        machine = cam.machines.post(deployment, 'computer2', 'test_project',
                                    'test_zone')
        users = cam.machines.entitlements.adusers.get(deployment,
                                                      userName='******')
        entitlement = cam.machines.entitlements.post(machine, users[0])
        assert entitlement['entitlementId'] == 'e3'
        assert entitlement['deploymentId'] == 'd1'
        assert entitlement['machineId'] == 'm2'
        assert entitlement['userGuid'] == 'guid1'

        entitlements = cam.machines.entitlements.get(deployment)
        assert len(entitlements) == 3
        assert entitlements[2]['entitlementId'] == 'e3'
        assert entitlements[2]['deploymentId'] == 'd1'
        assert entitlements[2]['machineId'] == 'm2'
        assert entitlements[2]['userGuid'] == 'guid1'
def test_machines(local_backend):
    """Test machines endpoints.

  Args:
    local_backend: Backend that intercepts requests and returns predictable
      test data.
  """
    with local_backend.activate() as backend:
        backend.expect(LocalBackend.GET,
                       camapi.Deployments.url,
                       params=dict(deploymentName='deployment1',
                                   showactive='true'),
                       result=dict(total=1, data=[backend.deployments[0]]))
        backend.expect(LocalBackend.GET,
                       camapi.Machines.url,
                       params=dict(deploymentId='d1', machineName='computer1'),
                       result=dict(total=1, data=[backend.machines[0]]))
        backend.expect(LocalBackend.GET,
                       camapi.Machines.url,
                       params=dict(deploymentId='d1',
                                   machineName='non-existent-computer'),
                       result=dict(total=0, data=[]))
        backend.expect(LocalBackend.POST,
                       camapi.Machines.url,
                       data=[
                           'provider',
                           'machineName',
                           'deploymentId',
                           'projectId',
                           'zone',
                           'active',
                           'managed',
                       ],
                       result=backend.machines_post)
        backend.expect(LocalBackend.GET,
                       camapi.Machines.url,
                       params=dict(deploymentId='d1'),
                       result=dict(total=2, data=backend.machines))

        cam = camapi.CloudAccessManager(token=backend.token)
        deployment = cam.deployments.get('deployment1')

        machines = cam.machines.get(deployment, machineName='computer1')
        assert len(machines) == 1
        assert machines[0]['deploymentId'] == 'd1'
        assert machines[0]['machineId'] == 'm1'
        assert machines[0]['machineName'] == 'computer1'
        assert machines[0]['projectId'] == 'test'
        assert machines[0]['zone'] == 'us-west2-b'
        assert machines[0]['active']
        assert machines[0]['managed']

        machines = cam.machines.get(deployment,
                                    machineName='non-existent-computer')
        assert not machines

        machine = cam.machines.post(deployment, 'computer2', 'test_project',
                                    'test_zone')
        assert machine['deploymentId'] == 'd1'
        assert machine['machineId'] == 'm2'
        assert machine['machineName'] == 'computer2'
        assert machine['projectId'] == 'test_project'
        assert machine['zone'] == 'test_zone'

        machines = cam.machines.get(deployment)
        assert len(machines) == 2
        assert machines[0]['deploymentId'] == 'd1'
        assert machines[0]['machineId'] == 'm1'
        assert machines[0]['machineName'] == 'computer1'
        assert machines[0]['projectId'] == 'test'
        assert machines[0]['zone'] == 'us-west2-b'
        assert machines[1]['deploymentId'] == 'd1'
        assert machines[1]['machineId'] == 'm2'
        assert machines[1]['machineName'] == 'computer2'
        assert machines[1]['projectId'] == 'test_project'
        assert machines[1]['zone'] == 'test_zone'
def test_connection_with_token():
    """Verify client can connect with an API token.
  """
    cam = camapi.CloudAccessManager(token='abc123')
    assert cam.scope == camapi.Scope.ALL
    assert cam.headers == dict(Authorization='abc123')
def test_connection_without_any_creddentials():
    """Verify client cannot connect without explicitly providing credentials.
  """
    with pytest.raises(RuntimeError):
        camapi.CloudAccessManager()