cloudly/readme.md
2024-06-20 19:20:16 +02:00

435 lines
14 KiB
Markdown

# @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.
## Install
To install `@serve.zone/cloudly`, run the following command in your terminal:
```bash
npm install @serve.zone/cloudly --save
```
This will install the package and add it to your project's `package.json` dependencies.
## 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.
### Getting Started
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.
#### Initializing Cloudly
First, import the `Cloudly` class from the package and initialize it as shown below:
```typescript
import { Cloudly } 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 = {
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
Cloudly allows managing Docker Swarmkit clusters through an abstracted interface, simplifying operations such as deployment and scaling. Below are examples to demonstrate these capabilities.
#### Example: Initializing a Cloudly Instance and Adding a Cluster
```typescript
import { Cloudly, ClusterManager } 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);
}
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() {
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 dnsInfo = {
zoneName: 'example.com',
recordName: 'sub.example.com',
recordType: 'A',
recordContent: '127.0.0.1',
};
const cfConnector = myCloudlyInstance.cloudflareConnector.cloudflare;
const newRecord = await cfConnector.createDNSRecord(
dnsInfo.zoneName,
dnsInfo.recordName,
dnsInfo.recordType,
dnsInfo.recordContent
);
console.log('DNS Record created:', newRecord);
}
manageDNSRecords();
```
#### Integrating with DigitalOcean
Integrate with DigitalOcean to manage droplets and other resources.
```typescript
import { Cloudly, DigitalOceanConnector } from '@serve.zone/cloudly';
async function manageDroplet() {
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 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);
}
manageDroplet();
```
### Using Cloudly Web Interface
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:
#### Web Dashboard Example
```typescript
import { commitinfo } from '../00_commitinfo_data.js';
import * as plugins from '../plugins.js';
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() {
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>
`;
}
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() {}
}
```
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.
## 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.