diff --git a/.github/ISSUE_TEMPLATE/DMP_2024.yml b/.github/ISSUE_TEMPLATE/DMP_2024.yml new file mode 100644 index 0000000..f729c73 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/DMP_2024.yml @@ -0,0 +1,264 @@ +name: DMP 2024 Project Template +description: List a new project for Dedicated Mentoring Program (DMP) 2024 +title: "[DMP 2024]: " +labels: ["DMP 2024"] +body: + - type: textarea + id: ticket-description + validations: + required: true + attributes: + label: Ticket Contents + value: | + ## Description + [Provide a brief description of the feature, including why it is needed and what it will accomplish.] + + - type: textarea + id: ticket-goals + validations: + required: true + attributes: + label: Goals & Mid-Point Milestone + description: List the goals of the feature. Please add the goals that must be achieved by Mid-point check-in i.e 1.5 months into the coding period. + value: | + ## Goals + - [ ] [Goal 1] + - [ ] [Goal 2] + - [ ] [Goal 3] + - [ ] [Goal 4] + - [ ] [Goals Achieved By Mid-point Milestone] + + - type: textarea + id: ticket-setup + attributes: + label: Setup/Installation + description: Please list or link setup or installation guide (if any) + + - type: textarea + id: ticket-expected-outcome + attributes: + label: Expected Outcome + description: Describe in detail what the final product or result should look like and how it should behave. + + - type: textarea + id: ticket-acceptance-criteria + attributes: + label: Acceptance Criteria + description: List the acceptance criteria for this feature. + + - type: textarea + id: ticket-implementation-details + validations: + required: true + attributes: + label: Implementation Details + description: List any technical details about the proposed implementation, including any specific technologies that will be used. + + - type: textarea + id: ticket-mockups + attributes: + label: Mockups/Wireframes + description: Include links to any visual aids, mockups, wireframes, or diagrams that help illustrate what the final product should look like. This is not always necessary, but can be very helpful in many cases. + + - type: input + id: ticket-product + attributes: + label: Product Name + placeholder: Enter Product Name + validations: + required: true + + - type: dropdown + id: ticket-organisation + attributes: + label: Organisation Name + description: Enter Organisation Name + multiple: false + options: + - Bandhu + - Belongg + - Blockster Global (CREDBEL) + - Civis + - Dhwani + - Dhiway + - EGov + - EkShop Marketplace + - FIDE + - If Me + - Key Education Foundation + - Norwegian Meteorological Institute + - Planet Read + - Project Second Chance + - Reap Benefit + - SamagraX + - ShikshaLokam + - Tech4Dev + - Tekdi + - The Mifos Initiative + - Tibil + - Ushahidi + - Arghyam + - Piramal Swasthya Management Research Institute + - Belongg AI + validations: + required: true + + - type: dropdown + id: ticket-governance-domain + attributes: + label: Domain + options: + - ⁠Healthcare + - ⁠Education + - Financial Inclusion + - ⁠Livelihoods + - ⁠Skilling + - ⁠Learning & Development + - ⁠Agriculture + - ⁠Service Delivery + - Open Source Library + - Water + validations: + required: true + + + - type: dropdown + id: ticket-technical-skills-required + attributes: + label: Tech Skills Needed + description: Select the technologies needed for this ticket (use Ctrl or Command to select multiple) + multiple: true + options: + - .NET + - Angular + - Artificial Intelligence + - ASP.NET + - AWS + - Babel + - Bootstrap + - C# + - Chart.js + - CI/CD + - Computer Vision + - CORS + - cURL + - Cypress + - D3.js + - Database + - Debugging + - Design + - DevOps + - Django + - Docker + - Electron + - ESLint + - Express.js + - Feature + - Flask + - Go + - GraphQL + - HTML + - Ionic + - Jest + - Java + - JavaScript + - Jenkins + - JWT + - Kubernetes + - Laravel + - Machine Learning + - Maintenance + - Markdown + - Material-UI + - Microservices + - MongoDB + - Mobile + - Mockups + - Mocha + - Natural Language Processing + - NestJS + - Node.js + - NUnit + - OAuth + - Performance Improvement + - Prettier + - Python + - Question + - React + - React Native + - Redux + - RESTful APIs + - Ruby + - Ruby on Rails + - Rust + - Scala + - Security + - Selenium + - SEO + - Serverless + - Solidity + - Spring Boot + - SQL + - Swagger + - Tailwind CSS + - Test + - Testing Library + - Three.js + - TypeScript + - UI/UX/Design + - Virtual Reality + - Vue.js + - WebSockets + - Webpack + - Other + validations: + required: true + + - type: textarea + id: ticket-mentors + attributes: + label: Mentor(s) + description: Please tag relevant mentors for the ticket + validations: + required: true + + - type: dropdown + id: ticket-category + attributes: + label: Category + description: Choose the categories that best describe your ticket + multiple: true + options: + - API + - Analytics + - Accessibility + - Backend + - Breaking Change + - Beginner Friendly + - Configuration + - CI/CD + - Database + - Data Science + - Deprecation + - Documentation + - Delpoyment + - Frontend + - Internationalization + - Localization + - Machine Learning + - Maintenance + - Mobile + - Performance Improvement + - Question + - Refactoring + - Research + - Needs Reproduction + - SEO + - Security + - Testing + - AI + - Other + validations: + required: true + + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0526ddf --- /dev/null +++ b/.gitignore @@ -0,0 +1,169 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/#use-with-ide +.pdm.toml + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +.idea/ + +#Helm +charts/ + +#gitrepos +mojaloop/ +ph/ +fineract/ +apps/ \ No newline at end of file diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md new file mode 100644 index 0000000..e69de29 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..cfd9e01 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,68 @@ +--- + +Thank you for your interest in contributing to the Mojafos repository! Your contributions are important and will help to improve the project for everyone. Before you begin, please consider the guidelines below. + +## Getting Started + +- Make sure you have [Git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) installed on your machine. +- Fork the repository and clone it locally. + + ``` + git clone https://github.com/openMF/mojafos.git + ``` + +- Create a new branch for your contributions + + ``` + git checkout -b feature-branch-name + ``` + +## Making Changes + +- Before making changes, ensure that you're working on the latest version of the `master` branch + + ``` + git pull origin master + ``` + +## Committing Changes + +- Stage your changes: + + ``` + git add file-name(s) + ``` +- Commit your changes with a descriptive message: + + ``` + git commit -m "Add feature" + ``` +- Push your changes to your forked repository: + + ``` + git push origin feature-branch-name + ``` + +## Submitting a Pull Request + +- Follow the steps outlined in [GitHub's documentation](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request) + +## Code Review + +- After submitting your PR, our team will review your changes. +- Address any feedback or requested changes promptly. +- Once approved, your PR will be merged into the `master` branch. + +## Finding a Task +- Check out the issues [here](https://github.com/openMF/mojafos/issues) +- Have a look at the README.md Can it be improved? Do you see any typos? You may initiate a PR. + +## Reporting Issues +If you find any bugs or have recommendations for improvements, please feel free to [open an issue](https://github.com/openMF/mojafos/issues) with a detailed explanation of changes. + +## Contact +- For further assistance or questions regarding contributions, feel free to join our Slack channel [here](https://mifos.slack.com/ssb/redirect) + +Thank you for contributing to [Mojafos](https://github.com/openMF/mojafos)! We look forward to your contributions. + +--- diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + 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. diff --git a/README.md b/README.md new file mode 100644 index 0000000..c5e9773 --- /dev/null +++ b/README.md @@ -0,0 +1,206 @@ +# A Deployable Package for Mifos/Fineract, Payment Hub EE, and Mojaloop (Mojafos) + +## Introduction + +The deployable package is intended to simplify and automate the deployment process of three software applications, namely Mojaloop, PaymentHub, and Fineract, onto a Kubernetes cluster. This package aims to streamline the deployment process, reduce manual errors, and enable someone to demo how these softwares can work together. + + +## Pre-requisites +Make sure you have the following before you go through this guide. +- You should be running Ubuntu 20.04 LTS on the machine where you are running this script +- 32GB of RAM +- 30GB+ free space in your home directory + +# Quick Start +> NOTE: The deployment made by this script is meant for demo purposes and not for production + +## Clone the repository +To use Mojafos, you need to clone the repository to be able to run the software scripts. +Clone the repository into a directory of your choice. +After cloning the repository, you need to change the directory into the cloned repository. +``` +git clone https://github.com/openMF/mojafos.git +``` + +Inside the directory run the following command to execute the script. + +```bash +sudo ./run.sh -u $USER -m deploy -d true -a all -f 2 -e local +``` +### Options +- `-u` This is used to pass in the user the script should use to execute it's commands. The value passed in is `$USER` which the current user of the shell +- `-m` This option specifies the mode in which the script should execute. The available values are + - `deploy` - Deploy applications + - `cleanup` - Undo what deploy did and clean up resources +- `-d` This flag tells the sccript whether to execute in verbose mode or not. The available values are : + - true - Output should provide as much information as possible + - false - Output should not be minimal +- `-a` This flag tells the script in which mode the depoloyment should be made. It is an optional flag therefore if it is not provided,the default deployment mode is all apps +- `-f` This flag specifies the number of fineract instances to deployed. If not specified, the default number of instances is 2 +- `-e` This flag specifies the environment into which the applications should be deployed. If not specified, it will deploy into k3s locally. + + +# App Deployment Modes -a +There are three modes of deployment currently supported by Mojafos. This is relevant for the -a option +- Only Mojaloop `moja` +- Only Fineract `fin` +- Only Payment Hub `ph` +- All Apps `all` + + +# Target Environment -e +You can set the environment into which the applications should be deployed by setting the -e argument at the point of executing the script. + +To use a remote kubernetes cluster, use the value `remote` and to create a local k8s cluster, use `local` +>Currently the tool is only tested on local kubernetes deployments but work is being done to test it on + + +After the script has successfully executed it will print the following output + +``` +======================================================================== +Thank you for installing Mojaloop, Paymenthub and Fineract using Mojafos +======================================================================== + + +TESTING +sudo ./run -u $USER -m test ml #For testing mojaloop +sudo ./run -u $USER -m test ph #For testing payment hub +sudo ./run -u $USER -m test fin #For testing fineract + + + +CHECK DEPLOYMENTS USING kubectl +kubectl get pods -n mojaloop #For testing mojaloop +kubectl get pods -n paymenthub #For testing paymenthub +kubectl get pods -n fineract-n #For testing fineract. n is a number of a fineract instance + + +Copyright © 2023 The Mifos Initiative +``` + +# USING THE DEPLOYED APPS + +## Accessing Mojaloop +The Mojafos scripts add the required host names to the 127.0.0.1 entry in the /etc/hosts of the "install system" i.e. the system where mojafos is run. To access Mojaloop from beyond this system it is necessary to:- + +ensure that http / port 80 is accessible on the install system. For instance if mojafos has installed Mojaloop onto a VM in the cloud then it will be necessary to ensure that the cloud network security rules allow inbound traffic on port 80 to that VM. + +## MacOs and Linux +add the hosts listed below to an entry for the external/public ip address of that install system in the /etc/hosts file of the laptop you are using. +For example if Mojaloop vNext is installed on a cloud VM with a public IP of 192.168.56.100 Then add an entry to your laptop's /etc/hosts similar to ... +```bash +192.168.56.100 vnextadmin.local elasticsearch.local kibana.local mongoexpress.local kafkaconsole.local fspiop.local bluebank.local greenbank.local +``` + +You should now be able to browse or curl to Mojaloop vNext admin url using http://vnextadmin you can also access the deloyed instances of the Mojaloop testing toolkit at http://bluebank.local and http://greenbank.local or access the mongo and kafka consoles. + +## Windows +- open Notepad +- Right click on Notepad and then Run as Administrator. +- allow this app to make changes to your device? type Yes. +- In Notepad, choose File then Open C:\Windows\System32\drivers\etc\hosts or click the address bar at the top and paste in the path and choose Enter. If you don’t see the host file in the /etc directory then select All files from the File name: drop-down list, then click on the hosts file. +- Add the IP from your VM or system and then add a host from the list of required hosts (see example below) +- flush your DNS cache. Click the Windows button and search command prompt, in the command prompt:- +```bash +ipconfig /flushdns +``` +Note you can only have one host per line so on windows 10 your hosts file should look something like: + +```bash +192.168.56.100 vnextadmin.local +192.168.56.100 elasticsearch.local +192.168.56.100 kibana.local +192.168.56.100 mongoexpress.local +192.168.56.100 kafkaconsole.local +192.168.56.100 fspiop.local +192.168.56.100 bluebank.local +192.168.56.100 greenbank.local +``` + +## Accessing Paymenthub + +To access paymenthub, you would follow a similar set of instructions just like for accessing mojaloop. + +## MacOs and Linux +add the hosts listed below to an entry for the external/public ip address of that install system in the /etc/hosts file of the laptop you are using. +For example if Paymenthub is installed on a cloud VM with a public IP of 192.168.56.100 Then add an entry to your laptop's /etc/hosts similar to ... + +```bash +192.168.56.100 ops.sandbox.mifos.io +``` + +You should now be able to browse or curl to Paymenthub Operations Web portal url using http://ops.sandbox.mifos.io . + +## Windows +- open Notepad +- Right click on Notepad and then Run as Administrator. +- allow this app to make changes to your device? type Yes. +- In Notepad, choose File then Open C:\Windows\System32\drivers\etc\hosts or click the address bar at the top and paste in the path and choose Enter. If you don’t see the host file in the /etc directory then select All files from the File name: drop-down list, then click on the hosts file. +- Add the IP from your VM or system and then add a host from the list of required hosts (see example below) +- flush your DNS cache. Click the Windows button and search command prompt, in the command prompt:- +```bash +ipconfig /flushdns +``` +Note you can only have one host per line so on windows 10 your hosts file should look something like: + +```bash +192.168.56.100 ops.sandbox.mifos.io +``` + +# Accessing Fineract +To access the fineract instances you just deployed using mojafos, you will needs to make similar edits to your hosts file configuration of your computer. + +## MacOs and Linux +add the hosts listed below to an entry for the external/public ip address of that install system in the /etc/hosts file of the laptop you are using. +For example if one of the instances of fineract is installed on a cloud VM with a public IP of 192.168.56.100 Then add an entry to your laptop's /etc/hosts similar to ... + +```bash +192.168.56.100 1-communityapp.sandbox.fynarfin.io 1-fynams.sandbox.fynarfin.io +``` +Notice the 1 at the begining of the host name. This is automatically prepended at the begining of a fineract instance's host names to form it's ingress domain name. + +If you set the number of fineract instances to 3, you would have domains ranging from `1-xxx.sandbox.fynarfin.io` to `3-xxx.fynarfin.io` + +After editing your hosts config with the number of fineract instances you deployed, you should now be able to browse or curl to Community App url using http://1-communityapp.sandbox.fynarfin.io and fineract at http://1-fynams.sandbox.fynarfin.io + +## Windows +- open Notepad +- Right click on Notepad and then Run as Administrator. +- allow this app to make changes to your device? type Yes. +- In Notepad, choose File then Open C:\Windows\System32\drivers\etc\hosts or click the address bar at the top and paste in the path and choose Enter. If you don’t see the host file in the /etc directory then select All files from the File name: drop-down list, then click on the hosts file. +- Add the IP from your VM or system and then add a host from the list of required hosts (see example below) +- flush your DNS cache. Click the Windows button and search command prompt, in the command prompt:- +```bash +ipconfig /flushdns +``` +Note you can only have one host per line so on windows 10 your hosts file should look something like: + +```bash +192.168.56.100 1-communityapp.sandbox.fynarfin.io +192.168.56.100 1-fynams.sandbox.fynarfin.io +``` +# Clean Up + +To tear down the infrastructure and all installed apps. You can run this command. + +```bash +sudo ./run.sh -u $USER -m cleanup -d true -e local +``` + +This will delete all resources in the created namespaces and if the kubernetes cluster is `k3s` it will delete it as well. + +Please note that cleaning up the resources will take some time. + +## CONTRIBUTION + +Find the contributing guidelines [here](./CONTRIBUTING.md) + +## CONCLUSION + +This tool is intended to simplify the deployment process for Payment Hub EE, Mojaloop and Fineract for testing purposes. + + + + + diff --git a/renovate.json b/renovate.json new file mode 100644 index 0000000..5db72dd --- /dev/null +++ b/renovate.json @@ -0,0 +1,6 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "extends": [ + "config:recommended" + ] +} diff --git a/run.sh b/run.sh new file mode 100755 index 0000000..557f749 --- /dev/null +++ b/run.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +source ./src/utils/logger.sh +source ./src/mojafos/commandline/commandline.sh + diff --git a/src/mojafos/commandline/commandline.sh b/src/mojafos/commandline/commandline.sh new file mode 100755 index 0000000..ede03fc --- /dev/null +++ b/src/mojafos/commandline/commandline.sh @@ -0,0 +1,132 @@ +#!/usr/bin/env bash + +source ./src/mojafos/configurationManager/config.sh +source ./src/mojafos/environmentSetup/environmentSetup.sh +source ./src/mojafos/deployer/deployer.sh + +function welcome { + echo -e "${BLUE}" + echo -e "███ ███ ██████ ██ █████ ███████ ██████ ███████ " + echo -e "████ ████ ██ ██ ██ ██ ██ ██ ██ ██ ██ " + echo -e "██ ████ ██ ██ ██ ██ ███████ █████ ██ ██ ███████ " + echo -e "██ ██ ██ ██ ██ █ ██ ██ ██ ██ ██ ██ ██ " + echo -e "██ ██ ██████ █████ ██ ██ ██ ██████ ███████ " + echo -e " " + echo -e " ${RESET}" +} + +function showUsage { + if [ $# -ne 0 ] ; then + echo "Incorrect number of arguments passed to function $0" + exit 1 + else +echo "USAGE: $0 -m [mode] -u [user] -d [true/false] +Example 1 : sudo $0 -m deploy -u \$USER -d true # install mojafos with debug mode and user \$USER +Example 2 : sudo $0 -m cleanup -u \$USER -d true # delete mojafos with debug mode and user \$USER +Example 3 : sudo $0 -m deploy -u \$USER -d false # install mojafos without debug mode and user \$USER + +Options: +-m mode ............... install|delete (-m is required) +-u user................ user that the process will use for execution +-d debug............... debug mode. if set debug is true, if not set debug is false +-h|H .................. display this message +" + fi + +} + +function getoptions { + local mode_opt + + while getopts "m:k:d:a:f:e:u:hH" OPTION ; do + case "${OPTION}" in + m) mode_opt="${OPTARG}" + ;; + k) k8s_distro="${OPTARG}" + ;; + d) debug="${OPTARG}" + ;; + a) apps="${OPTARG}" + ;; + f) fineract_instansces="${OPTARG}" + ;; + e) environment="${OPTARG}" + ;; + v) k8s_user_version="${OPTARG}" + ;; + u) k8s_user="${OPTARG}" + ;; + h|H) showUsage + exit 0 + ;; + *) echo "unknown option" + showUsage + exit 1 + ;; + esac + done + + if [ -z "$mode_opt" ]; then + echo "Error: Mode argument is required." + showUsage + exit 1 + fi + + if [ -z "$debug" ]; then + debug=false + fi + + mode="$mode_opt" +} + +# this function is called when Ctrl-C is sent +function cleanUp () +{ + # perform cleanup here + echo -e "${RED}Performing graceful clean up${RESET}" + + mode="cleanup" + echo "Doing cleanup" + envSetupMain "$mode" "k3s" "1.26" "$environment" + + # exit shell script with error code 2 + # if omitted, shell script will continue execution + exit 2 +} + +function trapCtrlc { + echo + echo -e "${RED}Ctrl-C caught...${RESET}" + cleanUp +} + +# initialise trap to call trap_ctrlc function +# when signal 2 (SIGINT) is received +trap "trapCtrlc" 2 + +########################################################################### +# MAIN +########################################################################### +function main { + welcome + getoptions "$@" + if [ $mode == "deploy" ]; then + echo -e "${YELLOW}" + echo -e "====================================================================================" + echo -e "The deployment made by this script is meant for demo purposes and not for production" + echo -e "====================================================================================" + echo -e "${RESET}" + envSetupMain "$mode" "k3s" "1.26" "$environment" + deployApps "$fineract_instansces" "$apps" + elif [ $mode == "cleanup" ]; then + logWithVerboseCheck $debug info "Cleaning up all traces of Mojafos" + envSetupMain "$mode" "k3s" "1.26" "$environment" + else + showUsage + fi +} + +########################################################################### +# CALL TO MAIN +########################################################################### +main "$@" diff --git a/src/mojafos/configurationManager/config.sh b/src/mojafos/configurationManager/config.sh new file mode 100755 index 0000000..db35517 --- /dev/null +++ b/src/mojafos/configurationManager/config.sh @@ -0,0 +1,161 @@ +#!/usr/bin/env bash + +######################################################################## +# GLOBAL VARS +######################################################################## +BASE_DIR=$(pwd) +APPS_DIR="$BASE_DIR/src/mojafos/deployer/apps/" +INFRA_NAMESPACE="infra" +INFRA_RELEASE_NAME="mojafos-infra" +#mojaloop +MOJALOOPBRANCH="beta1" +MOJALOOPREPO_DIR="mojaloop" +MOJALOOP_NAMESPACE="mojaloop" +MOJALOOP_REPO_LINK="https://github.com/mojaloop/platform-shared-tools.git" +MOJALOOP_LAYER_DIRS=("$BASE_DIR/src/mojafos/deployer/apps/mojaloop/packages/installer/manifests/crosscut" "$BASE_DIR/src/mojafos/deployer/apps/mojaloop/packages/installer/manifests/ttk" "$BASE_DIR/src/mojafos/deployer/apps/mojaloop/packages/installer/manifests/apps" "$BASE_DIR/src/mojafos/deployer/apps/mojaloop/packages/installer/manifests/reporting") +MOJALOOP_VALUES_FILE="$BASE_DIR/src/mojafos/configurationManager/mojaloop_values.json" +#paymenthubee +PHBRANCH="v1.2.0-release" +PHREPO_DIR="ph" +PH_NAMESPACE="paymenthub" +PH_RELEASE_NAME="moja-ph" +PH_VALUES_FILE="$BASE_DIR/src/mojafos/deployer/ph_values.yaml" +PH_REPO_LINK="https://github.com/openMF/ph-ee-env-labs.git" +PH_HELM_REPO_LINK="https://fynarfin.io/images/ph-ee-g2psandbox-1.5.0/" +PH_G2P_CHART_VERSION="1.5.0" +PH_CHART_REPO_NAME="g2p-sandbox-1-5" +PH_EE_ENV_LABS_REPO_LINK="https://github.com/openMF/ph-ee-env-labs.git" +PH_EE_ENV_LABS_REPO_BRANCH="master" +PH_EE_ENV_LABS_REPO_DIR="ph_env_labs" +PH_EE_ENV_TEMPLATE_REPO_LINK="https://github.com/openMF/ph-ee-env-template.git" +PH_EE_ENV_TEMPLATE_REPO_BRANCH="master" +PH_EE_ENV_TEMPLATE_REPO_DIR="ph_template" +# Define Kubernetes service and MySQL connection details +MYSQL_SERVICE_NAME="mysql" # Replace with your MySQL service name +MYSQL_SERVICE_PORT="3306" # Replace with the MySQL service port +LOCAL_PORT="3307" # Local port to forward to +MAX_WAIT_SECONDS=60 +# MySQL Connection Details +MYSQL_USER="root" +MYSQL_PASSWORD="ethieTieCh8ahv" +MYSQL_HOST="127.0.0.1" # This is the localhost because we are port forwarding +SQL_FILE="$BASE_DIR/src/mojafos/deployer/setup.sql" + +#fineract +FIN_NAMESPACE="fineract" +FIN_BRANCH="master" +FIN_REPO_LINK="https://github.com/fynarfin/fineract-env.git" +FIN_REPO_DIR="fineract" +FIN_NAMESPACE="fineract" +FIN_RELEASE_NAME="fineract" +FIN_VALUES_FILE="$BASE_DIR/src/mojafos/deployer/fin_values.yaml" + + +######################################################################## +# FUNCTIONS FOR CONFIGURATION MANAGEMENT +######################################################################## +function replaceValuesInFiles() { + local directories=("$@") + local json_file="$MOJALOOP_VALUES_FILE" + + # Check if jq is installed, if not, exit with an error message + if ! command -v jq &>/dev/null; then + echo "Error: 'jq' is not installed. Please install it (https://stedolan.github.io/jq/) and make sure it's in your PATH." + return 1 + fi + + # Check if the JSON file exists + if [ ! -f "$json_file" ]; then + echo "Error: JSON file '$json_file' does not exist." + return 1 + fi + + # Read the JSON file and create an associative array + declare -A replacements + while IFS= read -r json_object; do + local old_value new_value + old_value=$(echo "$json_object" | jq -r '.old_value') + new_value=$(echo "$json_object" | jq -r '.new_value') + replacements["$old_value"]="$new_value" + done < <(jq -c '.[]' "$json_file") + + # Loop through the directories and process each file + for dir in "${directories[@]}"; do + if [ -d "$dir" ]; then + find "$dir" -type f | while read -r file; do + local changed=false + for old_value in "${!replacements[@]}"; do + if grep -q "$old_value" "$file"; then + sed -i "s|$old_value|${replacements[$old_value]}|g" "$file" + changed=true + fi + done + if $changed; then + echo "Updated: $file" + fi + done + else + echo "Directory $dir does not exist." + fi + done +} + +function configureMojaloop() { + replaceValuesInFiles "${MOJALOOP_LAYER_DIRS[0]}" "${MOJALOOP_LAYER_DIRS[2]}" "${MOJALOOP_LAYER_DIRS[3]}" +} + + +function createSecret(){ + local namespace="$1" + echo -e "Creating secrets in the $namespace namespace" + if make secrets -e NAMESPACE="$namespace" >> /dev/null 2>&1 ; then + echo -e "${GREEN}Created secrets in the $namespace namespace${RESET}" + return 0 + else + echo -e "${RED}Creating secrets in the $namespace namespace${RESET} failed" + exit 1 + fi +} + +function configurePH() { + local ph_chart_dir=$1 + local previous_dir="$PWD" # Save the current working directory + echo -e "${BLUE}Configuring Payment Hub ${RESET}" + + cd $ph_chart_dir || exit 1 + + # Check if make is installed + if ! command -v make &> /dev/null; then + logWithVerboseCheck $debug info "make is not installed. Installing ..." + sudo apt update >> /dev/null 2>&1 + sudo apt install -y make >> /dev/null 2>&1 + logWithVerboseCheck $debug info "ok" + else + logWithVerboseCheck $debug info "make is installed. Proceeding to configure" + fi + # create secrets for paymenthub namespace and infra namespace + cd es-secret || exit 1 + createSecret "$PH_NAMESPACE" + createSecret "$INFRA_NAMESPACE" + cd .. + cd kibana-secret || exit 1 + createSecret "$PH_NAMESPACE" + createSecret "$INFRA_NAMESPACE" + cd .. + # kubectl create secret generic moja-ph-redis --from-literal=redis-password="" -n "$PH_NAMESPACE" + + # check if the configuration was successful + if [ $? -eq 0 ]; then + echo -e "${GREEN}Configuration of Paymenthub Successful${RESET}" + else + echo -e "${RED}Configuration of Paymenthub Failed${RESET}" + exit 1 + fi + + # Return to the previous working directory + cd "$previous_dir" || return 1 +} + +function configureFineract(){ + echo -e "${BLUE}Configuring fineract ${RESET}" +} \ No newline at end of file diff --git a/src/mojafos/configurationManager/mojaloop_values.json b/src/mojafos/configurationManager/mojaloop_values.json new file mode 100644 index 0000000..fff606d --- /dev/null +++ b/src/mojafos/configurationManager/mojaloop_values.json @@ -0,0 +1,18 @@ +[ + { + "old_value": "value: kafka:9092", + "new_value": "value: kafka.infra.svc.cluster.local:9092" + }, + { + "old_value": "value: mongodb:\\/\\/root:mongoDbPas42@mongodb:27017\\/", + "new_value": "value: mongodb:\\/\\/root:mongoDbPas42@mongodb.infra.svc.cluster.local:27017\\/" + }, + { + "old_value": "value: redis-master", + "new_value": "value: redis-master.infra.svc.cluster.local" + }, + { + "old_value": "value: http:\\/\\/infra-elasticsearch:9200", + "new_value": "value: http:\\/\\/mojafos-infra-elasticsearch.infra.svc.cluster.local:9200" + } +] diff --git a/src/mojafos/deployer/deployer.sh b/src/mojafos/deployer/deployer.sh new file mode 100755 index 0000000..630af21 --- /dev/null +++ b/src/mojafos/deployer/deployer.sh @@ -0,0 +1,498 @@ +#!/usr/bin/env bash + + +function deleteResourcesInNamespsceMatchingPattern(){ + local pattern="$1" + + # Check if the pattern is provided + if [ -z "$pattern" ]; then + echo "Pattern not provided." + exit 1 + fi + + # Get the list of namespaces and filter them based on the pattern + namespaces=$(kubectl get namespaces -o=name | grep "$pattern") + + # Loop through the filtered namespaces and delete resources in each one + while IFS= read -r namespace; do + namespace=$(echo "$namespace" | cut -d'/' -f2) + kubectl delete all --all -n "$namespace" + if [ $? -eq 0 ]; then + echo "All resources in namespace $namespace deleted successfully." + else + echo "Error deleting resources in namespace $namespace." + fi + done <<< "$namespaces" +} + +function deployHelmChartFromDir() { + # Check if Helm is installed + if ! command -v helm &>/dev/null; then + echo "Helm is not installed. Please install Helm first." + exit 1 + fi + + # Check if the chart directory exists + local chart_dir="$1" + local namespace="$2" + local release_name="$3" + if [ ! -d "$chart_dir" ]; then + echo "Chart directory '$chart_dir' does not exist." + exit 1 + fi + + # Check if a values file has been provided + values_file="$4" + + # Enter the chart directory + cd "$chart_dir" || exit 1 + + # Run helm dependency update to fetch dependencies + echo "Updating Helm chart dependencies..." + helm dependency update >> /dev/null 2>&1 + echo -e "==> Helm chart updated" + + # Run helm dependency build + echo "Building Helm chart dependencies..." + helm dependency build . >> /dev/null 2>&1 + echo -e "==> Helm chart dependencies built" + + # Determine whether to install or upgrade the chart also check whether to apply a values file + if [ -n "$values_file" ]; then + if helm list -n "$namespace" | grep -q "$release_name"; then + echo "Upgrading Helm chart..." + helm upgrade --install "$release_name" . -n "$namespace" -f "$values_file" + echo -e "==> Helm chart upgraded" + else + echo "Installing Helm chart..." + helm install "$release_name" . -n "$namespace" -f "$values_file" + echo -e "==> Helm chart installed" + fi + else + if helm list -n "$namespace" | grep -q "$release_name"; then + echo "Upgrading Helm chart..." + helm upgrade --install "$release_name" . -n "$namespace" + echo -e "==> Helm chart upgraded" + else + echo "Installing Helm chart..." + helm install "$release_name" . -n "$namespace" + echo -e "==> Helm chart installed" + fi + fi + + # Use kubectl to get the resource count in the specified namespace + resource_count=$(kubectl get pods -n "$namespace" --ignore-not-found=true 2>/dev/null | grep -v "No resources found" | wc -l) + + # Check if the deployment was successful + if [ $resource_count -gt 0 ]; then + echo "Helm chart deployed successfully." + else + echo -e "${RED}Helm chart deployment failed.${RESET}" + cleanUp + fi + + # Exit the chart directory + cd - || exit 1 + +} + +function preparePaymentHubChart(){ + # Clone the repositories + cloneRepo "$PH_EE_ENV_LABS_REPO_BRANCH" "$PH_EE_ENV_LABS_REPO_LINK" "$APPS_DIR" "$PH_EE_ENV_LABS_REPO_DIR" + cloneRepo "$PH_EE_ENV_TEMPLATE_REPO_BRANCH" "$PH_EE_ENV_TEMPLATE_REPO_LINK" "$APPS_DIR" "$PH_EE_ENV_TEMPLATE_REPO_DIR" + + # Update helm dependencies and repo index for ph-ee-engine + phEEenginePath="$APPS_DIR$PH_EE_ENV_TEMPLATE_REPO_DIR/helm/ph-ee-engine" + pushd "$phEEenginePath" + helm dep update + helm repo index . + popd + + # Update helm dependencies and repo index for g2p-sandbox in ph-ee-env-template + g2pSandboxChartPath="$APPS_DIR$PH_EE_ENV_TEMPLATE_REPO_DIR/helm/g2p-sandbox" + awk '/repository:/ && c == 0 {sub(/repository: .*/, "repository: file://../ph-ee-engine"); c++} {print}' "$g2pSandboxChartPath/Chart.yaml" > "$g2pSandboxChartPath/Chart.yaml.tmp" && mv "$g2pSandboxChartPath/Chart.yaml.tmp" "$g2pSandboxChartPath/Chart.yaml" + pushd "$g2pSandboxChartPath" + helm dep update + helm repo index . + popd + + # Update helm dependencies and repo index for g2p-sandbox-fynarfin-SIT in ph-ee-env-labs + g2pSandboxFinalChartPath="$APPS_DIR$PH_EE_ENV_LABS_REPO_DIR/helm/g2p-sandbox-fynarfin-SIT" + awk '/repository:/ && c == 0 {sub(/repository: .*/, "repository: file://../../../'$PH_EE_ENV_TEMPLATE_REPO_DIR'/helm/g2p-sandbox"); c++} {print}' "$g2pSandboxFinalChartPath/Chart.yaml" > "$g2pSandboxFinalChartPath/Chart.yaml.tmp" && mv "$g2pSandboxFinalChartPath/Chart.yaml.tmp" "$g2pSandboxFinalChartPath/Chart.yaml" + pushd "$g2pSandboxFinalChartPath" + helm dep update + helm repo index . + popd +} + +function deployPhHelmChartFromDir(){ + # Parameters + local namespace="$1" + local chartDir="$2" # Directory containing the Helm chart + local valuesFile="$3" # Values file for the Helm chart + + # Check if Helm is installed + if ! command -v helm &>/dev/null; then + echo "Helm is not installed. Please install Helm first." + exit 1 + fi + + # Check if kubectl is installed + if ! command -v kubectl &>/dev/null; then + echo "kubectl is not installed. Please install kubectl first." + exit 1 + fi + + # Install Prometheus Operator as a dependency + LATEST=$(curl -s https://api.github.com/repos/prometheus-operator/prometheus-operator/releases/latest | jq -cr .tag_name) + su - "$k8s_user" -c "curl -sL https://github.com/prometheus-operator/prometheus-operator/releases/download/${LATEST}/bundle.yaml | kubectl create -f -" + + # Install the Helm chart from the local directory + if [ -z "$valuesFile" ]; then + su - "$k8s_user" -c "helm install $PH_RELEASE_NAME $chartDir -n $namespace" + else + su - "$k8s_user" -c "helm install $PH_RELEASE_NAME $chartDir -n $namespace -f $valuesFile" + fi + + # Check deployment status + resource_count=$(kubectl get pods -n "$namespace" --ignore-not-found=true 2>/dev/null | grep -v "No resources found" | wc -l) + + if [ "$resource_count" -gt 0 ]; then + echo "Helm chart deployed successfully." + else + echo -e "${RED}Helm chart deployment failed.${RESET}" + cleanUp + fi +} + +function createNamespace () { + local namespace=$1 + printf "==> Creating namespace $namespace \n" + # Check if the namespace already exists + if kubectl get namespace "$namespace" >> /dev/null 2>&1; then + echo -e "${RED}Namespace $namespace already exists.${RESET}" + exit 1 + fi + + # Create the namespace + kubectl create namespace "$namespace" + if [ $? -eq 0 ]; then + echo -e "==> Namespace $namespace created successfully." + else + echo "Failed to create namespace $namespace." + fi +} + +function deployInfrastructure () { + printf "==> Deploying infrastructure \n" + createNamespace $INFRA_NAMESPACE + if [ "$debug" = true ]; then + deployHelmChartFromDir "./src/mojafos/deployer/helm/infra" "$INFRA_NAMESPACE" "$INFRA_RELEASE_NAME" + else + deployHelmChartFromDir "./src/mojafos/deployer/helm/infra" "$INFRA_NAMESPACE" "$INFRA_RELEASE_NAME" >> /dev/null 2>&1 + fi + echo -e "\n${GREEN}============================" + echo -e "Infrastructure Deployed" + echo -e "============================${RESET}\n" +} + +function cloneRepo() { + if [ "$#" -ne 4 ]; then + echo "Usage: cloneRepo " + return 1 + fi + + # Store the current working directory + original_dir="$(pwd)" + + branch="$1" + repo_link="$2" + target_directory="$3" + cloned_directory_name="$4" + + # Check if the target directory exists; if not, create it. + if [ ! -d "$target_directory" ]; then + mkdir -p "$target_directory" + fi + + # Change to the target directory. + cd "$target_directory" || return 1 + + # Clone the repository with the specified branch into the specified directory. + if [ -d "$cloned_directory_name" ]; then + echo -e "${YELLOW}$cloned_directory_name Repo exists deleting and re-cloning ${RESET}" + rm -rf "$cloned_directory_name" + git clone -b "$branch" "$repo_link" "$cloned_directory_name" >> /dev/null 2>&1 + else + git clone -b "$branch" "$repo_link" "$cloned_directory_name" >> /dev/null 2>&1 + fi + + if [ $? -eq 0 ]; then + echo "==> Repository cloned successfully." + else + echo "Failed to clone the repository." + fi + + # Change back to the original directory + cd "$original_dir" || return 1 +} + +function applyKubeManifests() { + if [ "$#" -ne 2 ]; then + echo "Usage: applyKubeManifests " + return 1 + fi + + local directory="$1" + local namespace="$2" + + # Check if the directory exists. + if [ ! -d "$directory" ]; then + echo "Directory '$directory' not found." + return 1 + fi + + # Use 'kubectl apply' to apply manifests in the specified directory. + kubectl apply -f "$directory" -n "$namespace" >> /dev/null 2>&1 + + if [ $? -eq 0 ]; then + echo -e "==>Kubernetes manifests applied successfully." + else + echo -e "${RED}Failed to apply Kubernetes manifests.${RESET}" + fi +} + +function runFailedSQLStatements(){ + echo "Fxing Operations App MySQL Race condition" + operationsDeplName=$(kubectl get deploy --no-headers -o custom-columns=":metadata.name" -n $PH_NAMESPACE | grep operations-app) + kubectl exec -it mysql-0 -n infra -- mysql -h mysql -uroot -pethieTieCh8ahv < src/mojafos/deployer/setup.sql + + if [ $? -eq 0 ];then + echo "SQL File execution successful" + else + echo "SQL File execution failed" + exit 1 + fi + + echo "Restarting Deployment for Operations App" + kubectl rollout restart deploy/$operationsDeplName -n $PH_NAMESPACE + + if [ $? -eq 0 ];then + echo "Deployment Restart successful" + else + echo "Deployment Restart failed" + exit 1 + fi +} + +function addKubeConfig(){ + K8sConfigDir="$k8s_user_home/.kube" + + if [ ! -d "$K8sConfigDir" ]; then + su - $k8s_user -c "mkdir -p $K8sConfigDir" + echo "K8sConfigDir created: $K8sConfigDir" + else + echo "K8sConfigDir already exists: $K8sConfigDir" + fi + su - $k8s_user -c "cp $k8s_user_home/k3s.yaml $K8sConfigDir/config" +} + +#Function to run kong migrations in Kong init container +function runKongMigrations(){ + echo "Fixing Kong Migrations" + #StoreKongPods + kongPods=$(kubectl get pods --no-headers -o custom-columns=":metadata.name" -n $PH_NAMESPACE | grep moja-ph-kong) + dBcontainerName="wait-for-db" + for pod in $kongPods; + do + podName=$(kubectl get pod $pod --no-headers -o custom-columns=":metadata.labels.app" -n $PH_NAMESPACE) + if [[ "$podName" == "moja-ph-kong" ]]; then + initContainerStatus=$(kubectl get pod $pod --no-headers -o custom-columns=":status.initContainerStatuses[0].ready" -n $PH_NAMESPACE) + while [[ "$initContainerStatus" != "true" ]]; do + printf "\rReady State: $initContainerStatus Waiting for status to become true ..." + initContainerStatus=$(kubectl get pod $pod --no-headers -o custom-columns=":status.initContainerStatuses[0].ready" -n $PH_NAMESPACE) + sleep 5 + done + echo "Status is now true" + while kubectl get pod "$podName" -o jsonpath="{:status.initContainersStatuses[1].name}" | grep -q "$dBcontainerName" ; do + printf "\r Waiting for Init DB container to be created ..." + sleep 5 + done + + echo && echo $pod + statusCode=1 + while [ $statusCode -eq 1 ]; do + printf "\rRunning Migrations ..." + kubectl exec $pod -c $dBcontainerName -n $PH_NAMESPACE -- kong migrations bootstrap >> /dev/null 2>&1 + statusCode=$? + if [ $statusCode -eq 0 ]; then + echo "\nKong Migrations Successful" + fi + done + else + continue + fi + done +} + +function postPaymenthubDeploymentScript(){ + #Run migrations in Kong Pod + runKongMigrations + # Run failed MySQL statements. + runFailedSQLStatements +} + +function deployMojaloop() { + echo "Deploying Mojaloop vNext application manifests" + createNamespace "$MOJALOOP_NAMESPACE" + echo + cloneRepo "$MOJALOOPBRANCH" "$MOJALOOP_REPO_LINK" "$APPS_DIR" "$MOJALOOPREPO_DIR" + echo + # renameOffToYaml "${MOJALOOP_LAYER_DIRS[0]}" + echo + configureMojaloop + + for index in "${!MOJALOOP_LAYER_DIRS[@]}"; do + folder="${MOJALOOP_LAYER_DIRS[index]}" + echo "Deploying files in $folder" + applyKubeManifests "$folder" "$MOJALOOP_NAMESPACE" + if [ "$index" -eq 0 ]; then + echo -e "${BLUE}Waiting for Mojaloop cross cutting concerns to come up${RESET}" + sleep 10 + echo -e "Proceeding ..." + fi + done + + echo -e "\n${GREEN}============================" + echo -e "Mojaloop Deployed" + echo -e "============================${RESET}\n" +} + +function deployPaymentHubEE() { + echo "Deploying PaymentHub EE" + createNamespace "$PH_NAMESPACE" + cloneRepo "$PHBRANCH" "$PH_REPO_LINK" "$APPS_DIR" "$PHREPO_DIR" + configurePH "$APPS_DIR$PHREPO_DIR/helm" + + for((i=1; i<=2; i++)) + do + if [ "$debug" = true ]; then + deployHelmChartFromDir "$APPS_DIR$PHREPO_DIR/helm/g2p-sandbox-fynarfin-SIT" "$PH_NAMESPACE" "$PH_RELEASE_NAME" "$PH_VALUES_FILE" + else + deployHelmChartFromDir "$APPS_DIR$PHREPO_DIR/helm/g2p-sandbox-fynarfin-SIT" "$PH_NAMESPACE" "$PH_RELEASE_NAME" "$PH_VALUES_FILE" >> /dev/null 2>&1 + fi + done + + echo -e "\n${YELLOW}Fixing Paymenthub post deployment issues(might take a while)...${RESET}" + postPaymenthubDeploymentScript >> /dev/null 2>&1 + + echo -e "\n${GREEN}============================" + echo -e "Paymenthub Deployed" + echo -e "============================${RESET}\n" +} + +function deployPH(){ + echo "Deploying PaymentHub EE" + createNamespace "$PH_NAMESPACE" + cloneRepo "$PHBRANCH" "$PH_REPO_LINK" "$APPS_DIR" "$PHREPO_DIR" + configurePH "$APPS_DIR$PHREPO_DIR/helm" + # deployPhHelmChartFromRepo "$PH_NAMESPACE" + preparePaymentHubChart + deployPhHelmChartFromDir "$PH_NAMESPACE" "$g2pSandboxFinalChartPath" "$PH_VALUES_FILE" + + echo -e "\n${GREEN}============================" + echo -e "Paymenthub Deployed" + echo -e "============================${RESET}\n" +} + +function deployFineract() { + echo -e "${BLUE}Deploying Fineract${RESET}" + + cloneRepo "$FIN_BRANCH" "$FIN_REPO_LINK" "$APPS_DIR" "$FIN_REPO_DIR" + configureFineract + + num_instances=$1 + + if [[ -z "$num_instances" ]];then + num_instances=2 + fi + + echo -e "Deploying $num_instances instances of fineract" + + # Check if the input is a valid integer + for ((i=1; i<=num_instances; i++)) + do + sed -i "s/\([0-9]-\)\?fynams.sandbox.fynarfin.io/$i-fynams.sandbox.fynarfin.io/" "$FIN_VALUES_FILE" + sed -i "s/\([0-9]-\)\?communityapp.sandbox.fynarfin.io/$i-communityapp.sandbox.fynarfin.io/" "$FIN_VALUES_FILE" + sed -i "s/\([0-9]-\)\?webapp.sandbox.fynarfin.io/$i-webapp.sandbox.fynarfin.io/" "$FIN_VALUES_FILE" + createNamespace "$FIN_NAMESPACE-$i" + if [ "$debug" = true ]; then + deployHelmChartFromDir "$APPS_DIR$FIN_REPO_DIR/helm/fineract" "$FIN_NAMESPACE-$i" "$FIN_RELEASE_NAME-$i" "$FIN_VALUES_FILE" + else + deployHelmChartFromDir "$APPS_DIR$FIN_REPO_DIR/helm/fineract" "$FIN_NAMESPACE-$i" "$FIN_RELEASE_NAME-$i" "$FIN_VALUES_FILE" >> /dev/null 2>&1 + fi + + echo -e "\n${GREEN}============================" + echo -e "fineract-$i Deployed" + echo -e "============================${RESET}\n" + done +} + +function test_ml { + echo "TODO" #TODO Write function to test apps +} + +function test_ph { + echo "TODO" +} + +function test_fin { + local instance_name=$1 +} + +function printEndMessage { + echo -e "===========================" + echo -e "Thank you for using Mojafos" + echo -e "===========================\n\n" + echo -e "CHECK DEPLOYMENTS USING kubectl" + echo -e "kubectl get pods -n mojaloop #For testing mojaloop" + echo -e "kubectl get pods -n paymenthub #For testing paymenthub" + echo -e "kubectl get pods -n fineract-x #For testing fineract. x is a number of a fineract instance\n\n" + echo -e "Copyright © 2023 The Mifos Initiative" +} + +function deployApps { + fin_num_instances="$1" + appsToDeploy="$2" + + if [ -z "$appsToDeploy" ]; then + echo -e "${BLUE}Deploying all apps ...${RESET}" + deployInfrastructure + deployMojaloop + deployPH + deployFineract "$fin_num_instances" + elif [[ "$appsToDeploy" == "all" ]]; then + echo -e "${BLUE}Deploying all apps ...${RESET}" + deployInfrastructure + deployMojaloop + deployPH + deployFineract "$fin_num_instances" + elif [[ "$appsToDeploy" == "moja" ]];then + deployInfrastructure + deployMojaloop + elif [[ "$appsToDeploy" == "fin" ]]; then + deployInfrastructure + deployFineract "$fin_num_instances" + elif [[ "$appsToDeploy" == "ph" ]]; then + deployPH + else + echo -e "${RED}Invalid option ${RESET}" + echo "Defaulting to all... " + deployInfrastructure + deployMojaloop + deployPH + deployFineract "$fin_num_instances" + fi + addKubeConfig >> /dev/null 2>&1 + printEndMessage +} diff --git a/src/mojafos/deployer/fin_values.yaml b/src/mojafos/deployer/fin_values.yaml new file mode 100644 index 0000000..9cd2d7b --- /dev/null +++ b/src/mojafos/deployer/fin_values.yaml @@ -0,0 +1,115 @@ +fineract: + enabled: true + db: fineract-mysql + DFSPIDS: "" + SPRING_PROFILES_ACTIVE: "bb" + image: "openmf/fineract:latest" + spec: + template: + spec: + containers: + env: + FINERACT_DEFAULT_TENANTDB_IDENTIFIER: "default" + FINERACT_DEFAULT_TENANTDB_NAME: "fineract_default" + FINERACT_DEFAULT_TENANTDB_HOSTNAME: "mysql.infra.svc.cluster.local" + FINERACT_DEFAULT_TENANTDB_PORT: "3306" + FINERACT_HIKARI_DRIVER_CLASS_NAME: org.mariadb.jdbc.Driver + FINERACT_HIKARI_JDBC_URL: jdbc:mariadb://mysql.infra.svc.cluster.local:3306/fineract_tenants + FINERACT_SERVER_PORT: 8443 + preStopScript: 'echo -e "******Fineract is stopping********";' + ingress: + enabled: true + hostname: "2-fynams.sandbox.fynarfin.io" + path: "/" + wildcardhostname: "*.sandbox.fynarfin.io" + annotations: + kubernetes.io/ingress.class: "nginx" + nginx.ingress.kubernetes.io/backend-protocol: "HTTPS" + resources: + limits: + cpu: "1000m" + memory: "2Gi" + requests: + cpu: "1m" + memory: "100m" + +communityapp: + enabled: true + lookforservice: true + image: "openmf/community-app:latest" + ingress: + enabled: true + hostname: "2-communityapp.sandbox.fynarfin.io" + path: "/" + wildcardhostname: "2-communityapp.sandbox.fynarfin.io" + annotations: + kubernetes.io/ingress.class: "nginx" + resources: + limits: + cpu: "500m" + memory: "1Gi" + requests: + cpu: "200m" + memory: "500m" + +webapp: + enabled: false + image: "fintecheando/web-app:master" + ingress: + enabled: true + hostname: "2-webapp.sandbox.fynarfin.io" + path: "/web" + annotations: + kubernetes.io/ingress.class: "nginx" + resources: + limits: + cpu: "500m" + memory: "1Gi" + requests: + cpu: "200m" + memory: "500m" + +selfservice: + image: "419830066942.dkr.ecr.ap-south-1.amazonaws.com/fineract/phee-ns/web-self-service-app:latest" + ingress: + enabled: false + hostname: "" + path: "/self" + annotations: {} + + +mariadb: + enabled: false + + +mysql: + fullnameOverride: fineract-mysql + enabled: false + image: + tag: "10.5.16-debian-11-r22" + debug: true + auth: + username: "mifos" + password: "password" + rootPassword: "4ET6ywqlGt" + initdbScripts: + setup.sql: |- + # create databases + CREATE DATABASE IF NOT EXISTS `fineract_tenants`; + CREATE DATABASE IF NOT EXISTS `fineract_default`; + # create root user and grant rights + GRANT ALL ON *.* TO 'root'@'%'; + GRANT ALL PRIVILEGES ON `fineract_tenants`.* TO 'mifos'; + GRANT ALL PRIVILEGES ON `fineract_default`.* TO 'mifos'; + primary: + resources: + requests: + memory: "500m" + cpu: "500m" + limits: + memory: "2Gi" + cpu: "1000m" + +wildcardhostname: "*.sandbox.fynarfin.io" + +tls: "" \ No newline at end of file diff --git a/src/mojafos/deployer/helm/infra/Chart.lock b/src/mojafos/deployer/helm/infra/Chart.lock new file mode 100644 index 0000000..3dd8d3d --- /dev/null +++ b/src/mojafos/deployer/helm/infra/Chart.lock @@ -0,0 +1,24 @@ +dependencies: +- name: kafka + repository: https://charts.bitnami.com/bitnami + version: 19.0.2 +- name: console + repository: https://charts.redpanda.com + version: 0.6.6 +- name: mongodb + repository: https://charts.bitnami.com/bitnami + version: 13.3.1 +- name: mongo-express + repository: https://cowboysysop.github.io/charts/ + version: 3.1.1 +- name: redis + repository: https://charts.bitnami.com/bitnami + version: 17.11.6 +- name: elasticsearch + repository: https://charts.bitnami.com/bitnami + version: 19.9.2 +- name: mysql + repository: https://charts.bitnami.com/bitnami + version: 9.4.5 +digest: sha256:7ba3ea9a03eaa2abafee8c647e7976a22d7b82ad48fdd2a9dfbaa3bb65bbf910 +generated: "2023-09-06T11:55:49.830694633Z" diff --git a/src/mojafos/deployer/helm/infra/Chart.yaml b/src/mojafos/deployer/helm/infra/Chart.yaml new file mode 100644 index 0000000..9e690f0 --- /dev/null +++ b/src/mojafos/deployer/helm/infra/Chart.yaml @@ -0,0 +1,84 @@ +apiVersion: v2 +description: Helm chart for mojafos infrastructure services +name: mojafos-infra +version: 15.0.0 +appVersion: "kafka: 19.0.2; console: 0.6.6; mongodb: 13.3.1; mongo-express: 3.1.1; elasticsearch:19.9.2; redis: 17.11.6" +home: https://summerofcode.withgoogle.com/programs/2023/projects/oQk6Gmup +icon: https://summerofcode.withgoogle.com/assets/media/logo.svg +sources: +- https://github.com/elijah0kello/mojafos +maintainers: +- name: Elijah Okello + email: elijahokello90@gmail.com +dependencies: +## kafka +- name: kafka + alias: kafka + condition: kafka.enabled + repository: https://charts.bitnami.com/bitnami + tags: + - mojafos + - dependency + - kafka + version: 19.0.2 +## redpanda kafka console +- name: console + alias: redpanda-console + condition: console.enabled + repository: https://charts.redpanda.com + tags: + - mojafos + - dependency + - kafka + - redpanda + version: 0.6.6 +## MongoDB +- name: mongodb + alias: mongodb + condition: mongodb.enabled + repository: https://charts.bitnami.com/bitnami + tags: + - mojafos + - dependency + - mongodb + version: 13.3.1 +## Mongo-express +- name: mongo-express + alias: mongo-express + condition: mongo-express.enabled + repository: https://cowboysysop.github.io/charts/ + tags: + - mojafos + - dependency + - mongodb + version: 3.1.1 +## redis +- name: redis + alias: redis + condition: redis.enabled + repository: https://charts.bitnami.com/bitnami + tags: + - mojafos + - dependency + - mongodb + version: 17.11.6 +## Elastic Search Kibana +- name: elasticsearch + alias: elasticsearch + condition: elasticsearch.enabled + repository: https://charts.bitnami.com/bitnami + tags: + - mojafos + - dependency + - elasticsearch + version: 19.9.2 +## MySQL +- name: mysql + alias: mysql + condition: mysql.enabled + repository: https://charts.bitnami.com/bitnami + tags: + - mojafos + - dependency + - mysql + version: 9.4.5 diff --git a/src/mojafos/deployer/helm/infra/values.yaml b/src/mojafos/deployer/helm/infra/values.yaml new file mode 100644 index 0000000..11d0bfd --- /dev/null +++ b/src/mojafos/deployer/helm/infra/values.yaml @@ -0,0 +1,217 @@ +# Declare global configurations +global: + kibanaEnabled: false + +############### Kafka and Zookeeper #################### +## Reference: https://github.com/bitnami/charts/blob/main/bitnami/kafka/values.yaml +kafka: + enabled: true + fullnameOverride: "kafka" + + persistence: + enabled: false + + ## https://github.com/bitnami/charts/blob/main/bitnami/zookeeper/values.yaml + zookeeper: + persistence: + enabled: true + + fullnameOverride: "zookeeper" + + ## Kafka provisioning + provisioning: + enabled: true + numPartitions: 1 + replicationFactor: 1 + + topics: + - name: KAFKA_AUDITS_TOPIC + value: audits + - name: KAFKA_LOGS_TOPIC + value: logs + - name: AccountLookupBcRequests + value: AccountLookupBcRequests + - name: AccountLookupBcEvents + value: AccountLookupBcEvents + - name: AccountLookupBcResponses + value: AccountLookupBcResponses + - name: AccountLookupBcErrors + value: AccountLookupBcErrors + - name: OperatorBcErrors + value: OperatorBcErrors + - name: QuotingBcErrors + value: QuotingBcErrors + - name: QuotingBcEvents + value: QuotingBcEvents + - name: QuotingBcRequests + value: QuotingBcRequests + - name: SettlementsBcRequests + value: SettlementsBcRequests + - name: TransfersBcErrors + value: TransfersBcErrors + - name: TransfersBcEvents + value: TransfersBcEvents + - name: TransfersBcRequests + value: TransfersBcRequests + - name: SettlementsBcEvents + value: SettlementsBcEvents + - name: SettlementsBcCommands + value: SettlementsBcCommands + - name: PlatformConfigurationBcEvents + value: PlatformConfigurationBcEvents + - name: TransfersBcTimeouts + value: TransfersBcTimeouts + - name: ParticipantsBcEvents + value: ParticipantsBcEvents + - name: SchedulingBcCommands + value: SchedulingBcCommands + - name: SchedulingBcEvents + value: SchedulingBcEvents + - name: SecurityBcAuthorizationEvents + value: SecurityBcAuthorizationEvents + - name: SecurityBcEvents + value: SecurityBcEvents + + + + + nodeSelector: {} + tolerations: [] + waitForKafka: true + +############### RedPanda Console for Kafka #################### +# https://artifacthub.io/packages/helm/redpanda-data/console?modal=values +# redpanda kakfa console config + +redpanda-console: + enabled: true + fullnameOverride: rpconsole + + console: + config: + kafka: + brokers: + - kafka:9092 + + ingress: + enabled: true + className: nginx + hosts: + - host: redpanda-console.local + paths: + - path: / + pathType: ImplementationSpecific + +############### MongoDB #################### +# https://github.com/bitnami/charts/tree/main/bitnami/mongodb +mongodb: + enabled: true + image: + tag: 5.0.18-debian-11-r8 + + fullnameOverride: "mongodb" + auth: + enabled: true + + rootUser: root + rootPassword: mongoDbPas42 + usernames: + - 'mojaloop' + passwords: + - 'password' + databases: + - 'mlos' + + replicaSetKey: "" + existingSecret: "" + persistence: + enabled: false + +############### Mongo Express #################### +# mongo express config +mongo-express: + fullnameOverride: mongo-express + enabled: true + + ingress: + enabled: true + ingressClassName: nginx + + mongodbEnableAdmin: true + mongodbAdminPassword: mongoDbPas42 + +############### Redis #################### +## Reference: https://github.com/bitnami/charts/blob/main/bitnami/redis/values.yaml +redis: + enabled: true + fullnameOverride: redis + architecture: standalone + auth: + enabled: false + master: + disableCommands: [] + persistence: + enabled: false + +############### Elasticsearch and Kibana #################### +elasticsearch: + enabled: true + # fullnameOverride: "elastic" + + security: + elasticPassword: elasticSearchPas42 + tls: + restEncryption: false + + coordinating: + replicaCount: 1 + + master: + replicaCount: 1 + persistence: + enabled: false + + data: + replicaCount: 1 + persistence: + enabled: false + + ingest: + replicaCount: 1 + + ingress: + enabled: true + # hostname: es01 + +############### MySQL #################### +mysql: + fullnameOverride: "mysql" + enabled: true + auth: + database: "tenants" + username: "mifos" + password: "password" + rootPassword: "ethieTieCh8ahv" + image: + tag: "5.7" + debug: false + initdbScripts: + setup.sql: |- + CREATE DATABASE messagegateway; + CREATE DATABASE `rhino`; + CREATE DATABASE `gorilla`; + CREATE DATABASE `lion`; + CREATE DATABASE `identity_account_mapper`; + CREATE DATABASE `voucher_management`; + GRANT ALL PRIVILEGES ON `rhino`.* TO 'mifos'; + GRANT ALL PRIVILEGES ON `gorilla`.* TO 'mifos'; + GRANT ALL PRIVILEGES ON `lion`.* TO 'mifos'; + GRANT ALL ON *.* TO 'root'@'%'; + GRANT ALL PRIVILEGES ON messagegateway.* TO 'mifos'; + GRANT ALL PRIVILEGES ON `identity_account_mapper`.* TO 'mifos'; + GRANT ALL PRIVILEGES ON `voucher_management`.* TO 'mifos'; + CREATE DATABASE IF NOT EXISTS `fineract_tenants`; + CREATE DATABASE IF NOT EXISTS `fineract_default`; + GRANT ALL ON *.* TO 'root'@'%'; + GRANT ALL PRIVILEGES ON `fineract_tenants`.* TO 'mifos'; + GRANT ALL PRIVILEGES ON `fineract_default`.* TO 'mifos'; diff --git a/src/mojafos/deployer/ph_values.yaml b/src/mojafos/deployer/ph_values.yaml new file mode 100644 index 0000000..a2bd83e --- /dev/null +++ b/src/mojafos/deployer/ph_values.yaml @@ -0,0 +1,24 @@ +ph-ee-engine: + elasticsearch: + volumeClaimTemplate: + storageClassName: "local-path" + + notifications: + limits: + cpu: "1000m" + memory: "2000M" + requests: + cpu: "1m" + memory: "1M" + + operations_web: + ingress: + enabled: true + + operations_app: + limits: + cpu: "1000m" + memory: "2000M" + requests: + cpu: "1m" + memory: "1M" \ No newline at end of file diff --git a/src/mojafos/deployer/setup.sql b/src/mojafos/deployer/setup.sql new file mode 100644 index 0000000..e3dd5d8 --- /dev/null +++ b/src/mojafos/deployer/setup.sql @@ -0,0 +1,6 @@ +DROP DATABASE `tenants`; +CREATE DATABASE `tenants`; +GRANT ALL PRIVILEGES ON `tenants`.* TO 'mifos'; +GRANT ALL PRIVILEGES ON `rhino`.* TO 'mifos'; +GRANT ALL PRIVILEGES ON `gorilla`.* TO 'mifos'; +GRANT ALL ON *.* TO 'root'@'%'; diff --git a/src/mojafos/environmentSetup/environmentSetup.sh b/src/mojafos/environmentSetup/environmentSetup.sh new file mode 100755 index 0000000..65e5627 --- /dev/null +++ b/src/mojafos/environmentSetup/environmentSetup.sh @@ -0,0 +1,582 @@ +#!/usr/bin/env bash + +function check_arch_ok { + if [[ ! "$k8s_arch" == "x86_64" ]]; then + printf " **** Warning : mojafos only works properly with x86_64 today but vNext should be ok *****\n" + fi +} + +function check_resources_ok { + # Get the total amount of installed RAM in GB + total_ram=$(free -g | awk '/^Mem:/{print $2}') + # Get the current free space on the root filesystem in GB + free_space=$(df -BG ~ | awk '{print $4}' | tail -n 1 | sed 's/G//') + + # Check RAM + if [[ "$total_ram" -lt "$MIN_RAM" ]]; then + printf " ** Error : mojafos currently requires $MIN_RAM GBs to run properly \n" + printf " Please increase RAM available before trying to run mojafos \n" + exit 1 + fi + # Check free space + if [[ "$free_space" -lt "$MIN_FREE_SPACE" ]] ; then + printf " ** Warning : mojafos currently requires %sGBs free storage in %s home directory \n" "$MIN_FREE_SPACE" "$k8s_user" + printf " but only found %sGBs free storage \n" "$free_space" + printf " mojafos installation will continue , but beware it might fail later due to insufficient storage \n" + fi +} + +function set_user { + # set the k8s_user +# k8s_user=`whoami | cut -d " " -f1` + logWithVerboseCheck $debug info "k8s user is $k8s_user" +} + +function k8s_already_installed { + if [[ -f "/usr/local/bin/k3s" ]]; then + printf "** Error , k3s is already installed , please delete before reinstalling kubernetes **\n" + exit 1 + fi + #check to ensure microk8s isn't already installed when installing k3s + if [[ -f "/snap/bin/microk8s" ]]; then + printf "** Error , microk8s is already installed, please delete before reinstalling kubernetes **\n" + exit 1 + fi +} + +function set_linux_os_distro { + + LINUX_VERSION="Unknown" + if [ -x "/usr/bin/lsb_release" ]; then + LINUX_OS=`lsb_release --d | perl -ne 'print if s/^.*Ubuntu.*(\d+).(\d+).*$/Ubuntu/' ` + LINUX_VERSION=`/usr/bin/lsb_release --d | perl -ne 'print $& if m/(\d+)/' ` + else + LINUX_OS="Untested" + fi + printf "\r==> Linux OS is [%s] " "$LINUX_OS" +} + +function check_os_ok { + printf "\r==> checking OS and kubernetes distro is tested with mojafos scripts\n" + set_linux_os_distro + + if [[ ! $LINUX_OS == "Ubuntu" ]]; then + printf "** Error , mojafos $MINILOOP_VERSION is only tested with Ubuntu OS at this time **\n" + exit 1 + fi +} + +function install_prerequisites { + printf "\n\r==> Install any OS prerequisites , tools & updates ...\n" + if [[ $LINUX_OS == "Ubuntu" ]]; then + printf "\rapt update \n" + apt update > /dev/null 2>&1 + + if [[ $k8s_distro == "microk8s" ]]; then + printf " install snapd\n" + apt install snapd -y > /dev/null 2>&1 + fi + + # Check if Docker is installed + if ! command -v docker &> /dev/null; then + logWithVerboseCheck $debug debug "Docker is not installed. Installing Docker..." + + # Update package index and install prerequisites + sudo apt update >> /dev/null 2>&1 + sudo apt install -y apt-transport-https ca-certificates curl software-properties-common >> /dev/null 2>&1 + + # Add Docker GPG key + curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg >> /dev/null 2>&1 + + # Add Docker repository + echo "deb [signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list >> /dev/null 2>&1 + + # Update package index again and install Docker + sudo apt update >> /dev/null 2>&1 + sudo apt install -y docker-ce docker-ce-cli containerd.io >> /dev/null 2>&1 + + # Add your user to the docker group (optional) + sudo usermod -aG docker $USER + + printf "ok \n" + else + logWithVerboseCheck $debug debug "Docker is already installed.\n" + fi + + # Check if nc (netcat) is installed + if ! command -v nc &> /dev/null; then + logWithVerboseCheck $debug debug "nc (netcat) is not installed. Installing..." + + # Update package manager repositories and install nc + apt-get update >> /dev/null 2>&1 + apt-get install -y netcat >> /dev/null 2>&1 + + printf "ok\n" + else + logWithVerboseCheck $debug debug "nc (netcat) is already installed.\n" + fi + + # Check if jq is installed + if ! command -v jq &> /dev/null; then + logWithVerboseCheck $debug debug "jq is not installed. Installing ..." + sudo apt-get update >> /dev/null 2>&1 + sudo apt-get -y install jq >> /dev/null 2>&1 + + printf "ok\n" + else + logWithVerboseCheck $debug debug "jq is already installed\n" + fi + fi +} + +function add_hosts { + printf "==> Mojafos : update hosts file \n" + ENDPOINTSLIST=(127.0.0.1 ml-api-adapter.local central-ledger.local account-lookup-service.local account-lookup-service-admin.local + quoting-service.local central-settlement-service.local transaction-request-service.local central-settlement.local bulk-api-adapter.local + moja-simulator.local sim-payerfsp.local sim-payeefsp.local sim-testfsp1.local sim-testfsp2.local sim-testfsp3.local sim-testfsp4.local + mojaloop-simulators.local finance-portal.local operator-settlement.local settlement-management.local testing-toolkit.local + testing-toolkit-specapi.local apachehost + mongohost.local mongo-express.local vnextadmin elasticsearch.local redpanda-console.local fspiop.local bluebank.local greenbank.local bluebank-specapi.local greenbank-specapi.local ) + + export ENDPOINTS=`echo ${ENDPOINTSLIST[*]}` + + perl -p -i.bak -e 's/127\.0\.0\.1.*localhost.*$/$ENV{ENDPOINTS} /' /etc/hosts + # TODO check the ping actually works > suggest cloud network rules if it doesn't + # also for cloud VMs might need to use something other than curl e.g. netcat ? + # ping -c 2 account-lookup-service-admin.local +} + +function set_k8s_distro { + if [ -z ${k8s_distro+x} ]; then + k8s_distro=$DEFAULT_K8S_DISTRO + printf "==> Using default kubernetes distro [%s]\n" "$k8s_distro" + else + k8s_distro=`echo "$k8s_distro" | perl -ne 'print lc'` + if [[ "$k8s_distro" == "microk8s" || "$k8s_distro" == "k3s" ]]; then + printf "\r==> kubernetes distro set to [%s] \n" "$k8s_distro" + else + printf "** Error : invalid kubernetes distro specified. Valid options are microk8s or k3s \n" + exit 1 + fi + fi +} + +function print_current_k8s_releases { + printf " Current Kubernetes releases are : " + for i in "${K8S_CURRENT_RELEASE_LIST[@]}"; do + printf " [v%s]" "$i" + done + printf "\n" +} + +function set_k8s_version { + # printf "========================================================================================\n" + # printf " set the k8s version to install \n" + # printf "========================================================================================\n\n" + # Users who want to run non-current versions of kubernetes will need to use earlier releases of mojafos and + # and be aware that these are not being actively maintained + if [ ! -z ${k8s_user_version+x} ] ; then + # strip off any leading characters + k8s_user_version=`echo $k8s_user_version | tr -d A-Z | tr -d a-z ` + for i in "${K8S_CURRENT_RELEASE_LIST[@]}"; do + if [[ "$k8s_user_version" == "$i" ]]; then + CURRENT_RELEASE=true + break + fi + done + if [[ $CURRENT_RELEASE == true ]]; then + K8S_VERSION=$k8s_user_version + else + printf "** Error: The specified kubernetes release [ %s ] is not a current release \n" "$k8s_user_version" + printf " when using the -v flag you must specify a current supported release \n" + print_current_k8s_releases + printf "** \n" + exit 1 + fi + else + printf "** Error: kubernetes release has not been specified with the -v flag \n" + printf " you must supply the -v flag and specify a current supported release \n\n" + showUsage + exit 1 + fi + printf "\r==> kubernetes version to install set to [%s] \n" "$K8S_VERSION" +} + +function do_microk8s_install { + # TODO : Microk8s can complain that This is insecure. Location: /var/snap/microk8s/2952/credentials/client.config + printf "==> Installing Kubernetes MicroK8s & enabling tools (helm,ingress etc) \n" + + echo "==> Mojaloop Microk8s Install: installing microk8s release $k8s_user_version ... " + # ensure k8s_user has clean .kube/config + rm -rf $k8s_user_home/.kube >> /dev/null 2>&1 + + snap install microk8s --classic --channel=$K8S_VERSION/stable + microk8s.status --wait-ready + + #echo "==> Mojaloop Microk8s Install: enable helm ... " + microk8s.enable helm3 + #echo "==> Mojaloop Microk8s Install: enable dns ... " + microk8s.enable dns + echo "==> Mojaloop: enable storage ... " + microk8s.enable storage + #echo "==> Mojaloop: enable ingress ... " + microk8s.enable ingress + + echo "==> Mojaloop: add convenient aliases..." + snap alias microk8s.kubectl kubectl + snap alias microk8s.helm3 helm + + echo "==> Mojaloop: add $k8s_user user to microk8s group" + usermod -a -G microk8s $k8s_user + + # ensure .kube/config points to this new cluster and KUBECONFIG is not set in .bashrc + perl -p -i.bak -e 's/^.*KUBECONFIG.*$//g' $k8s_user_home/.bashrc + perl -p -i.bak -e 's/^.*KUBECONFIG.*$//g' $k8s_user_home/.bash_profile + chown -f -R $k8s_user $k8s_user_home/.kube + microk8s config > $k8s_user_home/.kube/config +} + +function do_k3s_install { + printf "========================================================================================\n" + printf "Mojafos k3s install : Installing Kubernetes k3s engine and tools (helm/ingress etc) \n" + printf "========================================================================================\n" + # ensure k8s_user has clean .kube/config + rm -rf $k8s_user_home/.kube >> /dev/null 2>&1 + printf "\r==> installing k3s " + #echo $K8S_VERSION + curl -sfL https://get.k3s.io | K3S_KUBECONFIG_MODE="644" \ + INSTALL_K3S_CHANNEL="v$K8S_VERSION" \ + INSTALL_K3S_EXEC=" --disable traefik " sh > /dev/null 2>&1 + + # check k3s installed ok + status=`k3s check-config 2> /dev/null | grep "^STATUS" | awk '{print $2}' ` + if [[ "$status" -eq "pass" ]]; then + printf "[ok]\n" + else + printf "** Error : k3s check-config not reporting status of pass ** \n" + printf " run k3s check-config manually as user [%s] for more information ** \n" "$k8s_user" + exit 1 + fi + + # configure user environment to communicate with k3s kubernetes + export KUBECONFIG=/etc/rancher/k3s/k3s.yaml + sudo chown $k8s_user $KUBECONFIG + cp /etc/rancher/k3s/k3s.yaml $k8s_user_home/k3s.yaml + chown $k8s_user $k8s_user_home/k3s.yaml + chmod 600 $k8s_user_home/k3s.yaml + sudo chmod 600 $KUBECONFIG + + perl -p -i.bak -e 's/^.*KUBECONFIG.*$//g' $k8s_user_home/.bashrc + echo "export KUBECONFIG=\$HOME/k3s.yaml" >> $k8s_user_home/.bashrc + perl -p -i.bak -e 's/^.*source .bashrc.*$//g' $k8s_user_home/.bash_profile + perl -p -i.bak2 -e 's/^.*export KUBECONFIG.*$//g' $k8s_user_home/.bash_profile + echo "source .bashrc" >> $k8s_user_home/.bash_profile + echo "export KUBECONFIG=\$HOME/k3s.yaml" >> $k8s_user_home/.bash_profile + + # install helm + printf "\r==> installing helm " + helm_arch_str="" + if [[ "$k8s_arch" == "x86_64" ]]; then + helm_arch_str="amd64" + elif [[ "$k8s_arch" == "aarch64" ]]; then + helm_arch_str="arm64" + else + printf "** Error: architecture not recognised as x86_64 or arm64 ** \n" + exit 1 + fi + rm -rf /tmp/linux-$helm_arch_str /tmp/helm.tar + curl -L -s -o /tmp/helm.tar.gz https://get.helm.sh/helm-v$HELM_VERSION-linux-$helm_arch_str.tar.gz + gzip -d /tmp/helm.tar.gz + tar xf /tmp/helm.tar -C /tmp + mv /tmp/linux-$helm_arch_str/helm /usr/local/bin + rm -rf /tmp/linux-$helm_arch_str + /usr/local/bin/helm version > /dev/null 2>&1 + if [[ $? -eq 0 ]]; then + printf "[ok]\n" + else + printf "** Error : helm install seems to have failed ** \n" + exit 1 + fi + + #install nginx + printf "\r==> installing nginx ingress chart and wait for it to be ready " + su - $k8s_user -c "helm install --wait --timeout 300s ingress-nginx ingress-nginx --repo https://kubernetes.github.io/ingress-nginx" > /dev/null 2>&1 + # TODO : check to ensure that the ingress is indeed running + nginx_pod_name=$(kubectl get pods | grep nginx | awk '{print $1}') + + if [ -z "$nginx_pod_name" ]; then + printf "** Error : helm install of nginx seems to have failed , no nginx pod found ** \n" + exit 1 + fi + # Check if the Nginx pod is running + if kubectl get pods $nginx_pod_name | grep -q "Running"; then + printf "[ok]\n" + else + printf "** Error : helm install of nginx seems to have failed , nginx pod is not running ** \n" + exit 1 + fi + +} + +function install_k8s_tools { + printf "\r==> install kubernetes tools, kubens, kubectx kustomize \n" + curl -s -L https://github.com/ahmetb/kubectx/releases/download/v0.9.4/kubens_v0.9.4_linux_x86_64.tar.gz| gzip -d -c | tar xf - + mv ./kubens /usr/local/bin > /dev/null 2>&1 + curl -s -L https://github.com/ahmetb/kubectx/releases/download/v0.9.4/kubectx_v0.9.4_linux_x86_64.tar.gz | gzip -d -c | tar xf - + mv ./kubectx /usr/local/bin > /dev/null 2>&1 + + # install kustomize + curl -s "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh" | bash > /dev/null 2>&1 + mv ./kustomize /usr/local/bin > /dev/null 2>&1 +} + +function add_helm_repos { + # see readme at https://github.com/mojaloop/helm for required helm libs + printf "\r==> add the helm repos required to install and run infrastructure for Mojaloop, Paymenthub EE and Fineract\n" + su - $k8s_user -c "helm repo add kiwigrid https://kiwigrid.github.io" > /dev/null 2>&1 + su - $k8s_user -c "helm repo add kokuwa https://kokuwaio.github.io/helm-charts" > /dev/null 2>&1 #fluentd + su - $k8s_user -c "helm repo add elastic https://helm.elastic.co" > /dev/null 2>&1 + su - $k8s_user -c "helm repo add codecentric https://codecentric.github.io/helm-charts" > /dev/null 2>&1 # keycloak for TTK + su - $k8s_user -c "helm repo add bitnami https://charts.bitnami.com/bitnami" > /dev/null 2>&1 + su - $k8s_user -c "helm repo add mojaloop http://mojaloop.io/helm/repo/" > /dev/null 2>&1 + su - $k8s_user -c "helm repo add cowboysysop https://cowboysysop.github.io/charts/" > /dev/null 2>&1 # mongo-express + su - $k8s_user -c "helm repo add redpanda-data https://charts.redpanda.com/ " > /dev/null 2>&1 # kafka console + su - $k8s_user -c "helm repo add $PH_CHART_REPO_NAME $PH_HELM_REPO_LINK" > /dev/null 2>&1 #g2p-sandbox + + su - $k8s_user -c "helm repo update" > /dev/null 2>&1 +} + +function configure_k8s_user_env { + start_message="# ML_START start of config added by mojafos #" + grep "start of config added by mojafos" $k8s_user_home/.bashrc >/dev/null 2>&1 + if [[ $? -ne 0 ]]; then + printf "==> Adding configuration for %s to %s .bashrc\n" "$k8s_distro" "$k8s_user" + printf "%s\n" "$start_message" >> $k8s_user_home/.bashrc + echo "source <(kubectl completion bash)" >> $k8s_user_home/.bashrc # add autocomplete permanently to your bash shell. + echo "alias k=kubectl " >> $k8s_user_home/.bashrc + echo "complete -F __start_kubectl k " >> $k8s_user_home/.bashrc + echo "alias ksetns=\"kubectl config set-context --current --namespace\" " >> $k8s_user_home/.bashrc + echo "alias ksetuser=\"kubectl config set-context --current --user\" " >> $k8s_user_home/.bashrc + echo "alias cdml=\"cd $k8s_user_home/mojafos\" " >> $k8s_user_home/.bashrc + printf "#ML_END end of config added by mojafos #\n" >> $k8s_user_home/.bashrc + else + printf "\r==> Configuration for .bashrc for %s for user %s already exists ..skipping\n" "$k8s_distro" "$k8s_user" + fi +} + +function verify_user { +# ensure that the user for k8s exists + if [ -z ${k8s_user+x} ]; then + printf "** Error: The operating system user has not been specified with the -u flag \n" + printf " the user specified with the -u flag must exist and not be the root user \n" + printf "** \n" + exit 1 + fi + + if [[ `id -u $k8s_user >/dev/null 2>&1` == 0 ]]; then + printf "** Error: The user specified by -u should be a non-root user ** \n" + exit 1 + fi + + if id -u "$k8s_user" >/dev/null 2>&1 ; then + k8s_user_home=`eval echo "~$k8s_user"` + return + else + printf "** Error: The user [ %s ] does not exist in the operating system \n" $k8s_user + printf " please try again and specify an existing user \n" + printf "** \n" + exit 1 + fi +} + +function delete_k8s { + if [[ "$k8s_distro" == "microk8s" ]]; then + printf "==> removing any existing Microk8s installation " + snap remove microk8s > /dev/null 2>&1 + if [[ $? -eq 0 ]]; then + printf " [ ok ] \n" + else + printf " [ microk8s delete failed ] \n" + printf "** was microk8s installed ?? \n" + printf " if so please try running \"sudo snap remove microk8s\" manually ** \n" + fi + else + printf "==> removing any existing k3s installation and helm binary" + rm -f /usr/local/bin/helm >> /dev/null 2>&1 + /usr/local/bin/k3s-uninstall.sh >> /dev/null 2>&1 + if [[ $? -eq 0 ]]; then + printf " [ ok ] \n" + else + echo -e "\n==> k3s not installed" + fi + fi + # remove config from user .bashrc + perl -i -ne 'print unless /START_ML/ .. /END_ML/' $k8s_user_home/.bashrc +} + +function check_k8s_installed { + printf "\r==> Check the cluster is available and ready from kubectl " + k8s_ready=`su - $k8s_user -c "kubectl get nodes" | perl -ne 'print if s/^.*Ready.*$/Ready/'` + if [[ ! "$k8s_ready" == "Ready" ]]; then + printf "** Error : kubernetes is not installed , please run $0 -m install -u $k8s_user \n" + printf " before trying to install mojaloop \n " + exit 1 + fi + printf " [ ok ] \n" +} + +function print_end_message { + echo -e "\n${GREEN}============================" + echo -e "Environment setup successful" + echo -e "============================${RESET}\n" +} + +function print_end_message_tear_down { + echo -e "\n\n==============================================" + echo -e "Thank you for using Mojafos cleanup successful" + echo -e "==============================================\n\n" + echo -e "Copyright © 2023 The Mifos Initiative" +} + +################################################################################ +# Function: showUsage +################################################################################ +# Description: Display usage message +# Arguments: none +# Return values: none +# +function showUsage { + if [ $# -ne 0 ] ; then + echo "Incorrect number of arguments passed to function $0" + exit 1 + else +echo "USAGE: $0 -m [mode] -u [user] -v [k8 version] -k [distro] [-f] +Example 1 : run -m install -v 1.25 -k k3s # install k8s k3s version 1.24 +Example 2 : run -m delete -v 1.26 -k microk8s # delete k8s microk8s version 1.26 +Example 3 : run -m install -k microk8s -v 1.26 -k k3s # install k8s microk8s distro version 1.26 + +Options: +-m mode ............... install|delete (-m is required) +-k kubernetes distro... microk8s|k3s (default=k3s as it installs across multiple linux distros) +-v k8s version ........ 1.24|1.25|1.26 i.e. current k8s releases at time if this mojafos release +-h|H .................. display this message +" + fi + +} + +function setup_k8s_cluster { + cluster_type="$2" + + if [ -z "$cluster_type" ]; then + printf "Cluster type not set. Defaulting to local \n" + cluster_type="local" + fi + + if [[ "$cluster_type" == "remote" ]]; then + echo "Verifying connection to the remote Kubernetes cluster..." + kubectl get pods >/dev/null 2>&1 + if [[ $? -eq 0 ]]; then + echo "Successfully connected to the remote Kubernetes cluster." + else + echo "Failed to connect to the remote Kubernetes cluster. Please configure access to a remote cluster with kubectl to continue with a remote cluster." + echo "Otherwise,rerun the script and choose local" + exit 1 + fi + elif [[ "$cluster_type" == "local" ]]; then + if [[ "$k8s_distro" == "microk8s" ]]; then + do_microk8s_install + else + do_k3s_install + fi + else + echo "Invalid choice. Defaulting to local" + cluster_type="local" + if [[ "$k8s_distro" == "microk8s" ]]; then + do_microk8s_install + else + do_k3s_install + fi + fi +} + +################################################################################ +# MAIN +################################################################################ +function envSetupMain { + DEFAULT_K8S_DISTRO="k3s" # default to microk8s as this is what is in the mojaloop linux deploy docs. + K8S_VERSION="" + MINILOOP_VERSION="vNext" + + HELM_VERSION="3.12.0" # Feb 2023 + OS_VERSIONS_LIST=( 20 22 ) + K8S_CURRENT_RELEASE_LIST=( "1.26" "1.27" ) + CURRENT_RELEASE="false" + k8s_user_home="" + k8s_arch=`uname -p` # what arch + # Set the minimum amount of RAM in GB + MIN_RAM=4 + MIN_FREE_SPACE=30 + LINUX_OS_LIST=( "Ubuntu" ) + UBUNTU_OK_VERSIONS_LIST=(20 22) + + # ensure we are running as root + if [ "$EUID" -ne 0 ] + then echo "Please run as root" + exit 1 + fi + + # Check arguments + if [ $# -lt 1 ] ; then + showUsage + echo "Not enough arguments -m mode must be specified " + exit 1 + fi + + # Process function arguments as required + mode="$1" + k8s_distro="$2" + k8s_user_version="$3" + environment="$4" + + check_arch_ok + set_user + verify_user + + if [[ "$mode" == "deploy" ]] ; then + BASE_DIR=$( cd $(dirname "$0")/../.. ; pwd ) + RUN_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" # the directory that this script is run from + check_resources_ok + set_k8s_distro + set_k8s_version + k8s_already_installed + check_os_ok # todo add check to this once tested across other OS's more fully + install_prerequisites + add_hosts + setup_k8s_cluster $k8s_distro $environment + install_k8s_tools + add_helm_repos + configure_k8s_user_env + check_k8s_installed + printf "\r==> kubernetes distro:[%s] version:[%s] is now configured for user [%s] and ready for mojaloop deployment \n" \ + "$k8s_distro" "$K8S_VERSION" "$k8s_user" + print_end_message + elif [[ "$mode" == "cleanup" ]] ; then + deleteResourcesInNamespsceMatchingPattern "fineract" + deleteResourcesInNamespsceMatchingPattern "mojaloop" + deleteResourcesInNamespsceMatchingPattern "paymenthub" + deleteResourcesInNamespsceMatchingPattern "infra" + if [[ "$environment" == "local" ]]; then + echo "Deleting local kubernetes cluster..." + delete_k8s + echo "Local Kubernetes deleted" + fi + print_end_message_tear_down + else + showUsage + fi +} + + + + diff --git a/src/utils/logger.sh b/src/utils/logger.sh new file mode 100755 index 0000000..de9f9c9 --- /dev/null +++ b/src/utils/logger.sh @@ -0,0 +1,67 @@ +#!/usr/bin/env bash + +# Text color codes +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +RESET='\033[0m' + +# Log levels +DEBUG="debug" +INFO="info" +WARNING="warning" +ERROR="error" + +function logWithLevel() { + local logLevel=$1 + shift + + # Check if required arguments are provided + if [ -z "$logLevel" ] || [ -z "$1" ]; then + echo "Usage: logWithLevel " + return 1 + fi + + local logMessage=$@ + + case "$logLevel" in + "$DEBUG") + echo -e "${BLUE}DEBUG${RESET} $logMessage" + ;; + "$INFO") + echo -e "${BLUE}INFO${RESET} $logMessage" + ;; + "$WARNING") + echo -e "${YELLOW}WARNING${RESET} $logMessage" + ;; + "$ERROR") + echo -e "${RED}ERROR${RESET} $logMessage" + ;; + *) # Default case + echo "$logMessage" + ;; + esac +} + +function logWithVerboseCheck() { + local isVerbose=$1 + local logLevel=$2 + shift && shift + + # Check if required arguments are provided + if [ -z "$isVerbose" ] || [ -z "$logLevel" ] || [ -z "$1" ]; then + echo "Usage: logWithVerboseCheck " + return 1 + fi + + local message=$@ + + if [ "$isVerbose" = true ]; then + logWithLevel "$logLevel" "$message" + fi +} + +# Usage examples: +# logWithLevel "$DEBUG" "This is a debug message" +# logWithVerboseCheck true "$DEBUG" "Verbose debug message" diff --git a/tests/tests.sh b/tests/tests.sh new file mode 100644 index 0000000..e69de29