diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 7d8302e..9e85793 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -5,13 +5,25 @@ SAP Operations Collection Release Notes
.. contents:: Topics
-v1.21.0
+v1.22.0
=======
+Release Summary
+---------------
+
+Feature release
+
New Modules
-----------
-- sap.sap_operations.cf_marketplace_info - Fetches Cloud Foundry marketplace service offerings
+- sap.sap_operations.cf_service_instance - Manage Cloud Foundry service instances
+- sap.sap_operations.cf_service_instance_info - Fetch information about Cloud Foundry service instance
+- sap.sap_operations.cf_service_instances_info - Fetch information about Cloud Foundry service instances
+- sap.sap_operations.cf_service_plans_info - Fetch information about Cloud Foundry service plans
+- sap.sap_operations.cf_spaces_info - Fetch information about Cloud Foundry spaces
+
+v1.21.0
+=======
v1.20.0
=======
diff --git a/README.md b/README.md
index 4bca8c3..70cce64 100644
--- a/README.md
+++ b/README.md
@@ -25,6 +25,14 @@ If not, see .
Added roles to manage SAP JVM, SAP Cloud Connector and Cloud Foundry cli
+Added modules to manage SAP BTP Cloud Foundry.
+
+ - sap.sap_operations.cf_service_instance
+ - sap.sap_operations.cf_service_instance_info
+ - sap.sap_operations.cf_service_instances_info
+ - sap.sap_operations.cf_service_plans_info
+ - sap.sap_operations.cf_spaces_info
+
# Ansible Collection - sap.sap_operations
This collection contains modules and plugins to assist in automating SAP day 2 operations with Ansible.
diff --git a/galaxy.yml b/galaxy.yml
index 295cd81..84fb7b0 100644
--- a/galaxy.yml
+++ b/galaxy.yml
@@ -24,7 +24,7 @@ namespace: sap
name: sap_operations
-version: 1.21.0
+version: 1.22.0
readme: README.md
diff --git a/meta/runtime.yml b/meta/runtime.yml
index 78c2a84..4a99a66 100644
--- a/meta/runtime.yml
+++ b/meta/runtime.yml
@@ -24,3 +24,8 @@ requires_ansible: ">=2.14.0"
action_groups:
cf:
- sap.sap_operations.cf_marketplace_info
+ - sap.sap_operations.cf_service_instance
+ - sap.sap_operations.cf_service_instance_info
+ - sap.sap_operations.cf_service_instances_info
+ - sap.sap_operations.cf_plans_info
+ - sap.sap_operations.cf_spaces_info
diff --git a/plugins/action/cf_marketplace_info.py b/plugins/action/cf_marketplace_info.py
index 6c0dba4..cc8ea90 100644
--- a/plugins/action/cf_marketplace_info.py
+++ b/plugins/action/cf_marketplace_info.py
@@ -79,9 +79,10 @@ def run_method(
if headers is None:
headers = {"Content-Type": "application/x-www-form-urlencoded"}
# headers_command = [f'-H "{k}:{v}"' for k, v in headers]
+ data_string = json.dumps(data)
command_run = subprocess.run(
[
- f'cf curl "{path}" -X {method} -d "{json.dumps(data)}"',
+ f"""cf curl "{path}" -X {method} -d '{data_string}'""",
],
# + headers_command,
shell=True, # nosec B602
@@ -99,7 +100,6 @@ def run_method(
def run_action(client: CFClient) -> dict:
-
rc = client.authenticate()
if rc.get("failed"):
return rc
diff --git a/plugins/action/cf_service_instance.py b/plugins/action/cf_service_instance.py
new file mode 100644
index 0000000..c69bfc0
--- /dev/null
+++ b/plugins/action/cf_service_instance.py
@@ -0,0 +1,266 @@
+# -*- coding: utf-8 -*-
+#
+# SPDX-License-Identifier: GPL-3.0-only
+# SPDX-FileCopyrightText: 2024 Red Hat, Project Atmosphere
+#
+# Copyright 2024 Red Hat, Project Atmosphere
+#
+# This program is free software: you can redistribute it and/or modify it under the terms of the GNU
+# General Public License as published by the Free Software Foundation, version 3 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# You should have received a copy of the GNU General Public License along with this program.
+# If not, see .
+
+from __future__ import absolute_import, division, print_function
+import tempfile
+from ansible.errors import AnsibleActionFail
+
+__metaclass__ = type
+import json
+from ansible.plugins.action import ActionBase
+
+from ansible_collections.sap.sap_operations.plugins.action.cf_marketplace_info import (
+ CFClient,
+)
+from ansible_collections.sap.sap_operations.plugins.action.cf_service_plans_info import (
+ run_action as get_service_plans,
+)
+
+from ansible_collections.sap.sap_operations.plugins.action.cf_spaces_info import (
+ run_action as get_spaces,
+)
+
+
+def validate_service_plan_name(client: CFClient, name: str, service_plan: str) -> dict:
+ result = get_service_plans(client, service_offering_names=[name])
+ if result["failed"]:
+ return result
+
+ return {
+ "failed": service_plan
+ not in [sp["name"] for sp in result["cf_service_plans_info"]]
+ }
+
+
+def run_action( # noqa C901
+ # TODO: simplify function
+ client: CFClient,
+ name: str,
+ service: str,
+ state: str,
+ space_name: str,
+ parameters: dict,
+ service_plan_name: str,
+ metadata: dict,
+) -> dict:
+ rc = client.authenticate()
+ if rc.get("failed"):
+ return rc
+
+ rc, stdout, stderr = client.run_method(
+ path="/v3/service_instances",
+ method="GET",
+ headers={},
+ data={},
+ )
+
+ if rc or stderr:
+ return {"failed": True, "msg": stdout}
+
+ service_instances = json.loads(stdout)
+
+ if "errors" in service_instances:
+ return {
+ "failed": True,
+ "msg": "Error retrieving service instances",
+ "errors": service_instances["errors"],
+ }
+ service_instance = None
+
+ for si in service_instances["resources"]:
+ if name and si["name"] == name:
+ service_instance = si
+
+ if state == "absent" and service_instance:
+ service_instance_guid = service_instance["guid"]
+ rc, stdout, stderr = client.run_method(
+ path=f"/v3/service_instances/{service_instance_guid}",
+ method="DELETE",
+ headers={},
+ data={},
+ )
+ if rc:
+ return {
+ "failed": True,
+ "msg": "Could not delete service_instance",
+ "stdout": stdout,
+ }
+ return dict(failed=False, changed=True)
+
+ if state == "absent" and not service_instance:
+ return {"failed": False, "changed": False}
+
+ if state == "present" and service_instance:
+ return {"failed": False, "changed": False}
+
+ if state == "present" and not service_instance:
+ data = {}
+ data["type"] = "managed"
+ data["name"] = name
+ data["parameters"] = parameters
+ data["metadata"] = metadata
+ service_plans = get_service_plans(client, service_offering_names=[service])
+ service_plan = [
+ sp
+ for sp in service_plans["cf_service_plans_info"]
+ if sp["name"] == service_plan_name
+ ][0]
+
+ spaces = get_spaces(client)
+ space = [sp for sp in spaces["cf_spaces_info"] if sp["name"] == space_name][0]
+
+ data["relationships"] = {}
+ data["relationships"]["service_plan"] = {}
+ data["relationships"]["service_plan"]["data"] = {}
+ data["relationships"]["service_plan"]["data"]["guid"] = service_plan["guid"]
+
+ data["relationships"]["space"] = {}
+ data["relationships"]["space"]["data"] = {}
+ data["relationships"]["space"]["data"]["guid"] = space["guid"]
+
+ rc, stdout, stderr = client.run_method(
+ path="/v3/service_instances/",
+ method="POST",
+ # headers={"Content-type": "application/json"},
+ data=data,
+ )
+ if rc or stderr or "errors" in stdout:
+ return {
+ "failed": True,
+ "msg": "Could not create service_instance",
+ "stdout": stdout,
+ "stderr": stderr,
+ }
+ # return get_service_instance_info(client, name=name)
+ return {"failed": False, "stdout": stdout, "stderr": stderr}
+
+
+class CFServiceInstanceModule(ActionBase):
+ _VALID_ARGS = frozenset(
+ [
+ "username",
+ "password",
+ "api_endpoint",
+ "name",
+ "service",
+ "state",
+ "space",
+ "service_plan",
+ "parameters",
+ "metadata",
+ ]
+ )
+ argument_spec = dict(
+ username=dict(type="str", required=False),
+ password=dict(type="str", required=False),
+ api_endpoint=dict(type="str", required=False),
+ name=dict(type="str", required=True),
+ service=dict(type="str", required=True),
+ state=dict(
+ type="str", required=False, default="present", choices=["present", "absent"]
+ ),
+ space=dict(type="str", required=True),
+ service_plan=dict(type="str", required=False),
+ parameters=dict(type="dict", required=False),
+ metadata=dict(type="dict", required=False),
+ )
+ required_together = [
+ [
+ "username",
+ "password",
+ "api_endpoint",
+ ],
+ ]
+ mutually_exclusive = []
+ required_one_of = [
+ [
+ "username",
+ "password",
+ "api_endpoint",
+ ],
+ ]
+
+ def __init__(
+ self, task, connection, play_context, loader, templar, shared_loader_obj
+ ):
+ """Initialize action module."""
+ super().__init__(
+ task, connection, play_context, loader, templar, shared_loader_obj
+ )
+
+ def run(self, tmp=None, task_vars=None):
+ validation_results, _ignore = self.validate_argument_spec(
+ argument_spec=self.argument_spec,
+ required_together=self.required_together,
+ mutually_exclusive=self.mutually_exclusive,
+ required_one_of=self.required_one_of,
+ )
+
+ if validation_results.error_messages:
+ raise AnsibleActionFail(
+ message="Validation failed: {0}".format(
+ ", ".join(validation_results.error_messages)
+ ),
+ )
+ api_endpoint = self._task.args.get("api_endpoint")
+ username = self._task.args.get("username")
+ password = self._task.args.get("password")
+ name = self._task.args.get("name")
+ service = self._task.args.get("service")
+ state = self._task.args.get("state", "present")
+ space_name = self._task.args.get("space")
+ parameters = self._task.args.get("parameters", {})
+ service_plan = self._task.args.get("service_plan")
+ metadata = self._task.args.get("metadata", {})
+
+ with tempfile.TemporaryDirectory() as cf_home:
+ client = CFClient(
+ api_endpoint=api_endpoint,
+ username=username,
+ password=password,
+ cf_home=cf_home,
+ )
+ if state == "present":
+ validation_results = validate_service_plan_name(
+ client, name=service, service_plan=service_plan
+ )
+ if validation_results["failed"]:
+ return {
+ "failed": True,
+ "msg": f"Service plan name {service_plan=} is not correct for service name {service=}",
+ }
+
+ return run_action(
+ client,
+ name=name,
+ service=service,
+ state=state,
+ space_name=space_name,
+ parameters=parameters,
+ service_plan_name=service_plan,
+ metadata=metadata,
+ )
+
+
+class ActionModule(CFServiceInstanceModule):
+ pass
diff --git a/plugins/action/cf_service_instance_info.py b/plugins/action/cf_service_instance_info.py
new file mode 100644
index 0000000..6a995d6
--- /dev/null
+++ b/plugins/action/cf_service_instance_info.py
@@ -0,0 +1,146 @@
+# -*- coding: utf-8 -*-
+#
+# SPDX-License-Identifier: GPL-3.0-only
+# SPDX-FileCopyrightText: 2024 Red Hat, Project Atmosphere
+#
+# Copyright 2024 Red Hat, Project Atmosphere
+#
+# This program is free software: you can redistribute it and/or modify it under the terms of the GNU
+# General Public License as published by the Free Software Foundation, version 3 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# You should have received a copy of the GNU General Public License along with this program.
+# If not, see .
+
+from __future__ import absolute_import, division, print_function
+import tempfile
+from ansible.errors import AnsibleActionFail
+
+__metaclass__ = type
+import json
+from ansible.plugins.action import ActionBase
+
+from ansible_collections.sap.sap_operations.plugins.action.cf_marketplace_info import (
+ CFClient,
+)
+
+
+def run_action(client: CFClient, name: str = "", guid: str = "") -> dict:
+
+ rc = client.authenticate()
+ if rc.get("failed"):
+ return rc
+
+ rc, stdout, stderr = client.run_method(
+ path="/v3/service_instances",
+ method="GET",
+ headers={},
+ data={},
+ )
+
+ if rc or stderr:
+ return {"failed": True, "msg": stdout}
+
+ service_instances = json.loads(stdout)
+
+ if "errors" in service_instances:
+ return {
+ "failed": True,
+ "msg": "Error retrieving service instances",
+ "errors": service_instances["errors"],
+ }
+ for service_instance in service_instances["resources"]:
+ if name and service_instance["name"] == name:
+ return dict(
+ failed=False,
+ changed=False,
+ cf_service_instance_info=service_instance,
+ )
+ if guid and service_instance["guid"] == guid:
+ return dict(
+ failed=False,
+ changed=False,
+ cf_service_instance_info=service_instance,
+ )
+
+ return dict(
+ failed=True,
+ msg="Service instance not found",
+ )
+
+
+class CFServiceInstanceInfoModule(ActionBase):
+ _VALID_ARGS = frozenset(["username", "password", "api_endpoint", "name", "guid"])
+ argument_spec = dict(
+ username=dict(type="str", required=False),
+ password=dict(type="str", required=False),
+ api_endpoint=dict(type="str", required=False),
+ name=dict(type="str", required=False),
+ guid=dict(type="str", required=False),
+ )
+ required_together = [
+ [
+ "username",
+ "password",
+ "api_endpoint",
+ ],
+ ]
+ mutually_exclusive = [["name", "guid"]]
+ required_one_of = [
+ [
+ "username",
+ "password",
+ "api_endpoint",
+ ],
+ ["name", "guid"],
+ ]
+
+ def __init__(
+ self, task, connection, play_context, loader, templar, shared_loader_obj
+ ):
+ """Initialize action module."""
+ super().__init__(
+ task, connection, play_context, loader, templar, shared_loader_obj
+ )
+
+ def run(self, tmp=None, task_vars=None):
+ validation_results, _ignore = self.validate_argument_spec(
+ argument_spec=self.argument_spec,
+ required_together=self.required_together,
+ mutually_exclusive=self.mutually_exclusive,
+ required_one_of=self.required_one_of,
+ )
+
+ if validation_results.error_messages:
+ raise AnsibleActionFail(
+ message="Validation failed: {0}".format(
+ ", ".join(validation_results.error_messages)
+ ),
+ )
+ api_endpoint = self._task.args.get("api_endpoint")
+ username = self._task.args.get("username")
+ password = self._task.args.get("password")
+ name = self._task.args.get("name", "")
+ guid = self._task.args.get("guid", "")
+
+ with tempfile.TemporaryDirectory() as cf_home:
+ client = CFClient(
+ api_endpoint=api_endpoint,
+ username=username,
+ password=password,
+ cf_home=cf_home,
+ )
+ return run_action(client, name=name, guid=guid)
+
+
+class ActionModule(CFServiceInstanceInfoModule):
+ pass
diff --git a/plugins/action/cf_service_instances_info.py b/plugins/action/cf_service_instances_info.py
new file mode 100644
index 0000000..2f2a7c0
--- /dev/null
+++ b/plugins/action/cf_service_instances_info.py
@@ -0,0 +1,127 @@
+# -*- coding: utf-8 -*-
+#
+# SPDX-License-Identifier: GPL-3.0-only
+# SPDX-FileCopyrightText: 2024 Red Hat, Project Atmosphere
+#
+# Copyright 2024 Red Hat, Project Atmosphere
+#
+# This program is free software: you can redistribute it and/or modify it under the terms of the GNU
+# General Public License as published by the Free Software Foundation, version 3 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# You should have received a copy of the GNU General Public License along with this program.
+# If not, see .
+
+from __future__ import absolute_import, division, print_function
+import tempfile
+from ansible.errors import AnsibleActionFail
+
+__metaclass__ = type
+import json
+from ansible.plugins.action import ActionBase
+
+from ansible_collections.sap.sap_operations.plugins.action.cf_marketplace_info import (
+ CFClient,
+)
+
+
+def run_action(client: CFClient) -> dict:
+
+ rc = client.authenticate()
+ if rc.get("failed"):
+ return rc
+
+ rc, stdout, stderr = client.run_method(
+ path="/v3/service_instances",
+ method="GET",
+ headers={},
+ data={},
+ )
+
+ if rc or stderr:
+ return {"failed": True, "msg": stdout}
+
+ result = json.loads(stdout)
+
+ if "errors" in result:
+ return {
+ "failed": True,
+ "msg": "Error retrieving service instances",
+ "errors": result["errors"],
+ }
+
+ return dict(
+ failed=False, changed=False, cf_service_instances_info=result["resources"]
+ )
+
+
+class CFServiceInstancesInfoModule(ActionBase):
+ _VALID_ARGS = frozenset(["username", "password", "api_endpoint"])
+ argument_spec = dict(
+ username=dict(type="str", required=False),
+ password=dict(type="str", required=False),
+ api_endpoint=dict(type="str", required=False),
+ )
+ required_together = [
+ [
+ "username",
+ "password",
+ "api_endpoint",
+ ],
+ ]
+ mutually_exclusive = []
+ required_one_of = [
+ [
+ "username",
+ "password",
+ "api_endpoint",
+ ]
+ ]
+
+ def __init__(
+ self, task, connection, play_context, loader, templar, shared_loader_obj
+ ):
+ """Initialize action module."""
+ super().__init__(
+ task, connection, play_context, loader, templar, shared_loader_obj
+ )
+
+ def run(self, tmp=None, task_vars=None):
+ validation_results, _ignore = self.validate_argument_spec(
+ argument_spec=self.argument_spec,
+ required_together=self.required_together,
+ mutually_exclusive=self.mutually_exclusive,
+ required_one_of=self.required_one_of,
+ )
+
+ if validation_results.error_messages:
+ raise AnsibleActionFail(
+ message="Validation failed: {0}".format(
+ ", ".join(validation_results.error_messages)
+ ),
+ )
+ api_endpoint = self._task.args.get("api_endpoint")
+ username = self._task.args.get("username")
+ password = self._task.args.get("password")
+
+ with tempfile.TemporaryDirectory() as cf_home:
+ client = CFClient(
+ api_endpoint=api_endpoint,
+ username=username,
+ password=password,
+ cf_home=cf_home,
+ )
+ return run_action(client)
+
+
+class ActionModule(CFServiceInstancesInfoModule):
+ pass
diff --git a/plugins/action/cf_service_plans_info.py b/plugins/action/cf_service_plans_info.py
new file mode 100644
index 0000000..baa0728
--- /dev/null
+++ b/plugins/action/cf_service_plans_info.py
@@ -0,0 +1,132 @@
+# -*- coding: utf-8 -*-
+#
+# SPDX-License-Identifier: GPL-3.0-only
+# SPDX-FileCopyrightText: 2024 Red Hat, Project Atmosphere
+#
+# Copyright 2024 Red Hat, Project Atmosphere
+#
+# This program is free software: you can redistribute it and/or modify it under the terms of the GNU
+# General Public License as published by the Free Software Foundation, version 3 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# You should have received a copy of the GNU General Public License along with this program.
+# If not, see .
+
+from __future__ import absolute_import, division, print_function
+import tempfile
+from ansible.errors import AnsibleActionFail
+
+__metaclass__ = type
+import json
+from ansible.plugins.action import ActionBase
+
+from ansible_collections.sap.sap_operations.plugins.action.cf_marketplace_info import (
+ CFClient,
+)
+
+
+def run_action(client: CFClient, service_offering_names: list[str]) -> dict:
+ rc = client.authenticate()
+ if rc.get("failed"):
+ return rc
+ parameters_string = ""
+ if service_offering_names:
+ service_offering_names_string = ",".join(service_offering_names)
+ parameters_string += f"service_offering_names={service_offering_names_string},"
+
+ rc, stdout, stderr = client.run_method(
+ path=f"/v3/service_plans?{parameters_string}",
+ method="GET",
+ headers={},
+ data={},
+ )
+
+ if rc or stderr:
+ return {"failed": True, "msg": stdout}
+
+ result = json.loads(stdout)
+
+ if "errors" in result:
+ return {
+ "failed": True,
+ "msg": "Error retrieving service plans",
+ "errors": result["errors"],
+ }
+
+ return dict(failed=False, changed=False, cf_service_plans_info=result["resources"])
+
+
+class CFServicePlansInfoModule(ActionBase):
+ _VALID_ARGS = frozenset(
+ ["username", "password", "api_endpoint", "service_offering_names"]
+ )
+ argument_spec = dict(
+ username=dict(type="str", required=False),
+ password=dict(type="str", required=False),
+ api_endpoint=dict(type="str", required=False),
+ service_offering_names=dict(type="list", elements="str", required=False),
+ )
+ required_together = [
+ [
+ "username",
+ "password",
+ "api_endpoint",
+ ],
+ ]
+ mutually_exclusive = []
+ required_one_of = [
+ [
+ "username",
+ "password",
+ "api_endpoint",
+ ]
+ ]
+
+ def __init__(
+ self, task, connection, play_context, loader, templar, shared_loader_obj
+ ):
+ """Initialize action module."""
+ super().__init__(
+ task, connection, play_context, loader, templar, shared_loader_obj
+ )
+
+ def run(self, tmp=None, task_vars=None):
+ validation_results, _ignore = self.validate_argument_spec(
+ argument_spec=self.argument_spec,
+ required_together=self.required_together,
+ mutually_exclusive=self.mutually_exclusive,
+ required_one_of=self.required_one_of,
+ )
+
+ if validation_results.error_messages:
+ raise AnsibleActionFail(
+ message="Validation failed: {0}".format(
+ ", ".join(validation_results.error_messages)
+ ),
+ )
+ api_endpoint = self._task.args.get("api_endpoint")
+ username = self._task.args.get("username")
+ password = self._task.args.get("password")
+ service_offering_names = self._task.args.get("service_offering_names", [])
+
+ with tempfile.TemporaryDirectory() as cf_home:
+ client = CFClient(
+ api_endpoint=api_endpoint,
+ username=username,
+ password=password,
+ cf_home=cf_home,
+ )
+ return run_action(client, service_offering_names=service_offering_names)
+
+
+class ActionModule(CFServicePlansInfoModule):
+ pass
diff --git a/plugins/action/cf_spaces_info.py b/plugins/action/cf_spaces_info.py
new file mode 100644
index 0000000..17d4dce
--- /dev/null
+++ b/plugins/action/cf_spaces_info.py
@@ -0,0 +1,124 @@
+# -*- coding: utf-8 -*-
+#
+# SPDX-License-Identifier: GPL-3.0-only
+# SPDX-FileCopyrightText: 2024 Red Hat, Project Atmosphere
+#
+# Copyright 2024 Red Hat, Project Atmosphere
+#
+# This program is free software: you can redistribute it and/or modify it under the terms of the GNU
+# General Public License as published by the Free Software Foundation, version 3 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# You should have received a copy of the GNU General Public License along with this program.
+# If not, see .
+
+from __future__ import absolute_import, division, print_function
+import tempfile
+from ansible.errors import AnsibleActionFail
+
+__metaclass__ = type
+import json
+from ansible.plugins.action import ActionBase
+
+from ansible_collections.sap.sap_operations.plugins.action.cf_marketplace_info import (
+ CFClient,
+)
+
+
+def run_action(client: CFClient) -> dict:
+ rc = client.authenticate()
+ if rc.get("failed"):
+ return rc
+
+ rc, stdout, stderr = client.run_method(
+ path="/v3/spaces",
+ method="GET",
+ headers={},
+ data={},
+ )
+
+ if rc or stderr:
+ return {"failed": True, "msg": stdout}
+
+ result = json.loads(stdout)
+
+ if "errors" in result:
+ return {
+ "failed": True,
+ "msg": "Error retrieving spaces instances",
+ "errors": result["errors"],
+ }
+
+ return dict(failed=False, changed=False, cf_spaces_info=result["resources"])
+
+
+class CFSpacesInfo(ActionBase):
+ _VALID_ARGS = frozenset(["username", "password", "api_endpoint"])
+ argument_spec = dict(
+ username=dict(type="str", required=False),
+ password=dict(type="str", required=False),
+ api_endpoint=dict(type="str", required=False),
+ )
+ required_together = [
+ [
+ "username",
+ "password",
+ "api_endpoint",
+ ],
+ ]
+ mutually_exclusive = []
+ required_one_of = [
+ [
+ "username",
+ "password",
+ "api_endpoint",
+ ]
+ ]
+
+ def __init__(
+ self, task, connection, play_context, loader, templar, shared_loader_obj
+ ):
+ """Initialize action module."""
+ super().__init__(
+ task, connection, play_context, loader, templar, shared_loader_obj
+ )
+
+ def run(self, tmp=None, task_vars=None):
+ validation_results, _ignore = self.validate_argument_spec(
+ argument_spec=self.argument_spec,
+ required_together=self.required_together,
+ mutually_exclusive=self.mutually_exclusive,
+ required_one_of=self.required_one_of,
+ )
+
+ if validation_results.error_messages:
+ raise AnsibleActionFail(
+ message="Validation failed: {0}".format(
+ ", ".join(validation_results.error_messages)
+ ),
+ )
+ api_endpoint = self._task.args.get("api_endpoint")
+ username = self._task.args.get("username")
+ password = self._task.args.get("password")
+
+ with tempfile.TemporaryDirectory() as cf_home:
+ client = CFClient(
+ api_endpoint=api_endpoint,
+ username=username,
+ password=password,
+ cf_home=cf_home,
+ )
+ return run_action(client)
+
+
+class ActionModule(CFSpacesInfo):
+ pass
diff --git a/plugins/doc_fragments/cloud_foundry.py b/plugins/doc_fragments/cloud_foundry.py
new file mode 100644
index 0000000..aed92c7
--- /dev/null
+++ b/plugins/doc_fragments/cloud_foundry.py
@@ -0,0 +1,48 @@
+# SPDX-License-Identifier: GPL-3.0-only
+# SPDX-FileCopyrightText: 2024 Red Hat, Project Atmosphere
+#
+# Copyright 2024 Red Hat, Project Atmosphere
+#
+# This program is free software: you can redistribute it and/or modify it under the terms of the GNU
+# General Public License as published by the Free Software Foundation, version 3 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# You should have received a copy of the GNU General Public License along with this program.
+# If not, see .
+
+
+class ModuleDocFragment(object):
+ DOCUMENTATION = r"""
+---
+requirements:
+ - "python >= 3.6"
+ - cf CLI should be installed and available in PATH
+author:
+ - Kirill Satarin (@kksat)
+options:
+ username:
+ description:
+ - The username for authentication with the Cloud Foundry API.
+ - This is SAP BTP user email address
+ type: str
+ required: false
+ password:
+ description:
+ - The password for authentication with the Cloud Foundry API.
+ type: str
+ required: false
+ api_endpoint:
+ description:
+ - The endpoint URL of the Cloud Foundry API.
+ type: str
+ required: false
+"""
diff --git a/plugins/modules/cf_marketplace_info.py b/plugins/modules/cf_marketplace_info.py
index f96f746..dce250a 100644
--- a/plugins/modules/cf_marketplace_info.py
+++ b/plugins/modules/cf_marketplace_info.py
@@ -30,6 +30,7 @@
extends_documentation_fragment:
- sap.sap_operations.community
- sap.sap_operations.action_plugin
+ - sap.sap_operations.cloud_foundry
author:
- Kirill Satarin (@kksat)
@@ -43,27 +44,7 @@
version_added: "1.21.0"
-options:
- username:
- description:
- - The username for authentication with the Cloud Foundry API.
- - This is SAP BTP user email address
- type: str
- required: false
- password:
- description:
- - The password for authentication with the Cloud Foundry API.
- type: str
- required: false
- api_endpoint:
- description:
- - The endpoint URL of the Cloud Foundry API.
- type: str
- required: false
-
-requirements:
- - "python >= 3.6"
- - cf CLI should be installed and available in PATH
+options: {}
notes:
- This module does not modify any data and is safe to run in check mode.
diff --git a/plugins/modules/cf_service_instance.py b/plugins/modules/cf_service_instance.py
new file mode 100644
index 0000000..7f8df6c
--- /dev/null
+++ b/plugins/modules/cf_service_instance.py
@@ -0,0 +1,107 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# SPDX-License-Identifier: GPL-3.0-only
+# SPDX-FileCopyrightText: 2024 Red Hat, Project Atmosphere
+#
+# Copyright 2024 Red Hat, Project Atmosphere
+#
+# This program is free software: you can redistribute it and/or modify it under the terms of the GNU
+# General Public License as published by the Free Software Foundation, version 3 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# You should have received a copy of the GNU General Public License along with this program.
+# If not, see .
+
+
+DOCUMENTATION = r"""
+---
+module: cf_service_instance
+
+extends_documentation_fragment:
+ - sap.sap_operations.community
+ - sap.sap_operations.action_plugin
+ - sap.sap_operations.cloud_foundry
+
+author:
+ - Kirill Satarin (@kksat)
+
+short_description: Manage Cloud Foundry service instances
+
+description:
+ - This plugin allows managing service instances in a Cloud Foundry environment.
+ - It can create, delete service instances.
+ - Plugin is idempotent it will not create service instance with the same name it is already exists.
+ # TODO: add functionality to change service instance configuration
+ - Plugin will not change service instance parameters or metadata if service instance already exists (this functionality is planned)
+
+version_added: 1.22.0
+
+options:
+ name:
+ description: The name of the service instance.
+ type: str
+ required: True
+ service:
+ description: The name of the service offering.
+ type: str
+ required: True
+ state:
+ description: The desired state of the service instance.
+ choices: ['present', 'absent']
+ default: 'present'
+ type: str
+ required: False
+ space:
+ description: The name of the space in which to manage the service instance.
+ type: str
+ required: True
+ service_plan:
+ description: The name of the service plan for the service instance.
+ type: str
+ required: False
+ parameters:
+ description: A dictionary containing configuration parameters for the service instance.
+ type: dict
+ required: False
+ metadata:
+ description: A dictionary containing metadata for the service instance.
+ type: dict
+ required: False
+"""
+
+EXAMPLES = r"""
+---
+- name: Create a service instance
+ sap.sap_operations.cf_service_instance:
+ name: my_service_instance
+ service: my_service
+ state: present
+ space: my_space
+ service_plan: my_service_plan
+ parameters:
+ param1: value1
+ param2: value2
+ metadata:
+ label1: value1
+ label2: value2
+
+- name: Delete a service instance
+ sap.sap_operations.cf_service_instance:
+ name: my_service_instance
+ service: my_service
+ state: absent
+ space: my_space
+"""
+
+RETURN = r"""
+ """
diff --git a/plugins/modules/cf_service_instance_info.py b/plugins/modules/cf_service_instance_info.py
new file mode 100644
index 0000000..6fcb4c0
--- /dev/null
+++ b/plugins/modules/cf_service_instance_info.py
@@ -0,0 +1,77 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# SPDX-License-Identifier: GPL-3.0-only
+# SPDX-FileCopyrightText: 2024 Red Hat, Project Atmosphere
+#
+# Copyright 2024 Red Hat, Project Atmosphere
+#
+# This program is free software: you can redistribute it and/or modify it under the terms of the GNU
+# General Public License as published by the Free Software Foundation, version 3 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# You should have received a copy of the GNU General Public License along with this program.
+# If not, see .
+
+
+DOCUMENTATION = r"""
+---
+module: cf_service_instance_info
+
+extends_documentation_fragment:
+ - sap.sap_operations.community
+ - sap.sap_operations.action_plugin
+ - sap.sap_operations.cloud_foundry
+
+author:
+ - Kirill Satarin (@kksat)
+
+short_description: Fetch information about Cloud Foundry service instance
+
+description:
+ - Fetch information about Cloud Foundry service instance
+ - One of I(name) or I(guid) is required
+
+version_added: 1.22.0
+
+options:
+ name:
+ description: The name of the service instance.
+ type: str
+ required: False
+ guid:
+ description: The guid of the service instance.
+ type: str
+ required: False
+"""
+
+EXAMPLES = r"""
+---
+- name: Fetch information about service instance
+ sap.sap_operations.cf_service_instance_info:
+ username: user@email.domain
+ password: secret
+ api_endpoint:
+ name: service_instance_name
+
+- name: Fetch information about service instance
+ sap.sap_operations.cf_service_instance_info:
+ username: user@email.domain
+ password: secret
+ api_endpoint:
+ guid: service_instance_guid
+"""
+
+RETURN = r"""
+---
+# TODO: add documentation
+ """
diff --git a/plugins/modules/cf_service_instances_info.py b/plugins/modules/cf_service_instances_info.py
new file mode 100644
index 0000000..580294b
--- /dev/null
+++ b/plugins/modules/cf_service_instances_info.py
@@ -0,0 +1,60 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# SPDX-License-Identifier: GPL-3.0-only
+# SPDX-FileCopyrightText: 2024 Red Hat, Project Atmosphere
+#
+# Copyright 2024 Red Hat, Project Atmosphere
+#
+# This program is free software: you can redistribute it and/or modify it under the terms of the GNU
+# General Public License as published by the Free Software Foundation, version 3 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# You should have received a copy of the GNU General Public License along with this program.
+# If not, see .
+
+
+DOCUMENTATION = r"""
+---
+module: cf_service_instances_info
+
+extends_documentation_fragment:
+ - sap.sap_operations.community
+ - sap.sap_operations.action_plugin
+ - sap.sap_operations.cloud_foundry
+
+author:
+ - Kirill Satarin (@kksat)
+
+short_description: Fetch information about Cloud Foundry service instances
+
+description:
+ - Fetch information about Cloud Foundry service instances
+
+version_added: 1.22.0
+
+options: {}
+"""
+
+EXAMPLES = r"""
+---
+- name: Fetch information about service instances
+ sap.sap_operations.cf_service_instances_info:
+ username: user@email.domain
+ password: secret
+ api_endpoint:
+"""
+
+RETURN = r"""
+---
+# TODO: add documentation
+ """
diff --git a/plugins/modules/cf_service_plans_info.py b/plugins/modules/cf_service_plans_info.py
new file mode 100644
index 0000000..4a279c1
--- /dev/null
+++ b/plugins/modules/cf_service_plans_info.py
@@ -0,0 +1,60 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# SPDX-License-Identifier: GPL-3.0-only
+# SPDX-FileCopyrightText: 2024 Red Hat, Project Atmosphere
+#
+# Copyright 2024 Red Hat, Project Atmosphere
+#
+# This program is free software: you can redistribute it and/or modify it under the terms of the GNU
+# General Public License as published by the Free Software Foundation, version 3 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# You should have received a copy of the GNU General Public License along with this program.
+# If not, see .
+
+
+DOCUMENTATION = r"""
+---
+module: cf_service_plans_info
+
+extends_documentation_fragment:
+ - sap.sap_operations.community
+ - sap.sap_operations.action_plugin
+ - sap.sap_operations.cloud_foundry
+
+author:
+ - Kirill Satarin (@kksat)
+
+short_description: Fetch information about Cloud Foundry service plans
+
+description:
+ - Fetch information about Cloud Foundry service plans
+
+version_added: 1.22.0
+
+options: {}
+"""
+
+EXAMPLES = r"""
+---
+- name: Fetch information about service plans
+ sap.sap_operations.cf_service_plans_info:
+ username: user@email.domain
+ password: secret
+ api_endpoint:
+"""
+
+RETURN = r"""
+---
+# TODO: add documentation
+ """
diff --git a/plugins/modules/cf_spaces_info.py b/plugins/modules/cf_spaces_info.py
new file mode 100644
index 0000000..d692e09
--- /dev/null
+++ b/plugins/modules/cf_spaces_info.py
@@ -0,0 +1,60 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# SPDX-License-Identifier: GPL-3.0-only
+# SPDX-FileCopyrightText: 2024 Red Hat, Project Atmosphere
+#
+# Copyright 2024 Red Hat, Project Atmosphere
+#
+# This program is free software: you can redistribute it and/or modify it under the terms of the GNU
+# General Public License as published by the Free Software Foundation, version 3 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# You should have received a copy of the GNU General Public License along with this program.
+# If not, see .
+
+
+DOCUMENTATION = r"""
+---
+module: cf_spaces_info
+
+extends_documentation_fragment:
+ - sap.sap_operations.community
+ - sap.sap_operations.action_plugin
+ - sap.sap_operations.cloud_foundry
+
+author:
+ - Kirill Satarin (@kksat)
+
+short_description: Fetch information about Cloud Foundry spaces
+
+description:
+ - Fetch information about Cloud Foundry spaces
+
+version_added: 1.22.0
+
+options: {}
+"""
+
+EXAMPLES = r"""
+---
+- name: Fetch information about spaces
+ sap.sap_operations.cf_spaces_info:
+ username: user@email.domain
+ password: secret
+ api_endpoint:
+"""
+
+RETURN = r"""
+---
+# TODO: add documentation
+ """