Compare commits
110 Commits
Author | SHA1 | Date | |
---|---|---|---|
bc7a2ca5f1 | |||
77d911e47a | |||
b9c9c2d0a9 | |||
d5b91789d1 | |||
eb8350f453 | |||
b987ce27b8 | |||
630e363e53 | |||
a602021952 | |||
80585437a0 | |||
4674a20a2c | |||
820cdfcd48 | |||
6e5dd9b05a | |||
f3d5c21fab | |||
04b278ee28 | |||
7084d76c43 | |||
41d7550e89 | |||
4bf361d3a6 | |||
d70617a90c | |||
62ad1655d5 | |||
caf3a095f2 | |||
89e44b2e5f | |||
a617f51b19 | |||
355e04fd1d | |||
89bd767bea | |||
e567ebbf21 | |||
33311348e2 | |||
d6e914edab | |||
da7b866f23 | |||
7654d780b1 | |||
dbd9b661c6 | |||
e19d0b4deb | |||
f0ebb719f7 | |||
c8e0666bc6 | |||
0d0b106f90 | |||
c9073df7cd | |||
f65200703d | |||
57970b3d10 | |||
b4d9f40c41 | |||
a219725ff6 | |||
4b993fc6b3 | |||
d453da709f | |||
50fac41c95 | |||
affce1fcd1 | |||
df67ebd27a | |||
ef5bfd435a | |||
db07db930c | |||
f6309f600c | |||
7477704905 | |||
db89d86242 | |||
b74ce05845 | |||
79db68a4a2 | |||
5a3ddcf39b | |||
fe6bfc0a83 | |||
36a481ecd1 | |||
f7b2e203ed | |||
27c98c4e32 | |||
79257908d0 | |||
b5ca898eac | |||
53ade28931 | |||
fff4c7642d | |||
dafe6574cc | |||
b70dad4996 | |||
17b0b50fbd | |||
91a0272ab3 | |||
efd22d4087 | |||
c9e32540bf | |||
8344f96983 | |||
3b77089d79 | |||
b6bce76043 | |||
cab57ab303 | |||
804f1f3b12 | |||
f0144fdd5b | |||
81f286cb2f | |||
1f12cb9f94 | |||
26490e8ddd | |||
38d2120c35 | |||
f80b8decbc | |||
28cd6d1b49 | |||
899e5b0a7d | |||
0eff7c7510 | |||
7789348f4e | |||
66a23a515b | |||
7c1082f5a9 | |||
15ea5adec6 | |||
da0dddcceb | |||
b5433e412f | |||
7eb6bf794c | |||
b244518fcb | |||
95d0396abb | |||
a830299cc9 | |||
10fc1d7fba | |||
614ed78928 | |||
ea7f6a6477 | |||
2d746a9d1c | |||
a9fab24961 | |||
5548d5a72d | |||
6b52e05a86 | |||
87e273c30e | |||
0f3f4b8e3f | |||
5f16d8e494 | |||
5148bd1fff | |||
41c54a070c | |||
6956524c6e | |||
7a1d933559 | |||
343acd4997 | |||
337d111cf6 | |||
f49dce92cd | |||
c6abfe69b8 | |||
9d52c62335 | |||
971abd19c9 |
@ -6,13 +6,14 @@ on:
|
||||
- '*'
|
||||
|
||||
env:
|
||||
IMAGE: code.foss.global/hosttoday/ht-docker-node:npmci
|
||||
IMAGE: code.foss.global/host.today/ht-docker-node:npmci
|
||||
NPMCI_COMPUTED_REPOURL: https://${{gitea.repository_owner}}:${{secrets.GITEA_TOKEN}}@/${{gitea.repository}}.git
|
||||
NPMCI_TOKEN_NPM: ${{secrets.NPMCI_TOKEN_NPM}}
|
||||
NPMCI_TOKEN_NPM2: ${{secrets.NPMCI_TOKEN_NPM2}}
|
||||
NPMCI_GIT_GITHUBTOKEN: ${{secrets.NPMCI_GIT_GITHUBTOKEN}}
|
||||
NPMCI_LOGIN_DOCKER_GITEA: ${{ github.server_url }}|${{ gitea.repository_owner }}|${{ secrets.GITEA_TOKEN }}
|
||||
# NPMCI_GIT_GITHUBTOKEN: ${{secrets.NPMCI_GIT_GITHUBTOKEN}}
|
||||
# NPMCI_LOGIN_DOCKER_GITEA: ${{ github.server_url }}|${{ gitea.repository_owner }}|${{ secrets.GITEA_TOKEN }}
|
||||
NPMCI_LOGIN_DOCKER_DOCKERREGISTRY: ${{ secrets.NPMCI_LOGIN_DOCKER_DOCKERREGISTRY }}
|
||||
NPMCI_SECRET01: ${{ secrets.NPMCI_SECRET01 }}
|
||||
|
||||
jobs:
|
||||
security:
|
||||
@ -74,7 +75,7 @@ jobs:
|
||||
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: code.foss.global/hosttoday/ht-docker-dbase:npmci
|
||||
image: code.foss.global/host.today/ht-docker-dbase:npmci
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
@ -89,8 +90,7 @@ jobs:
|
||||
npmci docker login
|
||||
npmci docker build
|
||||
npmci docker test
|
||||
# npmci docker push
|
||||
npmci docker push
|
||||
npmci docker push code.foss.global
|
||||
|
||||
metadata:
|
||||
needs: test
|
||||
|
@ -1,6 +1,6 @@
|
||||
# gitzone dockerfile_service
|
||||
## STAGE 1 // BUILD
|
||||
FROM code.foss.global/hosttoday/ht-docker-node:npmci as node1
|
||||
FROM code.foss.global/host.today/ht-docker-node:npmci as node1
|
||||
COPY ./ /app
|
||||
WORKDIR /app
|
||||
ARG NPMCI_TOKEN_NPM2
|
||||
@ -12,7 +12,7 @@ RUN pnpm run build
|
||||
|
||||
# gitzone dockerfile_service
|
||||
## STAGE 2 // install production
|
||||
FROM code.foss.global/hosttoday/ht-docker-node:npmci as node2
|
||||
FROM code.foss.global/host.today/ht-docker-node:npmci as node2
|
||||
WORKDIR /app
|
||||
COPY --from=node1 /app /app
|
||||
RUN rm -rf .pnpm-store
|
||||
@ -24,7 +24,7 @@ RUN rm -rf node_modules/ && pnpm install --prod
|
||||
|
||||
|
||||
## STAGE 3 // rebuild dependencies for alpine
|
||||
FROM code.foss.global/hosttoday/ht-docker-node:alpinenpmci as node3
|
||||
FROM code.foss.global/host.today/ht-docker-node:alpine_npmci as node3
|
||||
WORKDIR /app
|
||||
COPY --from=node2 /app /app
|
||||
ARG NPMCI_TOKEN_NPM2
|
||||
@ -34,7 +34,7 @@ RUN pnpm config set store-dir .pnpm-store
|
||||
RUN pnpm rebuild -r
|
||||
|
||||
## STAGE 4 // the final production image with all dependencies in place
|
||||
FROM code.foss.global/hosttoday/ht-docker-node:alpine as node4
|
||||
FROM code.foss.global/host.today/ht-docker-node:alpine as node4
|
||||
WORKDIR /app
|
||||
COPY --from=node3 /app /app
|
||||
|
||||
|
@ -0,0 +1 @@
|
||||
FROM serve.zone/cloudly:latest
|
339
changelog.md
339
changelog.md
@ -1,5 +1,344 @@
|
||||
# Changelog
|
||||
|
||||
## 2025-04-25 - 5.0.4 - fix(platformservice/mta)
|
||||
Update getEmailStatus response schema: make details property optional
|
||||
|
||||
- Changed details property from required with fixed message to optional with a flexible message structure in IReq_GetEMailStats response
|
||||
|
||||
## 2025-04-25 - 5.0.3 - fix(mta)
|
||||
update email status response type in MTA platform service
|
||||
|
||||
- Changed the response 'status' field in IRequest_CheckEmailStatus from a literal 'unknown' to a generic string for improved flexibility
|
||||
|
||||
## 2025-04-25 - 5.0.2 - fix(platformservice/mta)
|
||||
Refactor email status response in MTA service
|
||||
|
||||
- Updated IReq_CheckEmailStatus response: replaced union type ('ok' | 'not ok') with fixed status 'unknown' and added a details object with message 'Email not found'.
|
||||
|
||||
## 2025-04-25 - 5.0.1 - fix(mta)
|
||||
Update email stats response interface in mta platform service to include totalEmailsSent, totalEmailsDelivered, totalEmailsBounced, averageDeliveryTimeMs, and lastUpdated timestamp.
|
||||
|
||||
- Modified IReq_GetEMailStats response in ts_interfaces/platformservice/mta.ts from an empty status object to a detailed email statistics structure.
|
||||
|
||||
## 2025-04-25 - 5.0.0 - BREAKING CHANGE(ts_interfaces/platformservice/mta)
|
||||
Rename mta interfaces and upgrade dependency versions
|
||||
|
||||
- Upgraded devDependencies: @git.zone/tsbuild, tsbundle, tsdoc, tstest, tswatch, and @push.rocks/tapbundle to newer versions.
|
||||
- Upgraded dependencies: @design.estate/dees-catalog, dees-domtools, dees-element, @push.rocks/smartdata, smartexpect, smartfile, smartpromise, smartrequest, smartrx, and tsclass (v4.2.0 to v9.0.0).
|
||||
- Added new packageManager field in package.json and introduced pnpm-workspace.yaml for additional workspace configuration.
|
||||
- Refactored mta API interfaces: renamed IRequest_SendEmail to IReq_SendEmail and IRequestRegisterRecipient to IReq_RegisterRecipient; added IReq_CheckEmailStatus and IReq_GetEMailStats.
|
||||
|
||||
## 2025-01-20 - 4.13.0 - feat(service)
|
||||
Add support for service creation, update, and deletion.
|
||||
|
||||
- Implemented TypedHandlers for creating a new service.
|
||||
- Added features to update existing service details.
|
||||
- Enabled deletion of services by their unique ID.
|
||||
|
||||
## 2025-01-20 - 4.12.2 - fix(service)
|
||||
Fix secret bundle and service management bugs
|
||||
|
||||
- Corrected the field name from 'includedImages' to 'imageClaims' in secret bundles.
|
||||
- Implemented 'getFlatKeyValueObject' for secret bundles and modified related API interactions.
|
||||
- Enhanced the Service class with methods for handling secret bundle data by resolving related groups and environments.
|
||||
|
||||
## 2025-01-02 - 4.12.1 - fix(deps)
|
||||
Updated @git.zone/tspublish to version ^1.9.1
|
||||
|
||||
|
||||
## 2025-01-02 - 4.12.0 - feat(cli)
|
||||
Add CLI support and external registries view
|
||||
|
||||
- Adds CLI client functionality
|
||||
- Introduces a new view for External Registries in the dashboard
|
||||
|
||||
## 2024-12-30 - 4.11.0 - feat(external-registry)
|
||||
Introduce external registry management
|
||||
|
||||
- Added ExternalRegistryManager to handle external registry operations.
|
||||
- Implemented ability to create, retrieve, and delete external registries.
|
||||
- Enhanced Cloudly class to include ExternalRegistryManager.
|
||||
|
||||
## 2024-12-29 - 4.10.0 - feat(apiclient)
|
||||
Added support for managing external registries in the API client.
|
||||
|
||||
- Introduced methods to get a registry by ID, get all registries, and create a new registry in the externalRegistry object.
|
||||
- Updated external registry request interfaces to match new API client capabilities.
|
||||
|
||||
## 2024-12-29 - 4.9.0 - feat(apiclient)
|
||||
Add external registry management capabilities to Cloudly API client.
|
||||
|
||||
- Introduce ExternalRegistry class with methods for getting, creating, and updating external registries.
|
||||
- Expand requests module to handle external registry management, including creation and deletion.
|
||||
|
||||
## 2024-12-28 - 4.8.1 - fix(interfaces)
|
||||
Fix image location schema in IImage interface
|
||||
|
||||
- Refactored the 'external' object within IImage data to a 'location' object.
|
||||
- Added 'internal' boolean to 'location' to specify internal/external status.
|
||||
|
||||
## 2024-12-28 - 4.8.0 - feat(manager.registry)
|
||||
Add external registry management
|
||||
|
||||
- Introduced ExternalRegistry class for handling external registry configurations.
|
||||
- Updated IExternalRegistry interface to include registry details.
|
||||
- Enhanced IImage interface to support linking with external registries.
|
||||
|
||||
## 2024-12-28 - 4.7.1 - fix(secretmanagement)
|
||||
Refactor secret bundle actions and improve authorization handling
|
||||
|
||||
- Refactored secret bundle handling by renaming methods and reorganizing static and instance methods in SecretBundle class.
|
||||
- Added getSecretBundleByAuthorization method to SecretBundle.
|
||||
- Improved getFlatKeyValueObjectForEnvironment to accurately retrieve key-value pairs for specified environments.
|
||||
- Removed deprecated IEnvBundle interface and related request handler for better clarity and code usage.
|
||||
- Updated request interfaces related to secret bundles for consistent method naming and arguments.
|
||||
|
||||
## 2024-12-22 - 4.7.0 - feat(apiclient)
|
||||
Add method to flatten secret bundles into key-value objects.
|
||||
|
||||
- SecretBundle: Implemented toFlatKeyValueObject method to flatten secret groups into key-value pairs.
|
||||
- Removed stale SecretManager class from apiclient.
|
||||
|
||||
## 2024-12-22 - 4.6.0 - feat(cloudlyapiclient)
|
||||
Extend CloudlyApiClient with cluster, secretbundle, and secretgroup methods
|
||||
|
||||
- Added methods to CloudlyApiClient for managing clusters: getClusterById, getClusters, createCluster.
|
||||
- Added methods to CloudlyApiClient for managing secret bundles: getSecretBundleById, getSecretBundles, createSecretBundle.
|
||||
- Added methods to CloudlyApiClient for managing secret groups: getSecretGroupById, getSecretGroups, createSecretGroup.
|
||||
|
||||
## 2024-12-22 - 4.5.5 - fix(apiclient)
|
||||
Fixed image creation method in cloudlyApiClient
|
||||
|
||||
- Corrected method call from 'images.createImage' to 'image.createImage' to ensure proper image creation.
|
||||
- Updated cluster retrieval methods and ensured proper API routes are being called.
|
||||
|
||||
## 2024-12-21 - 4.5.4 - fix(ts_web)
|
||||
Fix action type and data fields in appstate for CRUD operations
|
||||
|
||||
- Correct request method in createSecretGroupAction to accurately reflect the purpose.
|
||||
- Align the deleteSecretGroupAction and deleteSecretBundleAction request types with proper interfaces.
|
||||
- Ensure data payload matches backend requirements for secret group and secret bundle operations.
|
||||
|
||||
## 2024-12-21 - 4.5.3 - fix(secret-management)
|
||||
Refactor secret management to use distinct secret bundle and group APIs. Introduce API client classes for secret bundles and groups.
|
||||
|
||||
- Updated secret management logic to separate secret bundle and group APIs.
|
||||
- Implemented new API client classes for managing secret bundles and groups.
|
||||
- Fixed incorrect method usages for secret-related actions.
|
||||
|
||||
## 2024-12-20 - 4.5.2 - fix(apiclient)
|
||||
Implemented IService interface in Service class and improved secret bundle documentation.
|
||||
|
||||
- Implemented plugins.servezoneInterfaces.data.IService interface in the Service class within ts_apiclient.
|
||||
- Updated documentation comments for the type property in the ISecretBundle interface.
|
||||
|
||||
## 2024-12-17 - 4.5.1 - fix(core)
|
||||
Updated dependencies in package.json to latest versions.
|
||||
|
||||
- Bumped @git.zone/tswatch to version ^2.0.37
|
||||
- Bumped @types/node to version ^22.10.2
|
||||
- Bumped @design.estate/dees-catalog to version ^1.3.2
|
||||
- Bumped @push.rocks/smartfile to version ^11.0.23
|
||||
- Bumped @tsclass/tsclass to version ^4.2.0
|
||||
|
||||
## 2024-12-14 - 4.5.0 - feat(services)
|
||||
Add service management functionalities
|
||||
|
||||
- Integrated service-related API client methods including getServices, getServiceById, and createService.
|
||||
- Updated the deployment data structure in the service manager.
|
||||
- Enhanced service interface to incorporate additional fields for comprehensive data handling.
|
||||
- Ensured secure token generation for Cloudly authentication processes.
|
||||
|
||||
## 2024-11-18 - 4.4.0 - feat(api-client)
|
||||
Add static method getImageById for Image class in api-client
|
||||
|
||||
- Introduced a static method getImageById in the Image class.
|
||||
- Updated CloudlyApiClient to include the getImageById method in the images interface.
|
||||
|
||||
## 2024-11-18 - 4.3.21 - fix(interfaces)
|
||||
Remove deprecated deployment directive and update related interfaces
|
||||
|
||||
- Removed IDeploymentDirective from data and requests.
|
||||
- Updated IDeployment to remove references to directives.
|
||||
- Changed IRequest_Any_Cloudly_GetClusterConfig to return services instead of deployment directives.
|
||||
- Removed deploymentDirectiveIds from IService data structure.
|
||||
|
||||
## 2024-11-18 - 4.3.20 - fix(apiclient)
|
||||
Ensure mandatory parameter in CloudlyApiClient constructor
|
||||
|
||||
- Made the 'optionsArg' parameter mandatory in the constructor of CloudlyApiClient class.
|
||||
|
||||
## 2024-11-18 - 4.3.19 - fix(docker)
|
||||
Fix improper Docker push command preventing push to the correct registry.
|
||||
|
||||
- Corrected the docker push command in the '.gitea/workflows/docker_tags.yaml' file to push images to the 'code.foss.global' registry.
|
||||
|
||||
## 2024-11-17 - 4.3.18 - fix(docker_tags)
|
||||
Updated Docker configuration to include NPM tokens.
|
||||
|
||||
- Restored NPMCI_TOKEN_NPM and NPMCI_TOKEN_NPM2 environment variables in docker_tags.yaml for authentication purposes.
|
||||
|
||||
## 2024-11-17 - 4.3.17 - fix(Dockerfile)
|
||||
Corrected docker base image tag in Dockerfile for alpine compatibility.
|
||||
|
||||
- Updated Dockerfile to use the correct base image tag for Alpine.
|
||||
- Resolved any potential build issues related to incorrect image tag usage.
|
||||
|
||||
## 2024-11-17 - 4.3.16 - fix(infrastructure)
|
||||
Correct Docker image path in Dockerfile for improved build consistency.
|
||||
|
||||
- Dockerfile: Updated base image paths from 'code.foss.global/hosttoday/ht-docker-node' to 'code.foss.global/host.today/ht-docker-node'.
|
||||
|
||||
## 2024-11-17 - 4.3.15 - fix(project setup)
|
||||
fixed incorrect configuration in npmextra.json
|
||||
|
||||
- Removed unnecessary 'dockerBuildargEnvMap' entry for NPMCI_TOKEN_NPM2.
|
||||
- Corrected the githost and gitscope in gitzone module configuration.
|
||||
- Updated the license field to reflect the correct license.
|
||||
|
||||
## 2024-11-16 - 4.3.14 - fix(docker tags)
|
||||
Comment out unused secret variables in docker_tags.yaml
|
||||
|
||||
- Modified docker_tags.yaml to comment out unused secret variables related to NPM and GitHub tokens.
|
||||
|
||||
## 2024-11-16 - 4.3.13 - fix(package)
|
||||
Updated package dependencies
|
||||
|
||||
- Updated @design.estate/dees-catalog version to 1.3.1
|
||||
|
||||
## 2024-11-06 - 4.3.12 - fix(workflow)
|
||||
Fix Docker image path in GitHub action workflow
|
||||
|
||||
- Corrected the path of the Docker image used in the GitHub action workflow from 'code.foss.global/hosttoday/ht-docker-dbase:npmci' to 'code.foss.global/host.today/ht-docker-dbase:npmci'.
|
||||
|
||||
## 2024-11-06 - 4.3.11 - fix(overall)
|
||||
Refactor and improve code consistency across all modules
|
||||
|
||||
- Updated cloud configuration management for better reliability.
|
||||
- Enhanced security measures in the authentication and authorization processes.
|
||||
- Streamlined deployment logic in cluster management.
|
||||
- Refactored code to improve maintainability and readability.
|
||||
|
||||
## 2024-11-06 - 4.3.10 - fix(dependencies)
|
||||
Updated dependencies and fixed Docker Alpine image retrieval issue in tests
|
||||
|
||||
- Updated @push.rocks/tapbundle to version ^5.5.0 in devDependencies.
|
||||
- Updated @push.rocks/smartrequest to version ^2.0.23 in dependencies.
|
||||
- Ensured the Docker Alpine image is retrieved as a local tarball in cloudlyfactory.ts test helper.
|
||||
|
||||
## 2024-11-06 - 4.3.9 - fix(test and dependencies)
|
||||
Corrected cloudlyUrl in test.apiclient and updated tapbundle dependency.
|
||||
|
||||
- Fixed cloudlyUrl assignment in the test.apiclient to use the correct helper method.
|
||||
- Updated tapbundle dependency version from ^5.4.3 to ^5.4.4.
|
||||
|
||||
## 2024-11-06 - 4.3.8 - fix(api client)
|
||||
Fixed localhost URL issue in test.client.ts
|
||||
|
||||
- Changed the cloudlyUrl in test.client.ts from 'localhost' to '127.0.0.1' to ensure consistency in network requests.
|
||||
|
||||
## 2024-11-06 - 4.3.7 - fix(tests)
|
||||
Refactored test setup for consistency and isolated config initialization.
|
||||
|
||||
- test/helpers/cloudlyfactory.ts: Test configuration setup was refactored to ensure consistent initialization of cloudly configuration across tests.
|
||||
- test/test.apiclient.ts: Updated cloudlyApiClient test setup to use testCloudlyConfig for dynamic port allocation.
|
||||
|
||||
## 2024-11-06 - 4.3.6 - fix(test)
|
||||
Enhance test helpers with dynamic Hetzner token retrieval.
|
||||
|
||||
- Updated test/helpers/cloudlyfactory.ts to retrieve Hetzner token from environment variables.
|
||||
- Expanded docker_tags workflow to securely handle and pass new environment secrets.
|
||||
|
||||
## 2024-11-06 - 4.3.5 - fix(helpers)
|
||||
Add missing sslMode configuration to Cloudly config.
|
||||
|
||||
- Added the sslMode key with a value of 'none' to the Cloudly configuration object in test/helpers/cloudlyfactory.ts.
|
||||
|
||||
## 2024-11-06 - 4.3.4 - fix(testing)
|
||||
Fixed Cloudly testing setup and dependencies
|
||||
|
||||
- Updated devDependency @push.rocks/tapbundle version from ^5.3.0 to ^5.4.3 in package.json.
|
||||
- Updated devDependency @push.rocks/npmextra version from ^5.1.1 to ^5.1.2 in package.json.
|
||||
- Improved the Cloudly test suite setup to ensure proper initialization of MongoDB and S3 services.
|
||||
- Ensured asynchronous stopping and cleanup of MongoDB and S3 services post-test execution.
|
||||
|
||||
## 2024-11-05 - 4.3.3 - fix(core)
|
||||
Fix configuration initialization by accepting a config argument
|
||||
|
||||
- Configuration initialization now accepts an optional config argument
|
||||
- Updated test cloudly factory to use default public URL and port
|
||||
- Updated dependencies versions
|
||||
|
||||
## 2024-11-05 - 4.3.2 - fix(npmextra)
|
||||
Updated npm registry URL in npmextra.json
|
||||
|
||||
|
||||
## 2024-11-05 - 4.3.1 - fix(package)
|
||||
Update dependency version for @git.zone/tspublish
|
||||
|
||||
- Bump @git.zone/tspublish from version ^1.7.6 to ^1.7.7 in package.json
|
||||
|
||||
## 2024-11-05 - 4.3.0 - feat(dependencies)
|
||||
Upgrade dependencies and include publish orders
|
||||
|
||||
- Upgraded @git.zone/tsbuild to version ^2.2.0
|
||||
- Upgraded @git.zone/tspublish to version ^1.7.6
|
||||
- Upgraded @types/node to version ^22.8.7
|
||||
- Added publish order to ts_apiclient/tspublish.json and ts_interfaces/tspublish.json
|
||||
|
||||
## 2024-11-04 - 4.2.1 - fix(config)
|
||||
Fix Docker image URL in Gitea workflow.
|
||||
|
||||
- Corrected the IMAGE URL from 'hosttoday' to 'host.today'.
|
||||
|
||||
## 2024-11-04 - 4.2.0 - feat(cloudron)
|
||||
Add Dockerfile for Cloudron deployment
|
||||
|
||||
- Introduced a new Dockerfile for Cloudron deployment.
|
||||
- The Dockerfile uses the latest version of cloudly as a base image.
|
||||
|
||||
## 2024-10-28 - 4.1.3 - fix(dependency)
|
||||
Updated dependency @git.zone/tspublish to version ^1.6.0
|
||||
|
||||
- Bumped @git.zone/tspublish version from ^1.5.5 to ^1.6.0 in package.json
|
||||
|
||||
## 2024-10-28 - 4.1.2 - fix(core)
|
||||
Corrected description and devDependencies
|
||||
|
||||
- Updated package.json description to accurately reflect features.
|
||||
- Added `@git.zone/tsdoc` to devDependencies.
|
||||
- Corrected version discrepancy in `@types/node` devDependency.
|
||||
- Standardized description across multiple files including npmextra.json.
|
||||
|
||||
## 2024-10-28 - 4.1.1 - fix(core)
|
||||
Fixed syntax issues in commitinfo data and package.json file.
|
||||
|
||||
- Added a missing newline at the end of the package.json file.
|
||||
- Corrected a trailing comma and added proper syntax in the commitinfo data.
|
||||
|
||||
## 2024-10-28 - 4.1.0 - feat(core)
|
||||
Enhance core functionality for cloud management and orchestration
|
||||
|
||||
- Improved initialization and management of cloud environments with Docker Swarmkit.
|
||||
- Added capability to manage DNS records via Cloudflare.
|
||||
- Introduced integration support for DigitalOcean resources.
|
||||
|
||||
## 2024-10-28 - 4.0.1 - fix(package_manager)
|
||||
Update @git.zone/tspublish dependency version
|
||||
|
||||
- Bump @git.zone/tspublish version from 1.5.4 to 1.5.5.
|
||||
|
||||
## 2024-10-28 - 4.0.0 - BREAKING CHANGE(core)
|
||||
Significant overhaul with potential breaking changes, update to version 3.0.0
|
||||
|
||||
- Updated project version from 1.2.5 to 3.0.0 in package.json
|
||||
|
||||
## 2024-10-28 - 1.2.5 - fix(build)
|
||||
Updated devDependencies for tspublish and removed buildDocs script
|
||||
|
||||
- devDependencies updated: @git.zone/tspublish to version ^1.5.4
|
||||
- Removed: buildDocs script from the scripts section
|
||||
|
||||
## 2024-10-27 - 1.2.4 - fix(ci)
|
||||
Fix Docker images and npm registry URL in CI workflows
|
||||
|
||||
|
19
license
Normal file
19
license
Normal file
@ -0,0 +1,19 @@
|
||||
Copyright (c) 2014 Task Venture Capital GmbH (hello@task.vc)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
@ -2,51 +2,48 @@
|
||||
"npmci": {
|
||||
"npmGlobalTools": [],
|
||||
"npmAccessLevel": "public",
|
||||
"npmRegistryUrl": "verdaccio.lossless.one",
|
||||
"npmRegistryUrl": "verdaccio.lossless.digital",
|
||||
"dockerRegistryRepoMap": {
|
||||
"registry.gitlab.com": "losslessone/services/servezone/cloudly"
|
||||
"code.foss.global": "serve.zone/cloudly"
|
||||
},
|
||||
"dockerBuildargEnvMap": {
|
||||
"NPMCI_TOKEN_NPM2": "NPMCI_TOKEN_NPM2"
|
||||
}
|
||||
"dockerBuildargEnvMap": {}
|
||||
},
|
||||
"gitzone": {
|
||||
"projectType": "service",
|
||||
"module": {
|
||||
"githost": "gitlab.com",
|
||||
"gitscope": "servezone/private",
|
||||
"githost": "code.foss.global",
|
||||
"gitscope": "serve.zone",
|
||||
"gitrepo": "cloudly",
|
||||
"description": "A comprehensive multi-cloud manager leveraging Docker Swarmkit to orchestrate containerized applications across various cloud services and provide robust configuration and API integration.",
|
||||
"description": "A comprehensive tool for managing containerized applications across multiple cloud providers using Docker Swarmkit, featuring web, CLI, and API interfaces.",
|
||||
"npmPackagename": "@serve.zone/cloudly",
|
||||
"license": "UNLICENSED",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
"cloud management",
|
||||
"multi-cloud management",
|
||||
"Docker Swarmkit",
|
||||
"container orchestration",
|
||||
"cloud services",
|
||||
"API integration",
|
||||
"web interface",
|
||||
"CLI",
|
||||
"CI/CD integration",
|
||||
"cloud providers",
|
||||
"DigitalOcean",
|
||||
"Hetzner Cloud",
|
||||
"Cloudflare",
|
||||
"configuration management",
|
||||
"SSL management",
|
||||
"API integration",
|
||||
"TypeScript",
|
||||
"node.js",
|
||||
"Node.js",
|
||||
"infrastructure automation",
|
||||
"devOps",
|
||||
"cloud API client",
|
||||
"system logging",
|
||||
"secret management",
|
||||
"CI/CD integration",
|
||||
"configuration management",
|
||||
"task scheduling",
|
||||
"logging",
|
||||
"SSL management",
|
||||
"system logging",
|
||||
"cloud API client",
|
||||
"frontend",
|
||||
"backend",
|
||||
"CLI",
|
||||
"web interface",
|
||||
"cloud providers",
|
||||
"security",
|
||||
"logging"
|
||||
"security"
|
||||
]
|
||||
}
|
||||
},
|
||||
|
81
package.json
81
package.json
@ -1,8 +1,8 @@
|
||||
{
|
||||
"name": "@serve.zone/cloudly",
|
||||
"version": "1.2.4",
|
||||
"version": "5.0.4",
|
||||
"private": false,
|
||||
"description": "A comprehensive multi-cloud manager leveraging Docker Swarmkit to orchestrate containerized applications across various cloud services and provide robust configuration and API integration.",
|
||||
"description": "A comprehensive tool for managing containerized applications across multiple cloud providers using Docker Swarmkit, featuring web, CLI, and API interfaces.",
|
||||
"type": "module",
|
||||
"exports": {
|
||||
".": "./dist/index.js",
|
||||
@ -19,43 +19,44 @@
|
||||
"startTs": "node cli.ts.js",
|
||||
"watch": "tswatch website",
|
||||
"publish": "tspublish",
|
||||
"buildDocs": "tsdoc"
|
||||
"docs": "tsdoc aidoc"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@git.zone/tsbuild": "^2.1.85",
|
||||
"@git.zone/tsbundle": "^2.1.0",
|
||||
"@git.zone/tspublish": "^1.4.0",
|
||||
"@git.zone/tstest": "^1.0.90",
|
||||
"@git.zone/tswatch": "^2.0.25",
|
||||
"@push.rocks/tapbundle": "^5.3.0",
|
||||
"@types/node": "^22.8.1"
|
||||
"@git.zone/tsbuild": "^2.3.2",
|
||||
"@git.zone/tsbundle": "^2.2.5",
|
||||
"@git.zone/tsdoc": "^1.4.4",
|
||||
"@git.zone/tspublish": "^1.9.1",
|
||||
"@git.zone/tstest": "^1.0.96",
|
||||
"@git.zone/tswatch": "^2.1.0",
|
||||
"@push.rocks/tapbundle": "^5.6.3",
|
||||
"@types/node": "^22.15.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@api.global/typedrequest": "3.1.10",
|
||||
"@api.global/typedrequest-interfaces": "^3.0.19",
|
||||
"@api.global/typedserver": "^3.0.51",
|
||||
"@api.global/typedserver": "^3.0.74",
|
||||
"@api.global/typedsocket": "^3.0.1",
|
||||
"@apiclient.xyz/cloudflare": "^6.0.1",
|
||||
"@apiclient.xyz/docker": "^1.2.7",
|
||||
"@apiclient.xyz/docker": "^1.3.0",
|
||||
"@apiclient.xyz/hetznercloud": "^1.2.0",
|
||||
"@apiclient.xyz/slack": "^3.0.9",
|
||||
"@design.estate/dees-catalog": "^1.2.0",
|
||||
"@design.estate/dees-domtools": "^2.0.64",
|
||||
"@design.estate/dees-element": "^2.0.39",
|
||||
"@design.estate/dees-catalog": "^1.8.0",
|
||||
"@design.estate/dees-domtools": "^2.3.2",
|
||||
"@design.estate/dees-element": "^2.0.42",
|
||||
"@git.zone/tsrun": "^1.3.3",
|
||||
"@push.rocks/early": "^4.0.3",
|
||||
"@push.rocks/npmextra": "^5.0.23",
|
||||
"@push.rocks/npmextra": "^5.1.2",
|
||||
"@push.rocks/projectinfo": "^5.0.1",
|
||||
"@push.rocks/qenv": "^6.0.5",
|
||||
"@push.rocks/qenv": "^6.1.0",
|
||||
"@push.rocks/smartacme": "^5.0.0",
|
||||
"@push.rocks/smartbucket": "^3.0.23",
|
||||
"@push.rocks/smartbucket": "^3.3.7",
|
||||
"@push.rocks/smartcli": "^4.0.11",
|
||||
"@push.rocks/smartclickhouse": "^2.0.17",
|
||||
"@push.rocks/smartdata": "^5.2.10",
|
||||
"@push.rocks/smartdata": "^5.15.1",
|
||||
"@push.rocks/smartdelay": "^3.0.5",
|
||||
"@push.rocks/smartexit": "^1.0.23",
|
||||
"@push.rocks/smartexpect": "^1.2.1",
|
||||
"@push.rocks/smartfile": "^11.0.21",
|
||||
"@push.rocks/smartexpect": "^1.6.1",
|
||||
"@push.rocks/smartfile": "^11.2.0",
|
||||
"@push.rocks/smartguard": "^3.1.0",
|
||||
"@push.rocks/smartjson": "^5.0.19",
|
||||
"@push.rocks/smartjwt": "^2.2.1",
|
||||
@ -63,17 +64,17 @@
|
||||
"@push.rocks/smartlog-destination-clickhouse": "^1.0.13",
|
||||
"@push.rocks/smartlog-interfaces": "^3.0.2",
|
||||
"@push.rocks/smartpath": "^5.0.18",
|
||||
"@push.rocks/smartpromise": "^4.0.4",
|
||||
"@push.rocks/smartrequest": "^2.0.22",
|
||||
"@push.rocks/smartrx": "^3.0.7",
|
||||
"@push.rocks/smartpromise": "^4.2.3",
|
||||
"@push.rocks/smartrequest": "^2.1.0",
|
||||
"@push.rocks/smartrx": "^3.0.10",
|
||||
"@push.rocks/smartssh": "^2.0.1",
|
||||
"@push.rocks/smartstate": "^2.0.19",
|
||||
"@push.rocks/smartstream": "^3.2.4",
|
||||
"@push.rocks/smartstream": "^3.2.5",
|
||||
"@push.rocks/smartstring": "^4.0.15",
|
||||
"@push.rocks/smartunique": "^3.0.9",
|
||||
"@push.rocks/taskbuffer": "^3.0.2",
|
||||
"@push.rocks/webjwt": "^1.0.9",
|
||||
"@tsclass/tsclass": "^4.1.2"
|
||||
"@tsclass/tsclass": "^9.0.0"
|
||||
},
|
||||
"files": [
|
||||
"ts/**/*",
|
||||
@ -99,32 +100,32 @@
|
||||
},
|
||||
"homepage": "https://gitlab.com/servezone/private/cloudly#readme",
|
||||
"keywords": [
|
||||
"cloud management",
|
||||
"multi-cloud management",
|
||||
"Docker Swarmkit",
|
||||
"container orchestration",
|
||||
"cloud services",
|
||||
"API integration",
|
||||
"web interface",
|
||||
"CLI",
|
||||
"CI/CD integration",
|
||||
"cloud providers",
|
||||
"DigitalOcean",
|
||||
"Hetzner Cloud",
|
||||
"Cloudflare",
|
||||
"configuration management",
|
||||
"SSL management",
|
||||
"API integration",
|
||||
"TypeScript",
|
||||
"node.js",
|
||||
"Node.js",
|
||||
"infrastructure automation",
|
||||
"devOps",
|
||||
"cloud API client",
|
||||
"system logging",
|
||||
"secret management",
|
||||
"CI/CD integration",
|
||||
"configuration management",
|
||||
"task scheduling",
|
||||
"logging",
|
||||
"SSL management",
|
||||
"system logging",
|
||||
"cloud API client",
|
||||
"frontend",
|
||||
"backend",
|
||||
"CLI",
|
||||
"web interface",
|
||||
"cloud providers",
|
||||
"security",
|
||||
"logging"
|
||||
]
|
||||
"security"
|
||||
],
|
||||
"packageManager": "pnpm@10.7.0+sha512.6b865ad4b62a1d9842b61d674a393903b871d9244954f652b8842c2b553c72176b278f64c463e52d40fff8aba385c235c8c9ecf5cc7de4fd78b8bb6d49633ab6"
|
||||
}
|
||||
|
14393
pnpm-lock.yaml
generated
14393
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
4
pnpm-workspace.yaml
Normal file
4
pnpm-workspace.yaml
Normal file
@ -0,0 +1,4 @@
|
||||
onlyBuiltDependencies:
|
||||
- esbuild
|
||||
- mongodb-memory-server
|
||||
- puppeteer
|
559
readme.md
559
readme.md
@ -1,6 +1,6 @@
|
||||
# @serve.zone/cloudly
|
||||
|
||||
A comprehensive multi-cloud manager leveraging Docker Swarmkit to orchestrate containerized applications across various cloud services and integrate robust configuration and API management capabilities.
|
||||
A multi-cloud management tool utilizing Docker Swarmkit for orchestrating containerized apps across various cloud providers, with web, CLI, and API interfaces for configuration and integration management.
|
||||
|
||||
## Install
|
||||
|
||||
@ -14,117 +14,70 @@ This will install the package and add it to your project's `package.json` depend
|
||||
|
||||
## Usage
|
||||
|
||||
`@serve.zone/cloudly` is designed to help you manage and configure cloud environments. This package provides a comprehensive TypeScript and ESM-based interface for interacting with various cloud services, including Docker Swarmkit cluster management, and integration with cloud providers such as DigitalOcean, Hetzner Cloud, and Cloudflare.
|
||||
`@serve.zone/cloudly` is designed to provide a unified interface for managing multi-cloud environments, encapsulating complex cloud interactions with Docker Swarmkit into simpler, programmable entities. This document will guide you through various use-cases and implementation examples to give you a comprehensive understanding of the module's capabilities.
|
||||
|
||||
### Getting Started
|
||||
### Prerequisites
|
||||
|
||||
Before diving into the specifics, ensure your environment is properly set up. This includes having Node.js installed (preferably the latest LTS version), and if you are working in a TypeScript project, ensure TypeScript is configured.
|
||||
Before you begin, ensure your environment is set up correctly:
|
||||
- You have Node.js installed (preferably the latest LTS version).
|
||||
- Your environment is configured to use TypeScript if you're working in a TypeScript project.
|
||||
|
||||
#### Initializing Cloudly
|
||||
### Basic Setup
|
||||
|
||||
First, import the `Cloudly` class from the package and initialize it as shown below:
|
||||
#### Creating a Cloudly Instance
|
||||
|
||||
The foundation of working with `@serve.zone/cloudly` involves creating an instance of the `Cloudly` class. This instance serves as the gateway to managing cloud resources and orchestrates interactions within the platform. Here’s how to get started:
|
||||
|
||||
```typescript
|
||||
import { Cloudly } from '@serve.zone/cloudly';
|
||||
import { Cloudly, ICloudlyConfig } from '@serve.zone/cloudly';
|
||||
|
||||
const myCloudlyInstance = new Cloudly();
|
||||
```
|
||||
|
||||
The `Cloudly` class is the entry point to using the library features. It prepares the environment for configuring the cloud services.
|
||||
|
||||
#### Configuration
|
||||
|
||||
Configuration plays a pivotal role in how `@serve.zone/cloudly` operates. The library expects certain configurations to be provided, which can include credentials for cloud services, database connections, etc.
|
||||
|
||||
For example, to configure a connection to MongoDB, specify your MongoDB details as shown:
|
||||
|
||||
```typescript
|
||||
const myCloudlyConfig = {
|
||||
const myCloudlyConfig: ICloudlyConfig = {
|
||||
cfToken: 'your_cloudflare_api_token',
|
||||
hetznerToken: 'your_hetzner_api_token',
|
||||
environment: 'development',
|
||||
letsEncryptEmail: 'lets_encrypt_email@example.com',
|
||||
publicUrl: 'example.com',
|
||||
publicPort: '8443',
|
||||
mongoDescriptor: {
|
||||
mongoDbUrl: 'mongodb+srv://<username>:<password>@<cluster>.mongodb.net/myFirstDatabase',
|
||||
mongoDbName: 'myDatabase',
|
||||
mongoDbUser: 'myUser',
|
||||
mongoDbPass: 'myPassword',
|
||||
},
|
||||
cfToken: 'your_cloudflare_api_token',
|
||||
environment: 'development',
|
||||
letsEncryptEmail: 'lets_encrypt_email@example.com',
|
||||
publicUrl: 'example.com',
|
||||
publicPort: 8443,
|
||||
hetznerToken: 'your_hetzner_api_token',
|
||||
};
|
||||
|
||||
const myCloudlyInstance = new Cloudly(myCloudlyConfig);
|
||||
```
|
||||
|
||||
### Managing Docker Swarmkit Clusters
|
||||
The configuration object `ICloudlyConfig` provides essential information needed for initializing external services, such as Cloudflare, Hetzner, and a MongoDB server. Adjust the parameters to match your actual service credentials and specifications.
|
||||
|
||||
Cloudly allows managing Docker Swarmkit clusters through an abstracted interface, simplifying operations such as deployment and scaling. Below are examples to demonstrate these capabilities.
|
||||
### Core Features and Use Cases
|
||||
|
||||
#### Example: Initializing a Cloudly Instance and Adding a Cluster
|
||||
#### Orchestrating Docker Swarmkit Clusters
|
||||
|
||||
Docker Swarmkit cluster management is a primary feature of `@serve.zone/cloudly`. Through its abstracted, programmable interface, you can operate clusters effortlessly. Here’s an example of how to create a cluster using `Cloudly`:
|
||||
|
||||
```typescript
|
||||
import { Cloudly, ClusterManager } from '@serve.zone/cloudly';
|
||||
import { Cloudly } from '@serve.zone/cloudly';
|
||||
|
||||
async function main() {
|
||||
const myCloudlyConfig = {
|
||||
mongoDescriptor: {
|
||||
mongoDbUrl: 'mongodb+srv://<username>:<password>@<cluster>.mongodb.net/myFirstDatabase',
|
||||
mongoDbName: 'myDatabase',
|
||||
mongoDbUser: 'myUser',
|
||||
mongoDbPass: 'myPassword',
|
||||
},
|
||||
cfToken: 'your_cloudflare_api_token',
|
||||
environment: 'development',
|
||||
letsEncryptEmail: 'lets_encrypt_email@example.com',
|
||||
publicUrl: 'example.com',
|
||||
publicPort: 8443,
|
||||
hetznerToken: 'your_hetzner_api_token',
|
||||
};
|
||||
|
||||
const myCloudlyInstance = new Cloudly(myCloudlyConfig);
|
||||
await myCloudlyInstance.start();
|
||||
|
||||
const clusterManager = myCloudlyInstance.clusterManager;
|
||||
const newCluster = await clusterManager.storeCluster({
|
||||
id: 'example_cluster_id',
|
||||
data: {
|
||||
name: 'example_cluster',
|
||||
jumpCode: 'random_jump_code',
|
||||
jumpCodeUsedAt: null,
|
||||
secretKey: 'example_secret_key',
|
||||
acmeInfo: null,
|
||||
cloudlyUrl: 'https://example.com:8443',
|
||||
servers: [],
|
||||
sshKeys: [],
|
||||
},
|
||||
});
|
||||
|
||||
console.log('Cluster added:', newCluster);
|
||||
interface ICluster {
|
||||
name: string;
|
||||
id: string;
|
||||
cloudlyUrl: string;
|
||||
servers: string[];
|
||||
sshKeys: string[];
|
||||
}
|
||||
|
||||
main();
|
||||
```
|
||||
|
||||
### Additional Use Cases
|
||||
|
||||
#### Managing Cloudflare DNS Records
|
||||
|
||||
You can manage Cloudflare DNS records using the `CloudflareConnector` provided by Cloudly.
|
||||
|
||||
```typescript
|
||||
import { Cloudly, CloudflareConnector } from '@serve.zone/cloudly';
|
||||
|
||||
async function manageDNSRecords() {
|
||||
async function manageClusters() {
|
||||
const myCloudlyConfig = {
|
||||
cfToken: 'your_cloudflare_api_token',
|
||||
environment: 'development',
|
||||
mongoDescriptor: {
|
||||
mongoDbUrl: 'mongodb+srv://<username>:<password>@<cluster>.mongodb.net/myFirstDatabase',
|
||||
mongoDbName: 'myDatabase',
|
||||
mongoDbUser: 'myUser',
|
||||
mongoDbPass: 'myPassword',
|
||||
},
|
||||
cfToken: 'your_cloudflare_api_token',
|
||||
environment: 'development',
|
||||
letsEncryptEmail: 'lets_encrypt_email@example.com',
|
||||
publicUrl: 'example.com',
|
||||
publicPort: 8443,
|
||||
@ -134,285 +87,249 @@ async function manageDNSRecords() {
|
||||
const myCloudlyInstance = new Cloudly(myCloudlyConfig);
|
||||
await myCloudlyInstance.start();
|
||||
|
||||
const dnsInfo = {
|
||||
zoneName: 'example.com',
|
||||
recordName: 'sub.example.com',
|
||||
recordType: 'A',
|
||||
recordContent: '127.0.0.1',
|
||||
const newCluster: ICluster = {
|
||||
name: 'example_cluster',
|
||||
id: 'example_cluster_id',
|
||||
cloudlyUrl: 'https://example.com:8443',
|
||||
servers: [],
|
||||
sshKeys: [],
|
||||
};
|
||||
|
||||
// Store the newly created cluster with Cloudly
|
||||
const storedCluster = await myCloudlyInstance.clusterManager.storeCluster(newCluster);
|
||||
console.log('Cluster stored:', storedCluster);
|
||||
}
|
||||
|
||||
manageClusters();
|
||||
```
|
||||
|
||||
In this scenario, a cluster called `example_cluster` is initialized using the `Cloudly` instance. This method represents a central mechanism to efficiently handle cluster entities and associated metadata.
|
||||
|
||||
#### Integrating With Cloudflare for DNS Management
|
||||
|
||||
`@serve.zone/cloudly` provides built-in capabilities for managing DNS records through integration with Cloudflare. Using the `CloudflareConnector`, you can programmatically create, manage, and delete DNS entries:
|
||||
|
||||
```typescript
|
||||
import { Cloudly } from '@serve.zone/cloudly';
|
||||
|
||||
async function configureCloudflareDNS() {
|
||||
const myCloudlyConfig = {
|
||||
cfToken: 'your_cloudflare_api_token',
|
||||
environment: 'development',
|
||||
letsEncryptEmail: 'lets_encrypt_email@example.com',
|
||||
publicUrl: 'example.com',
|
||||
publicPort: 8443,
|
||||
hetznerToken: 'your_hetzner_api_token',
|
||||
mongoDescriptor: {
|
||||
mongoDbUrl: 'mongodb+srv://<username>:<password>@<cluster>.mongodb.net/myFirstDatabase',
|
||||
mongoDbName: 'myDatabase',
|
||||
mongoDbUser: 'myUser',
|
||||
mongoDbPass: 'myPassword',
|
||||
},
|
||||
};
|
||||
|
||||
const myCloudlyInstance = new Cloudly(myCloudlyConfig);
|
||||
await myCloudlyInstance.start();
|
||||
|
||||
const cfConnector = myCloudlyInstance.cloudflareConnector.cloudflare;
|
||||
const newRecord = await cfConnector.createDNSRecord(
|
||||
dnsInfo.zoneName,
|
||||
dnsInfo.recordName,
|
||||
dnsInfo.recordType,
|
||||
dnsInfo.recordContent
|
||||
);
|
||||
|
||||
console.log('DNS Record created:', newRecord);
|
||||
const dnsRecord = await cfConnector.createDNSRecord('example.com', 'sub.example.com', 'A', '127.0.0.1');
|
||||
console.log('DNS Record:', dnsRecord);
|
||||
}
|
||||
manageDNSRecords();
|
||||
|
||||
configureCloudflareDNS();
|
||||
```
|
||||
|
||||
#### Integrating with DigitalOcean
|
||||
Here, you create an A record for the subdomain `sub.example.com` pointing to `127.0.0.1`. All communication with Cloudflare is handled directly through the interface without manual intervention.
|
||||
|
||||
Integrate with DigitalOcean to manage droplets and other resources.
|
||||
#### Dynamic Interaction with DigitalOcean
|
||||
|
||||
DigitalOcean resource management, including droplet creation, is simplified in Cloudly. By extending the API to encapsulate calls to external providers, Cloudly provides a seamless experience:
|
||||
|
||||
```typescript
|
||||
import { Cloudly, DigitalOceanConnector } from '@serve.zone/cloudly';
|
||||
import { Cloudly } from '@serve.zone/cloudly';
|
||||
|
||||
async function manageDroplet() {
|
||||
async function createDigitalOceanDroplets() {
|
||||
const myCloudlyConfig = {
|
||||
mongoDescriptor: {
|
||||
mongoDbUrl: 'mongodb+srv://<username>:<password>@<cluster>.mongodb.net/myFirstDatabase',
|
||||
mongoDbName: 'myDatabase',
|
||||
mongoDbUser: 'myUser',
|
||||
mongoDbPass: 'myPassword',
|
||||
},
|
||||
cfToken: 'your_cloudflare_api_token',
|
||||
environment: 'development',
|
||||
letsEncryptEmail: 'lets_encrypt_email@example.com',
|
||||
publicUrl: 'example.com',
|
||||
publicPort: 8443,
|
||||
hetznerToken: 'your_hetzner_api_token',
|
||||
mongoDescriptor: {
|
||||
mongoDbUrl: 'mongodb+srv://<username>:<password>@<cluster>.mongodb.net/myFirstDatabase',
|
||||
mongoDbName: 'myDatabase',
|
||||
mongoDbUser: 'myUser',
|
||||
mongoDbPass: 'myPassword',
|
||||
},
|
||||
};
|
||||
|
||||
const myCloudlyInstance = new Cloudly(myCloudlyConfig);
|
||||
await myCloudlyInstance.start();
|
||||
|
||||
const doConnector = myCloudlyInstance.digitaloceanConnector;
|
||||
const dropletInfo = {
|
||||
name: 'example-droplet',
|
||||
region: 'nyc3',
|
||||
size: 's-1vcpu-1gb',
|
||||
image: 'ubuntu-20-04-x64',
|
||||
};
|
||||
|
||||
const newDroplet = await doConnector.createDroplet(
|
||||
dropletInfo.name,
|
||||
dropletInfo.region,
|
||||
dropletInfo.size,
|
||||
dropletInfo.image
|
||||
);
|
||||
|
||||
console.log('Droplet created:', newDroplet);
|
||||
const droplet = await doConnector.createDroplet('example-droplet', 'nyc3', 's-1vcpu-1gb', 'ubuntu-20-04-x64');
|
||||
console.log('Droplet created:', droplet);
|
||||
}
|
||||
manageDroplet();
|
||||
|
||||
createDigitalOceanDroplets();
|
||||
```
|
||||
|
||||
### Using Cloudly Web Interface
|
||||
In this script, a droplet named `example-droplet` is created within the `nyc3` region using the `ubuntu-20-04-x64` image. The module abstracts complexities by directly interfacing with DigitalOcean.
|
||||
|
||||
If your project includes a web interface to manage various sections like DNS, deployments, clusters, etc., you can use the provided elements and state management. Below is an example of setting up a dashboard using the components defined:
|
||||
### Advanced Use Cases
|
||||
|
||||
#### Web Dashboard Example
|
||||
#### Implementing Web Management Interface
|
||||
|
||||
`@serve.zone/cloudly` facilitates dashboard management with advanced Web Components built with `@design.estate`. This section of the library allows the creation of dynamic, interactive panels for real-time resource management in a modern browser interface.
|
||||
|
||||
```typescript
|
||||
import { commitinfo } from '../00_commitinfo_data.js';
|
||||
import * as plugins from '../plugins.js';
|
||||
import { html } from '@design.estate/dees-element';
|
||||
|
||||
import * as appstate from '../appstate.js';
|
||||
|
||||
import {
|
||||
DeesElement,
|
||||
css,
|
||||
cssManager,
|
||||
customElement,
|
||||
html,
|
||||
state
|
||||
} from '@design.estate/dees-element';
|
||||
import { CloudlyViewBackups } from './cloudly-view-backups.js';
|
||||
import { CloudlyViewClusters } from './cloudly-view-clusters.js';
|
||||
import { CloudlyViewDbs } from './cloudly-view-dbs.js';
|
||||
import { CloudlyViewDeployments } from './cloudly-view-deployments.js';
|
||||
import { CloudlyViewDns } from './cloudly-view-dns.js';
|
||||
import { CloudlyViewImages } from './cloudly-view-images.js';
|
||||
import { CloudlyViewLogs } from './cloudly-view-logs.js';
|
||||
import { CloudlyViewMails } from './cloudly-view-mails.js';
|
||||
import { CloudlyViewOverview } from './cloudly-view-overview.js';
|
||||
import { CloudlyViewS3 } from './cloudly-view-s3.js';
|
||||
import { CloudlyViewSecretBundles } from './cloudly-view-secretbundles.js';
|
||||
import { CloudlyViewSecretGroups } from './cloudly-view-secretgroups.js';
|
||||
import { CloudlyViewServices } from './cloudly-view-services.js';
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
'cloudly-dashboard': CloudlyDashboard;
|
||||
}
|
||||
}
|
||||
|
||||
@customElement('cloudly-dashboard')
|
||||
export class CloudlyDashboard extends DeesElement {
|
||||
@state() private jwt: string;
|
||||
@state() private data: appstate.IDataState = {
|
||||
secretGroups: [],
|
||||
secretBundles: [],
|
||||
clusters: [],
|
||||
};
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
document.title = `cloudly v${commitinfo.version}`;
|
||||
const subcription = appstate.dataState
|
||||
.select((stateArg) => stateArg)
|
||||
.subscribe((dataArg) => {
|
||||
this.data = dataArg;
|
||||
});
|
||||
this.rxSubscriptions.push(subcription);
|
||||
}
|
||||
|
||||
public static styles = [
|
||||
cssManager.defaultStyles,
|
||||
css`
|
||||
.maincontainer {
|
||||
position: relative;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-weight: 400;
|
||||
font-size: 24px;
|
||||
font-family: 'Cal Sans';
|
||||
}
|
||||
`,
|
||||
];
|
||||
public render() {
|
||||
const renderDashboard = () => {
|
||||
return html`
|
||||
<div class="maincontainer">
|
||||
<dees-simple-login name="cloudly v${commitinfo.version}">
|
||||
<dees-simple-appdash name="cloudly v${commitinfo.version}"
|
||||
.viewTabs=${[
|
||||
{
|
||||
name: 'Overview',
|
||||
element: CloudlyViewOverview,
|
||||
},
|
||||
{
|
||||
name: 'SecretGroups',
|
||||
element: CloudlyViewSecretGroups,
|
||||
},
|
||||
{
|
||||
name: 'SecretBundles',
|
||||
element: CloudlyViewSecretBundles,
|
||||
},
|
||||
{
|
||||
name: 'Clusters',
|
||||
element: CloudlyViewClusters,
|
||||
},
|
||||
{
|
||||
name: 'Images',
|
||||
element: CloudlyViewImages,
|
||||
},
|
||||
{
|
||||
name: 'Services',
|
||||
element: CloudlyViewServices,
|
||||
},
|
||||
{
|
||||
name: 'Deployments',
|
||||
element: CloudlyViewDeployments,
|
||||
},
|
||||
{
|
||||
name: 'DNS',
|
||||
element: CloudlyViewDns,
|
||||
},
|
||||
{
|
||||
name: 'Mails',
|
||||
element: CloudlyViewMails,
|
||||
},
|
||||
{
|
||||
name: 'Logs',
|
||||
element: CloudlyViewLogs,
|
||||
},
|
||||
{
|
||||
name: 's3',
|
||||
element: CloudlyViewS3,
|
||||
},
|
||||
{
|
||||
name: 'DBs',
|
||||
element: CloudlyViewDbs,
|
||||
},
|
||||
{
|
||||
name: 'Backups',
|
||||
element: CloudlyViewBackups,
|
||||
},
|
||||
{
|
||||
name: 'Fleet',
|
||||
element: CloudlyViewBackups,
|
||||
}
|
||||
] as plugins.deesCatalog.IView[]}
|
||||
></dees-simple-appdash>
|
||||
</dees-simple-login>
|
||||
</div>
|
||||
<cloudly-dashboard>
|
||||
<dees-simple-appdash>
|
||||
<!-- Define sections and elements -->
|
||||
<cloudly-view-clusters></cloudly-view-clusters>
|
||||
<cloudly-view-dns></cloudly-view-dns>
|
||||
<cloudly-view-images></cloudly-view-images>
|
||||
<!-- Other custom views -->
|
||||
</dees-simple-appdash>
|
||||
</cloudly-dashboard>
|
||||
`;
|
||||
}
|
||||
public async firstUpdated() {
|
||||
const simpleLogin = this.shadowRoot.querySelector('dees-simple-login');
|
||||
simpleLogin.addEventListener('login', (e: CustomEvent) => {
|
||||
console.log(e.detail);
|
||||
this.login(e.detail.data.username, e.detail.data.password);
|
||||
});
|
||||
this.addEventListener('contextmenu', (eventArg) => {
|
||||
plugins.deesCatalog.DeesContextmenu.openContextMenuWithOptions(eventArg, [
|
||||
{
|
||||
name: 'About',
|
||||
iconName: 'mugHot',
|
||||
action: async () => {
|
||||
await plugins.deesCatalog.DeesModal.createAndShow({
|
||||
heading: 'About',
|
||||
content: html`cloudly ${commitinfo.version}`,
|
||||
menuOptions: [
|
||||
{
|
||||
name: 'close',
|
||||
iconName: null,
|
||||
action: async (modalArg) => {
|
||||
await modalArg.destroy();
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
},
|
||||
},
|
||||
]);
|
||||
});
|
||||
};
|
||||
|
||||
// lets deal with initial state
|
||||
const domtools = await this.domtoolsPromise;
|
||||
const loginState = appstate.loginStatePart.getState();
|
||||
console.log(loginState);
|
||||
if (loginState.jwt) {
|
||||
this.jwt = loginState.jwt;
|
||||
await simpleLogin.switchToSlottedContent();
|
||||
await appstate.dataState.dispatchAction(appstate.getAllDataAction, null);
|
||||
}
|
||||
}
|
||||
|
||||
private async login(username: string, password: string) {
|
||||
const domtools = await this.domtoolsPromise;
|
||||
console.log(`attempting to login...`);
|
||||
const simpleLogin = this.shadowRoot.querySelector('dees-simple-login');
|
||||
const form = simpleLogin.shadowRoot.querySelector('dees-form');
|
||||
form.setStatus('pending', 'Logging in...');
|
||||
const state = await appstate.loginStatePart.dispatchAction(appstate.loginAction, {
|
||||
username,
|
||||
password,
|
||||
});
|
||||
if (state.jwt) {
|
||||
console.log('got jwt');
|
||||
this.jwt = state.jwt;
|
||||
form.setStatus('success', 'Logged in!');
|
||||
await simpleLogin.switchToSlottedContent();
|
||||
await appstate.dataState.dispatchAction(appstate.getAllDataAction, null);
|
||||
} else {
|
||||
form.setStatus('error', 'Login failed!');
|
||||
await domtools.convenience.smartdelay.delayFor(2000);
|
||||
form.reset();
|
||||
}
|
||||
}
|
||||
|
||||
private async logout() {}
|
||||
}
|
||||
document.body.appendChild(renderDashboard());
|
||||
```
|
||||
|
||||
With the examples provided above, you should now have a good understanding of how to use `@serve.zone/cloudly` to manage your cloud infrastructure programmatically. For deeper insights and additional features, refer to the documentation relevant to specific modules and methods used in your application.
|
||||
Utilizing the custom web components designed specifically for Cloudly, dashboards are adaptable, interactive, and maintainable. These elements allow you to structure a complete cloud management center without needing to delve into detailed UI engineering.
|
||||
|
||||
#### Comprehensive Log Management
|
||||
|
||||
With Cloudly’s Log Management capabilities, you can track and analyze system logs for better insights into your cloud ecosystem’s behavior:
|
||||
|
||||
```typescript
|
||||
import { Cloudly } from '@serve.zone/cloudly';
|
||||
|
||||
async function initiateLogManagement() {
|
||||
const myCloudlyConfig = {
|
||||
cfToken: 'your_cloudflare_api_token',
|
||||
environment: 'development',
|
||||
letsEncryptEmail: 'lets_encrypt_email@example.com',
|
||||
publicUrl: 'example.com',
|
||||
publicPort: 8443,
|
||||
hetznerToken: 'your_hetzner_api_token',
|
||||
mongoDescriptor: {
|
||||
mongoDbUrl: 'mongodb+srv://<username>:<password>@<cluster>.mongodb.net/myFirstDatabase',
|
||||
mongoDbName: 'myDatabase',
|
||||
mongoDbUser: 'myUser',
|
||||
mongoDbPass: 'myPassword',
|
||||
},
|
||||
};
|
||||
|
||||
const myCloudlyInstance = new Cloudly(myCloudlyConfig);
|
||||
await myCloudlyInstance.start();
|
||||
|
||||
const logs = await myCloudlyInstance.logManager.fetchLogs();
|
||||
console.log('Logs:', logs);
|
||||
}
|
||||
|
||||
initiateLogManagement();
|
||||
```
|
||||
|
||||
Cloudly provides the tools needed to collect and process logs within your cloud infrastructure. Logs are an essential part of system validation, troubleshooting, monitoring, and auditing.
|
||||
|
||||
#### Secret Management and Bundles
|
||||
|
||||
Managing secrets securely and efficiently is critical for cloud operations. Cloudly allows you to create and manage secret groups and bundles that can be used across multiple applications and environments:
|
||||
|
||||
```typescript
|
||||
import { Cloudly } from '@serve.zone/cloudly';
|
||||
|
||||
async function createSecrets() {
|
||||
const myCloudlyConfig = {
|
||||
cfToken: 'your_cloudflare_api_token',
|
||||
environment: 'development',
|
||||
letsEncryptEmail: 'lets_encrypt_email@example.com',
|
||||
publicUrl: 'example.com',
|
||||
publicPort: 8443,
|
||||
hetznerToken: 'your_hetzner_api_token',
|
||||
mongoDescriptor: {
|
||||
mongoDbUrl: 'mongodb+srv://<username>:<password>@<cluster>.mongodb.net/myFirstDatabase',
|
||||
mongoDbName: 'myDatabase',
|
||||
mongoDbUser: 'myUser',
|
||||
mongoDbPass: 'myPassword',
|
||||
},
|
||||
};
|
||||
|
||||
const myCloudlyInstance = new Cloudly(myCloudlyConfig);
|
||||
await myCloudlyInstance.start();
|
||||
|
||||
const newSecretGroup = await myCloudlyInstance.secretManager.createSecretGroup({
|
||||
name: 'example_secret_group',
|
||||
secrets: [
|
||||
{ key: 'SECRET_KEY', value: 's3cr3t' },
|
||||
],
|
||||
});
|
||||
|
||||
const newSecretBundle = await myCloudlyInstance.secretManager.createSecretBundle({
|
||||
name: 'example_bundle',
|
||||
secretGroups: [newSecretGroup],
|
||||
});
|
||||
|
||||
console.log('Created Secret Group and Bundle:', newSecretGroup, newSecretBundle);
|
||||
}
|
||||
|
||||
createSecrets();
|
||||
```
|
||||
|
||||
Secrets, such as API keys and sensitive configuration data, are managed efficiently using secret groups and bundles. This structured approach to secret management enhances both security and accessibility.
|
||||
|
||||
### Task Scheduling and Management
|
||||
|
||||
With task buffers, you can schedule and manage background tasks integral to cloud operations:
|
||||
|
||||
```typescript
|
||||
import { Cloudly } from '@serve.zone/cloudly';
|
||||
import { TaskBuffer } from '@push.rocks/taskbuffer';
|
||||
|
||||
async function scheduleTasks() {
|
||||
const myCloudlyConfig = {
|
||||
cfToken: 'your_cloudflare_api_token',
|
||||
environment: 'development',
|
||||
letsEncryptEmail: 'lets_encrypt_email@example.com',
|
||||
publicUrl: 'example.com',
|
||||
publicPort: 8443,
|
||||
hetznerToken: 'your_hetzner_api_token',
|
||||
mongoDescriptor: {
|
||||
mongoDbUrl: 'mongodb+srv://<username>:<password>@<cluster>.mongodb.net/myFirstDatabase',
|
||||
mongoDbName: 'myDatabase',
|
||||
mongoDbUser: 'myUser',
|
||||
mongoDbPass: 'myPassword',
|
||||
},
|
||||
};
|
||||
|
||||
const myCloudlyInstance = new Cloudly(myCloudlyConfig);
|
||||
await myCloudlyInstance.start();
|
||||
|
||||
const taskManager = new TaskBuffer();
|
||||
taskManager.scheduleEvery('minute', async () => {
|
||||
console.log('Running scheduled task...');
|
||||
// Task logic
|
||||
});
|
||||
|
||||
console.log('Tasks scheduled.');
|
||||
}
|
||||
|
||||
scheduleTasks();
|
||||
```
|
||||
|
||||
The example demonstrates setting up periodic task execution using task buffers as part of Cloudly's task management. Whether it's maintenance routines, data updates, or resource checks, tasks can be managed effectively.
|
||||
|
||||
This comprehensive overview of `@serve.zone/cloudly` is designed to help you leverage its full capabilities in managing multi-cloud environments. Each example is meant to serve as a starting point, and you are encouraged to explore further by consulting the relevant sections in the documentation, engaging with community discussions, or experimenting in your own environment.
|
||||
|
||||
## License and Legal Information
|
||||
|
||||
|
@ -3,25 +3,48 @@ const testQenv = new Qenv('./', './.nogit/');
|
||||
|
||||
import * as cloudly from '../../ts/index.js';
|
||||
|
||||
const stopFunctions: Array<() => Promise<void>> = [];
|
||||
|
||||
const tapToolsNodeMod = await import('@push.rocks/tapbundle/node');
|
||||
const smartmongo = await tapToolsNodeMod.tapNodeTools.createSmartmongo();
|
||||
stopFunctions.push(async () => {
|
||||
await smartmongo.stopAndDumpToDir('./.nogit/mongodump');
|
||||
});
|
||||
const smarts3 = await tapToolsNodeMod.tapNodeTools.createSmarts3();
|
||||
await smarts3.createBucket('cloudly-test');
|
||||
stopFunctions.push(async () => {
|
||||
await smarts3.stop();
|
||||
});
|
||||
|
||||
export const testCloudlyConfig: cloudly.ICloudlyConfig = {
|
||||
cfToken: await testQenv.getEnvVarOnDemand('CF_TOKEN'),
|
||||
environment: 'integration',
|
||||
letsEncryptEmail: 'test@serve.zone',
|
||||
publicUrl: '127.0.0.1',
|
||||
publicPort: '8080',
|
||||
mongoDescriptor: await smartmongo.getMongoDescriptor(),
|
||||
s3Descriptor: await smarts3.getS3Descriptor(),
|
||||
sslMode: 'none',
|
||||
...(() => {
|
||||
if (process.env.NPMCI_SECRET01) {
|
||||
return {
|
||||
hetznerToken: process.env.NPMCI_SECRET01,
|
||||
};
|
||||
}
|
||||
})(),
|
||||
};
|
||||
|
||||
await tapToolsNodeMod.tapNodeTools.testFileProvider.getDockerAlpineImageAsLocalTarball();
|
||||
|
||||
export const createCloudly = async () => {
|
||||
const cloudlyConfig: cloudly.ICloudlyConfig = {
|
||||
cfToken: await testQenv.getEnvVarOnDemand('CF_TOKEN'),
|
||||
environment: 'integration',
|
||||
letsEncryptEmail: await testQenv.getEnvVarOnDemand('LETSENCRYPT_EMAIL'),
|
||||
publicUrl: await testQenv.getEnvVarOnDemand('SERVEZONE_URL'),
|
||||
publicPort: await testQenv.getEnvVarOnDemand('SERVEZONE_PORT'),
|
||||
mongoDescriptor: {
|
||||
mongoDbName: await testQenv.getEnvVarOnDemand('MONGODB_DATABASE'),
|
||||
mongoDbUser: await testQenv.getEnvVarOnDemand('MONGODB_USER'),
|
||||
mongoDbPass: await testQenv.getEnvVarOnDemand('MONGODB_PASSWORD'),
|
||||
mongoDbUrl: await testQenv.getEnvVarOnDemand('MONGODB_URL'),
|
||||
},
|
||||
};
|
||||
const cloudlyInstance = new cloudly.Cloudly();
|
||||
const cloudlyInstance = new cloudly.Cloudly(testCloudlyConfig);
|
||||
return cloudlyInstance;
|
||||
}
|
||||
};
|
||||
|
||||
export const stopCloudly = async () => {
|
||||
await Promise.all(stopFunctions.map((stopFunction) => stopFunction()));
|
||||
};
|
||||
|
||||
export const getEnvVarOnDemand = async (envVarName: string) => {
|
||||
return testQenv.getEnvVarOnDemand(envVarName);
|
||||
}
|
||||
|
||||
};
|
||||
|
@ -33,7 +33,7 @@ tap.preTask('should create a new machine user for testing', async () => {
|
||||
tap.test('should create a new cloudlyApiClient', async () => {
|
||||
testClient = new cloudlyApiClient.CloudlyApiClient({
|
||||
registerAs: 'api',
|
||||
cloudlyUrl: `http://localhost:${await helpers.getEnvVarOnDemand('SERVEZONE_PORT')}`,
|
||||
cloudlyUrl: `http://${helpers.testCloudlyConfig.publicUrl}:${helpers.testCloudlyConfig.publicPort}`,
|
||||
});
|
||||
await testClient.start();
|
||||
expect(testClient).toBeTruthy();
|
||||
@ -57,7 +57,7 @@ tap.test('should get an identity', async () => {
|
||||
|
||||
let image: Image;
|
||||
tap.test('should create and upload an image', async () => {
|
||||
image = await testClient.images.createImage({
|
||||
image = await testClient.image.createImage({
|
||||
name: 'test',
|
||||
description: 'test'
|
||||
});
|
||||
@ -73,6 +73,7 @@ tap.test('should upload an image version', async () => {
|
||||
|
||||
tap.test('should stop the apiclient', async (toolsArg) => {
|
||||
await toolsArg.delayFor(10000);
|
||||
await helpers.stopCloudly();
|
||||
await testClient.stop();
|
||||
await testCloudly.stop();
|
||||
})
|
||||
|
@ -14,8 +14,10 @@ tap.test('should init cloudly', async () => {
|
||||
});
|
||||
|
||||
tap.test('should end the service', async (tools) => {
|
||||
await tools.delayFor(5000);
|
||||
await helpers.stopCloudly();
|
||||
await testCloudly.stop();
|
||||
tools.delayFor(1000).then(() => process.exit())
|
||||
tools.delayFor(1000).then(() => process.exit());
|
||||
});
|
||||
|
||||
tap.start();
|
||||
|
@ -3,6 +3,6 @@
|
||||
*/
|
||||
export const commitinfo = {
|
||||
name: '@serve.zone/cloudly',
|
||||
version: '1.2.4',
|
||||
description: 'A comprehensive multi-cloud manager leveraging Docker Swarmkit to orchestrate containerized applications across various cloud services and provide robust configuration and API integration.'
|
||||
version: '5.0.4',
|
||||
description: 'A comprehensive tool for managing containerized applications across multiple cloud providers using Docker Swarmkit, featuring web, CLI, and API interfaces.'
|
||||
}
|
||||
|
@ -63,7 +63,7 @@ for (let i = 0; i < demoSecretGroups.length; i++) {
|
||||
id: `configBundleId${i + 1}`,
|
||||
data: {
|
||||
name: `Demo Config Bundle ${i + 1}`,
|
||||
includedImages: [],
|
||||
imageClaims: [],
|
||||
type: 'external',
|
||||
description: 'Demo Purpose',
|
||||
includedSecretGroupIds: [secretGroup.id],
|
||||
|
@ -20,6 +20,7 @@ import { CloudlyTaskmanager } from './manager.task/taskmanager.js';
|
||||
import { CloudlySecretManager } from './manager.secret/classes.secretmanager.js';
|
||||
import { CloudlyServerManager } from './manager.server/classes.servermanager.js';
|
||||
import { ExternalApiManager } from './manager.status/statusmanager.js';
|
||||
import { ExternalRegistryManager } from './manager.externalregistry/index.js';
|
||||
import { ImageManager } from './manager.image/classes.imagemanager.js';
|
||||
import { logger } from './logger.js';
|
||||
import { CloudlyAuthManager } from './manager.auth/classes.authmanager.js';
|
||||
@ -54,13 +55,16 @@ export class Cloudly {
|
||||
public clusterManager: ClusterManager;
|
||||
public coreflowManager: CloudlyCoreflowManager;
|
||||
public externalApiManager: ExternalApiManager;
|
||||
public externalRegistryManager: ExternalRegistryManager;
|
||||
public imageManager: ImageManager;
|
||||
public taskManager: CloudlyTaskmanager;
|
||||
public serverManager: CloudlyServerManager;
|
||||
|
||||
private readyDeferred = new plugins.smartpromise.Deferred();
|
||||
|
||||
constructor() {
|
||||
private configOptions: plugins.servezoneInterfaces.data.ICloudlyConfig;
|
||||
constructor(configArg?: plugins.servezoneInterfaces.data.ICloudlyConfig) {
|
||||
this.configOptions = configArg;
|
||||
this.cloudlyInfo = new CloudlyInfo(this);
|
||||
this.config = new CloudlyConfig(this);
|
||||
|
||||
@ -78,6 +82,7 @@ export class Cloudly {
|
||||
this.clusterManager = new ClusterManager(this);
|
||||
this.coreflowManager = new CloudlyCoreflowManager(this);
|
||||
this.externalApiManager = new ExternalApiManager(this);
|
||||
this.externalRegistryManager = new ExternalRegistryManager(this);
|
||||
this.imageManager = new ImageManager(this);
|
||||
this.taskManager = new CloudlyTaskmanager(this);
|
||||
this.secretManager = new CloudlySecretManager(this);
|
||||
@ -90,7 +95,7 @@ export class Cloudly {
|
||||
*/
|
||||
public async start() {
|
||||
// config
|
||||
await this.config.init();
|
||||
await this.config.init(this.configOptions);
|
||||
|
||||
// manageers
|
||||
await this.authManager.start();
|
||||
|
@ -15,7 +15,7 @@ export class CloudlyConfig {
|
||||
this.cloudlyRef = cloudlyRefArg;
|
||||
}
|
||||
|
||||
public async init() {
|
||||
public async init(configArg?: plugins.servezoneInterfaces.data.ICloudlyConfig) {
|
||||
this.appData =
|
||||
await plugins.npmextra.AppData.createAndInit<plugins.servezoneInterfaces.data.ICloudlyConfig>(
|
||||
{
|
||||
@ -54,6 +54,7 @@ export class CloudlyConfig {
|
||||
'environment',
|
||||
'mongoDescriptor',
|
||||
],
|
||||
overwriteObject: configArg,
|
||||
},
|
||||
);
|
||||
|
||||
|
@ -38,13 +38,13 @@ export class ClusterManager {
|
||||
console.log(await cluster.createSavableObject());
|
||||
this.cloudlyRef.serverManager.ensureServerInfrastructure();
|
||||
return {
|
||||
clusterConfig: await cluster.createSavableObject(),
|
||||
cluster: await cluster.createSavableObject(),
|
||||
};
|
||||
}),
|
||||
);
|
||||
|
||||
this.typedrouter.addTypedHandler<plugins.servezoneInterfaces.requests.cluster.IRequest_GetAllClusters>(
|
||||
new plugins.typedrequest.TypedHandler('getAllClusters', async (dataArg) => {
|
||||
this.typedrouter.addTypedHandler<plugins.servezoneInterfaces.requests.cluster.IReq_Any_Cloudly_GetClusters>(
|
||||
new plugins.typedrequest.TypedHandler('getClusters', async (dataArg) => {
|
||||
// TODO: do authentication here
|
||||
const clusters = await this.getAllClusters();
|
||||
return {
|
||||
@ -56,12 +56,12 @@ export class ClusterManager {
|
||||
);
|
||||
|
||||
// delete cluster
|
||||
this.typedrouter.addTypedHandler<plugins.servezoneInterfaces.requests.cluster.IRequest_DeleteCluster>(
|
||||
new plugins.typedrequest.TypedHandler('deleteCluster', async (reqDataArg, toolsArg) => {
|
||||
this.typedrouter.addTypedHandler<plugins.servezoneInterfaces.requests.cluster.IReq_Any_Cloudly_DeleteClusterById>(
|
||||
new plugins.typedrequest.TypedHandler('deleteClusterById', async (reqDataArg, toolsArg) => {
|
||||
await toolsArg.passGuards([this.cloudlyRef.authManager.adminIdentityGuard], reqDataArg);
|
||||
await this.deleteCluster(reqDataArg.clusterId);
|
||||
return {
|
||||
success: true,
|
||||
ok: true,
|
||||
};
|
||||
}),
|
||||
);
|
||||
|
40
ts/manager.externalregistry/classes.externalregistry.ts
Normal file
40
ts/manager.externalregistry/classes.externalregistry.ts
Normal file
@ -0,0 +1,40 @@
|
||||
import * as plugins from '../plugins.js';
|
||||
import * as paths from '../paths.js';
|
||||
import type { Cloudly } from 'ts/classes.cloudly.js';
|
||||
import type { ExternalRegistryManager } from './classes.externalregistrymanager.js';
|
||||
|
||||
export class ExternalRegistry extends plugins.smartdata.SmartDataDbDoc<ExternalRegistry, plugins.servezoneInterfaces.data.IExternalRegistry, ExternalRegistryManager> {
|
||||
// STATIC
|
||||
public static async getRegistryById(registryIdArg: string) {
|
||||
const externalRegistry = await this.getInstance({
|
||||
id: registryIdArg,
|
||||
});
|
||||
return externalRegistry;
|
||||
}
|
||||
|
||||
public static async getRegistries() {
|
||||
const externalRegistries = await this.getInstances({});
|
||||
return externalRegistries;
|
||||
}
|
||||
|
||||
public static async createExternalRegistry(registryDataArg: Partial<plugins.servezoneInterfaces.data.IExternalRegistry['data']>) {
|
||||
const externalRegistry = new ExternalRegistry();
|
||||
externalRegistry.id = await ExternalRegistry.getNewId();
|
||||
Object.assign(externalRegistry, registryDataArg);
|
||||
await externalRegistry.save();
|
||||
return externalRegistry;
|
||||
}
|
||||
|
||||
// INSTANCE
|
||||
|
||||
@plugins.smartdata.svDb()
|
||||
public id: string;
|
||||
|
||||
@plugins.smartdata.svDb()
|
||||
public data: plugins.servezoneInterfaces.data.IExternalRegistry['data'];
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
import * as plugins from '../plugins.js';
|
||||
import { Cloudly } from '../classes.cloudly.js';
|
||||
import { ExternalRegistry } from './classes.externalregistry.js';
|
||||
|
||||
export class ExternalRegistryManager {
|
||||
public cloudlyRef: Cloudly;
|
||||
public typedrouter = new plugins.typedrequest.TypedRouter();
|
||||
public CExternalRegistry = plugins.smartdata.setDefaultManagerForDoc(this, ExternalRegistry);
|
||||
|
||||
get db() {
|
||||
return this.cloudlyRef.mongodbConnector.smartdataDb;
|
||||
}
|
||||
|
||||
constructor(cloudlyRef: Cloudly) {
|
||||
this.cloudlyRef = cloudlyRef;
|
||||
}
|
||||
|
||||
public async start() {
|
||||
// lets set up a typedrouter
|
||||
this.typedrouter.addTypedRouter(this.typedrouter);
|
||||
|
||||
this.typedrouter.addTypedHandler<plugins.servezoneInterfaces.requests.externalRegistry.IReq_GetRegistryById>(
|
||||
new plugins.typedrequest.TypedHandler('getExternalRegistryById', async (dataArg) => {
|
||||
const registry = await ExternalRegistry.getRegistryById(dataArg.id);
|
||||
return {
|
||||
registry: await registry.createSavableObject(),
|
||||
};
|
||||
})
|
||||
);
|
||||
|
||||
this.typedrouter.addTypedHandler<plugins.servezoneInterfaces.requests.externalRegistry.IReq_GetRegistries>(
|
||||
new plugins.typedrequest.TypedHandler('getExternalRegistries', async (dataArg) => {
|
||||
const registries = await ExternalRegistry.getRegistries();
|
||||
return {
|
||||
registries: await Promise.all(
|
||||
registries.map((registry) => registry.createSavableObject())
|
||||
),
|
||||
};
|
||||
})
|
||||
);
|
||||
|
||||
this.typedrouter.addTypedHandler<plugins.servezoneInterfaces.requests.externalRegistry.IReq_CreateRegistry>(
|
||||
new plugins.typedrequest.TypedHandler('createExternalRegistry', async (dataArg) => {
|
||||
const registry = await ExternalRegistry.createExternalRegistry(dataArg.registryData);
|
||||
return {
|
||||
registry: await registry.createSavableObject(),
|
||||
};
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
2
ts/manager.externalregistry/index.ts
Normal file
2
ts/manager.externalregistry/index.ts
Normal file
@ -0,0 +1,2 @@
|
||||
export * from './classes.externalregistrymanager.js';
|
||||
export * from './classes.externalregistry.js';
|
@ -59,4 +59,16 @@ export class SecretBundle extends plugins.smartdata.SmartDataDbDoc<
|
||||
}
|
||||
return returnObject;
|
||||
}
|
||||
|
||||
public async getFlatKeyValueObject(environmentArg: string) {
|
||||
if (!environmentArg) {
|
||||
throw new Error('environment is required');
|
||||
}
|
||||
const secretGroups = await this.getSecretGroups();
|
||||
const returnObject = {};
|
||||
for (const secretGroup of secretGroups) {
|
||||
returnObject[secretGroup.data.key] = secretGroup.data.environments[environmentArg].value;
|
||||
}
|
||||
return returnObject;
|
||||
}
|
||||
}
|
||||
|
@ -35,20 +35,71 @@ export class CloudlySecretManager {
|
||||
this.typedrouter = new plugins.typedrequest.TypedRouter();
|
||||
this.cloudlyRef.typedrouter.addTypedRouter(this.typedrouter);
|
||||
|
||||
this.typedrouter.addTypedHandler(
|
||||
new plugins.typedrequest.TypedHandler<plugins.servezoneInterfaces.requests.secret.IReq_Admin_GetConfigBundlesAndSecretGroups>(
|
||||
'adminGetConfigBundlesAndSecretGroups',
|
||||
// secretbundle routes
|
||||
this.typedrouter.addTypedHandler<plugins.servezoneInterfaces.requests.secretbundle.IReq_GetSecretBundles>(
|
||||
new plugins.typedrequest.TypedHandler(
|
||||
'getSecretBundles',
|
||||
async (dataArg, toolsArg) => {
|
||||
await toolsArg.passGuards([this.cloudlyRef.authManager.adminIdentityGuard], dataArg);
|
||||
dataArg.identity.jwt;
|
||||
const secretBundles = await SecretBundle.getInstances({});
|
||||
const secretGroups = await SecretGroup.getInstances({});
|
||||
return {
|
||||
secretBundles: [
|
||||
...(await Promise.all(
|
||||
secretBundles.map((configBundle) => configBundle.createSavableObject()),
|
||||
)),
|
||||
],
|
||||
};
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
this.typedrouter.addTypedHandler<plugins.servezoneInterfaces.requests.secretbundle.IReq_CreateSecretBundle>(
|
||||
new plugins.typedrequest.TypedHandler('createSecretBundle', async (dataArg) => {
|
||||
const secretBundle = new SecretBundle();
|
||||
secretBundle.id = plugins.smartunique.shortId(8);
|
||||
secretBundle.data = dataArg.secretBundle.data;
|
||||
await secretBundle.save();
|
||||
return {
|
||||
resultSecretBundle: await secretBundle.createSavableObject(),
|
||||
};
|
||||
}),
|
||||
);
|
||||
|
||||
this.typedrouter.addTypedHandler<plugins.servezoneInterfaces.requests.secretbundle.IReq_UpdateSecretBundle>(
|
||||
new plugins.typedrequest.TypedHandler('updateSecretBundle', async (dataArg) => {
|
||||
const secretBundle = await SecretBundle.getInstance({
|
||||
id: dataArg.secretBundle.id,
|
||||
});
|
||||
secretBundle.data = dataArg.secretBundle.data;
|
||||
await secretBundle.save();
|
||||
return {
|
||||
resultSecretBundle: await secretBundle.createSavableObject(),
|
||||
};
|
||||
}),
|
||||
);
|
||||
|
||||
this.typedrouter.addTypedHandler<plugins.servezoneInterfaces.requests.secretbundle.IReq_DeleteSecretBundleById>(
|
||||
new plugins.typedrequest.TypedHandler('deleteSecretBundleById', async (dataArg) => {
|
||||
const secretBundle = await SecretBundle.getInstance({
|
||||
id: dataArg.secretBundleId,
|
||||
});
|
||||
await secretBundle.delete();
|
||||
return {
|
||||
ok: true,
|
||||
};
|
||||
}),
|
||||
);
|
||||
|
||||
// secretgroup routes
|
||||
this.typedrouter.addTypedHandler<plugins.servezoneInterfaces.requests.secretgroup.IReq_GetSecretGroups>(
|
||||
new plugins.typedrequest.TypedHandler(
|
||||
'getSecretGroups',
|
||||
async (dataArg, toolsArg) => {
|
||||
await toolsArg.passGuards([this.cloudlyRef.authManager.adminIdentityGuard], dataArg);
|
||||
dataArg.identity.jwt;
|
||||
const secretGroups = await SecretGroup.getInstances({});
|
||||
return {
|
||||
secretGroups: [
|
||||
...(await Promise.all(
|
||||
secretGroups.map((secretGroup) => secretGroup.createSavableObject()),
|
||||
@ -59,73 +110,64 @@ export class CloudlySecretManager {
|
||||
),
|
||||
);
|
||||
|
||||
this.typedrouter.addTypedHandler<plugins.servezoneInterfaces.requests.secret.IReq_Admin_CreateConfigBundlesAndSecretGroups>(
|
||||
new plugins.typedrequest.TypedHandler(
|
||||
'adminCreateConfigBundlesAndSecretGroups',
|
||||
async (dataArg) => {
|
||||
for (const secretGroupObject of dataArg.secretGroups) {
|
||||
const secretGroup = new SecretGroup();
|
||||
secretGroup.id = plugins.smartunique.shortId(8);
|
||||
secretGroup.data = secretGroupObject.data;
|
||||
await secretGroup.save();
|
||||
}
|
||||
return {
|
||||
ok: true,
|
||||
};
|
||||
},
|
||||
),
|
||||
this.typedrouter.addTypedHandler<plugins.servezoneInterfaces.requests.secretgroup.IReq_CreateSecretGroup>(
|
||||
new plugins.typedrequest.TypedHandler('createSecretGroup', async (dataArg) => {
|
||||
const secretGroup = new SecretGroup();
|
||||
secretGroup.id = plugins.smartunique.shortId(8);
|
||||
secretGroup.data = dataArg.secretGroup.data;
|
||||
await secretGroup.save();
|
||||
return {
|
||||
resultSecretGroup: await secretGroup.createSavableObject(),
|
||||
};
|
||||
}),
|
||||
);
|
||||
|
||||
this.typedrouter.addTypedHandler<plugins.servezoneInterfaces.requests.secretgroup.IReq_UpdateSecretGroup>(
|
||||
new plugins.typedrequest.TypedHandler('updateSecretGroup', async (dataArg) => {
|
||||
const secretGroup = await SecretGroup.getInstance({
|
||||
id: dataArg.secretGroup.id,
|
||||
});
|
||||
secretGroup.data = dataArg.secretGroup.data;
|
||||
await secretGroup.save();
|
||||
return {
|
||||
resultSecretGroup: await secretGroup.createSavableObject(),
|
||||
};
|
||||
}),
|
||||
);
|
||||
|
||||
this.typedrouter.addTypedHandler<plugins.servezoneInterfaces.requests.secretgroup.IReq_DeleteSecretGroupById>(
|
||||
new plugins.typedrequest.TypedHandler('deleteSecretGroupById', async (dataArg) => {
|
||||
const secretGroup = await SecretGroup.getInstance({
|
||||
id: dataArg.secretGroupId,
|
||||
});
|
||||
await secretGroup.delete();
|
||||
return {
|
||||
ok: true,
|
||||
};
|
||||
}),
|
||||
);
|
||||
|
||||
this.typedrouter.addTypedHandler(
|
||||
new plugins.typedrequest.TypedHandler<plugins.servezoneInterfaces.requests.secret.IReq_Admin_DeleteConfigBundlesAndSecretGroups>(
|
||||
'adminDeleteConfigBundlesAndSecretGroups',
|
||||
async (dataArg) => {
|
||||
for (const secretGroupId of dataArg.secretGroupIds) {
|
||||
const secretGroup = await SecretGroup.getInstance({
|
||||
id: secretGroupId,
|
||||
});
|
||||
await secretGroup.delete();
|
||||
}
|
||||
for (const secretBundleId of dataArg.secretBundleIds) {
|
||||
const configBundle = await SecretBundle.getInstance({
|
||||
id: secretBundleId,
|
||||
});
|
||||
await configBundle.delete();
|
||||
console.log(`deleted configbundle ${secretBundleId}`);
|
||||
}
|
||||
return {
|
||||
ok: true,
|
||||
};
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
// lets add typedrouter routes for accessing the configvailt from apps
|
||||
this.typedrouter.addTypedHandler(
|
||||
new plugins.typedrequest.TypedHandler<plugins.servezoneInterfaces.requests.secret.IReq_GetEnvBundle>(
|
||||
'getEnvBundle',
|
||||
new plugins.typedrequest.TypedHandler<plugins.servezoneInterfaces.requests.secretbundle.IReq_GetFlatKeyValueObject>(
|
||||
'getFlatKeyValueObject',
|
||||
async (dataArg) => {
|
||||
const wantedBundle = await SecretBundle.getInstance({
|
||||
data: {
|
||||
authorizations: {
|
||||
// @ts-ignore
|
||||
$elemMatch: {
|
||||
secretAccessKey: dataArg.authorization,
|
||||
secretAccessKey: dataArg.secretBundleAuthorization.secretAccessKey,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
const authorization = await wantedBundle.getAuthorizationFromAuthKey(
|
||||
dataArg.authorization,
|
||||
dataArg.secretBundleAuthorization.secretAccessKey,
|
||||
);
|
||||
return {
|
||||
envBundle: {
|
||||
configKeyValueObject: await wantedBundle.getKeyValueObjectForEnvironment(
|
||||
authorization.environment,
|
||||
),
|
||||
environment: authorization.environment,
|
||||
timeSensitive: false,
|
||||
},
|
||||
flatKeyValueObject: await wantedBundle.getKeyValueObjectForEnvironment(
|
||||
authorization.environment,
|
||||
),
|
||||
};
|
||||
},
|
||||
),
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { SecretBundle } from 'ts/manager.secret/classes.secretbundle.js';
|
||||
import * as plugins from '../plugins.js';
|
||||
import { ServiceManager } from './classes.servicemanager.js';
|
||||
|
||||
@ -6,9 +7,51 @@ export class Service extends plugins.smartdata.SmartDataDbDoc<
|
||||
plugins.servezoneInterfaces.data.IService,
|
||||
ServiceManager
|
||||
> {
|
||||
// STATIC
|
||||
public static async getServiceById(serviceIdArg: string) {
|
||||
const service = await this.getInstance({
|
||||
id: serviceIdArg,
|
||||
});
|
||||
return service;
|
||||
}
|
||||
|
||||
public static async getServices() {
|
||||
const services = await this.getInstances({});
|
||||
return services;
|
||||
}
|
||||
|
||||
public static async createService(serviceDataArg: Partial<plugins.servezoneInterfaces.data.IService['data']>) {
|
||||
const service = new Service();
|
||||
service.id = await Service.getNewId();
|
||||
Object.assign(service, serviceDataArg);
|
||||
await service.save();
|
||||
return service;
|
||||
}
|
||||
|
||||
// INSTANCE
|
||||
@plugins.smartdata.svDb()
|
||||
public id: string;
|
||||
|
||||
@plugins.smartdata.svDb()
|
||||
public data: plugins.servezoneInterfaces.data.IService['data'];
|
||||
|
||||
/**
|
||||
* a service runs in a specific environment
|
||||
* so -> this method returns the secret bundles as a flat object accordingly.
|
||||
* in other words, it resolves secret groups for the relevant environment
|
||||
* @param environmentArg
|
||||
*/
|
||||
public async getSecretBundlesAsFlatObject(environmentArg: string = 'production') {
|
||||
const secreBundleIds = this.data.additionalSecretBundleIds || [];
|
||||
secreBundleIds.push(this.data.secretBundleId); // put this last, so it overwrites any other secret bundles.
|
||||
let finalFlatObject = {};
|
||||
for (const secretBundleId of secreBundleIds) {
|
||||
const secretBundle = await SecretBundle.getInstance({
|
||||
id: secretBundleId,
|
||||
});
|
||||
const flatObject = await secretBundle.getFlatKeyValueObject(environmentArg);
|
||||
Object.assign(finalFlatObject, flatObject);
|
||||
}
|
||||
return finalFlatObject;
|
||||
}
|
||||
}
|
||||
|
@ -14,5 +14,87 @@ export class ServiceManager {
|
||||
|
||||
constructor(cloudlyRef: Cloudly) {
|
||||
this.cloudlyRef = cloudlyRef;
|
||||
|
||||
this.typedrouter.addTypedHandler(
|
||||
new plugins.typedrequest.TypedHandler<plugins.servezoneInterfaces.requests.service.IRequest_Any_Cloudly_GetServices>(
|
||||
'getServices',
|
||||
async (reqArg) => {
|
||||
await plugins.smartguard.passGuardsOrReject(reqArg, [
|
||||
this.cloudlyRef.authManager.validIdentityGuard,
|
||||
]);
|
||||
|
||||
const services = await this.CService.getInstances({});
|
||||
|
||||
return {
|
||||
services: await Promise.all(
|
||||
services.map((service) => {
|
||||
return service.createSavableObject();
|
||||
})
|
||||
),
|
||||
};
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
this.typedrouter.addTypedHandler(
|
||||
new plugins.typedrequest.TypedHandler<plugins.servezoneInterfaces.requests.service.IRequest_Any_Cloudly_GetServiceSecretBundlesAsFlatObject>(
|
||||
'getServiceSecretBundlesAsFlatObject',
|
||||
async (dataArg) => {
|
||||
const service = await Service.getInstance({
|
||||
id: dataArg.serviceId,
|
||||
});
|
||||
const flatKeyValueObject = await service.getSecretBundlesAsFlatObject(dataArg.environment);
|
||||
return {
|
||||
flatKeyValueObject: flatKeyValueObject,
|
||||
};
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
this.typedrouter.addTypedHandler(
|
||||
new plugins.typedrequest.TypedHandler<plugins.servezoneInterfaces.requests.service.IRequest_Any_Cloudly_CreateService>(
|
||||
'createService',
|
||||
async (dataArg) => {
|
||||
const service = await Service.createService(dataArg.serviceData);
|
||||
return {
|
||||
service: await service.createSavableObject(),
|
||||
};
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
this.typedrouter.addTypedHandler(
|
||||
new plugins.typedrequest.TypedHandler<plugins.servezoneInterfaces.requests.service.IRequest_Any_Cloudly_UpdateService>(
|
||||
'updateService',
|
||||
async (dataArg) => {
|
||||
const service = await Service.getInstance({
|
||||
id: dataArg.serviceId,
|
||||
});
|
||||
service.data = {
|
||||
...service.data,
|
||||
...dataArg.serviceData,
|
||||
};
|
||||
await service.save();
|
||||
return {
|
||||
service: await service.createSavableObject(),
|
||||
};
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
this.typedrouter.addTypedHandler(
|
||||
new plugins.typedrequest.TypedHandler<plugins.servezoneInterfaces.requests.service.IRequest_Any_Cloudly_DeleteServiceById>(
|
||||
'deleteServiceById',
|
||||
async (dataArg) => {
|
||||
const service = await Service.getInstance({
|
||||
id: dataArg.serviceId,
|
||||
});
|
||||
await service.delete();
|
||||
return {
|
||||
success: true,
|
||||
};
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,11 @@ import * as plugins from './plugins.js';
|
||||
export type TClientType = 'api' | 'ci' | 'coreflow' | 'cli' | 'serverconfig';
|
||||
|
||||
import { Image } from './classes.image.js';
|
||||
import { Service } from './classes.service.js';
|
||||
import { Cluster } from './classes.cluster.js';
|
||||
import { SecretBundle } from './classes.secretbundle.js';
|
||||
import { SecretGroup } from './classes.secretgroup.js';
|
||||
import { ExternalRegistry } from './classes.externalregistry.js';
|
||||
|
||||
export class CloudlyApiClient {
|
||||
private cloudlyUrl: string;
|
||||
@ -20,7 +25,7 @@ export class CloudlyApiClient {
|
||||
plugins.servezoneInterfaces.requests.server.IRequest_TriggerServerAction['request']
|
||||
>();
|
||||
|
||||
constructor(optionsArg?: {
|
||||
constructor(optionsArg: {
|
||||
registerAs: TClientType;
|
||||
cloudlyUrl?: string;
|
||||
}) {
|
||||
@ -155,8 +160,24 @@ export class CloudlyApiClient {
|
||||
return typedResponse.certificate;
|
||||
}
|
||||
|
||||
public images = {
|
||||
public externalRegistry = {
|
||||
// ExternalRegistry
|
||||
getRegistryById: async (registryNameArg: string) => {
|
||||
return ExternalRegistry.getExternalRegistryById(this, registryNameArg);
|
||||
},
|
||||
getRegistries: async () => {
|
||||
return ExternalRegistry.getExternalRegistries(this);
|
||||
},
|
||||
createRegistry: async (optionsArg: Parameters<typeof ExternalRegistry.createExternalRegistry>[1]) => {
|
||||
return ExternalRegistry.createExternalRegistry(this, optionsArg);
|
||||
}
|
||||
}
|
||||
|
||||
public image = {
|
||||
// Images
|
||||
getImageById: async (imageIdArg: string) => {
|
||||
return Image.getImageById(this, imageIdArg);
|
||||
},
|
||||
getImages: async () => {
|
||||
return Image.getImages(this);
|
||||
},
|
||||
@ -164,4 +185,56 @@ export class CloudlyApiClient {
|
||||
return Image.createImage(this, optionsArg);
|
||||
}
|
||||
}
|
||||
|
||||
public services = {
|
||||
// Services
|
||||
getServiceById: async (serviceIdArg: string) => {
|
||||
return Service.getServiceById(this, serviceIdArg);
|
||||
},
|
||||
getServices: async () => {
|
||||
return Service.getServices(this);
|
||||
},
|
||||
createService: async (optionsArg: Parameters<typeof Service.createService>[1]) => {
|
||||
return Service.createService(this, optionsArg);
|
||||
}
|
||||
}
|
||||
|
||||
public cluster = {
|
||||
// Clusters
|
||||
getClusterById: async (clusterIdArg: string) => {
|
||||
return Cluster.getClusterById(this, clusterIdArg);
|
||||
},
|
||||
getClusters: async () => {
|
||||
return Cluster.getClusters(this);
|
||||
},
|
||||
createCluster: async (optionsArg: Parameters<typeof Cluster.createCluster>[1]) => {
|
||||
return Cluster.createCluster(this, optionsArg);
|
||||
}
|
||||
}
|
||||
|
||||
public secretbundle = {
|
||||
// SecretBundles
|
||||
getSecretBundleById: async (secretBundleIdArg: string) => {
|
||||
return SecretBundle.getSecretBundleById(this, secretBundleIdArg);
|
||||
},
|
||||
getSecretBundles: async () => {
|
||||
return SecretBundle.getSecretBundles(this);
|
||||
},
|
||||
createSecretBundle: async (optionsArg: Parameters<typeof SecretBundle.createSecretBundle>[1]) => {
|
||||
return SecretBundle.createSecretBundle(this, optionsArg);
|
||||
}
|
||||
}
|
||||
|
||||
public secretgroup = {
|
||||
// SecretGroups
|
||||
getSecretGroupById: async (secretGroupIdArg: string) => {
|
||||
return SecretGroup.getSecretGroupById(this, secretGroupIdArg);
|
||||
},
|
||||
getSecretGroups: async () => {
|
||||
return SecretGroup.getSecretGroups(this);
|
||||
},
|
||||
createSecretGroup: async (optionsArg: Parameters<typeof SecretGroup.createSecretGroup>[1]) => {
|
||||
return SecretGroup.createSecretGroup(this, optionsArg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,84 @@
|
||||
import { CloudlyApiClient } from './classes.cloudlyapiclient.js';
|
||||
import * as plugins from './plugins.js';
|
||||
|
||||
export class Cluster {
|
||||
public getServers() {}
|
||||
|
||||
export class Cluster implements plugins.servezoneInterfaces.data.ICluster {
|
||||
// STATIC
|
||||
public static async getClusterById(cloudlyClientRef: CloudlyApiClient, clusterIdArg: string) {
|
||||
const getClusterByIdTR = cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.cluster.IReq_Any_Cloudly_GetClusterById>(
|
||||
'getClusterById'
|
||||
);
|
||||
const response = await getClusterByIdTR.fire({
|
||||
identity: cloudlyClientRef.identity,
|
||||
clusterId: clusterIdArg,
|
||||
});
|
||||
const newCluster = new Cluster(cloudlyClientRef);
|
||||
Object.assign(newCluster, response.cluster);
|
||||
return newCluster;
|
||||
}
|
||||
|
||||
public static async getClusters(cloudlyClientRef: CloudlyApiClient) {
|
||||
const getClustersTR = cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.cluster.IReq_Any_Cloudly_GetClusters>(
|
||||
'getClusters'
|
||||
);
|
||||
const response = await getClustersTR.fire({
|
||||
identity: cloudlyClientRef.identity,
|
||||
});
|
||||
const clusterConfigs: Cluster[] = [];
|
||||
for (const clusterConfig of response.clusters) {
|
||||
const newCluster = new Cluster(cloudlyClientRef);
|
||||
Object.assign(newCluster, clusterConfig);
|
||||
clusterConfigs.push(newCluster);
|
||||
}
|
||||
return clusterConfigs;
|
||||
}
|
||||
|
||||
public static async createCluster(cloudlyClientRef: CloudlyApiClient, clusterNameArg: string) {
|
||||
const createClusterTR = cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.cluster.IRequest_CreateCluster>(
|
||||
'createCluster'
|
||||
);
|
||||
const response = await createClusterTR.fire({
|
||||
identity: cloudlyClientRef.identity,
|
||||
clusterName: clusterNameArg,
|
||||
});
|
||||
const newCluster = new Cluster(cloudlyClientRef);
|
||||
Object.assign(newCluster, response.cluster);
|
||||
return newCluster;
|
||||
}
|
||||
|
||||
// INSTANCE
|
||||
public id: string;
|
||||
public data: plugins.servezoneInterfaces.data.ICluster['data'];
|
||||
public cloudlyClientRef: CloudlyApiClient;
|
||||
|
||||
constructor(cloudlyClientRef: CloudlyApiClient) {
|
||||
this.cloudlyClientRef = cloudlyClientRef;
|
||||
}
|
||||
|
||||
|
||||
public async update() {
|
||||
const updateClusterTR = this.cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.cluster.IReq_Any_Cloudly_UpdateCluster>(
|
||||
'updateCluster'
|
||||
);
|
||||
const response = await updateClusterTR.fire({
|
||||
identity: this.cloudlyClientRef.identity,
|
||||
clusterData: this.data,
|
||||
});
|
||||
|
||||
const resultClusterData = response.resultCluster.data;
|
||||
plugins.smartexpect.expect(resultClusterData).toEqual(this.data);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public async delete(cloudlyClientRef: CloudlyApiClient, clusterIdArg: string) {
|
||||
const deleteClusterTR = cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.cluster.IReq_Any_Cloudly_DeleteClusterById>(
|
||||
'deleteClusterById'
|
||||
);
|
||||
const response = await deleteClusterTR.fire({
|
||||
identity: cloudlyClientRef.identity,
|
||||
clusterId: this.id,
|
||||
});
|
||||
plugins.smartexpect.expect(response.ok).toBeTrue();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
83
ts_apiclient/classes.externalregistry.ts
Normal file
83
ts_apiclient/classes.externalregistry.ts
Normal file
@ -0,0 +1,83 @@
|
||||
import * as plugins from './plugins.js';
|
||||
import type { CloudlyApiClient } from './classes.cloudlyapiclient.js';
|
||||
|
||||
export class ExternalRegistry implements plugins.servezoneInterfaces.data.IExternalRegistry {
|
||||
// STATIC
|
||||
public static async getExternalRegistryById(cloudlyClientRef: CloudlyApiClient, registryNameArg: string) {
|
||||
const getRegistryByIdTR = cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.externalRegistry.IReq_GetRegistryById>(
|
||||
'getExternalRegistryById'
|
||||
);
|
||||
const response = await getRegistryByIdTR.fire({
|
||||
identity: cloudlyClientRef.identity,
|
||||
id: registryNameArg,
|
||||
});
|
||||
const newRegistry = new ExternalRegistry(cloudlyClientRef);
|
||||
Object.assign(newRegistry, response.registry);
|
||||
return newRegistry;
|
||||
}
|
||||
|
||||
public static async getExternalRegistries(cloudlyClientRef: CloudlyApiClient) {
|
||||
const getRegistriesTR = cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.externalRegistry.IReq_GetRegistries>(
|
||||
'getExternalRegistries'
|
||||
);
|
||||
const response = await getRegistriesTR.fire({
|
||||
identity: cloudlyClientRef.identity,
|
||||
});
|
||||
const registryConfigs: ExternalRegistry[] = [];
|
||||
for (const registryConfig of response.registries) {
|
||||
const newRegistry = new ExternalRegistry(cloudlyClientRef);
|
||||
Object.assign(newRegistry, registryConfig);
|
||||
registryConfigs.push(newRegistry);
|
||||
}
|
||||
return registryConfigs;
|
||||
}
|
||||
|
||||
public static async createExternalRegistry(cloudlyClientRef: CloudlyApiClient, registryDataArg: Partial<plugins.servezoneInterfaces.data.IExternalRegistry['data']>) {
|
||||
const createRegistryTR = cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.externalRegistry.IReq_CreateRegistry>(
|
||||
'createExternalRegistry'
|
||||
);
|
||||
const response = await createRegistryTR.fire({
|
||||
identity: cloudlyClientRef.identity,
|
||||
registryData: registryDataArg as plugins.servezoneInterfaces.data.IExternalRegistry['data'],
|
||||
});
|
||||
const newRegistry = new ExternalRegistry(cloudlyClientRef);
|
||||
Object.assign(newRegistry, response.registry);
|
||||
return newRegistry;
|
||||
}
|
||||
|
||||
// INSTANCE
|
||||
public id: string;
|
||||
public data: plugins.servezoneInterfaces.data.IExternalRegistry['data'];
|
||||
public cloudlyClientRef: CloudlyApiClient;
|
||||
|
||||
constructor(cloudlyClientRef: CloudlyApiClient) {
|
||||
this.cloudlyClientRef = cloudlyClientRef;
|
||||
}
|
||||
|
||||
public async update() {
|
||||
const updateRegistryTR = this.cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.externalRegistry.IReq_UpdateRegistry>(
|
||||
'updateExternalRegistry'
|
||||
);
|
||||
const response = await updateRegistryTR.fire({
|
||||
identity: this.cloudlyClientRef.identity,
|
||||
registryData: this.data,
|
||||
});
|
||||
|
||||
const resultRegistryData = response.resultRegistry.data;
|
||||
plugins.smartexpect.expect(resultRegistryData).toEqual(this.data);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public async delete(cloudlyClientRef: CloudlyApiClient, registryIdArg: string) {
|
||||
const deleteRegistryTR = cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.externalRegistry.IReq_DeleteRegistryById>(
|
||||
'deleteExternalRegistryById'
|
||||
);
|
||||
const response = await deleteRegistryTR.fire({
|
||||
identity: cloudlyClientRef.identity,
|
||||
registryId: this.id,
|
||||
});
|
||||
plugins.smartexpect.expect(response.ok).toBeTrue();
|
||||
return null;
|
||||
}
|
||||
}
|
@ -18,6 +18,19 @@ export class Image implements plugins.servezoneInterfaces.data.IImage {
|
||||
return resultImages;
|
||||
}
|
||||
|
||||
public static async getImageById(cloudlyClientRef: CloudlyApiClient, imageIdArg: string) {
|
||||
const getImageByIdTR = cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.image.IRequest_GetImage>(
|
||||
'getImage'
|
||||
);
|
||||
const response = await getImageByIdTR.fire({
|
||||
identity: cloudlyClientRef.identity,
|
||||
imageId: imageIdArg,
|
||||
});
|
||||
const newImage = new Image(cloudlyClientRef);
|
||||
Object.assign(newImage, response.image);
|
||||
return newImage;
|
||||
}
|
||||
|
||||
/**
|
||||
* creates a new image
|
||||
*/
|
||||
|
135
ts_apiclient/classes.secretbundle.ts
Normal file
135
ts_apiclient/classes.secretbundle.ts
Normal file
@ -0,0 +1,135 @@
|
||||
import * as plugins from './plugins.js';
|
||||
import type { CloudlyApiClient } from './classes.cloudlyapiclient.js';
|
||||
import { SecretGroup } from './classes.secretgroup.js';
|
||||
|
||||
export class SecretBundle implements plugins.servezoneInterfaces.data.ISecretBundle {
|
||||
// STATIC
|
||||
public static async getSecretBundleById(cloudlyClientRef: CloudlyApiClient, secretBundleIdArg: string) {
|
||||
const getSecretBundleByIdTR = cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.secretbundle.IReq_GetSecretBundleById>(
|
||||
'getSecretBundleById'
|
||||
);
|
||||
const response = await getSecretBundleByIdTR.fire({
|
||||
identity: cloudlyClientRef.identity,
|
||||
secretBundleId: secretBundleIdArg,
|
||||
});
|
||||
const newSecretBundle = new SecretBundle(cloudlyClientRef);
|
||||
Object.assign(newSecretBundle, response.secretBundle);
|
||||
return newSecretBundle;
|
||||
}
|
||||
|
||||
public static async getSecretBundleByAuthorization(cloudlyClientRef: CloudlyApiClient, secretBundleAuthorizationArg: plugins.servezoneInterfaces.data.ISecretBundleAuthorization) {
|
||||
const getSecretBundleByAuthorizationTR = cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.secretbundle.IReq_GetSecretBundleByAuthorization>(
|
||||
'getSecretBundleByAuthorization'
|
||||
);
|
||||
const response = await getSecretBundleByAuthorizationTR.fire({
|
||||
identity: cloudlyClientRef.identity,
|
||||
secretBundleAuthorization: secretBundleAuthorizationArg,
|
||||
});
|
||||
const newSecretBundle = new SecretBundle(cloudlyClientRef);
|
||||
Object.assign(newSecretBundle, response.secretBundle);
|
||||
return newSecretBundle;
|
||||
}
|
||||
|
||||
public static async getSecretBundles(cloudlyClientRef: CloudlyApiClient) {
|
||||
const getSecretBundlesTR = cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.secretbundle.IReq_GetSecretBundles>(
|
||||
'getSecretBundles'
|
||||
);
|
||||
const response = await getSecretBundlesTR.fire({
|
||||
identity: cloudlyClientRef.identity,
|
||||
});
|
||||
const secretBundles: SecretBundle[] = [];
|
||||
for (const secretBundle of response.secretBundles) {
|
||||
const newSecretBundle = new SecretBundle(cloudlyClientRef);
|
||||
Object.assign(newSecretBundle, secretBundle);
|
||||
secretBundles.push(newSecretBundle);
|
||||
}
|
||||
return secretBundles;
|
||||
}
|
||||
|
||||
public static async createSecretBundle(cloudlyClientRef: CloudlyApiClient, secretBundleDataArg: Partial<plugins.servezoneInterfaces.data.ISecretBundle['data']>) {
|
||||
const createSecretBundleTR = cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.secretbundle.IReq_CreateSecretBundle>(
|
||||
'createSecretBundle'
|
||||
);
|
||||
const response = await createSecretBundleTR.fire({
|
||||
identity: cloudlyClientRef.identity,
|
||||
secretBundle: {
|
||||
id: null,
|
||||
data: {
|
||||
name: secretBundleDataArg.name,
|
||||
description: secretBundleDataArg.description,
|
||||
type: secretBundleDataArg.type,
|
||||
authorizations: secretBundleDataArg.authorizations,
|
||||
imageClaims: secretBundleDataArg.imageClaims,
|
||||
includedSecretGroupIds: secretBundleDataArg.includedSecretGroupIds,
|
||||
includedTags: secretBundleDataArg.includedTags,
|
||||
},
|
||||
},
|
||||
});
|
||||
const newSecretBundle = new SecretBundle(cloudlyClientRef);
|
||||
Object.assign(newSecretBundle, response.resultSecretBundle);
|
||||
return newSecretBundle;
|
||||
}
|
||||
|
||||
// INSTANCE
|
||||
|
||||
public cloudlyClientRef: CloudlyApiClient;
|
||||
|
||||
public id: string;
|
||||
public data: plugins.servezoneInterfaces.data.ISecretBundle['data'];
|
||||
|
||||
constructor(cloudlyClientRef: CloudlyApiClient) {
|
||||
this.cloudlyClientRef = cloudlyClientRef;
|
||||
}
|
||||
|
||||
public async update() {
|
||||
const updateSecretBundleTR = this.cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.secretbundle.IReq_UpdateSecretBundle>(
|
||||
'updateSecretBundle'
|
||||
);
|
||||
const response = await updateSecretBundleTR.fire({
|
||||
identity: this.cloudlyClientRef.identity,
|
||||
secretBundle: {
|
||||
id: this.id,
|
||||
data: this.data,
|
||||
},
|
||||
});
|
||||
|
||||
const resultSecretBundleData = response.resultSecretBundle.data;
|
||||
plugins.smartexpect.expect(resultSecretBundleData).toEqual(this.data);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public async delete(cloudlyClientRef: CloudlyApiClient, secretBundleIdArg: string) {
|
||||
const deleteSecretBundleTR = cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.secretbundle.IReq_DeleteSecretBundleById>(
|
||||
'deleteSecretBundleById'
|
||||
);
|
||||
const response = await deleteSecretBundleTR.fire({
|
||||
identity: cloudlyClientRef.identity,
|
||||
secretBundleId: this.id,
|
||||
});
|
||||
plugins.smartexpect.expect(response.ok).toBeTrue();
|
||||
return null;
|
||||
}
|
||||
|
||||
public async getFlatKeyValueObjectForEnvironment(environmentArg: string = 'production') {
|
||||
const bundleAuthorization = this.data.authorizations.find(authorization => {
|
||||
return authorization.environment === environmentArg;
|
||||
});
|
||||
if (bundleAuthorization) {
|
||||
throw new Error(`no matching environment >>${environmentArg} found in secret bundle`);
|
||||
}
|
||||
|
||||
const getFlatKeyValueObjectTR = this.cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.secretbundle.IReq_GetFlatKeyValueObject>(
|
||||
'getFlatKeyValueObject'
|
||||
);
|
||||
const response = await getFlatKeyValueObjectTR.fire({
|
||||
identity: this.cloudlyClientRef.identity,
|
||||
seccretBundleId: this.id,
|
||||
secretBundleAuthorization: bundleAuthorization,
|
||||
});
|
||||
|
||||
const flatKeyValueObject: {[key: string]: string} = response.flatKeyValueObject;
|
||||
|
||||
return flatKeyValueObject;
|
||||
}
|
||||
}
|
96
ts_apiclient/classes.secretgroup.ts
Normal file
96
ts_apiclient/classes.secretgroup.ts
Normal file
@ -0,0 +1,96 @@
|
||||
import * as plugins from './plugins.js';
|
||||
import type { CloudlyApiClient } from './classes.cloudlyapiclient.js';
|
||||
|
||||
export class SecretGroup implements plugins.servezoneInterfaces.data.ISecretGroup {
|
||||
public cloudlyClientRef: CloudlyApiClient;
|
||||
|
||||
public id: string;
|
||||
public data: plugins.servezoneInterfaces.data.ISecretGroup['data'];
|
||||
|
||||
constructor(cloudlyClientRef: CloudlyApiClient) {
|
||||
this.cloudlyClientRef = cloudlyClientRef;
|
||||
}
|
||||
|
||||
public static async getSecretGroupById(cloudlyClientRef: CloudlyApiClient, secretGroupIdArg: string) {
|
||||
const getSecretGroupByIdTR = cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.secretgroup.IReq_GetSecretGroupById>(
|
||||
'getSecretGroupById'
|
||||
);
|
||||
const response = await getSecretGroupByIdTR.fire({
|
||||
identity: cloudlyClientRef.identity,
|
||||
secretGroupId: secretGroupIdArg,
|
||||
});
|
||||
const newSecretGroup = new SecretGroup(cloudlyClientRef);
|
||||
Object.assign(newSecretGroup, response.secretGroup);
|
||||
return newSecretGroup;
|
||||
}
|
||||
|
||||
public static async getSecretGroups(cloudlyClientRef: CloudlyApiClient) {
|
||||
const getSecretGroupsTR = cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.secretgroup.IReq_GetSecretGroups>(
|
||||
'getSecretGroups'
|
||||
);
|
||||
const response = await getSecretGroupsTR.fire({
|
||||
identity: cloudlyClientRef.identity,
|
||||
});
|
||||
const secretGroups: SecretGroup[] = [];
|
||||
for (const secretGroup of response.secretGroups) {
|
||||
const newSecretGroup = new SecretGroup(cloudlyClientRef);
|
||||
Object.assign(newSecretGroup, secretGroup);
|
||||
secretGroups.push(newSecretGroup);
|
||||
}
|
||||
return secretGroups;
|
||||
}
|
||||
|
||||
public static async createSecretGroup(cloudlyClientRef: CloudlyApiClient, secretGroupDataArg: Partial<plugins.servezoneInterfaces.data.ISecretGroup['data']>) {
|
||||
const createSecretGroupTR = cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.secretgroup.IReq_CreateSecretGroup>(
|
||||
'createSecretGroup'
|
||||
);
|
||||
const response = await createSecretGroupTR.fire({
|
||||
identity: cloudlyClientRef.identity,
|
||||
secretGroup: {
|
||||
id: null,
|
||||
data: {
|
||||
name: secretGroupDataArg.name,
|
||||
description: secretGroupDataArg.description,
|
||||
environments: secretGroupDataArg.environments,
|
||||
key: secretGroupDataArg.key,
|
||||
tags: secretGroupDataArg.tags,
|
||||
priority: secretGroupDataArg.priority,
|
||||
},
|
||||
},
|
||||
});
|
||||
const newSecretGroup = new SecretGroup(cloudlyClientRef);
|
||||
Object.assign(newSecretGroup, response.resultSecretGroup);
|
||||
return newSecretGroup;
|
||||
}
|
||||
|
||||
// INSTANCE
|
||||
public async update() {
|
||||
const updateSecretGroupTR = this.cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.secretgroup.IReq_UpdateSecretGroup>(
|
||||
'updateSecretGroup'
|
||||
);
|
||||
const response = await updateSecretGroupTR.fire({
|
||||
identity: this.cloudlyClientRef.identity,
|
||||
secretGroup: {
|
||||
id: this.id,
|
||||
data: this.data,
|
||||
},
|
||||
});
|
||||
|
||||
const resultSecretGroupData = response.resultSecretGroup.data;
|
||||
plugins.smartexpect.expect(resultSecretGroupData).toEqual(this.data);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public async delete(cloudlyClientRef: CloudlyApiClient, secretGroupIdArg: string) {
|
||||
const deleteSecretGroupTR = cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.secretgroup.IReq_DeleteSecretGroupById>(
|
||||
'deleteSecretGroupById'
|
||||
);
|
||||
const response = await deleteSecretGroupTR.fire({
|
||||
identity: cloudlyClientRef.identity,
|
||||
secretGroupId: this.id,
|
||||
});
|
||||
plugins.smartexpect.expect(response.ok).toBeTrue();
|
||||
return null;
|
||||
}
|
||||
}
|
@ -1,5 +1,78 @@
|
||||
import * as plugins from './plugins.js';
|
||||
import type { CloudlyApiClient } from './classes.cloudlyapiclient.js';
|
||||
|
||||
export class Service {
|
||||
export class Service implements plugins.servezoneInterfaces.data.IService {
|
||||
public static async getServices(cloudlyClientRef: CloudlyApiClient) {
|
||||
const getAllServicesTR = cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.service.IRequest_Any_Cloudly_GetServices>(
|
||||
'getServices'
|
||||
);
|
||||
const response = await getAllServicesTR.fire({
|
||||
identity: cloudlyClientRef.identity,
|
||||
});
|
||||
const resultServices: Service[] = [];
|
||||
for (const service of response.services) {
|
||||
const newService = new Service(cloudlyClientRef);
|
||||
Object.assign(newService, service);
|
||||
resultServices.push(newService);
|
||||
}
|
||||
return resultServices;
|
||||
}
|
||||
|
||||
public static async getServiceById(cloudlyClientRef: CloudlyApiClient, serviceIdArg: string) {
|
||||
const getServiceByIdTR = cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.service.IRequest_Any_Cloudly_GetServiceById>(
|
||||
'getServiceById'
|
||||
);
|
||||
const response = await getServiceByIdTR.fire({
|
||||
identity: cloudlyClientRef.identity,
|
||||
serviceId: serviceIdArg,
|
||||
});
|
||||
const newService = new Service(cloudlyClientRef);
|
||||
Object.assign(newService, response.service);
|
||||
return newService;
|
||||
}
|
||||
|
||||
/**
|
||||
* creates a new service
|
||||
*/
|
||||
public static async createService(cloudlyClientRef: CloudlyApiClient, serviceDataArg: Partial<plugins.servezoneInterfaces.data.IService['data']>) {
|
||||
const createServiceTR = cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.service.IRequest_Any_Cloudly_CreateService>(
|
||||
'createService'
|
||||
);
|
||||
const response = await createServiceTR.fire({
|
||||
identity: cloudlyClientRef.identity,
|
||||
serviceData: serviceDataArg as plugins.servezoneInterfaces.data.IService['data'],
|
||||
});
|
||||
const newService = new Service(cloudlyClientRef);
|
||||
Object.assign(newService, response.service);
|
||||
return newService;
|
||||
}
|
||||
|
||||
// INSTANCE
|
||||
cloudlyClientRef: CloudlyApiClient;
|
||||
|
||||
public id: string;
|
||||
public data: plugins.servezoneInterfaces.data.IService['data'];
|
||||
|
||||
constructor(cloudlyClientRef: CloudlyApiClient) {
|
||||
this.cloudlyClientRef = cloudlyClientRef;
|
||||
}
|
||||
|
||||
/**
|
||||
* The service has a secret bundle.
|
||||
* This function essentially returns the secret bundle as a flat object.
|
||||
* In other words, it resolves secret groups and
|
||||
*/
|
||||
public async getSecretBundleAsFlatObject(environmentArg: string = 'production') {
|
||||
const getServiceSecretBundlesAsFlatObjectTR = this.cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.service.IRequest_Any_Cloudly_GetServiceSecretBundlesAsFlatObject>(
|
||||
'getServiceSecretBundlesAsFlatObject'
|
||||
);
|
||||
const response = await getServiceSecretBundlesAsFlatObjectTR.fire({
|
||||
identity: this.cloudlyClientRef.identity,
|
||||
serviceId: this.id,
|
||||
environment: environmentArg,
|
||||
});
|
||||
const flatKeyValueObject: {[key: string]: string} = response.flatKeyValueObject;
|
||||
|
||||
return flatKeyValueObject;
|
||||
}
|
||||
}
|
||||
|
@ -6,11 +6,13 @@ export {
|
||||
}
|
||||
|
||||
// @push.rocks scope
|
||||
import * as smartexpect from '@push.rocks/smartexpect';
|
||||
import * as smartpromise from '@push.rocks/smartpromise';
|
||||
import * as smartrx from '@push.rocks/smartrx';
|
||||
import * as webstream from '@push.rocks/smartstream/web';
|
||||
|
||||
export {
|
||||
smartexpect,
|
||||
smartpromise,
|
||||
smartrx,
|
||||
webstream,
|
||||
|
202
ts_apiclient/readme.md
Normal file
202
ts_apiclient/readme.md
Normal file
@ -0,0 +1,202 @@
|
||||
# @serve.zone/api
|
||||
|
||||
The `@serve.zone/api` module is a robust and versatile API client, designed to facilitate seamless communication with various cloud resources managed by the Cloudly platform. This API client extends a rich set of functionalities, offering developers a comprehensive and programmable interface for interacting with their multi-cloud infrastructure.
|
||||
|
||||
## Install
|
||||
|
||||
To install the `@serve.zone/api` package, execute the following command in your terminal:
|
||||
|
||||
```bash
|
||||
npm install @serve.zone/api --save
|
||||
```
|
||||
|
||||
This command will download the module and add it to your project's `package.json` dependencies, allowing you to utilize its capabilities within your application.
|
||||
|
||||
## Usage
|
||||
|
||||
The `@serve.zone/api` client is tailored to handle various operations within a multi-cloud environment efficiently. Throughout this section, we will explore the different features and use-cases of this API client, aiding you in leveraging its full potential.
|
||||
|
||||
### Prerequisites
|
||||
|
||||
Before integrating `@serve.zone/api` into your project, ensure the following prerequisites are satisfied:
|
||||
- You have Node.js installed on your system (preferably the latest Long-Term Support version).
|
||||
- You're utilizing a TypeScript-compatible environment for development.
|
||||
|
||||
### Establishing an API Client Instance
|
||||
|
||||
The cornerstone of using `@serve.zone/api` is initializing a `CloudlyApiClient` instance. It serves as the main point of interaction, enabling communication with underlying cloud infrastructures managed by Cloudly. Here's a basic setup guide:
|
||||
|
||||
```typescript
|
||||
import { CloudlyApiClient, TClientType } from '@serve.zone/api';
|
||||
|
||||
async function initializeClient() {
|
||||
const client = new CloudlyApiClient({
|
||||
registerAs: 'api' as TClientType,
|
||||
cloudlyUrl: 'https://yourcloudly.url:443'
|
||||
});
|
||||
|
||||
await client.start();
|
||||
return client;
|
||||
}
|
||||
|
||||
const cloudlyClient = await initializeClient();
|
||||
```
|
||||
|
||||
The above code initializes the `CloudlyApiClient` object, connecting your application to the configured Cloudly environment.
|
||||
|
||||
### Authentication and Identity Management
|
||||
|
||||
To execute operations via the API client, authenticated access is necessary. The most prevalent method for this is obtaining an identity token using a service token:
|
||||
|
||||
```typescript
|
||||
import { CloudlyApiClient } from '@serve.zone/api';
|
||||
|
||||
async function authenticate(client: CloudlyApiClient, serviceToken: string) {
|
||||
const identity = await client.getIdentityByToken(serviceToken, {
|
||||
tagConnection: true,
|
||||
statefullIdentity: true
|
||||
});
|
||||
|
||||
console.log(`Authenticated identity:`, identity);
|
||||
return identity;
|
||||
}
|
||||
|
||||
const serviceToken = 'your_service_token';
|
||||
const identity = await authenticate(cloudlyClient, serviceToken);
|
||||
```
|
||||
|
||||
In this function, the `getIdentityByToken` method authenticates using a service token and acquires an identity object that includes user details and security claims.
|
||||
|
||||
### Interacting with Cloudly Features
|
||||
|
||||
#### Image Management
|
||||
|
||||
Image management is one of the key features supported by the API Client. You can create, upload, and manage Docker images easily within your cloud ecosystem:
|
||||
|
||||
```typescript
|
||||
async function manageImages(client: CloudlyApiClient, identity) {
|
||||
// Creating a new image
|
||||
const newImage = await client.images.createImage({
|
||||
name: 'my_new_image',
|
||||
description: 'A test image'
|
||||
});
|
||||
|
||||
console.log(`Created image:`, newImage);
|
||||
|
||||
// Uploading an image version
|
||||
const imageStream = fetchYourImageStreamHere(); // Provide the source image stream
|
||||
await newImage.pushImageVersion('1.0.0', imageStream);
|
||||
console.log('Image version uploaded successfully.');
|
||||
}
|
||||
|
||||
await manageImages(cloudlyClient, identity);
|
||||
|
||||
// Helper function for obtaining image stream (implement accordingly)
|
||||
function fetchYourImageStreamHere() {
|
||||
// Logic to fetch and return a readable stream for your image
|
||||
return new ReadableStream<Uint8Array>();
|
||||
}
|
||||
```
|
||||
|
||||
In this example, the `manageImages` function underscores the typical workflow of creating an image entry within Cloudly and then proceeding to upload a specific version using the `pushImageVersion` method.
|
||||
|
||||
#### Cluster Configuration
|
||||
|
||||
Another powerful capability is managing clusters, which allows for orchestrating and configuring Docker Swarm clusters:
|
||||
|
||||
```typescript
|
||||
async function configureCluster(client: CloudlyApiClient, identity) {
|
||||
// Fetching cluster configuration
|
||||
const clusterConfig = await client.getClusterConfigFromCloudlyByIdentity(identity);
|
||||
console.log(`Cluster configuration retrieved:`, clusterConfig);
|
||||
}
|
||||
|
||||
await configureCluster(cloudlyClient, identity);
|
||||
```
|
||||
|
||||
The `getClusterConfigFromCloudlyByIdentity` method retrieved the configuration needed to set up and manage your clusters within the multi-cloud environment.
|
||||
|
||||
### Advanced Communication via Typed Sockets
|
||||
|
||||
The API client leverages `TypedRequest` and `TypedSocket` from the `@api.global` family, enabling statically-typed, real-time communication. Here's an example demonstrating socket integration:
|
||||
|
||||
```typescript
|
||||
async function configureSocketCommunication(client: CloudlyApiClient) {
|
||||
client.configUpdateSubject.subscribe({
|
||||
next: (configData) => {
|
||||
console.log('Received configuration update:', configData);
|
||||
}
|
||||
});
|
||||
|
||||
client.serverActionSubject.subscribe({
|
||||
next: (actionRequest) => {
|
||||
console.log('Server action requested:', actionRequest);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
configureSocketCommunication(cloudlyClient);
|
||||
```
|
||||
|
||||
The client utilizes RxJS `Subject` to enable simple yet powerful handling of incoming socket requests, whereby one can act upon updates and actions as they occur.
|
||||
|
||||
### Integrating Certificates
|
||||
|
||||
Certificate operations, such as obtaining SSL certificates for your domains, are also streamlined using this API client:
|
||||
|
||||
```typescript
|
||||
async function retrieveCertificate(client: CloudlyApiClient, domainName: string, identity) {
|
||||
const certificate = await client.getCertificateForDomain({
|
||||
domainName: domainName,
|
||||
type: 'ssl',
|
||||
identity: identity
|
||||
});
|
||||
|
||||
console.log('Retrieved SSL Certificate:', certificate);
|
||||
}
|
||||
|
||||
const yourDomain = 'example.com';
|
||||
await retrieveCertificate(cloudlyClient, yourDomain, identity);
|
||||
```
|
||||
|
||||
This example demonstrates fetching SSL certificates using given domain credentials and an authenticated identity.
|
||||
|
||||
### API Client Cleanup
|
||||
|
||||
When operations are complete and the application is shutting down, it's crucial to gracefully terminate the API client connection:
|
||||
|
||||
```typescript
|
||||
async function cleanup(client: CloudlyApiClient) {
|
||||
await client.stop();
|
||||
console.log('Cloudly API client disconnected gracefully.');
|
||||
}
|
||||
|
||||
await cleanup(cloudlyClient);
|
||||
```
|
||||
|
||||
By invoking the `stop` method, the API client securely terminates its connection to ensure no resources are left hanging, preventing potential memory leaks.
|
||||
|
||||
### Miscellaneous Features
|
||||
|
||||
This section would be remiss without mentioning various utility functionalities such as secret management, server actions, DNS configurator options, and more, all underpinned by an intelligently designed API, enriching cloud resource interactivity.
|
||||
|
||||
In conclusion, by employing `@serve.zone/api`, developers gain unparalleled access to a multitude of modular functions pertinent to multi-cloud administration, significantly amplifying productivity and management effectiveness across diverse computing environments.
|
||||
|
||||
## License and Legal Information
|
||||
|
||||
This repository contains open-source code that is licensed under the MIT License. A copy of the MIT License can be found in the [license](license) file within this repository.
|
||||
|
||||
**Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.
|
||||
|
||||
### Trademarks
|
||||
|
||||
This project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH and are not included within the scope of the MIT license granted herein. Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines, and any usage must be approved in writing by Task Venture Capital GmbH.
|
||||
|
||||
### Company Information
|
||||
|
||||
Task Venture Capital GmbH
|
||||
Registered at District court Bremen HRB 35230 HB, Germany
|
||||
|
||||
For any legal inquiries or if you require further information, please contact us via email at hello@task.vc.
|
||||
|
||||
By using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.
|
@ -1,4 +1,5 @@
|
||||
{
|
||||
"order": 1,
|
||||
"name": "@serve.zone/api",
|
||||
"dependencies": [
|
||||
"@serve.zone/interfaces",
|
||||
|
15
ts_cliclient/classes.cliclient.ts
Normal file
15
ts_cliclient/classes.cliclient.ts
Normal file
@ -0,0 +1,15 @@
|
||||
import * as plugins from './plugins.js';
|
||||
import { CloudlyApiClient } from '@serve.zone/api';
|
||||
|
||||
export class CliClient {
|
||||
public cloudlyApiClient: CloudlyApiClient;
|
||||
|
||||
constructor(cloudlyApiClientArg: CloudlyApiClient) {
|
||||
this.cloudlyApiClient = cloudlyApiClientArg;
|
||||
}
|
||||
|
||||
public async getClusters() {
|
||||
const clusters = await this.cloudlyApiClient.cluster.getClusters();
|
||||
console.log(clusters);
|
||||
}
|
||||
}
|
@ -1 +1,11 @@
|
||||
console.log('this is the cli client.');
|
||||
import * as plugins from './plugins.js';
|
||||
import { CliClient } from "./classes.cliclient.js";
|
||||
|
||||
export const runCli = async () => {
|
||||
const cliQenv = new plugins.qenv.Qenv();
|
||||
const apiClient = new plugins.servezoneApi.CloudlyApiClient({
|
||||
registerAs: 'cli',
|
||||
cloudlyUrl: await cliQenv.getEnvVarOnDemand('CLOUDLY_URL'),
|
||||
});
|
||||
const cliClient = new CliClient(apiClient);
|
||||
};
|
17
ts_cliclient/plugins.ts
Normal file
17
ts_cliclient/plugins.ts
Normal file
@ -0,0 +1,17 @@
|
||||
// @serve.zone scope
|
||||
import * as servezoneApi from '@serve.zone/api';
|
||||
import * as servezoneInterfaces from '@serve.zone/interfaces';
|
||||
|
||||
export {
|
||||
servezoneApi,
|
||||
servezoneInterfaces
|
||||
}
|
||||
|
||||
// @push.rocks scope
|
||||
import * as projectinfo from '@push.rocks/projectinfo';
|
||||
import * as qenv from '@push.rocks/qenv';
|
||||
|
||||
export {
|
||||
projectinfo,
|
||||
qenv,
|
||||
}
|
262
ts_cliclient/readme.md
Normal file
262
ts_cliclient/readme.md
Normal file
@ -0,0 +1,262 @@
|
||||
# @serve.zone/cli
|
||||
|
||||
A comprehensive command-line interface (CLI) tool for managing multi-cloud environments, leveraging the features of the @serve.zone/cloudly platform. This CLI is crafted to facilitate seamless interactions with complex cloud configurations and deployments, utilizing Docker Swarmkit orchestration.
|
||||
|
||||
## Install
|
||||
|
||||
To begin using the `@serve.zone/cli` in your projects, install it via npm by running:
|
||||
|
||||
```bash
|
||||
npm install @serve.zone/cli --save
|
||||
```
|
||||
|
||||
This command will download the package and integrate it into your project's `node_modules` directory, reflecting the dependency in your `package.json`.
|
||||
|
||||
## Usage
|
||||
|
||||
The `@serve.zone/cli` is a powerful command-line tool aimed at developers and system administrators who are managing containerized applications across various cloud platforms. Through this CLI, users can interact with their cloud infrastructure efficiently, enabling and extending `Cloudly’s` capabilities directly from the terminal.
|
||||
|
||||
### Prerequisites
|
||||
|
||||
Before proceeding to use the `@serve.zone/cli`, ensure your system meets the following prerequisites:
|
||||
- Latest Node.js LTS version installed.
|
||||
- Familiarity with basic command-line operations.
|
||||
- Properly configured cloud service accounts (like Cloudflare, Hetzner), necessary for managing respective services.
|
||||
|
||||
### Setting Up the CLI
|
||||
|
||||
Begin setting up the `Cloudly` instance for CLI usage:
|
||||
```typescript
|
||||
// Import required modules
|
||||
import { Cloudly } from '@serve.zone/cloudly';
|
||||
import * as path from 'path';
|
||||
|
||||
// Define the configuration needed for cloud operations
|
||||
const cloudlyConfig = {
|
||||
cfToken: 'your-cloudflare-token',
|
||||
hetznerToken: 'your-hetzner-token',
|
||||
environment: 'production',
|
||||
publicUrl: 'your-public-url',
|
||||
};
|
||||
|
||||
// Instantiate and start the Cloudly instance
|
||||
const cloudlyInstance = new Cloudly(cloudlyConfig);
|
||||
await cloudlyInstance.start();
|
||||
|
||||
// Log the setup information to ensure it’s correct
|
||||
console.log(`Cloudly is set up at ${cloudlyInstance.config.data.publicUrl}`);
|
||||
```
|
||||
|
||||
This snippet initializes a Cloudly instance with necessary environment configuration, setting the groundwork for all subsequent CLI operations.
|
||||
|
||||
### Core Operations with the CLI
|
||||
|
||||
Here's how you leverage various operational commands within the CLI feature:
|
||||
|
||||
#### Managing Clusters
|
||||
|
||||
To create, list, and delete clusters, you’ll require invoking the `Cloudly` class with its cluster management logic:
|
||||
|
||||
```typescript
|
||||
// Module imports
|
||||
import { Cloudly } from '@serve.zone/cloudly';
|
||||
|
||||
// Async function for cluster management
|
||||
async function manageCluster() {
|
||||
// Prepare configuration
|
||||
const config = {
|
||||
cfToken: 'YOUR_CLOUDFLARE_TOKEN',
|
||||
hetznerToken: 'YOUR_HETZNER_TOKEN',
|
||||
};
|
||||
|
||||
// Initialize Cloudly
|
||||
const cloudlyInstance = new Cloudly(config);
|
||||
await cloudlyInstance.start();
|
||||
|
||||
// Example: Creating a new cluster
|
||||
const cluster = await cloudlyInstance.clusterManager.createCluster({
|
||||
id: 'example_cluster_id',
|
||||
data: {
|
||||
name: 'example_cluster',
|
||||
servers: [],
|
||||
sshKeys: [],
|
||||
}
|
||||
});
|
||||
|
||||
// Log cluster details
|
||||
console.log('Cluster created:', cluster);
|
||||
}
|
||||
```
|
||||
With the above example, you can dynamically manage cluster configurations, ensuring your application components are effectively orchestrated across cloud environments.
|
||||
|
||||
#### Deploying Services
|
||||
|
||||
Deploying cloud-native services within your clusters can be achieved through the CLI:
|
||||
|
||||
```typescript
|
||||
import { Cloudly } from '@serve.zone/cloudly';
|
||||
|
||||
// Function to handle service deployment
|
||||
async function deployService() {
|
||||
const config = {
|
||||
cfToken: 'YOUR_CLOUDFLARE_TOKEN',
|
||||
hetznerToken: 'YOUR_HETZNER_TOKEN',
|
||||
};
|
||||
|
||||
const cloudlyInstance = new Cloudly(config);
|
||||
await cloudlyInstance.start();
|
||||
|
||||
// Deploy a new service to a specified cluster
|
||||
const newService = {
|
||||
id: 'example_service_id',
|
||||
data: {
|
||||
name: 'example_service',
|
||||
imageId: 'example_image_id',
|
||||
imageVersion: '1.0.0',
|
||||
environment: {},
|
||||
ports: { web: 80 }
|
||||
}
|
||||
};
|
||||
|
||||
// Store service into database and deploy
|
||||
console.log('Deploying service:', newService)
|
||||
await cloudlyInstance.serverManager.deployService(newService);
|
||||
}
|
||||
|
||||
deployService();
|
||||
```
|
||||
|
||||
By streamlining your service deployments through CLI, you ensure reproducibility and clarity in development operations.
|
||||
|
||||
#### Managing Certificates
|
||||
|
||||
Ensuring secure connections by managing SSL certificates is essential. The CLI aids in this through Let's Encrypt integration:
|
||||
|
||||
```typescript
|
||||
import { Cloudly } from '@serve.zone/cloudly';
|
||||
|
||||
// Function to acquire a certificate
|
||||
async function getCertificate() {
|
||||
const config = {
|
||||
cfToken: 'YOUR_CLOUDFLARE_TOKEN',
|
||||
hetznerToken: 'YOUR_HETZNER_TOKEN',
|
||||
};
|
||||
|
||||
const cloudlyInstance = new Cloudly(config);
|
||||
await cloudlyInstance.start();
|
||||
|
||||
// Fetch certificate using Let's Encrypt
|
||||
const domainName = 'example.com';
|
||||
const cert = await cloudlyInstance.letsencryptConnector.getCertificateForDomain(domainName);
|
||||
console.log(`Obtained certificate for domain ${domainName}:`, cert);
|
||||
}
|
||||
|
||||
getCertificate();
|
||||
```
|
||||
|
||||
This process facilitates the automation of SSL certificates provisioning, ensuring high security in your apps.
|
||||
|
||||
### Automating Tasks with the CLI
|
||||
|
||||
Task scheduling is a feature you can utilize to automate recurring processes. Here’s an example of how `@serve.zone/cli` accomplishes task scheduling:
|
||||
|
||||
```typescript
|
||||
import { TaskBuffer } from '@push.rocks/taskbuffer';
|
||||
|
||||
// Schedule a task to run every day
|
||||
const dailyTask = new TaskBuffer({
|
||||
schedule: '0 0 * * *', // Using cron schedule
|
||||
taskFunction: async () => {
|
||||
console.log('Performing daily backup check...');
|
||||
// Include backup logic here
|
||||
},
|
||||
});
|
||||
|
||||
// Initiate task scheduling
|
||||
dailyTask.start();
|
||||
```
|
||||
|
||||
Scheduled tasks like periodic maintenance, data synchronization, or backups ensure you keep your cloud environment robust and reliable.
|
||||
|
||||
### Integrating Third-Party APIs
|
||||
|
||||
Expand the scope of your applications with API integrations offered via `@serve.zone/cli`:
|
||||
|
||||
```typescript
|
||||
import { Cloudly } from '@serve.zone/cloudly';
|
||||
|
||||
// Function to send notifications
|
||||
async function sendNotification() {
|
||||
const cloudlyConfig = {
|
||||
cfToken: 'your-cloudflare-token',
|
||||
hetznerToken: 'your-hetzner-token',
|
||||
};
|
||||
|
||||
const cloudly = new Cloudly(cloudlyConfig);
|
||||
await cloudly.start();
|
||||
|
||||
// Configure and send push notification
|
||||
await cloudly.externalApiManager.sendPushMessage({
|
||||
deviceToken: 'some_device_token',
|
||||
message: 'Hello from Cloudly!',
|
||||
});
|
||||
}
|
||||
|
||||
sendNotification();
|
||||
```
|
||||
|
||||
API integrations via the CLI extend Cloudly’s reach, enabling comprehensive service interconnections.
|
||||
|
||||
### Security and Access Management
|
||||
|
||||
Effective identity management is possible through `@serve.zone/cli`. Manage user roles, token validations, and more:
|
||||
|
||||
```typescript
|
||||
import { Cloudly } from '@serve.zone/cloudly';
|
||||
|
||||
// Configuring and verifying identity
|
||||
async function authenticateUser() {
|
||||
const cloudlyConfig = {
|
||||
cfToken: 'your-cloudflare-token',
|
||||
hetznerToken: 'your-hetzner-token',
|
||||
};
|
||||
|
||||
const cloudly = new Cloudly(cloudlyConfig);
|
||||
await cloudly.start();
|
||||
|
||||
// Sample user credentials
|
||||
const userIdentity = {
|
||||
userId: 'unique_user_id',
|
||||
jwt: 'user_jwt_token',
|
||||
};
|
||||
|
||||
// Validate identity
|
||||
const isValid = cloudly.authManager.validateIdentity(userIdentity);
|
||||
console.log(`Is user identity valid? ${isValid}`);
|
||||
}
|
||||
|
||||
authenticateUser();
|
||||
```
|
||||
|
||||
The applications of identity validation streamline operational security and enforce access controls across your systems.
|
||||
|
||||
These examples offer a glimpse into the vast potential of @serve.zone/cli, which combines automation, security, and flexibility for state-of-the-art cloud management. You are encouraged to build upon this documentation to harness Cloudly's full capabilities in your infrastructure and process ecosystems. Let the CLI transform your cloud management experience with precision and adaptability.
|
||||
|
||||
## License and Legal Information
|
||||
|
||||
This repository contains open-source code that is licensed under the MIT License. A copy of the MIT License can be found in the [license](license) file within this repository.
|
||||
|
||||
**Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.
|
||||
|
||||
### Trademarks
|
||||
|
||||
This project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH and are not included within the scope of the MIT license granted herein. Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines, and any usage must be approved in writing by Task Venture Capital GmbH.
|
||||
|
||||
### Company Information
|
||||
|
||||
Task Venture Capital GmbH
|
||||
Registered at District court Bremen HRB 35230 HB, Germany
|
||||
|
||||
For any legal inquiries or if you require further information, please contact us via email at hello@task.vc.
|
||||
|
||||
By using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.
|
@ -1,8 +1,15 @@
|
||||
{
|
||||
"name": "@serve.zone/cli",
|
||||
"dependencies": [],
|
||||
"dependencies": [
|
||||
"@serve.zone/api",
|
||||
"@serve.zone/interfaces",
|
||||
"@push.rocks/projectinfo",
|
||||
"@push.rocks/qenv",
|
||||
"@push.rocks/smartcli"
|
||||
],
|
||||
"registries": [
|
||||
"registry.npmjs.org:public",
|
||||
"verdaccio.lossless.digital:public"
|
||||
]
|
||||
],
|
||||
"bin": ["servezone"]
|
||||
}
|
@ -1,12 +1,11 @@
|
||||
import * as plugins from '../plugins.js';
|
||||
|
||||
/**
|
||||
* results from a DeploymentDirective
|
||||
* a deployment happens when a service is deployed
|
||||
* tracks the status of a deployment
|
||||
*/
|
||||
export interface IDeployment {
|
||||
id: string;
|
||||
deploymentDirectiveId: string;
|
||||
affectedServiceIds: string[];
|
||||
usedImageId: string;
|
||||
deploymentLog: string[];
|
||||
|
@ -1,14 +0,0 @@
|
||||
import type { IServiceRessources } from "./docker.js";
|
||||
|
||||
/**
|
||||
* used for tellilng a cluster about a disired deployment
|
||||
* and specifies its configuration
|
||||
*/
|
||||
export interface IDeploymentDirective {
|
||||
id: string;
|
||||
name: string;
|
||||
imageClaim: string;
|
||||
ports: { hostPort: number; containerPort: number }[];
|
||||
environment: { [key: string]: string };
|
||||
resources?: IServiceRessources;
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
|
||||
export interface IEnvBundle {
|
||||
environment: string;
|
||||
timeSensitive: boolean;
|
||||
configKeyValueObject: {[key: string]: string};
|
||||
}
|
12
ts_interfaces/data/externalregistry.ts
Normal file
12
ts_interfaces/data/externalregistry.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import * as plugins from '../plugins.js';
|
||||
|
||||
export interface IExternalRegistry {
|
||||
id: string;
|
||||
data: {
|
||||
type: 'docker' | 'npm';
|
||||
name: string;
|
||||
url: string;
|
||||
username: string;
|
||||
password: string;
|
||||
};
|
||||
}
|
@ -4,6 +4,11 @@ export interface IImage {
|
||||
id: string;
|
||||
data: {
|
||||
name: string;
|
||||
location: {
|
||||
internal: boolean;
|
||||
externalRegistryId: string;
|
||||
externalImageTag: string;
|
||||
}
|
||||
description: string;
|
||||
versions: Array<{
|
||||
versionString: string;
|
||||
|
@ -2,10 +2,9 @@ export * from './cloudlyconfig.js';
|
||||
export * from './cluster.js';
|
||||
export * from './config.js';
|
||||
export * from './deployment.js';
|
||||
export * from './deploymentdirective.js';
|
||||
export * from './docker.js';
|
||||
export * from './env.js';
|
||||
export * from './event.js';
|
||||
export * from './externalregistry.js';
|
||||
export * from './image.js';
|
||||
export * from './secretbundle.js';
|
||||
export * from './secretgroup.js'
|
||||
|
@ -7,16 +7,33 @@ export interface ISecretBundle {
|
||||
/**
|
||||
* determines if the secret is a service or an external secret
|
||||
* if external secret additional checks are put in place to protect the secret
|
||||
*
|
||||
* * service:
|
||||
* the bundle belongs to a service and can only be used by that service
|
||||
* * npmci:
|
||||
* the bundle is a secret bundle that is used by an npmci pipeline
|
||||
* production secrets will be omitted in any case
|
||||
* * gitzone:
|
||||
* the bundle is a secret bundle that is used by a gitzone.
|
||||
* Only local environment variables are allowed
|
||||
* * external:
|
||||
* the bundle is a secret bundle that is used by an external service
|
||||
*/
|
||||
type: 'service' | 'npmci' | 'gitzone' | 'external';
|
||||
|
||||
|
||||
/**
|
||||
* set this if the secretBundle belongs to a service
|
||||
*/
|
||||
serviceId?: string;
|
||||
|
||||
/**
|
||||
* You can add specific secret groups using this
|
||||
*/
|
||||
includedSecretGroupIds: string[];
|
||||
|
||||
/**
|
||||
* You can add specific tags using this
|
||||
* access to this secretBundle also grants access to resources with matching tags
|
||||
*/
|
||||
includedTags: {
|
||||
key: string;
|
||||
@ -24,19 +41,21 @@ export interface ISecretBundle {
|
||||
}[];
|
||||
|
||||
/**
|
||||
* add images
|
||||
* access to this secretBundle also grants access to the images
|
||||
*/
|
||||
includedImages: {
|
||||
imageClaims: {
|
||||
imageId: string;
|
||||
permissions: ('read' | 'write')[];
|
||||
}[];
|
||||
}[];
|
||||
|
||||
/**
|
||||
* authrozations select a specific environment of a config bundle
|
||||
*/
|
||||
authorizations: Array<{
|
||||
secretAccessKey: string;
|
||||
environment: string;
|
||||
}>;
|
||||
authorizations: Array<ISecretBundleAuthorization>;
|
||||
};
|
||||
}
|
||||
|
||||
export interface ISecretBundleAuthorization {
|
||||
secretAccessKey: string;
|
||||
environment: string;
|
||||
}
|
||||
|
@ -4,10 +4,19 @@ export interface IService {
|
||||
id: string;
|
||||
data: {
|
||||
name: string;
|
||||
description: string;
|
||||
imageId: string;
|
||||
imageVersion: string;
|
||||
environment: { [key: string]: string };
|
||||
/**
|
||||
* the main secret bundle id, exclusive to the service
|
||||
*/
|
||||
secretBundleId: string;
|
||||
/**
|
||||
* those secret bundle ids do not belong to the service itself
|
||||
* and thus live past the service lifecycle
|
||||
*/
|
||||
additionalSecretBundleIds?: string[];
|
||||
scaleFactor: number;
|
||||
balancingStrategy: 'round-robin' | 'least-connections';
|
||||
ports: {
|
||||
@ -21,6 +30,5 @@ export interface IService {
|
||||
protocol?: 'http' | 'https' | 'ssh';
|
||||
}[];
|
||||
deploymentIds: string[];
|
||||
deploymentDirectiveIds: string[];
|
||||
};
|
||||
}
|
||||
|
@ -2,9 +2,9 @@ import * as plugins from '../plugins.js';
|
||||
|
||||
export type TTemplates = 'default' | 'linkaction' | 'notification';
|
||||
|
||||
export interface IRequest_SendEmail extends plugins.typedrequestInterfaces.implementsTR<
|
||||
export interface IReq_SendEmail extends plugins.typedrequestInterfaces.implementsTR<
|
||||
plugins.typedrequestInterfaces.ITypedRequest,
|
||||
IRequest_SendEmail
|
||||
IReq_SendEmail
|
||||
> {
|
||||
method: 'sendEmail';
|
||||
request: {
|
||||
@ -25,9 +25,9 @@ export interface IRequest_SendEmail extends plugins.typedrequestInterfaces.imple
|
||||
};
|
||||
}
|
||||
|
||||
export interface IRequestRegisterRecipient extends plugins.typedrequestInterfaces.implementsTR<
|
||||
export interface IReq_RegisterRecipient extends plugins.typedrequestInterfaces.implementsTR<
|
||||
plugins.typedrequestInterfaces.ITypedRequest,
|
||||
IRequestRegisterRecipient
|
||||
IReq_RegisterRecipient
|
||||
> {
|
||||
method: 'registerRecepient';
|
||||
request: {
|
||||
@ -37,3 +37,34 @@ export interface IRequestRegisterRecipient extends plugins.typedrequestInterface
|
||||
status: 'ok' | 'not ok';
|
||||
};
|
||||
}
|
||||
|
||||
export interface IReq_CheckEmailStatus extends plugins.typedrequestInterfaces.implementsTR<
|
||||
plugins.typedrequestInterfaces.ITypedRequest,
|
||||
IReq_CheckEmailStatus
|
||||
> {
|
||||
method: 'checkEmailStatus';
|
||||
request: {
|
||||
emailId: string;
|
||||
};
|
||||
response: {
|
||||
status: string,
|
||||
details?: { message: string; }
|
||||
};
|
||||
}
|
||||
|
||||
export interface IReq_GetEMailStats extends plugins.typedrequestInterfaces.implementsTR<
|
||||
plugins.typedrequestInterfaces.ITypedRequest,
|
||||
IReq_GetEMailStats
|
||||
> {
|
||||
method: 'getEmailStats';
|
||||
request: {
|
||||
jwt: string;
|
||||
};
|
||||
response: {
|
||||
totalEmailsSent: number;
|
||||
totalEmailsDelivered: number;
|
||||
totalEmailsBounced: number;
|
||||
averageDeliveryTimeMs: number;
|
||||
lastUpdated: string;
|
||||
};
|
||||
}
|
||||
|
223
ts_interfaces/readme.md
Normal file
223
ts_interfaces/readme.md
Normal file
@ -0,0 +1,223 @@
|
||||
# @serve.zone/interfaces
|
||||
|
||||
interfaces for working with containers
|
||||
|
||||
## Install
|
||||
|
||||
To install `@serve.zone/interfaces`, run the following command in your terminal:
|
||||
|
||||
```bash
|
||||
npm install @serve.zone/interfaces --save
|
||||
```
|
||||
|
||||
This will add `@serve.zone/interfaces` to your project's dependencies, allowing you to import and use various predefined interfaces that facilitate container operations and interactions within the ServeZone ecosystem.
|
||||
|
||||
## Usage
|
||||
|
||||
The `@serve.zone/interfaces` module provides a robust set of TypeScript interfaces designed to standardize interaction with various services and components in a cloud-native environment. The interfaces are targeted at simplifying the integration process with container orchestration, network configurations, logging, and service definitions. The module is particularly useful if you're working on infrastructure or service orchestration solutions using Node.js and TypeScript.
|
||||
|
||||
This document guides you through a comprehensive use case scenario of `@serve.zone/interfaces`. We will cover how to effectively utilize these interfaces to set up cloud services, manage application configurations, and handle system-related communications. This tutorial will explore various feature sets within the module, focusing on real-world implementations and practical coding strategies.
|
||||
|
||||
### Prerequisites
|
||||
|
||||
Before diving in, make sure to satisfy the following prerequisites:
|
||||
|
||||
- **Node.js**: Ensure you have Node.js installed (preferably the latest LTS version).
|
||||
|
||||
- **TypeScript**: Your environment should support TypeScript, as this module leverages strong typing offered by TypeScript.
|
||||
|
||||
- **Cloud Account Access**: Some of the interfaces interact with live cloud services; thus, ensure you have necessary credentials (like API tokens) available for testing or integration.
|
||||
|
||||
### Core Interfaces and Scenarios
|
||||
|
||||
#### 1. Handling Typed Requests
|
||||
|
||||
One fundamental aspect is defining typed requests, which standardizes API call definitions across different microservices or components. The module offers interfaces such as `IRequest_GetAllImages`, `IRequest_CreateCluster`, that you can extend or implement within your service logic to ensure strong typing and consistency.
|
||||
|
||||
```typescript
|
||||
import { IRequest_GetAllImages } from '@serve.zone/interfaces/requests/image';
|
||||
|
||||
class ImageService {
|
||||
private cloudlyClient;
|
||||
|
||||
constructor(cloudlyClient: CloudlyApiClient) {
|
||||
this.cloudlyClient = cloudlyClient;
|
||||
}
|
||||
|
||||
public async fetchAllImages() {
|
||||
const request: IRequest_GetAllImages['request'] = {
|
||||
identity: this.cloudlyClient.identity,
|
||||
};
|
||||
const response = await this.cloudlyClient.typedsocketClient.fireTypedRequest<IRequest_GetAllImages>(request);
|
||||
return response.images;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
In the above code, we structured a simple function to retrieve all images from a service, assuming the `cloudlyClient` is your authenticated API client. The typed request interface ensures that both the request and response align with the expected types.
|
||||
|
||||
#### 2. Logging and Smart Logging Interfaces
|
||||
|
||||
Logging is a crucial aspect of cloud applications. The module provides interfaces to assist in integrating logging systems like `@push.rocks/smartlog-interfaces`.
|
||||
|
||||
```typescript
|
||||
import { ILogger, ILogConfig } from '@push.rocks/smartlog-interfaces';
|
||||
|
||||
class LoggerService {
|
||||
private logger: ILogger;
|
||||
|
||||
constructor(logConfig: ILogConfig) {
|
||||
this.logger = new SmartLogger(logConfig);
|
||||
}
|
||||
|
||||
public logMessage(logPackage: ILogPackage) {
|
||||
this.logger.log(logPackage);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This illustrates a logger service utilizing `ILogConfig` to configure and initiate a logging mechanism. You can log structured data using `logPackage`, thus enhancing traceability and debugging efficiency.
|
||||
|
||||
#### 3. Container Service Management
|
||||
|
||||
Managing containers, particularly when dealing with microservices, can be complex, but interfaces like `IService`, `ICluster`, and `IServer` aid in structuring container service management.
|
||||
|
||||
```typescript
|
||||
import { IService } from '@serve.zone/interfaces/data/service';
|
||||
|
||||
function defineService(): IService {
|
||||
return {
|
||||
id: 'unique-service-id',
|
||||
data: {
|
||||
name: 'my-container-service',
|
||||
imageId: 'unique-image-id',
|
||||
imageVersion: '1.0.0',
|
||||
environment: { KEY: 'VALUE' },
|
||||
secretBundleId: 'bundle-id',
|
||||
scaleFactor: 2,
|
||||
balancingStrategy: 'round-robin',
|
||||
ports: { web: 80 },
|
||||
domains: [{ name: 'example.com' }],
|
||||
deploymentIds: [],
|
||||
deploymentDirectiveIds: [],
|
||||
}
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
In the example, a service definition is drafted, encapsulating critical service metadata, including its environment variables, domain configuration, and load balancing strategy. Adhering to `IService` ensures that all necessary service data is encapsulated correctly.
|
||||
|
||||
#### 4. Network Configuration and Routing
|
||||
|
||||
Networking is integral to cloud-native applications. Interfaces in `@serve.zone/interfaces` help shape network interaction patterns.
|
||||
|
||||
```typescript
|
||||
import { IReverseProxyConfig } from '@serve.zone/interfaces/data/traffic';
|
||||
|
||||
const proxyConfig: IReverseProxyConfig = {
|
||||
domain: 'example.com',
|
||||
path: '/',
|
||||
serviceAddress: 'http://service:8080',
|
||||
ssl: true,
|
||||
};
|
||||
|
||||
function configureProxy() {
|
||||
// Logic to apply the proxyConfig, potentially using Typedi, Smartclient, or similar libraries.
|
||||
}
|
||||
```
|
||||
|
||||
Here, `IReverseProxyConfig` is used to define a reverse proxy for a service. Such configurations are necessary for routing external requests into internal services securely.
|
||||
|
||||
### Advanced Interface Utilization
|
||||
|
||||
#### Monitoring and Metrics Collection
|
||||
|
||||
For observability, you can track system metrics using `IServerMetrics` or cluster status interfaces.
|
||||
|
||||
```typescript
|
||||
import { IServerMetrics } from '@serve.zone/interfaces/data/server';
|
||||
|
||||
function reportMetrics(metrics: IServerMetrics) {
|
||||
console.log(`CPU Usage: ${metrics.cpuUsageInPercent}%`);
|
||||
console.log(`Memory Usage: ${metrics.memoryUsageinMB}MB`);
|
||||
}
|
||||
|
||||
const sampleMetrics: IServerMetrics = {
|
||||
serverId: 'server-123',
|
||||
cpuUsageInPercent: 45,
|
||||
memoryUsageinMB: 2048,
|
||||
memoryAvailableInMB: 4096,
|
||||
containerCount: 10,
|
||||
containerMetrics: [],
|
||||
};
|
||||
|
||||
reportMetrics(sampleMetrics);
|
||||
```
|
||||
|
||||
Implementing such metrics tracking provides insight into performance bottlenecks and helps strategize scaling decisions.
|
||||
|
||||
#### Certificate Management
|
||||
|
||||
To handle SSL certificates programmatically, utilize interfaces such as `IRequest_Any_Cloudly_GetCertificateForDomain`.
|
||||
|
||||
```typescript
|
||||
import { IRequest_Any_Cloudly_GetCertificateForDomain } from '@serve.zone/interfaces/requests/certificate';
|
||||
|
||||
async function fetchCertificate(cloudlyClient: CloudlyApiClient, domainName: string) {
|
||||
const request: IRequest_Any_Cloudly_GetCertificateForDomain['request'] = {
|
||||
identity: cloudlyClient.identity,
|
||||
domainName: domainName,
|
||||
type: 'ssl'
|
||||
};
|
||||
|
||||
return await cloudlyClient.typedsocketClient.fireTypedRequest<IRequest_Any_Cloudly_GetCertificateForDomain>(request);
|
||||
}
|
||||
```
|
||||
|
||||
Managing certificates dynamically via typed requests simplifies deployment and automates the security dimensions of your applications.
|
||||
|
||||
#### Integrating with External Messaging Services
|
||||
|
||||
Use `IRequest_SendEmail` to integrate platform services for sending emails:
|
||||
|
||||
```typescript
|
||||
import { IRequest_SendEmail } from '@serve.zone/interfaces/platformservice/mta';
|
||||
|
||||
async function sendNotification(emailClient: any) {
|
||||
const emailRequest: IRequest_SendEmail['request'] = {
|
||||
title: 'Welcome to ServeZone!',
|
||||
from: 'service@company.com',
|
||||
to: 'user@example.com',
|
||||
body: '<h1>Congratulations</h1><p>Your account has been created successfully.</p>',
|
||||
};
|
||||
|
||||
await emailClient.sendEmail(emailRequest);
|
||||
}
|
||||
```
|
||||
|
||||
This approach demonstrates abstracting the email sending functionality using typed interfaces, contributing to code consistency and robustness.
|
||||
|
||||
### Conclusion
|
||||
|
||||
The `@serve.zone/interfaces` module equips developers with a set of interfaces tailored for managing containers, orchestrating cloud services, and handling system interactions seamlessly. By applying these interfaces, projects can achieve coherence, reduce coupling, and simplify the integration process across various service domains.
|
||||
|
||||
Focusing on practical applications, try extending these interfaces to suit additional requirements in your projects. Engage actively with the module community, or contribute new ideas to enhance the breadth and depth of this interface library. Explore the integration patterns showcased here and contribute toward a sophisticated cloud-native development framework.
|
||||
|
||||
## License and Legal Information
|
||||
|
||||
This repository contains open-source code that is licensed under the MIT License. A copy of the MIT License can be found in the [license](license) file within this repository.
|
||||
|
||||
**Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.
|
||||
|
||||
### Trademarks
|
||||
|
||||
This project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH and are not included within the scope of the MIT license granted herein. Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines, and any usage must be approved in writing by Task Venture Capital GmbH.
|
||||
|
||||
### Company Information
|
||||
|
||||
Task Venture Capital GmbH
|
||||
Registered at District court Bremen HRB 35230 HB, Germany
|
||||
|
||||
For any legal inquiries or if you require further information, please contact us via email at hello@task.vc.
|
||||
|
||||
By using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.
|
16
ts_interfaces/requests/admin.ts
Normal file
16
ts_interfaces/requests/admin.ts
Normal file
@ -0,0 +1,16 @@
|
||||
import * as plugins from '../plugins.js';
|
||||
import * as userInterfaces from '../data/user.js';
|
||||
|
||||
export interface IReq_Admin_LoginWithUsernameAndPassword extends plugins.typedrequestInterfaces.implementsTR<
|
||||
plugins.typedrequestInterfaces.ITypedRequest,
|
||||
IReq_Admin_LoginWithUsernameAndPassword
|
||||
> {
|
||||
method: 'adminLoginWithUsernameAndPassword';
|
||||
request: {
|
||||
username: string;
|
||||
password: string;
|
||||
};
|
||||
response: {
|
||||
identity: userInterfaces.IIdentity;
|
||||
}
|
||||
}
|
@ -5,11 +5,11 @@ import * as plugins from '../plugins.js';
|
||||
/**
|
||||
* get all clusters
|
||||
*/
|
||||
export interface IRequest_GetAllClusters extends plugins.typedrequestInterfaces.implementsTR<
|
||||
export interface IReq_Any_Cloudly_GetClusters extends plugins.typedrequestInterfaces.implementsTR<
|
||||
plugins.typedrequestInterfaces.ITypedRequest,
|
||||
IRequest_GetAllClusters
|
||||
IReq_Any_Cloudly_GetClusters
|
||||
> {
|
||||
method: 'getAllClusters';
|
||||
method: 'getClusters';
|
||||
request: {
|
||||
identity: userInterfaces.IIdentity;
|
||||
};
|
||||
@ -18,6 +18,21 @@ export interface IRequest_GetAllClusters extends plugins.typedrequestInterfaces.
|
||||
};
|
||||
}
|
||||
|
||||
export interface IReq_Any_Cloudly_GetClusterById
|
||||
extends plugins.typedrequestInterfaces.implementsTR<
|
||||
plugins.typedrequestInterfaces.ITypedRequest,
|
||||
IReq_Any_Cloudly_GetClusterById
|
||||
> {
|
||||
method: 'getClusterById';
|
||||
request: {
|
||||
identity: userInterfaces.IIdentity;
|
||||
clusterId: string;
|
||||
};
|
||||
response: {
|
||||
cluster: clusterInterfaces.ICluster;
|
||||
};
|
||||
}
|
||||
|
||||
export interface IRequest_CreateCluster extends plugins.typedrequestInterfaces.implementsTR<
|
||||
plugins.typedrequestInterfaces.ITypedRequest,
|
||||
IRequest_CreateCluster
|
||||
@ -28,40 +43,40 @@ export interface IRequest_CreateCluster extends plugins.typedrequestInterfaces.i
|
||||
clusterName: string;
|
||||
};
|
||||
response: {
|
||||
clusterConfig: clusterInterfaces.ICluster;
|
||||
cluster: clusterInterfaces.ICluster;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* updates a cluster
|
||||
*/
|
||||
export interface IRequest_UpdateCluster extends plugins.typedrequestInterfaces.implementsTR<
|
||||
export interface IReq_Any_Cloudly_UpdateCluster extends plugins.typedrequestInterfaces.implementsTR<
|
||||
plugins.typedrequestInterfaces.ITypedRequest,
|
||||
IRequest_UpdateCluster
|
||||
IReq_Any_Cloudly_UpdateCluster
|
||||
> {
|
||||
method: 'updateCluster';
|
||||
request: {
|
||||
identity: userInterfaces.IIdentity;
|
||||
clusterConfig: clusterInterfaces.ICluster;
|
||||
clusterData: clusterInterfaces.ICluster['data'];
|
||||
};
|
||||
response: {
|
||||
clusterConfig: clusterInterfaces.ICluster;
|
||||
resultCluster: clusterInterfaces.ICluster;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* deletes a cluster
|
||||
*/
|
||||
export interface IRequest_DeleteCluster extends plugins.typedrequestInterfaces.implementsTR<
|
||||
export interface IReq_Any_Cloudly_DeleteClusterById extends plugins.typedrequestInterfaces.implementsTR<
|
||||
plugins.typedrequestInterfaces.ITypedRequest,
|
||||
IRequest_DeleteCluster
|
||||
IReq_Any_Cloudly_DeleteClusterById
|
||||
> {
|
||||
method: 'deleteCluster';
|
||||
method: 'deleteClusterById';
|
||||
request: {
|
||||
identity: userInterfaces.IIdentity;
|
||||
clusterId: string;
|
||||
};
|
||||
response: {
|
||||
success: boolean;
|
||||
ok: boolean;
|
||||
};
|
||||
}
|
||||
|
@ -3,7 +3,6 @@ import * as clusterInterfaces from '../data/cluster.js';
|
||||
import * as serverInterfaces from '../data/server.js';
|
||||
import * as userInterfaces from '../data/user.js';
|
||||
import type { IService } from '../data/service.js';
|
||||
import type { IDeploymentDirective } from '../data/deploymentdirective.js';
|
||||
|
||||
export interface IRequest_Any_Cloudly_GetServerConfig
|
||||
extends plugins.typedrequestInterfaces.implementsTR<
|
||||
@ -31,7 +30,7 @@ extends plugins.typedrequestInterfaces.implementsTR<
|
||||
};
|
||||
response: {
|
||||
configData: clusterInterfaces.ICluster;
|
||||
deploymentDirectives: IDeploymentDirective[];
|
||||
services: IService[];
|
||||
};
|
||||
}
|
||||
|
||||
@ -43,7 +42,7 @@ extends plugins.typedrequestInterfaces.implementsTR<
|
||||
method: 'pushClusterConfig';
|
||||
request: {
|
||||
configData: clusterInterfaces.ICluster;
|
||||
deploymentDirectives: IDeploymentDirective[];
|
||||
services: IService[];
|
||||
};
|
||||
response: {};
|
||||
}
|
||||
|
72
ts_interfaces/requests/externalregistry.ts
Normal file
72
ts_interfaces/requests/externalregistry.ts
Normal file
@ -0,0 +1,72 @@
|
||||
import * as plugins from '../plugins.js';
|
||||
import * as data from '../data/index.js';
|
||||
import * as userInterfaces from '../data/user.js';
|
||||
|
||||
export interface IReq_GetRegistryById extends plugins.typedrequestInterfaces.implementsTR<
|
||||
plugins.typedrequestInterfaces.ITypedRequest,
|
||||
IReq_GetRegistryById
|
||||
> {
|
||||
method: 'getExternalRegistryById';
|
||||
request: {
|
||||
identity: userInterfaces.IIdentity;
|
||||
id: string;
|
||||
};
|
||||
response: {
|
||||
registry: data.IExternalRegistry;
|
||||
};
|
||||
}
|
||||
|
||||
export interface IReq_GetRegistries extends plugins.typedrequestInterfaces.implementsTR<
|
||||
plugins.typedrequestInterfaces.ITypedRequest,
|
||||
IReq_GetRegistries
|
||||
> {
|
||||
method: 'getExternalRegistries';
|
||||
request: {
|
||||
identity: userInterfaces.IIdentity;
|
||||
};
|
||||
response: {
|
||||
registries: data.IExternalRegistry[];
|
||||
};
|
||||
}
|
||||
|
||||
export interface IReq_CreateRegistry extends plugins.typedrequestInterfaces.implementsTR<
|
||||
plugins.typedrequestInterfaces.ITypedRequest,
|
||||
IReq_CreateRegistry
|
||||
> {
|
||||
method: 'createExternalRegistry';
|
||||
request: {
|
||||
identity: userInterfaces.IIdentity;
|
||||
registryData: data.IExternalRegistry['data'];
|
||||
};
|
||||
response: {
|
||||
registry: data.IExternalRegistry;
|
||||
};
|
||||
}
|
||||
|
||||
export interface IReq_UpdateRegistry extends plugins.typedrequestInterfaces.implementsTR<
|
||||
plugins.typedrequestInterfaces.ITypedRequest,
|
||||
IReq_UpdateRegistry
|
||||
> {
|
||||
method: 'updateExternalRegistry';
|
||||
request: {
|
||||
identity: userInterfaces.IIdentity;
|
||||
registryData: data.IExternalRegistry['data'];
|
||||
};
|
||||
response: {
|
||||
resultRegistry: data.IExternalRegistry;
|
||||
};
|
||||
}
|
||||
|
||||
export interface IReq_DeleteRegistryById extends plugins.typedrequestInterfaces.implementsTR<
|
||||
plugins.typedrequestInterfaces.ITypedRequest,
|
||||
IReq_DeleteRegistryById
|
||||
> {
|
||||
method: 'deleteExternalRegistryById';
|
||||
request: {
|
||||
identity: userInterfaces.IIdentity;
|
||||
registryId: string;
|
||||
};
|
||||
response: {
|
||||
ok: boolean;
|
||||
};
|
||||
}
|
@ -18,6 +18,7 @@ export interface IRequest_GetAllImages extends plugins.typedrequestInterfaces.im
|
||||
|
||||
/**
|
||||
* gets a single image
|
||||
* authentication can happen via imageClaim or identity
|
||||
*/
|
||||
export interface IRequest_GetImage extends plugins.typedrequestInterfaces.implementsTR<
|
||||
plugins.typedrequestInterfaces.ITypedRequest,
|
||||
|
@ -1,31 +1,39 @@
|
||||
import * as plugins from '../plugins.js';
|
||||
|
||||
import * as adminRequests from './admin.js';
|
||||
import * as certificateRequests from './certificate.js';
|
||||
import * as clusterRequests from './cluster.js';
|
||||
import * as configRequests from './config.js';
|
||||
import * as externalRegistryRequests from './externalregistry.js';
|
||||
import * as identityRequests from './identity.js';
|
||||
import * as imageRequests from './image.js';
|
||||
import * as informRequests from './inform.js';
|
||||
import * as logRequests from './log.js';
|
||||
import * as networkRequests from './network.js';
|
||||
import * as routingRequests from './routing.js';
|
||||
import * as secretRequests from './secret.js';
|
||||
import * as secretBundleRequests from './secretbundle.js';
|
||||
import * as secretGroupRequests from './secretgroup.js';
|
||||
import * as serverRequests from './server.js';
|
||||
import * as serviceRequests from './service.js';
|
||||
import * as statusRequests from './status.js';
|
||||
import * as versionRequests from './version.js';
|
||||
|
||||
export {
|
||||
adminRequests as admin,
|
||||
certificateRequests as certificate,
|
||||
clusterRequests as cluster,
|
||||
configRequests as config,
|
||||
externalRegistryRequests as externalRegistry,
|
||||
identityRequests as identity,
|
||||
imageRequests as image,
|
||||
informRequests as inform,
|
||||
logRequests as log,
|
||||
networkRequests as network,
|
||||
routingRequests as routing,
|
||||
secretRequests as secret,
|
||||
secretBundleRequests as secretbundle,
|
||||
secretGroupRequests as secretgroup,
|
||||
serverRequests as server,
|
||||
serviceRequests as service,
|
||||
statusRequests as status,
|
||||
versionRequests as version,
|
||||
};
|
||||
|
@ -1,94 +0,0 @@
|
||||
import * as plugins from '../plugins.js';
|
||||
import * as data from '../data/index.js';
|
||||
import * as userInterfaces from '../data/user.js';
|
||||
|
||||
export interface IReq_GetEnvBundle extends plugins.typedrequestInterfaces.implementsTR<
|
||||
plugins.typedrequestInterfaces.ITypedRequest,
|
||||
IReq_GetEnvBundle
|
||||
> {
|
||||
method: 'getEnvBundle';
|
||||
request: {
|
||||
authorization: string;
|
||||
/**
|
||||
* specify this if you want to get a warning, if the envBundle is for an unexpected environment
|
||||
*/
|
||||
environment?: string;
|
||||
};
|
||||
response: {
|
||||
envBundle: data.IEnvBundle;
|
||||
};
|
||||
}
|
||||
|
||||
export interface IReq_Admin_LoginWithUsernameAndPassword extends plugins.typedrequestInterfaces.implementsTR<
|
||||
plugins.typedrequestInterfaces.ITypedRequest,
|
||||
IReq_Admin_LoginWithUsernameAndPassword
|
||||
> {
|
||||
method: 'adminLoginWithUsernameAndPassword';
|
||||
request: {
|
||||
username: string;
|
||||
password: string;
|
||||
};
|
||||
response: {
|
||||
identity: userInterfaces.IIdentity;
|
||||
}
|
||||
}
|
||||
|
||||
export interface IReq_Admin_GetConfigBundlesAndSecretGroups extends plugins.typedrequestInterfaces.implementsTR<
|
||||
plugins.typedrequestInterfaces.ITypedRequest,
|
||||
IReq_Admin_GetConfigBundlesAndSecretGroups
|
||||
> {
|
||||
method: 'adminGetConfigBundlesAndSecretGroups';
|
||||
request: {
|
||||
identity: userInterfaces.IIdentity;
|
||||
};
|
||||
response: {
|
||||
secretBundles: data.ISecretBundle[];
|
||||
secretGroups: data.ISecretGroup[];
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
export interface IReq_Admin_CreateConfigBundlesAndSecretGroups extends plugins.typedrequestInterfaces.implementsTR<
|
||||
plugins.typedrequestInterfaces.ITypedRequest,
|
||||
IReq_Admin_CreateConfigBundlesAndSecretGroups
|
||||
> {
|
||||
method: 'adminCreateConfigBundlesAndSecretGroups';
|
||||
request: {
|
||||
identity: userInterfaces.IIdentity;
|
||||
secretBundles: data.ISecretBundle[];
|
||||
secretGroups: data.ISecretGroup[];
|
||||
};
|
||||
response: {
|
||||
ok: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
export interface IReq_Admin_UpdateConfigBundlesAndSecretGroups extends plugins.typedrequestInterfaces.implementsTR<
|
||||
plugins.typedrequestInterfaces.ITypedRequest,
|
||||
IReq_Admin_UpdateConfigBundlesAndSecretGroups
|
||||
> {
|
||||
method: 'adminUpdateConfigBundlesAndSecretGroups';
|
||||
request: {
|
||||
identity: userInterfaces.IIdentity;
|
||||
configBundles: data.ISecretBundle[];
|
||||
secretGroups: data.ISecretGroup[];
|
||||
};
|
||||
response: {
|
||||
ok: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
export interface IReq_Admin_DeleteConfigBundlesAndSecretGroups extends plugins.typedrequestInterfaces.implementsTR<
|
||||
plugins.typedrequestInterfaces.ITypedRequest,
|
||||
IReq_Admin_DeleteConfigBundlesAndSecretGroups
|
||||
> {
|
||||
method: 'adminDeleteConfigBundlesAndSecretGroups';
|
||||
request: {
|
||||
identity: userInterfaces.IIdentity;
|
||||
secretBundleIds: string[];
|
||||
secretGroupIds: string[];
|
||||
};
|
||||
response: {
|
||||
ok: boolean;
|
||||
};
|
||||
}
|
103
ts_interfaces/requests/secretbundle.ts
Normal file
103
ts_interfaces/requests/secretbundle.ts
Normal file
@ -0,0 +1,103 @@
|
||||
import * as plugins from '../plugins.js';
|
||||
import * as data from '../data/index.js';
|
||||
import * as userInterfaces from '../data/user.js';
|
||||
|
||||
export interface IReq_GetSecretBundles extends plugins.typedrequestInterfaces.implementsTR<
|
||||
plugins.typedrequestInterfaces.ITypedRequest,
|
||||
IReq_GetSecretBundles
|
||||
> {
|
||||
method: 'getSecretBundles';
|
||||
request: {
|
||||
identity: userInterfaces.IIdentity;
|
||||
};
|
||||
response: {
|
||||
secretBundles: data.ISecretBundle[];
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
export interface IReq_GetSecretBundleById extends plugins.typedrequestInterfaces.implementsTR<
|
||||
plugins.typedrequestInterfaces.ITypedRequest,
|
||||
IReq_GetSecretBundleById
|
||||
> {
|
||||
method: 'getSecretBundleById';
|
||||
request: {
|
||||
identity: userInterfaces.IIdentity;
|
||||
secretBundleId: string;
|
||||
};
|
||||
response: {
|
||||
secretBundle: data.ISecretBundle;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
export interface IReq_CreateSecretBundle extends plugins.typedrequestInterfaces.implementsTR<
|
||||
plugins.typedrequestInterfaces.ITypedRequest,
|
||||
IReq_CreateSecretBundle
|
||||
> {
|
||||
method: 'createSecretBundle';
|
||||
request: {
|
||||
identity: userInterfaces.IIdentity;
|
||||
secretBundle: data.ISecretBundle;
|
||||
};
|
||||
response: {
|
||||
resultSecretBundle: data.ISecretBundle;
|
||||
};
|
||||
}
|
||||
|
||||
export interface IReq_UpdateSecretBundle extends plugins.typedrequestInterfaces.implementsTR<
|
||||
plugins.typedrequestInterfaces.ITypedRequest,
|
||||
IReq_UpdateSecretBundle
|
||||
> {
|
||||
method: 'updateSecretBundle';
|
||||
request: {
|
||||
identity: userInterfaces.IIdentity;
|
||||
secretBundle: data.ISecretBundle;
|
||||
};
|
||||
response: {
|
||||
resultSecretBundle: data.ISecretBundle;
|
||||
};
|
||||
}
|
||||
|
||||
export interface IReq_DeleteSecretBundleById extends plugins.typedrequestInterfaces.implementsTR<
|
||||
plugins.typedrequestInterfaces.ITypedRequest,
|
||||
IReq_DeleteSecretBundleById
|
||||
> {
|
||||
method: 'deleteSecretBundleById';
|
||||
request: {
|
||||
identity: userInterfaces.IIdentity;
|
||||
secretBundleId: string;
|
||||
};
|
||||
response: {
|
||||
ok: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
export interface IReq_GetSecretBundleByAuthorization extends plugins.typedrequestInterfaces.implementsTR<
|
||||
plugins.typedrequestInterfaces.ITypedRequest,
|
||||
IReq_GetSecretBundleByAuthorization
|
||||
> {
|
||||
method: 'getSecretBundleByAuthorization';
|
||||
request: {
|
||||
identity: userInterfaces.IIdentity;
|
||||
secretBundleAuthorization: data.ISecretBundleAuthorization;
|
||||
};
|
||||
response: {
|
||||
secretBundle: data.ISecretBundle;
|
||||
};
|
||||
}
|
||||
|
||||
export interface IReq_GetFlatKeyValueObject extends plugins.typedrequestInterfaces.implementsTR<
|
||||
plugins.typedrequestInterfaces.ITypedRequest,
|
||||
IReq_GetFlatKeyValueObject
|
||||
> {
|
||||
method: 'getFlatKeyValueObject';
|
||||
request: {
|
||||
identity: userInterfaces.IIdentity;
|
||||
seccretBundleId: string;
|
||||
secretBundleAuthorization: data.ISecretBundleAuthorization;
|
||||
};
|
||||
response: {
|
||||
flatKeyValueObject: {[key: string]: string};
|
||||
};
|
||||
}
|
74
ts_interfaces/requests/secretgroup.ts
Normal file
74
ts_interfaces/requests/secretgroup.ts
Normal file
@ -0,0 +1,74 @@
|
||||
import * as plugins from '../plugins.js';
|
||||
import * as data from '../data/index.js';
|
||||
import * as userInterfaces from '../data/user.js';
|
||||
|
||||
export interface IReq_GetSecretGroups extends plugins.typedrequestInterfaces.implementsTR<
|
||||
plugins.typedrequestInterfaces.ITypedRequest,
|
||||
IReq_GetSecretGroups
|
||||
> {
|
||||
method: 'getSecretGroups';
|
||||
request: {
|
||||
identity: userInterfaces.IIdentity;
|
||||
};
|
||||
response: {
|
||||
secretGroups: data.ISecretGroup[];
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
export interface IReq_GetSecretGroupById extends plugins.typedrequestInterfaces.implementsTR<
|
||||
plugins.typedrequestInterfaces.ITypedRequest,
|
||||
IReq_GetSecretGroupById
|
||||
> {
|
||||
method: 'getSecretGroupById';
|
||||
request: {
|
||||
identity: userInterfaces.IIdentity;
|
||||
secretGroupId: string;
|
||||
};
|
||||
response: {
|
||||
secretGroup: data.ISecretGroup;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
export interface IReq_CreateSecretGroup extends plugins.typedrequestInterfaces.implementsTR<
|
||||
plugins.typedrequestInterfaces.ITypedRequest,
|
||||
IReq_CreateSecretGroup
|
||||
> {
|
||||
method: 'createSecretGroup';
|
||||
request: {
|
||||
identity: userInterfaces.IIdentity;
|
||||
secretGroup: data.ISecretGroup;
|
||||
};
|
||||
response: {
|
||||
resultSecretGroup: data.ISecretGroup;
|
||||
};
|
||||
}
|
||||
|
||||
export interface IReq_UpdateSecretGroup extends plugins.typedrequestInterfaces.implementsTR<
|
||||
plugins.typedrequestInterfaces.ITypedRequest,
|
||||
IReq_UpdateSecretGroup
|
||||
> {
|
||||
method: 'updateSecretGroup';
|
||||
request: {
|
||||
identity: userInterfaces.IIdentity;
|
||||
secretGroup: data.ISecretGroup;
|
||||
};
|
||||
response: {
|
||||
resultSecretGroup: data.ISecretGroup;
|
||||
};
|
||||
}
|
||||
|
||||
export interface IReq_DeleteSecretGroupById extends plugins.typedrequestInterfaces.implementsTR<
|
||||
plugins.typedrequestInterfaces.ITypedRequest,
|
||||
IReq_DeleteSecretGroupById
|
||||
> {
|
||||
method: 'deleteSecretGroupById';
|
||||
request: {
|
||||
identity: userInterfaces.IIdentity;
|
||||
secretGroupId: string;
|
||||
};
|
||||
response: {
|
||||
ok: boolean;
|
||||
};
|
||||
}
|
95
ts_interfaces/requests/service.ts
Normal file
95
ts_interfaces/requests/service.ts
Normal file
@ -0,0 +1,95 @@
|
||||
import * as plugins from '../plugins.js';
|
||||
import type { IService } from '../data/service.js';
|
||||
import type { IIdentity } from '../data/user.js';
|
||||
import type { IServiceRessources } from '../data/docker.js';
|
||||
|
||||
export interface IRequest_Any_Cloudly_GetServiceById
|
||||
extends plugins.typedrequestInterfaces.implementsTR<
|
||||
plugins.typedrequestInterfaces.ITypedRequest,
|
||||
IRequest_Any_Cloudly_GetServiceById
|
||||
> {
|
||||
method: 'getServiceById';
|
||||
request: {
|
||||
identity: IIdentity;
|
||||
serviceId: string;
|
||||
};
|
||||
response: {
|
||||
service: IService;
|
||||
};
|
||||
}
|
||||
|
||||
export interface IRequest_Any_Cloudly_GetServices
|
||||
extends plugins.typedrequestInterfaces.implementsTR<
|
||||
plugins.typedrequestInterfaces.ITypedRequest,
|
||||
IRequest_Any_Cloudly_GetServices
|
||||
> {
|
||||
method: 'getServices';
|
||||
request: {
|
||||
identity: IIdentity;
|
||||
};
|
||||
response: {
|
||||
services: IService[];
|
||||
};
|
||||
}
|
||||
|
||||
export interface IRequest_Any_Cloudly_CreateService
|
||||
extends plugins.typedrequestInterfaces.implementsTR<
|
||||
plugins.typedrequestInterfaces.ITypedRequest,
|
||||
IRequest_Any_Cloudly_CreateService
|
||||
> {
|
||||
method: 'createService';
|
||||
request: {
|
||||
identity: IIdentity;
|
||||
serviceData: IService['data'];
|
||||
};
|
||||
response: {
|
||||
service: IService;
|
||||
};
|
||||
}
|
||||
|
||||
export interface IRequest_Any_Cloudly_UpdateService
|
||||
extends plugins.typedrequestInterfaces.implementsTR<
|
||||
plugins.typedrequestInterfaces.ITypedRequest,
|
||||
IRequest_Any_Cloudly_UpdateService
|
||||
> {
|
||||
method: 'updateService';
|
||||
request: {
|
||||
identity: IIdentity;
|
||||
serviceId: string;
|
||||
serviceData: IService['data'];
|
||||
};
|
||||
response: {
|
||||
service: IService;
|
||||
};
|
||||
}
|
||||
|
||||
export interface IRequest_Any_Cloudly_DeleteServiceById
|
||||
extends plugins.typedrequestInterfaces.implementsTR<
|
||||
plugins.typedrequestInterfaces.ITypedRequest,
|
||||
IRequest_Any_Cloudly_DeleteServiceById
|
||||
> {
|
||||
method: 'deleteServiceById';
|
||||
request: {
|
||||
identity: IIdentity;
|
||||
serviceId: string;
|
||||
};
|
||||
response: {
|
||||
success: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
export interface IRequest_Any_Cloudly_GetServiceSecretBundlesAsFlatObject
|
||||
extends plugins.typedrequestInterfaces.implementsTR<
|
||||
plugins.typedrequestInterfaces.ITypedRequest,
|
||||
IRequest_Any_Cloudly_GetServiceSecretBundlesAsFlatObject
|
||||
> {
|
||||
method: 'getServiceSecretBundlesAsFlatObject';
|
||||
request: {
|
||||
identity: IIdentity;
|
||||
serviceId: string;
|
||||
environment: string;
|
||||
};
|
||||
response: {
|
||||
flatKeyValueObject: {[key: string]: string};
|
||||
};
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
{
|
||||
"order": 0,
|
||||
"name": "@serve.zone/interfaces",
|
||||
"dependencies": [
|
||||
"@api.global/typedrequest-interfaces",
|
||||
|
@ -3,6 +3,6 @@
|
||||
*/
|
||||
export const commitinfo = {
|
||||
name: '@serve.zone/cloudly',
|
||||
version: '1.2.4',
|
||||
description: 'A comprehensive multi-cloud manager leveraging Docker Swarmkit to orchestrate containerized applications across various cloud services and provide robust configuration and API integration.'
|
||||
version: '5.0.4',
|
||||
description: 'A comprehensive tool for managing containerized applications across multiple cloud providers using Docker Swarmkit, featuring web, CLI, and API interfaces.'
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ export const loginAction = loginStatePart.createAction<{ username: string; passw
|
||||
async (statePartArg, payloadArg) => {
|
||||
const currentState = statePartArg.getState();
|
||||
const trLogin =
|
||||
new domtools.plugins.typedrequest.TypedRequest<plugins.interfaces.requests.secret.IReq_Admin_LoginWithUsernameAndPassword>(
|
||||
new domtools.plugins.typedrequest.TypedRequest<plugins.interfaces.requests.admin.IReq_Admin_LoginWithUsernameAndPassword>(
|
||||
'/typedrequest',
|
||||
'adminLoginWithUsernameAndPassword'
|
||||
);
|
||||
@ -77,20 +77,34 @@ export const dataState = await appstate.getStatePart<IDataState>(
|
||||
);
|
||||
|
||||
// Getting data
|
||||
export const getAllDataAction = dataState.createAction(async (statePartArg, partialArg?: 'secrets' | 'images') => {
|
||||
export const getAllDataAction = dataState.createAction(async (statePartArg) => {
|
||||
let currentState = statePartArg.getState();
|
||||
// Secrets
|
||||
const trGetSecrets =
|
||||
new domtools.plugins.typedrequest.TypedRequest<plugins.interfaces.requests.secret.IReq_Admin_GetConfigBundlesAndSecretGroups>(
|
||||
// SecretsGroups
|
||||
const trGetSecretGroups =
|
||||
new domtools.plugins.typedrequest.TypedRequest<plugins.interfaces.requests.secretgroup.IReq_GetSecretGroups>(
|
||||
'/typedrequest',
|
||||
'adminGetConfigBundlesAndSecretGroups'
|
||||
'getSecretGroups'
|
||||
);
|
||||
const response = await trGetSecrets.fire({
|
||||
const response = await trGetSecretGroups.fire({
|
||||
identity: loginStatePart.getState().identity,
|
||||
});
|
||||
currentState = {
|
||||
...currentState,
|
||||
...response,
|
||||
secretGroups: response.secretGroups,
|
||||
};
|
||||
|
||||
// SecretBundles
|
||||
const trGetSecretBundles =
|
||||
new domtools.plugins.typedrequest.TypedRequest<plugins.interfaces.requests.secretbundle.IReq_GetSecretBundles>(
|
||||
'/typedrequest',
|
||||
'getSecretBundles'
|
||||
);
|
||||
const responseSecretBundles = await trGetSecretBundles.fire({
|
||||
identity: loginStatePart.getState().identity,
|
||||
});
|
||||
currentState = {
|
||||
...currentState,
|
||||
secretBundles: responseSecretBundles.secretBundles,
|
||||
};
|
||||
|
||||
// images
|
||||
@ -104,14 +118,14 @@ export const getAllDataAction = dataState.createAction(async (statePartArg, part
|
||||
});
|
||||
currentState = {
|
||||
...currentState,
|
||||
...responseImages,
|
||||
images: responseImages.images,
|
||||
};
|
||||
|
||||
// Clusters
|
||||
const trGetClusters =
|
||||
new domtools.plugins.typedrequest.TypedRequest<plugins.interfaces.requests.cluster.IRequest_GetAllClusters>(
|
||||
new domtools.plugins.typedrequest.TypedRequest<plugins.interfaces.requests.cluster.IReq_Any_Cloudly_GetClusters>(
|
||||
'/typedrequest',
|
||||
'getAllClusters'
|
||||
'getClusters'
|
||||
);
|
||||
const responseClusters = await trGetClusters.fire({
|
||||
identity: loginStatePart.getState().identity,
|
||||
@ -119,7 +133,7 @@ export const getAllDataAction = dataState.createAction(async (statePartArg, part
|
||||
|
||||
currentState = {
|
||||
...currentState,
|
||||
...responseClusters,
|
||||
clusters: responseClusters.clusters,
|
||||
}
|
||||
|
||||
return currentState;
|
||||
@ -130,14 +144,13 @@ export const createSecretGroupAction = dataState.createAction(
|
||||
async (statePartArg, payloadArg: plugins.interfaces.data.ISecretGroup) => {
|
||||
let currentState = statePartArg.getState();
|
||||
const trCreateSecretGroup =
|
||||
new domtools.plugins.typedrequest.TypedRequest<plugins.interfaces.requests.secret.IReq_Admin_CreateConfigBundlesAndSecretGroups>(
|
||||
new domtools.plugins.typedrequest.TypedRequest<plugins.interfaces.requests.secretgroup.IReq_CreateSecretGroup>(
|
||||
'/typedrequest',
|
||||
'adminCreateConfigBundlesAndSecretGroups'
|
||||
'createSecretGroup'
|
||||
);
|
||||
const response = await trCreateSecretGroup.fire({
|
||||
identity: loginStatePart.getState().identity,
|
||||
secretBundles: [],
|
||||
secretGroups: [payloadArg],
|
||||
secretGroup: payloadArg,
|
||||
});
|
||||
currentState = await dataState.dispatchAction(getAllDataAction, null);
|
||||
return currentState;
|
||||
@ -149,14 +162,13 @@ export const deleteSecretGroupAction = dataState.createAction(
|
||||
async (statePartArg, payloadArg: { secretGroupId: string }) => {
|
||||
let currentState = statePartArg.getState();
|
||||
const trDeleteSecretGroup =
|
||||
new domtools.plugins.typedrequest.TypedRequest<plugins.interfaces.requests.secret.IReq_Admin_DeleteConfigBundlesAndSecretGroups>(
|
||||
new domtools.plugins.typedrequest.TypedRequest<plugins.interfaces.requests.secretgroup.IReq_DeleteSecretGroupById>(
|
||||
'/typedrequest',
|
||||
'adminDeleteConfigBundlesAndSecretGroups'
|
||||
'deleteSecretGroupById'
|
||||
);
|
||||
const response = await trDeleteSecretGroup.fire({
|
||||
identity: loginStatePart.getState().identity,
|
||||
secretBundleIds: [],
|
||||
secretGroupIds: [payloadArg.secretGroupId],
|
||||
secretGroupId: payloadArg.secretGroupId,
|
||||
});
|
||||
currentState = await dataState.dispatchAction(getAllDataAction, null);
|
||||
return currentState;
|
||||
@ -168,14 +180,13 @@ export const deleteSecretBundleAction = dataState.createAction(
|
||||
async (statePartArg, payloadArg: { configBundleId: string }) => {
|
||||
let currentState = statePartArg.getState();
|
||||
const trDeleteConfigBundle =
|
||||
new domtools.plugins.typedrequest.TypedRequest<plugins.interfaces.requests.secret.IReq_Admin_DeleteConfigBundlesAndSecretGroups>(
|
||||
new domtools.plugins.typedrequest.TypedRequest<plugins.interfaces.requests.secretbundle.IReq_DeleteSecretBundleById>(
|
||||
'/typedrequest',
|
||||
'adminDeleteConfigBundlesAndSecretGroups'
|
||||
'deleteSecretBundleById'
|
||||
);
|
||||
const response = await trDeleteConfigBundle.fire({
|
||||
identity: loginStatePart.getState().identity,
|
||||
secretBundleIds: [payloadArg.configBundleId],
|
||||
secretGroupIds: [],
|
||||
secretBundleId: payloadArg.configBundleId,
|
||||
});
|
||||
currentState = await dataState.dispatchAction(getAllDataAction, null);
|
||||
return currentState;
|
||||
@ -249,7 +260,7 @@ export const addClusterAction = dataState.createAction(
|
||||
currentState = {
|
||||
...currentState,
|
||||
...{
|
||||
clusters: [...currentState.clusters, response.clusterConfig],
|
||||
clusters: [...currentState.clusters, response.cluster],
|
||||
},
|
||||
}
|
||||
return currentState;
|
||||
|
@ -24,6 +24,7 @@ import { CloudlyViewS3 } from './cloudly-view-s3.js';
|
||||
import { CloudlyViewSecretBundles } from './cloudly-view-secretbundles.js';
|
||||
import { CloudlyViewSecretGroups } from './cloudly-view-secretgroups.js';
|
||||
import { CloudlyViewServices } from './cloudly-view-services.js';
|
||||
import { CloudlyViewExternalRegistries } from './cloudly-view-externalregistries.js';
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
@ -89,6 +90,10 @@ export class CloudlyDashboard extends DeesElement {
|
||||
name: 'Clusters',
|
||||
element: CloudlyViewClusters,
|
||||
},
|
||||
{
|
||||
name: 'ExternalRegistries',
|
||||
element: CloudlyViewExternalRegistries,
|
||||
},
|
||||
{
|
||||
name: 'Images',
|
||||
element: CloudlyViewImages,
|
||||
|
129
ts_web/elements/cloudly-view-externalregistries.ts
Normal file
129
ts_web/elements/cloudly-view-externalregistries.ts
Normal file
@ -0,0 +1,129 @@
|
||||
import * as plugins from '../plugins.js';
|
||||
import * as shared from '../elements/shared/index.js';
|
||||
|
||||
import {
|
||||
DeesElement,
|
||||
customElement,
|
||||
html,
|
||||
state,
|
||||
css,
|
||||
cssManager,
|
||||
} from '@design.estate/dees-element';
|
||||
|
||||
import * as appstate from '../appstate.js';
|
||||
|
||||
@customElement('cloudly-view-externalregistries')
|
||||
export class CloudlyViewExternalRegistries extends DeesElement {
|
||||
@state()
|
||||
private data: appstate.IDataState = {
|
||||
secretGroups: [],
|
||||
secretBundles: [],
|
||||
};
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
const subecription = appstate.dataState
|
||||
.select((stateArg) => stateArg)
|
||||
.subscribe((dataArg) => {
|
||||
this.data = dataArg;
|
||||
});
|
||||
this.rxSubscriptions.push(subecription);
|
||||
}
|
||||
|
||||
public static styles = [
|
||||
cssManager.defaultStyles,
|
||||
shared.viewHostCss,
|
||||
css`
|
||||
`,
|
||||
];
|
||||
|
||||
public render() {
|
||||
return html`
|
||||
<cloudly-sectionheading>External Registries</cloudly-sectionheading>
|
||||
<dees-table
|
||||
.heading1=${'External Registries'}
|
||||
.heading2=${'decoded in client'}
|
||||
.data=${this.data.deployments}
|
||||
.displayFunction=${(itemArg: plugins.interfaces.data.ICluster) => {
|
||||
return {
|
||||
id: itemArg.id,
|
||||
serverAmount: itemArg.data.servers.length,
|
||||
};
|
||||
}}
|
||||
.dataActions=${[
|
||||
{
|
||||
name: 'add configBundle',
|
||||
iconName: 'plus',
|
||||
type: ['header', 'footer'],
|
||||
actionFunc: async (dataActionArg) => {
|
||||
const modal = await plugins.deesCatalog.DeesModal.createAndShow({
|
||||
heading: 'Add ConfigBundle',
|
||||
content: html`
|
||||
<dees-form>
|
||||
<dees-input-text .key=${'id'} .label=${'ID'} .value=${''}></dees-input-text>
|
||||
<dees-input-text
|
||||
.key=${'data.secretGroupIds'}
|
||||
.label=${'secretGroupIds'}
|
||||
.value=${''}
|
||||
></dees-input-text>
|
||||
<dees-input-text
|
||||
.key=${'data.includedTags'}
|
||||
.label=${'includedTags'}
|
||||
.value=${''}
|
||||
></dees-input-text>
|
||||
</dees-form>
|
||||
`,
|
||||
menuOptions: [
|
||||
{ name: 'create', action: async (modalArg) => {} },
|
||||
{
|
||||
name: 'cancel',
|
||||
action: async (modalArg) => {
|
||||
modalArg.destroy();
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'delete',
|
||||
iconName: 'trash',
|
||||
type: ['contextmenu', 'inRow'],
|
||||
actionFunc: async (actionDataArg) => {
|
||||
plugins.deesCatalog.DeesModal.createAndShow({
|
||||
heading: `Delete ConfigBundle ${actionDataArg.item.id}`,
|
||||
content: html`
|
||||
<div style="text-align:center">
|
||||
Do you really want to delete the ConfigBundle?
|
||||
</div>
|
||||
<div
|
||||
style="font-size: 0.8em; color: red; text-align:center; padding: 16px; margin-top: 24px; border: 1px solid #444; font-family: Intel One Mono; font-size: 16px;"
|
||||
>
|
||||
${actionDataArg.item.id}
|
||||
</div>
|
||||
`,
|
||||
menuOptions: [
|
||||
{
|
||||
name: 'cancel',
|
||||
action: async (modalArg) => {
|
||||
await modalArg.destroy();
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'delete',
|
||||
action: async (modalArg) => {
|
||||
appstate.dataState.dispatchAction(appstate.deleteSecretBundleAction, {
|
||||
configBundleId: actionDataArg.item.id,
|
||||
});
|
||||
await modalArg.destroy();
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
},
|
||||
},
|
||||
] as plugins.deesCatalog.ITableAction[]}
|
||||
></dees-table>
|
||||
`;
|
||||
}
|
||||
}
|
@ -18,11 +18,28 @@ export class CloudlySectionheading extends DeesElement {
|
||||
public static styles = [
|
||||
cssManager.defaultStyles,
|
||||
css`
|
||||
:host {
|
||||
display: grid;
|
||||
grid-template-columns: min-content min-content;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-family: 'Cal Sans';
|
||||
letter-spacing: 0.025em;
|
||||
margin: 0px;
|
||||
margin-bottom: 16px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.flag {
|
||||
border-radius: 4px;
|
||||
background: #8a0183;
|
||||
height: 20px;
|
||||
padding: 2px 4px;
|
||||
margin-left: 16px;
|
||||
font-size: 12px;
|
||||
transform: translateY(12px);
|
||||
white-space: nowrap;
|
||||
}
|
||||
`,
|
||||
]
|
||||
@ -30,6 +47,7 @@ export class CloudlySectionheading extends DeesElement {
|
||||
public render() {
|
||||
return html`
|
||||
<h1><slot></slot></h1>
|
||||
<div class="flag">stability: alpha</div>
|
||||
`;
|
||||
}
|
||||
}
|
@ -10,13 +10,13 @@
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@serve.zone/api": [
|
||||
"./ts_apiclient/index.ts"
|
||||
"./ts_apiclient/index.js"
|
||||
],
|
||||
"@serve.zone/cli": [
|
||||
"./ts_cliclient/index.ts"
|
||||
"./ts_cliclient/index.js"
|
||||
],
|
||||
"@serve.zone/interfaces": [
|
||||
"./ts_interfaces/index.ts"
|
||||
"./ts_interfaces/index.js"
|
||||
]
|
||||
}
|
||||
},
|
||||
|
Loading…
x
Reference in New Issue
Block a user