Skip to content
Closed
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
6 changes: 6 additions & 0 deletions virtana_pack/actions/echo_alert.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from st2common.runners.base_action import Action

class EchoAlertAction(Action):
def run(self, text):
self.logger.info(f"Echo alert received: {text}")
return text
12 changes: 12 additions & 0 deletions virtana_pack/actions/echo_alert.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
name: "echo_alert"
description: "Echoes the input text"
runner_type: "python-script"
entry_point: "echo_alert.py"
enabled: true
parameters:
text:
type: "string"
required: true
description: "Text message to echo"
tags:
- name: "dev"
55 changes: 55 additions & 0 deletions virtana_pack/actions/restart_vm.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import ansible_runner
from st2common.runners.base_action import Action


class RestartVMAction(Action):
def run(self, vcenter_hostname, vm_name):
try:
# Validate both parameters are provided as strings
if not vcenter_hostname or not isinstance(vcenter_hostname, str):
raise ValueError("vcenter_hostname must be a non-empty string.")

if not vm_name or not isinstance(vm_name, str):
raise ValueError("vm_name must be a non-empty string.")

# Retrieve credentials from stackstorm datastore
vcenter_username = self.action_service.get_value('vcenter.username', decrypt=True, local=False)
vcenter_password = self.action_service.get_value('vcenter.password', decrypt=True, local=False)

if not vcenter_username or not vcenter_password:
raise Exception("vCenter credentials are missing in the datastore.")

# Prepare the extra variables for the Ansible playbook
extra_vars = {
"vcenter_hostname": vcenter_hostname,
"vcenter_username": vcenter_username,
"vcenter_password": vcenter_password,
"vm_name": vm_name,
"validate_certs": False
}

# Path to the Ansible playbook
playbook_path = '/opt/stackstorm/packs/virtana_pack/ansible/restart_vm.yml'

# Run the Ansible playbook using the provided credentials and parameters
runner = ansible_runner.run(
private_data_dir='.',
playbook=playbook_path,
extravars=extra_vars
)

# Check the result of the playbook execution
if runner.status == "failed":
raise Exception(f"Ansible playbook failed with status: {runner.status}")

# Return the result of the operation
return {
"status": "VM restarted successfully",
"vm_name": vm_name,
"vcenter": vcenter_hostname,
"ansible_result": runner.stats
}

except Exception as e:
# Raise exception
raise
18 changes: 18 additions & 0 deletions virtana_pack/actions/restart_vm.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
name: "restart_vm"
runner_type: "python-script"
description: "Restart a VM in vSphere based on vcenter_hostname and vm_name inputs"
enabled: true
entry_point: "restart_vm.py"

parameters:
vcenter_hostname:
type: "string"
required: true
description: "vCenter hostname (e.g., vcenter.example.com)"

vm_name:
type: "string"
required: true
description: "Name of the VM to restart"
tags:
- name: "dev"
97 changes: 97 additions & 0 deletions virtana_pack/ansible/restart_vm.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
- name: Restart VM
hosts: localhost
gather_facts: no
collections:
- community.vmware

tasks:

# Authenticate with vCenter using REST API
- name: Authenticate with vCenter
uri:
url: "https://{{ vcenter_hostname }}/rest/com/vmware/cis/session"
method: POST
user: "{{ vcenter_username }}"
password: "{{ vcenter_password }}"
force_basic_auth: yes
validate_certs: "{{ validate_certs }}"
status_code: 200
return_content: yes
register: login_response
no_log: true

# Save the session token returned from authentication
- name: Save session token
set_fact:
session_token: "{{ login_response.json.value }}"

# Fetch list of all VMs from vCenter
- name: Get list of VMs
uri:
url: "https://{{ vcenter_hostname }}/rest/vcenter/vm"
method: GET
headers:
vmware-api-session-id: "{{ session_token }}"
validate_certs: "{{ validate_certs }}"
status_code: 200
register: vm_list
no_log: true

# Identify VM ID by matching VM name
- name: Find VM ID by name
set_fact:
vm_id: "{{ item.vm }}"
loop: "{{ vm_list.json.value }}"
when: item.name == vm_name

# Fail the play if VM not found
- name: Fail if VM not found
fail:
msg: "VM not found."
when: vm_id is not defined

# Power off the VM
- name: Stop VM
uri:
url: "https://{{ vcenter_hostname }}/rest/vcenter/vm/{{ vm_id }}/power/stop"
method: POST
headers:
vmware-api-session-id: "{{ session_token }}"
validate_certs: "{{ validate_certs }}"
status_code: 200
timeout: 60
register: stop_result

# Wait until the VM is fully powered off
- name: Wait for power off
uri:
url: "https://{{ vcenter_hostname }}/rest/vcenter/vm/{{ vm_id }}/power"
method: GET
headers:
vmware-api-session-id: "{{ session_token }}"
validate_certs: "{{ validate_certs }}"
register: power_status
until: power_status.json.value.state == "POWERED_OFF"
retries: 10
delay: 10
no_log: true

# Power on the VM again
- name: Start VM
uri:
url: "https://{{ vcenter_hostname }}/rest/vcenter/vm/{{ vm_id }}/power/start"
method: POST
headers:
vmware-api-session-id: "{{ session_token }}"
validate_certs: "{{ validate_certs }}"
status_code: 200
timeout: 60
register: start_result
retries: 5
delay: 10
until: start_result.status == 200

# Output final message on success
- name: Print result
debug:
msg: "VM restarted successfully."
Binary file added virtana_pack/icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
13 changes: 13 additions & 0 deletions virtana_pack/pack.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
ref: virtana_pack
name: "Virtana Platform Pack"
description: "Register Remote Stackstorm to Virtana Platform"
keywords:
- StackStorm
- Global View
- Actions
version: "1.0.1"
author: "Virtana"
email: "support@virtana.com"
python_versions:
- "3"
4 changes: 4 additions & 0 deletions virtana_pack/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
requests
ansible
ansible-runner
pyvmomi
46 changes: 46 additions & 0 deletions virtana_pack/sensors/action_execution_polling.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import logging
from st2reactor.sensor.base import PollingSensor
from lib.action_executor import process_queued_actions

# Configure Logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)


class ActionExecutionPolling(PollingSensor):
def __init__(self, sensor_service, config=None, poll_interval=30):
super(ActionExecutionPolling, self).__init__(sensor_service=sensor_service,
config=config,
poll_interval=poll_interval)
self.pack_name = config.get("pack_name", "virtana_pack")
self.sensor_name = self.__class__.__name__

def setup(self):
"""Called when the sensor starts."""
logger.info(f"Sensor '{self.sensor_name}' for '{self.pack_name}' is initialized.")

def poll(self):
"""Runs at defined intervals and calls process_queued_actions()."""
logger.info("Polling for queued actions...")
success, results = process_queued_actions(self.config)

if success:
logger.info(f"Processed queued actions successfully: {results}")
else:
logger.error(f"Failed to process queued actions: {results}")

def cleanup(self):
"""Called when the sensor stops."""
logger.info("Cleaning up ActionExecutionPolling")

def add_trigger(self, trigger):
"""Called when a trigger is added."""
logger.info(f"Trigger added: {trigger}")

def update_trigger(self, trigger):
"""Called when an existing trigger is updated."""
logger.info(f"Trigger updated: {trigger}")

def remove_trigger(self, trigger):
"""Called when a trigger is removed."""
logger.info(f"Trigger removed: {trigger}")
5 changes: 5 additions & 0 deletions virtana_pack/sensors/action_execution_polling.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class_name: "ActionExecutionPolling"
entry_point: "action_execution_polling.py"
description: "A sensor that polls queued actions for executions from VP platform at defined intervals."
poll_interval: 20
enabled: true
46 changes: 46 additions & 0 deletions virtana_pack/sensors/action_status_polling.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import logging
from st2reactor.sensor.base import PollingSensor
from lib.update_and_cleanup_executions import update_and_cleanup_executions

# Configure Logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)


class ActionStatusPolling(PollingSensor):
def __init__(self, sensor_service, config=None, poll_interval=30):
super(ActionStatusPolling, self).__init__(sensor_service=sensor_service,
config=config,
poll_interval=poll_interval)
self.pack_name = config.get("pack_name", "virtana_pack")
self.sensor_name = self.__class__.__name__

def setup(self):
"""Called when the sensor starts."""
logger.info(f"Sensor '{self.sensor_name}' for '{self.pack_name}' is initialized.")

def poll(self):
"""Runs at defined intervals and calls process_queued_actions()."""
logger.info("Polling for queued actions statuses...")
success, results = update_and_cleanup_executions(self.config)

if success:
logger.info(f"Processed queued actions successfully: {results}")
else:
logger.error(f"Failed to process queued actions: {results}")

def cleanup(self):
"""Called when the sensor stops."""
logger.info("Cleaning up ActionStatusPolling")

def add_trigger(self, trigger):
"""Called when a trigger is added."""
logger.info(f"Trigger added: {trigger}")

def update_trigger(self, trigger):
"""Called when an existing trigger is updated."""
logger.info(f"Trigger updated: {trigger}")

def remove_trigger(self, trigger):
"""Called when a trigger is removed."""
logger.info(f"Trigger removed: {trigger}")
5 changes: 5 additions & 0 deletions virtana_pack/sensors/action_status_polling.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class_name: "ActionStatusPolling"
entry_point: "action_status_polling.py"
description: "A sensor that polls actions status submitted for executions from VP platform at defined intervals."
poll_interval: 20
enabled: true
Empty file.
Loading
Loading