Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
- name: Setup Python
uses: actions/setup-python@v3
with:
python-version: '3.8'
python-version: "3.8"

- name: Upgrade pip
run: |
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/flake8.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@ jobs:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3
- name: GitHub Action for Flake8
uses: cclauss/GitHub-Action-for-Flake8@v0.5.0
- uses: actions/checkout@v3
- name: GitHub Action for Flake8
uses: cclauss/GitHub-Action-for-Flake8@v0.5.0
34 changes: 17 additions & 17 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,25 @@ name: Upload Python Package
on:
push:
tags:
- 'v*'
- "v*"

jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v3
with:
python-version: '3.x'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -U setuptools wheel twine
- name: Build and publish
env:
TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }}
TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
run: |
python setup.py sdist bdist_wheel
twine upload dist/*
- uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v3
with:
python-version: "3.x"
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -U setuptools wheel twine
- name: Build and publish
env:
TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }}
TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
run: |
python setup.py sdist bdist_wheel
twine upload dist/*
27 changes: 13 additions & 14 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,21 @@ jobs:
build:
runs-on: ubuntu-latest
strategy:
max-parallel: 4
max-parallel: 3
matrix:
python-version:
- "3.6"
- "3.7"
- "3.8"
- "3.10"

steps:
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v3
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install tox tox-gh-actions
- name: Test with tox
run: tox
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v3
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install tox tox-gh-actions
- name: Test with tox
run: tox
37 changes: 37 additions & 0 deletions docs/cloud.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,5 +122,42 @@ cloud:
# ddos_protection: true
# firewall_group_id: ...
# enable_private_network: true
```

## Apache CloudStack

```yaml
kind: cloudstack
launch_config:
service_offering: cpu2-ram2
template: Linux Template xyz
zone: my-zone
ssh_key: my_ssh_key
tags:
project: gemini
root_disk_size: 20
user_data: |
#cloud-config
manage_etc_hosts: true
packages:
- nginx
```

## Exoscale

```yaml
kind: exoscale
launch_config:
service_offering: Micro
template: Linux Debian 11 (Bullseye) 64-bit
zone: ch-dk-2
ssh_key: my-ssh-key
tags:
project: gemini
root_disk_size: 20
user_data: |
#cloud-config
manage_etc_hosts: true
packages:
- nginx
```
6 changes: 3 additions & 3 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
cloudscale-sdk==0.6.2
cloudscale-sdk==0.7.0
cs==3.0.0
hcloud==1.16.0
prometheus-api-client==0.5.0
prometheus-client==0.13.1
pydantic==1.9.0
pydantic-yaml==0.6.3
pydantic==1.9.1
python-digitalocean==1.17.0
python-dotenv==0.19.2
python-json-logger==2.0.2
PyYAML==6.0
requests==2.27.1
schedule==1.1.0
pydantic-yaml==0.6.3
8 changes: 4 additions & 4 deletions scalr/cloud/adapters/cloudscale_ch.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ def __init__(self):
def get_current_instances(self) -> List[GenericCloudInstance]:
filter_tag = f"scalr={self.filter}"
log.info(f"cloudscale: Querying with filter_tag: {filter_tag}")
servers = self.cloudscale.server.get_all(filter_tag=filter_tag) # type: ignore
servers = self.cloudscale.server.get_all(filter_tag=filter_tag)
return [
GenericCloudInstance(
id=server["uuid"],
Expand All @@ -28,7 +28,7 @@ def ensure_instances_running(self) -> None:
for instance in self.get_current_instances():
log.info(f"cloudscale: instance, {instance.name} status {instance.status}")
if instance.status == "stopped":
self.cloudscale.server.start(uuid=instance.id) # type: ignore
self.cloudscale.server.start(uuid=instance.id)
log.info(f"cloudscale: Instance {instance.name} started")

def deploy_instance(self, name: str) -> None:
Expand All @@ -44,8 +44,8 @@ def deploy_instance(self, name: str) -> None:
"tags": tags,
}
)
self.cloudscale.server.create(**launch_config) # type: ignore
self.cloudscale.server.create(**launch_config)

def destroy_instance(self, instance: GenericCloudInstance) -> None:
log.info(f"cloudscale: Destroying instance {instance}")
self.cloudscale.server.delete(uuid=instance.id) # type: ignore
self.cloudscale.server.delete(uuid=instance.id)
176 changes: 60 additions & 116 deletions scalr/cloud/adapters/cloudstack.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,76 +16,19 @@ def __init__(self):
secret=os.getenv("CLOUDSTACK_API_SECRET"),
)

def get_current_instances(self) -> List[GenericCloudInstance]:
filter_tag = f"scalr={self.filter}"
log.info(f"cloudstack: Querying with filter_tag: {filter_tag}")
servers = self.cs.listVirtualMachines(
tags=[
{
"key": "scalr",
"value": self.filter,
}
],
fetch_list=True,
)
return [
GenericCloudInstance(
id=server["id"],
name=server["name"],
status=server["status"],
)
for server in sorted(servers, key=lambda i: i["created"])
]


def ensure_instances_running(self):

def deploy_instance(self, name: str):

def destroy_instance(self, instance: GenericCloudInstance):



class CloudstackCloudAdapter2(CloudAdapter):


def get_current(self) -> list:
if self.current_servers is None:
servers = self.cs.listVirtualMachines(
tags=[
{
"key": "scalr",
"value": self.name,
}
],
fetch_list=True,
)
self.current_servers = sorted(servers, key=lambda i: i["created"])
return self.current_servers

def ensure_running(self):
for server in self.get_current():
log.info(f"server {server['name']} status {server['state']}")
if server["state"] in ["stopping", "stopped"]:
if not self.dry_run:
self.cs.startVirtualMachine(id=server["id"])
log.info(f"Server {server['name']} started")
else:
log.info(f"Dry run server {server['name']} started")

def _get_service_offering(self, name):
def get_service_offering(self, name) -> dict:
res = self.cs.listServiceOfferings(name=name)
if not res:
raise Exception(f"Error: Service offering not found: {name}")
return res["serviceoffering"][0]

def _get_zone(self, name):
def get_zone(self, name) -> dict:
res = self.cs.listZones(name=name)
if not res:
raise Exception(f"Error: Zone not found: {name}")
return res["zone"][0]

def _get_template(self, name):
def get_template(self, name) -> dict:
for tf in ["community", "self"]:
res = self.cs.listTemplates(name=name, templatefilter=tf)
if res:
Expand All @@ -94,72 +37,73 @@ def _get_template(self, name):
raise Exception(f"Error: Template not found: {name}")
return res["template"][0]

def _get_deploy_params(self, lc):
user_data = lc.get("user_data")
def get_params(self, name: str) -> dict:
user_data = self.launch.get("user_data")
if user_data:
user_data = base64.b64encode(user_data.encode("utf-8"))

return {
"serviceofferingid": self._get_service_offering(
name=lc["service_offering"]
"displayname": name,
"serviceofferingid": self.get_service_offering(
name=self.launch["service_offering"]
).get("id"),
"affinitygroupnames": lc.get("affinity_groups"),
"securitygroupnames": lc.get("security_groups"),
"templateid": self._get_template(name=lc["template"]).get("id"),
"zoneid": self._get_zone(name=lc["zone"]).get("id"),
"affinitygroupnames": self.launch.get("affinity_groups"),
"securitygroupnames": self.launch.get("security_groups"),
"templateid": self.get_template(name=self.launch["template"]).get("id"),
"zoneid": self.get_zone(name=self.launch["zone"]).get("id"),
"userdata": user_data,
"keypair": lc.get("ssh_key"),
"group": lc.get("group"),
"rootdisksize": lc.get("root_disk_size"),
"keypair": self.launch.get("ssh_key"),
"group": self.launch.get("group"),
"rootdisksize": self.launch.get("root_disk_size"),
}

def scale_up(self, diff: int):
log.info(f"scaling up {diff}")

if diff > 0:
lc = self.launch_config.copy()
params = self._get_deploy_params(lc)

while diff > 0:

name = self.get_unique_name()
params.update(
{
"name": name,
}
)
lc_tags = lc.get("tags", {})
tags = [
def get_current_instances(self) -> List[GenericCloudInstance]:
filter_tag = f"scalr={self.filter}"
log.info(f"cloudstack: Querying with filter_tag: {filter_tag}")
servers = self.cs.listVirtualMachines(
tags=[
{
"key": "scalr",
"value": self.name,
"value": self.filter,
}
]
for key, value in lc_tags.items():
if key != self.name:
tags.append({"key": key, "value": value})
],
fetch_list=True,
)
return [
GenericCloudInstance(
id=server["id"],
name=server["name"],
status=server["state"].lower(),
)
for server in sorted(servers, key=lambda i: i["created"])
]

if not self.dry_run:
server = self.cs.deployVirtualMachine(**params)
self.cs.createTags(
resourceids=[
server["id"],
],
resourcetype="UserVm",
tags=tags,
)
log.info(f"Creating server name={name}")
else:
log.info(f"Dry run creating server name={name}")
diff -= 1
def ensure_instances_running(self):
for server in self.get_current_instances():
log.info(f"cloudstack: Server {server.name} status {server.status}")
if server.status in ["stopping", "stopped"]:
self.cs.startVirtualMachine(id=server.id)
log.info(f"cloudstack: Server {server.name} started")

def deploy_instance(self, name: str):
params = self.get_params(name=name)

tags = self.launch.get("tags", {})
tags = [
{
"key": "scalr",
"value": self.filter,
}
]
server = self.cs.deployVirtualMachine(**params)
self.cs.createTags(
resourceids=[
server["id"],
],
resourcetype="UserVm",
tags=tags,
)

def scale_down(self, diff: int):
log.info(f"scaling down {diff}")
while diff > 0:
server = self.get_selected_server()
if not self.dry_run:
self.cs.destroyVirtualMachine(id=server["id"])
log.info(f"Deleting server id={server['id']}")
else:
log.info(f"Dry run deleting server id={server['id']}")
diff -= 1
def destroy_instance(self, instance: GenericCloudInstance):
log.info(f"cloudstack: Destroying instance {instance}")
self.cs.destroyVirtualMachine(id=instance.id)
Loading