diff --git a/contrib/generate_module.sh b/contrib/generate_module.sh
new file mode 100755
index 00000000..abec2c30
--- /dev/null
+++ b/contrib/generate_module.sh
@@ -0,0 +1,5 @@
+#!/bin/bash
+# For resource changing module
+ansible localhost -c local -m template -a "src=module_template.py.j2 dest=my_module.py" -e @module_template_vars.yaml
+# For resource info collection module
+ansible localhost -c local -m template -a "src=module_info_template.py.j2 dest=my_module_info.py" -e @module_template_vars.yaml
diff --git a/contrib/module_info_template.py.j2 b/contrib/module_info_template.py.j2
new file mode 100644
index 00000000..da646ecb
--- /dev/null
+++ b/contrib/module_info_template.py.j2
@@ -0,0 +1,110 @@
+#!/usr/bin/python
+# coding: utf-8 -*-
+
+# Copyright (c) 2020, {{ author_name }} <{{ author_mail }}>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+DOCUMENTATION = '''
+---
+module: {{ module_name }}
+short_description: {{ module_short_description }}
+author: {{ author_name }} <{{ author_mail }}>
+description:
+  - {{ module_long_description }}
+options:
+  {{ options|to_nice_yaml(indent=2,sort_keys=false)|indent(width=2)|trim }}
+
+requirements:
+  - "python >= 3.6"
+  - "openstacksdk"
+
+extends_documentation_fragment:
+  - openstack.cloud.openstack
+'''
+
+RETURN = '''
+{{ module_returns_example|to_nice_yaml(indent=2,sort_keys=false) }}
+'''
+
+EXAMPLES = '''
+# What modules does for example
+- {{ module_name }}:
+    name:
+      - name1
+      - name2
+    timeout: 200
+'''
+
+from ansible_collections.openstack.cloud.plugins.module_utils.openstack import OpenStackModule
+
+
+class {{ module_name.split("_")|map("capitalize")|list|join("") }}Module(OpenStackModule):
+
+    argument_spec = dict(
+{% for k, v in options.items() %}
+{{ k | indent( width=8, indentfirst=True) }}=dict(type={{ v.type }}
+{%- if 'required' in v %}, required={{ v.required }}{% endif %}
+{%- if 'elements' in v %}, elements={{ v.elements }}{% endif %}
+{%- if 'default' in v %}, default={% if v.type == 'str' %}"{{ v.default }}"{% else %}{{ v.default }}{% endif %}{% endif %}
+{%- if 'aliases' in v %}, aliases={{ v.aliases }}{% endif %}
+{%- if 'choices' in v %}, choices={{ v.choices }}{% endif %}),
+{% endfor %}
+    ),
+
+    # Optional arguments requirements
+    module_kwargs = dict(
+        required_if=[
+            ['action', 'rebuild', ['image']],  # if need to rebuild image (only), the 'image' is required
+            ["state", "present", ["username", "user_roles"]],  # for creating user 'user_roles' is required
+            ["state", "absent", ["username"]],  # for state 'absent' only username is required
+        ],
+        required_by=dict(  # for weather and population 'city' is required to set
+            weather=('city'),
+            population=('city'),
+        ),
+        mutually_exclusive=[
+            ['use_cloud1', 'use_cloud2']  # can't run on both, choose only one to set
+        ],
+        required_together=[
+            ['remove_image', 'image_name']  # if need to remove image, must to specify which one
+        ],
+        required_one_of_args=[["password", "password_hash"]],  # one of these args must be set
+        supports_check_mode={{ check_mode_support }},  # good practice is to support check_mode
+    )
+
+    # you main funciton is here
+    def run(self):
+        # do any arguments check if needed
+        data = self.preliminary_checks()
+        # check if we need to prepare various filters for results
+        filters = self.prepare_filters()
+        # run SDK call to get information about requested resource
+        result = self.conn.compute.resource_list(
+            filters=filters,
+            detailed=self.params['detailed'],
+            # any other parameters
+            )
+        # process results if they require a change
+        result = self.normalize_result()
+        self.results.update({'resource_name': result})
+
+    def preliminary_checks(self):
+        # you checks before running like arguments and options checks, etc
+        return data
+
+    def prepare_filters(self):
+        # process filters if they require additional checks
+        return filters
+
+    def normalize_result(self):
+        # process filters if they require additional checks
+        return result
+
+
+def main():
+    module = {{ module_name.split("_")|map("capitalize")|list|join("") }}Module()
+    module()
+
+
+if __name__ == '__main__':
+    main()
diff --git a/contrib/module_template.py.j2 b/contrib/module_template.py.j2
new file mode 100644
index 00000000..44d76606
--- /dev/null
+++ b/contrib/module_template.py.j2
@@ -0,0 +1,149 @@
+#!/usr/bin/python
+# coding: utf-8 -*-
+
+# Copyright (c) 2020, {{ author_name }} <{{ author_mail }}>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+DOCUMENTATION = '''
+---
+module: {{ module_name }}
+short_description: {{ module_short_description }}
+author: {{ author_name }} <{{ author_mail }}>
+description:
+  - {{ module_long_description }}
+options:
+  {{ options|to_nice_yaml(indent=2,sort_keys=false)|indent(width=2)|trim }}
+
+requirements:
+  - "python >= 3.6"
+  - "openstacksdk"
+
+extends_documentation_fragment:
+  - openstack.cloud.openstack
+'''
+
+RETURN = '''
+{{ module_returns_example|to_nice_yaml(indent=2,sort_keys=false) }}
+'''
+
+EXAMPLES = '''
+# What modules does for example
+- {{ module_name }}:
+    action: pause
+    auth:
+      auth_url: https://identity.example.com
+      username: admin
+      password: admin
+      project_name: admin
+    server: vm1
+    timeout: 200
+'''
+
+from ansible_collections.openstack.cloud.plugins.module_utils.openstack import OpenStackModule
+
+
+class {{ module_name.split("_")|map("capitalize")|list|join("") }}Module(OpenStackModule):
+
+    argument_spec = dict(
+{% for k, v in options.items() %}
+{{ k | indent( width=8, indentfirst=True) }}=dict(type={{ v.type }}
+{%- if 'required' in v %}, required={{ v.required }}{% endif %}
+{%- if 'elements' in v %}, elements={{ v.elements }}{% endif %}
+{%- if 'default' in v %}, default={% if v.type == 'str' %}"{{ v.default }}"{% else %}{{ v.default }}{% endif %}{% endif %}
+{%- if 'aliases' in v %}, aliases={{ v.aliases }}{% endif %}
+{%- if 'choices' in v %}, choices={{ v.choices }}{% endif %}),
+{% endfor %}
+    ),
+
+    # Optional arguments requirements
+    module_kwargs = dict(
+        required_if=[
+            ['action', 'rebuild', ['image']],  # if need to rebuild image (only), the 'image' is required
+            ["state", "present", ["username", "user_roles"]],  # for creating user 'user_roles' is required
+            ["state", "absent", ["username"]],  # for state 'absent' only username is required
+        ],
+        required_by=dict(  # for weather and population 'city' is required to set
+            weather=('city'),
+            population=('city'),
+        ),
+        mutually_exclusive=[
+            ['use_cloud1', 'use_cloud2']  # can't run on both, choose only one to set
+        ],
+        required_together=[
+            ['remove_image', 'image_name']  # if need to remove image, must to specify which one
+        ],
+        required_one_of_args=[["password", "password_hash"]],  # one of these args must be set
+        supports_check_mode={{ check_mode_support }},  # good practice is to support check_mode
+    )
+
+    # you main funciton is here
+    def run(self):
+        # do any arguments check if needed
+        data = self.preliminary_checks()
+        # check if we need to run or the resource is in desired state already
+        must_run = self.check_mode_test()
+        # if the resource is good
+        if not must_run:
+            # updated returned results if need
+            self.results.update({"returning_data": some_data})
+            # returning {changed: False, ...} because we didn't change resource
+            self.exit_json(self.results)
+        # do something if must to run the module
+        self.execute()
+
+    def preliminary_checks(self):
+        # you checks before running like arguments and options checks, etc
+        return data
+
+    def check_mode_test(self):
+        # check the idempotency - does module should do anything or
+        # it's already in the desired state?
+        return must_run
+
+    def execute(self):
+        # doing here what should be done, using OpenstackSDK
+        # for example actions for resource:
+        # self.params['action'] = "rebuild"
+        action_name = self.params['action'] + "_resource"  # action_name='rebuild_resource'
+        try:
+            # find a method "rebuild_resource" in openstack SDK compute:
+            func_name = getattr(self.conn.compute, action_name)
+            # found self.conn.compute.rebuild_resource
+        except AttributeError:
+            self.fail_json(
+                msg="Method %s wasn't found in OpenstackSDK compute" % action_name)
+        summary = func_name(data)  # summary = self.conn.compute.rebuild_resource(data)
+        self.results.update({"returning_data": summary})
+        # that's it, exiting, results will be returned from module automatically
+
+    # another option for states
+    def execute_with_action_map(self):
+        actions_map = {
+            'start': self._start_resource,
+            'stop': self._stop_resource,
+            'restart': self._restart_resource,
+            'absent': self._absent_resource,
+        }
+        summary = actions_map(self.params['action'])()  # summary = self.start_resource()
+        self.results.update({"changed": True, "data2return": summary})
+
+    def _start_resource(self, some_other_data):
+        pass
+
+    def _stop_resource(self, some_other_data):
+        pass
+
+    def _restart_resource(self, some_other_data):
+        pass
+
+    def _absent_resource(self, some_other_data):
+        pass
+
+
+def main():
+    module = {{ module_name.split("_")|map("capitalize")|list|join("") }}Module()
+    module()
+
+
+if __name__ == '__main__':
+    main()
diff --git a/contrib/module_template_vars.yaml b/contrib/module_template_vars.yaml
new file mode 100644
index 00000000..83578776
--- /dev/null
+++ b/contrib/module_template_vars.yaml
@@ -0,0 +1,81 @@
+##### PLEASE READ BEFORE #####
+
+# Module format and documentation
+# https://docs.ansible.com/ansible/latest/dev_guide/developing_modules_documenting.html#module-format-and-documentation
+
+
+module_name: server_manage
+author_name: 'Happy Ansible User'
+author_mail: dontwriteme@example.com
+module_short_description: "Doing something very useful"
+module_long_description: "Here is the place to release your inner writer"
+check_mode_support: True  # good practice to support check_mode:
+# https://docs.ansible.com/ansible/latest/user_guide/playbooks_checkmode.html#check-mode-dry-run
+
+module_returns_example:
+  image:
+    description: Image inspection results for the image that was pulled, pushed, or built.
+    returned: always  # or 'success' in case of success only
+    type: dict
+    sample:
+      Image Name: Sample Image
+      Image ID: e6471d00796a13de8142c15d7ad3a44f
+      Nested:
+        images list:
+          - data 1
+          - image 1234
+        boolean_1: True
+
+options:
+  optional_string:
+    description:
+      - This variable is set for having string argument, for example 'action'
+    type: str
+    required: true
+    default: "my_lovely_action"
+    choices:
+      - allowed_option1
+      - allowed_option1
+  optional_boolean:
+    description:
+      - This variable is set for having a boolean argument, for example whether
+        to wait for resource creation or not
+    type: bool
+    required: false # may be omitted if false
+    # and no default because not required
+  optional_integer:
+    description:
+      - This variable is set for having a integer argument, for example how many
+        seconds to wait for the resource to come alive
+    required: true
+    default: 60
+    type: int
+    aliases: # sometimes we allow to pass the same option with different name
+      - old_optional_integer_name
+      - different_option_name
+  optional_list:
+    description:
+      - This variable is set for having a list argument, for example files need
+        to create with the resource
+    type: list
+    elements: str  # type of elements of the list, can be dict, str, int, list
+  optional_dictionary:
+    description:
+      - This variable is set for having a dictionary argument, for example to
+        set environment variables or to pass more complex data to SDK
+    required: true
+    default: {}
+    type: dict
+    suboptions:
+      suboption_1:
+        description:
+          - suboption_1 description, what it does
+        type: str
+        aliases:
+          - suboption_1_another_name
+      suboption_2:
+        description:
+          - suboption_2 description, what it does
+        type: list
+        elements: str
+        default: []