diff --git a/actions/auto_remediate_satellite.yaml b/actions/auto_remediate_satellite.yaml new file mode 100644 index 0000000..50065f5 --- /dev/null +++ b/actions/auto_remediate_satellite.yaml @@ -0,0 +1,24 @@ +--- +name: auto_remediate_satellite +runner_type: orquesta +description: "Remediate satellite hosts" +enabled: true +entry_point: workflows/auto_remediate_satellite.yaml +name: auto_remediate_satellite +pack: foreman +parameters: + server_name: + type: string + description: "Server name of host" + required: true + username: + type: string + description: "Username" + required: true + default: "{{ st2kv.system.linux.username }}" + password: + type: string + description: "Password" + required: true + secret: true + default: "{{ st2kv.system.linux.password | decrypt_kv }}" diff --git a/actions/workflows/auto_remediate_satellite.yaml b/actions/workflows/auto_remediate_satellite.yaml new file mode 100644 index 0000000..49e8f0b --- /dev/null +++ b/actions/workflows/auto_remediate_satellite.yaml @@ -0,0 +1,89 @@ +--- +version: 1.0 + +description: Remediate Satellite hosts that haven't checked in + +input: + - server_name + - username + - password + +output: + - username: <% ctx().username %> + - password: <% ctx().password %> + - server_name: <% ctx().server_name %> + +tasks: + + task1: + action: core.echo + input: + message: <% ctx().server_name %> + next: + - when: <% succeeded() %> + publish: <% result().stdout() %> + do: + - task2 + task2: + action: core.remote + input: + hosts: <% ctx().server_name %> + username: <% ctx().username %> + password: <% ctx().password %> + cmd: subscription-manager status + next: + - when: <% succeeded() %> + publish: <% result() %> + do: + - task3 + task3: + action: core.remote + input: + hosts: <% ctx().server_name %> + username: <% ctx().username %> + password: <% ctx().password %> + cmd: subscription-manager identity + next: + - when: <% succeeded() %> + publish: <% result() %> + do: + - task4 + + task4: + action: core.remote + input: + hosts: <% ctx().server_name %> + username: <% ctx().username %> + password: <% ctx().password %> + cmd: subscription-manager unregister + next: + - when: <% succeeded() %> + publish: <% result() %> + do: + - task5 + + task5: + action: core.remote + input: + hosts: <% ctx().server_name %> + username: <% ctx().username %> + password: <% ctx().password %> + cmd: subscription-manager register --org="EMS" --activationkey="RHEL_7" + next: + - when: <% succeeded() %> + publish: <% result() %> + do: + - task6 + + task6: + action: core.remote + input: + hosts: <% ctx().server_name %> + username: <% ctx().username %> + password: <% ctx().password %> + cmd: subscription-manager list --consumed + next: + - when: <% succeeded() %> + publish: <% result() %> + do: + - noop diff --git a/config.schema.yaml b/config.schema.yaml index 0517e0a..4f8b39b 100644 --- a/config.schema.yaml +++ b/config.schema.yaml @@ -1,6 +1,6 @@ --- foreman: - type: "object" + type: object required: true patternProperties: "^\\w+": @@ -8,7 +8,7 @@ foreman: additionalProperties: false connections: - type: "object" + type: object properties: server: type: string @@ -24,3 +24,12 @@ connections: required: true secret: true additionalProperties: false + +query: + type: object + required: true + properties: + days: + type: string + description: "Days since last response" + required: true diff --git a/rules/remediate_satellite.yaml b/rules/remediate_satellite.yaml new file mode 100644 index 0000000..0b0bbdb --- /dev/null +++ b/rules/remediate_satellite.yaml @@ -0,0 +1,14 @@ +--- +name: "remediate_satellite" +pack: "foreman" +description: "Remediate Satellite hosts that haven't checked in" +enabled : true + +trigger: + type: "foreman.auto_remediate_satellite" + parameters: {} + +action: + ref: "foreman.auto_remediate_satellite" + parameters: + server_name: "{{ trigger.server_name }}" diff --git a/sensors/foreman_auto_remediate_sensor.py b/sensors/foreman_auto_remediate_sensor.py new file mode 100644 index 0000000..c375355 --- /dev/null +++ b/sensors/foreman_auto_remediate_sensor.py @@ -0,0 +1,94 @@ +import json +import requests +from st2reactor.sensor.base import PollingSensor +from datetime import datetime, timedelta, date + + +class ForemanAutoRemediateSensor(PollingSensor): + def __init__(self, sensor_service, config=None, poll_interval=None): + + super(ForemanAutoRemediateSensor, self).__init__( + sensor_service=sensor_service, config=config, poll_interval=poll_interval + ) + self._logger = self._sensor_service.get_logger(__name__) + self._trigger_ref = "foreman.auto_remediate_satellite" + + def setup(self): + + self._USERNAME = self._config["foreman"]["dev"]["username"] + self._PASSWORD = self._config["foreman"]["dev"]["password"] + self._SERVER = self._config["foreman"]["dev"]["server"] + self._SSL_VERIFY = False + self._query = self._config["query"]["days"] + self._url = "http://{}/".format(self._SERVER) + self._url = self._url + "api/hosts" + + def poll(self): + + session = requests.Session() + session.auth = (self._USERNAME, self._PASSWORD) + session.verify = self._SSL_VERIFY + response = session.get(self._url) + if response.status_code != 200: + print(response.raise_for_status) + exit() + + result = response.json() + result_json = json.dumps(result) + parsed = json.loads(result_json) + + output_parse = json.dumps(parsed, indent=4, sort_keys=True) + parsed_list = parsed["results"] + + query_date = int(self._query) + + count = 0 + + for obj in parsed_list: + + if "subscription_facet_attributes" in obj: + server_checkin_date_uni = obj["subscription_facet_attributes"][ + "last_checkin" + ] + # print(type(server_checkin_date)) + query_checkin_date = date.today() - timedelta(days=query_date) + # print(type(query_checkin_date)) + + server_checkin_date = datetime.strptime( + server_checkin_date_uni.split()[0], "%Y-%m-%d" + ).date() + # print(type(server_checkin_date)) + + if query_checkin_date < server_checkin_date: + print("This server responded within the query timeframe") + else: + # print("This server didn't respond since before query checkin date") + self.dispatch_trigger(obj["certname"], server_checkin_date) + count += 1 + else: + print("Subscription facet attributes don't exist") + print("This is count: " + str(count)) + + def dispatch_trigger(self, server_name, last_checkin): + + trigger = self._trigger_ref + payload = {"server_name": server_name, "last_checkin": last_checkin.strftime("%m/%d/%Y")} + + self.sensor_service.dispatch(trigger=trigger, payload=payload) + + def cleanup(self): + # This is called when the st2 system goes down. You can perform cleanup operations like + # closing the connections to external system here. + pass + + def add_trigger(self, trigger): + # This method is called when trigger is created + pass + + def update_trigger(self, trigger): + # This method is called when trigger is updated + pass + + def remove_trigger(self, trigger): + # This method is called when trigger is deleted + pass diff --git a/sensors/foreman_auto_remediate_sensor.yaml b/sensors/foreman_auto_remediate_sensor.yaml new file mode 100644 index 0000000..bf07024 --- /dev/null +++ b/sensors/foreman_auto_remediate_sensor.yaml @@ -0,0 +1,17 @@ +--- + class_name: "ForemanAutoRemediateSensor" + entry_point: "foreman_auto_remediate_sensor.py" + description: "Sensor to check to make sure servers are responding" + poll_interval: 100000 + trigger_types: + - + name: "auto_remediate_satellite" + description: "Trigger to remediate hosts that aren't responding" + + payload_schema: + type: "object" + properties: + server_name: + type: "string" + last_checkin: + type: "string"