{"id":6354,"library":"duplocloud-client","title":"DuploCloud Client","description":"The `duplocloud-client` library provides a Python SDK for programmatically interacting with DuploCloud portals, enabling management of infrastructure, tenants, services, and various cloud resources. It serves as the underlying library for the `duploctl` command-line interface. Currently at version 0.4.3, the library maintains a frequent release cadence with minor updates and fixes, often coinciding with new feature introductions in the DuploCloud platform.","status":"active","version":"0.4.3","language":"en","source_language":"en","source_url":"https://github.com/duplocloud/duploctl","tags":["devops","cloud","cli","duplocloud","automation"],"install":[{"cmd":"pip install duplocloud-client","lang":"bash","label":"Install latest version"}],"dependencies":[{"reason":"Required for execution","package":"python","optional":false}],"imports":[{"note":"The PyPI package is `duplocloud-client`, which exposes its main client through `duplocloud.client`.","wrong":"from duploctl import DuploClient","symbol":"DuploClient","correct":"from duplocloud.client import DuploClient"},{"note":"Used for a CLI-like callable interface, often configured from environment variables.","symbol":"DuploCtl","correct":"from duplocloud.controller import DuploCtl"}],"quickstart":{"code":"import os\nfrom duplocloud.client import DuploClient\n\n# Ensure DUPLO_HOST and DUPLO_TOKEN are set in your environment\nduplo_host = os.environ.get('DUPLO_HOST', 'https://example.duplocloud.net') # Replace with your DuploCloud portal URL\nduplo_token = os.environ.get('DUPLO_TOKEN', '') # Replace with your DuploCloud API token\nduplo_tenant = os.environ.get('DUPLO_TENANT', 'default') # Optional: your target tenant\n\nif not duplo_token:\n    print(\"Error: DUPLO_TOKEN environment variable not set.\")\n    exit(1)\n\nif not duplo_host:\n    print(\"Error: DUPLO_HOST environment variable not set.\")\n    exit(1)\n\ntry:\n    # Initialize the client\n    client = DuploClient(host=duplo_host, token=duplo_token, tenant_name=duplo_tenant)\n    print(f\"Successfully initialized DuploClient for host: {duplo_host}, tenant: {duplo_tenant}\")\n\n    # Example: List tenants (assuming the token has appropriate permissions)\n    # The client often exposes resources as attributes or methods following CLI patterns.\n    # Direct programmatic access might vary, but a common pattern is to access resource managers.\n    # For this example, we'll assume a 'tenant' resource is accessible for listing.\n    # Note: Specific resource methods might require exploration of the DuploClient object.\n    print(\"\\nAttempting to list tenants...\")\n    try:\n        # This is an illustrative example. Actual resource access might be via client.get('tenant')\n        # or client.tenant.list(). Refer to DuploCloud's SDK documentation for exact methods.\n        # The `duploctl` CLI uses `duplocloud.controller.DuploCtl.from_env()` for a callable interface.\n        from duplocloud.controller import DuploCtl\n        duplo_cli_callable, _ = DuploCtl.from_env() # Reads from env vars for convenience\n        tenants = duplo_cli_callable(\"tenant\", \"list\")\n        print(\"Tenants:\")\n        for tenant in tenants:\n            print(f\"  - {tenant.get('Name')} (ID: {tenant.get('TenantId')})\")\n    except Exception as e:\n        print(f\"Could not list tenants (this might be due to permissions or API structure): {e}\")\n\nexcept Exception as e:\n    print(f\"An error occurred during client initialization or operation: {e}\")\n","lang":"python","description":"This quickstart demonstrates how to initialize the `DuploClient` using environment variables for authentication and then attempts to list tenants. Ensure `DUPLO_HOST`, `DUPLO_TOKEN`, and optionally `DUPLO_TENANT` are set in your environment. The example also shows how to use the `DuploCtl.from_env()` for a CLI-like callable interface to interact with resources."},"warnings":[{"fix":"Review classes extending `DuploTenantResourceV2` or `DuploTenantResourceV3`. Update them to use the `@Resource(name, scope=\"portal\"|\"tenant\")` decorator and adapt to the mixin pattern for dynamic tenant functionality.","message":"Version 0.4.0 introduced a significant architectural change with a new decorator-based scope system (`@Resource`). This release removed previous deep inheritance hierarchies like `DuploTenantResourceV2` and `DuploTenantResourceV3`. Code relying on these older class structures will break and needs to be refactored to use the new decorator pattern.","severity":"breaking","affected_versions":">=0.4.0"},{"fix":"Upgrade to version 0.4.1 or newer. For older versions, ensure you provide the `duploservices-<tenant>-<name>` prefix when searching for AWS secrets, or implement retry logic.","message":"Prior to version 0.4.1, the `aws_secret find` command/method could incorrectly return 'Resource not found' even when the secret existed, especially if the full prefixed name was not initially provided. This required manual prefixing or retrying with different names.","severity":"gotcha","affected_versions":"<0.4.1"},{"fix":"Review error handling for `apply()` operations. Consider catching `DuploNotFound` specifically for 404 errors, or ensure your general `DuploError` handler still covers the desired cases if `DuploNotFound` inherits from `DuploError` (which is likely).","message":"As of version 0.4.3, the `apply()` method now specifically catches `DuploNotFound` errors (HTTP 404) instead of the broader `DuploError`. If your code had a generic `except DuploError` block for 404 scenarios within `apply()`, it might now need to explicitly catch `DuploNotFound` or adjust its error handling for more granular control.","severity":"gotcha","affected_versions":">=0.4.3"}],"env_vars":null,"last_verified":"2026-04-15T00:00:00.000Z","next_check":"2026-07-14T00:00:00.000Z"}