Monday, August 9, 2021

Changing the WSO2 Management console's interface

The user interfaces of every Carbon product allows you to configure, monitor, tune, and maintain the product. The components that formulate the design and style of these user interfaces are defined in resource (JAR) files. 

The user interface of every Carbon product consists of two layers:

  • The common product layout/design inherited from the Carbon platform: All the common templates, styles (CSS files), and images are stored in the Carbon core UI bundle, which is named org.wso2.carbon.ui-<version-number>.jar (<version-number> is the particular version of the bundle). This bundle is responsible for the overall look and feel of the entire Carbon platform.

  • The styles/images unique to each product: Each Carbon product (that is built on Carbon kernel) has another style bundle, which contains all the overriding style sheets and images: org.wso2.<product-name>.styles-<version-number>.jar.

You can customize the user interfaces by modifying these resource files. You need to create a fragment bundle for the original resource file. Then, you can pack the modified resource files in the required bundle. The files in the required bundle will get precedence and will override the files in the original bundle.

You can use this same technique to customize any aspect of the user interfaces. The advantage of this technique is that you will not lose your customizations when you apply official patches to the product by replacing the original bundles.



Follow the steps below to customize the above management console by changing the logo.

  1. Open the <PRODUCT_HOME>/repository/components/plugins/ directory. You need to find the bundle that contains the resource files that you want to modify. In this case, the logo and the related CSS files are contained in the org.wso2.carbon.ui_<version-number>.jar file. Copy the org.wso2.carbon.ui_<version-number>.jar file to a separate location on your computer, and extract the file. Note the symbolic name of this bundle, which is org.wso2.carbon.ui_<version-number>
  2. Create a new Maven project using your IDE. Be sure to include the symbolic name of the original bundle that you extracted in the previous step (which is org.wso2.carbon.ui_<version-number>) in the Maven project name. For example, you can use org.wso2.carbon.ui_<version-number>_patch as the Maven project name. 
  3. Add the following content to the pom.xml file of the  org.wso2.carbon.ui_<version-number>_patch project. In this pom.xml file, be sure to replace the <version-number> of org.wso2.carbon.ui_<version-number>_patch with the correct version value. (ex: org.wso2.carbon.ui_4.5.3_patch)

  4. Create directories in your Maven project as explained below.
    1. Create the /web folder under the /src/main/resources directory of the org.wso2.carbon.ui_<version-number>_patch project.
    2. Then, create the /admin directory under /web.
    3. Finally, create the /css, /images, and /layout directories under /admin.


  5. Create a new CSS file (e.g. customizations.css with the following content and Add the customizations.css file to the org.wso2.carbon.ui_<version-number>_patch/src/main/resources/web/admin/css/ directory. This file contains the logo customization styles.

  6. Locate the template.jsp file that is in the org.wso2.carbon.ui_<version-number>.jar bundle, which you extracted in step 1 above. You will find template.jsp file inside the org.wso2.carbon.ui_<version-number>.jar/web/admin/layout/ directory. Then, copy this file to the org.wso2.carbon.ui_<version-number>_patch/src/main/resources/web/admin/layout/ directory.
  7. Add below line into this template.jsp file. <link href="../admin/css/customizations.css" rel="stylesheet" type="text/css" media="all"/>

  8. You can update the Title and the favicon as well.

  9. Add the new image as the new logo (e.g.  new-logo.png) to the org.wso2.carbon.ui_<version-number>_patch/src/main/resources/web/admin/images/ directory.
  10. Create another Maven project using your IDE. Be sure to include the symbolic name of the original bundle that you extracted in step 1 above (which is org.wso2.carbon.ui_<version-number>) in the project name. For example, you can use org.wso2.carbon.ui_<version-number>_fragment as the Maven project name. This creates a project for the fragment bundle. Since the symbolic name of the original bundle is org.wso2.carbon.ui, the fragment host value of this bundle should be the same (e.g. org.wso2.carbon.ui_<version-number>_fragment). This fragment bundle will not contain anything (expect the pom.xml file) when it is built.
  11. Add the following content to the pom.xml file of the org.wso2.carbon.ui_<version-number>_fragment project. In this pom.xml file, replace the <version-number>  of org.wso2.carbon.ui_<version-number>_patch and org.wso2.carbon.ui_<version-number>_fragment with the correct version value. This pom.xml file of the fragment bundle defines properties, which includes the required bundle value (ex: org.wso2.carbon.ui_<version-number>_patch)
     

  12. Now you can build the two projects. Open a terminal, navigate to the relevant project directory (listed above), and execute the following command: mvn clean install.
    • org.wso2.carbon.ui_<version-number>_fragment 

    • org.wso2.carbon.ui_<version-number>_patch 

  13. Once the project is built, copy the two JAR files listed below (from the <PROJECT_HOME>/target/ directory) to the <PRODUCT_HOME>/dropins/ directory.
    • org.wso2.carbon.ui_<version-number>_fragment-1.0.0.jar 

    • org.wso2.carbon.ui_<version-number>_patch-1.0.0.jar

  14.  Restart the WSO2 product server.
  15. Access the management console of your WSO2 product using the following URL: https://localhost:9443/carbon/You view the new logo, which the patch bundle contains as shown below.

Saturday, May 1, 2021

WSO2 EI Backend Retry Handling

 Requirement:

Retry backend call 3 times with 5 seconds delay when backend not available.

Implementation:

Use below in-sequence and fault-sequence for your mediation.

1. sample-mediation-in-sequence

<?xml version="1.0" encoding="UTF-8"?>
<sequence name="sample-mediation-in-sequence" onError="sample-mediation-fault-sequence" trace="disable" xmlns="http://ws.apache.org/ns/synapse">
    <log>
        <property value="Invoking in sequence" name="sample-mediation-in-sequence"/>
    </log>
    <enrich>
        <source clone="true" type="body"/>
        <target property="payload" type="property"/>
    </enrich>
    <log>
        <property value="Calling MAAIF backend" name="sample-mediation-in-sequence"/>
    </log>
    <call>
        <endpoint>
            <http method="post" uri-template="http://sample.backend.url"/>
        </endpoint>
    </call>
    <log>
        <property expression="fn:concat('[MAAIF] ' , $ctx:uri.var.path,  ' status ', get-property('axis2', 'HTTP_SC'))" name="sample-mediation-in-sequence"/>
    </log>
    <respond/>
</sequence>

Note: Change this as per your backend.

2. sample-mediation-fault-sequence

<?xml version="1.0" encoding="UTF-8"?>
<sequence name="sample-mediation-fault-sequence" trace="disable" xmlns="http://ws.apache.org/ns/synapse">
    <filter xmlns:ns="http://org.apache.synapse/xsd" xmlns:ns3="http://org.apache.synapse/xsd" xpath="get-property('retry_count')">
        <then>
            <log>
                <property name="[Error] sample-mediation-fault-sequence" value="Error invorking backend API"/>
                <property expression="get-property('CODE')" name="error code"/>
                <property expression="get-property('ERROR_MESSAGE')" name="error message"/>
            </log>
            <property expression="number(get-property('retry_count'))+1" name="retry_count" scope="default"/>
            <filter xpath="get-property('retry_count') > 3">
                <then>
                    <payloadFactory media-type="xml">
                        <format>
                            <error xmlns="">
                                <details>$1</details>
                                <code>$2</code>
                                <message>$3</message>
                            </error>
                        </format>
                        <args>
                            <arg value="Error invorking backend API"/>
                            <arg evaluator="xml" expression="get-property('CODE')"/>
                            <arg evaluator="xml" expression="get-property('ERROR_MESSAGE')"/>
                        </args>
                    </payloadFactory>
                    <property name="HTTP_SC" scope="axis2" type="STRING" value="500"/>
                    <respond/>
                </then>
                <else>
                    <log>
                        <property name="[Error] sample-mediation-fault-sequence" expression="fn:concat('retry count ' , $ctx:retry_count)"/>
                    </log>
                    <script language="js"><![CDATA[java.lang.Thread.sleep(5000);]]></script>
                    <log>
                        <property name="[Error] sample-mediation-fault-sequence" value="Retrying backend call"/>
                    </log>
                    <clone continueParent="true" sequential="false">
                        <target sequence="sample-mediation-in-sequence"/>
                    </clone>
                </else>
            </filter>
        </then>
        <else>
            <property name="retry_count" scope="default" type="STRING" value="1"/>
            <clone continueParent="true" sequential="false">
                <target sequence="sample-mediation-fault-sequence"/>
            </clone>
        </else>
    </filter>
</sequence>

Monday, January 27, 2020

Implement CI/CD for Xamarin Mobile Application using Azure DevOps

What is Azure DevOps?


Azure DevOps is a Software as a service (SaaS) platform from Microsoft that provides an end-to-end DevOps toolchain for developing and deploying software.  It also integrates with most leading tools on the market and is a great option for orchestrating a DevOps toolchain.  At DevOpsGroup, we have lots of customers who have found Azure DevOps fits their needs irrespective of their language, platform or cloud.


What can Azure DevOps do?

Azure DevOps comprises a range of services covering the full development life-cycle.  At the time of writing these are:



  • Azure Boards: agile planning, work item tracking, visualization, and reporting tool.
  • Azure Pipelines: a language, platform and cloud-agnostic CI/CD platform with support for containers or Kubernetes.
  • Azure Repos: provides cloud-hosted private git repositories.
  • Azure Artifacts: provides integrated package management with support for Maven, npm, Python and NuGet package feeds from public or private sources.
  • Azure Test Plans: provides an integrated planned and exploratory testing solution.



Azure DevOps can also be used to orchestrate third-party tools.

View of Azure DevOps:



Repository for Xamarin-app in Azure DevOps Repos

You can you Azure DevOps as for your version control system.


Create a Pipeline for Xamarin.Android Application

This will cover the basics of the Xamarin build pipeline.

In-order to create build pipeline for your xamarin app you can follow the steps below.

To create a build pipeline for Xamarin.Android application, go to Pipelines in left side bar and inside the Builds click the New pipeline button.


It will direct you to below page


Here you can select which way you need to create a pipeline. Mainly it will go to YAML template format. But if you are not much familiar with YAML format my recommendation is to go with the classic editor to create a pipeline. It will easy to manage every config and will take less time to complete.

In this tutorial, I'm using the classic editor to create this pipeline. You can follow the steps as below.

Select your repository:


You can select whichever source you have in the above list (GitHub, Bitbucket... etc). You can select the Team project, Repository, and branch for the builds. Once you provide the repository information click on Continue.

In the next window, you can select which template you need to use for the build pipeline.



In the search box enter xamarin and select Xamarin.Android. Then click next.


It will create a template for Xamarin.Android with all necessary tasks as below. 



You can add or remove tasks from your job as your preference. Then provide the relevant configurations for each task as follows:

  • Agent job configurations:
Select the agent specification you want to run your android build. You can configure the execution plan as well.
  • NuGet tool installer task configurations:
Specify the version of the NuGet tool.

  • NuGet restore task configurations:
Configure the solution file path for NuGet packages restore.


  • Xamarin.Android task configurations:
Select below configurations:
  •  Android project file path (android.csproj)
  • Output directory
  • Configuration - Build configuration create an environment variable "BuildConfiguration" and assign the relevant value. (Debug, Release...etc)
  • MSBuild version
  • MSBuild architecture
  • Additional arguments for MSBuild (If any)
  • Select JDK for the build

  • App signing task configurations:
You need to provide .apk file path to sign the built apk file. Provide Keystore file, Keystore password, alias and key password.


  • Publish build artifacts task configurations:
Using this you can publish your build artifacts into artifactory.

Finally, Click Save & queue. 
You will all logs related to each and every task in this build job.



Create a Pipeline for Xamarin.iOS Application

Create a build pipeline for Xamarin.iOS application you can go to Pipelines and click the New and select New build pipeline.



Click on classic editor


Select your repository details and click Continue


Select the template for the pipeline. 

In the search box enter xamarin and select Xamarin.iOS and click on Apply.


It will create a template for Xamarin.iOS as follows


You can provide relevant configurations for each task.

For agent job please select macOS as an agent for iOS build job.


Specify the xamarin iOS project file (iOS.csproj) for the Solution parameter. Add the BuildConfiguration (as an environment variable) for the Configuration parameter.

Finally click Save & queue.

You can see the log for every task in build job.




Sunday, August 18, 2019

Show GIT branch with colours in bash prompt.

Update the below code in ~/.bashrc file

force_color_prompt=yes
color_prompt=yes

parse_git_branch() {
 git branch 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/(\1)/'
}

if [ "$color_prompt" = yes ]; then
    PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[01;31m\] $(parse_git_branch)\[\033[00m\]\$ '
else
    PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w$(parse_git_branch)\$ '
fi

Comment-out below line if it's uncommented.

#unset color_prompt force_color_prompt

Reload the ~/.bashrc file using below command:

source ~/.bashrc

Friday, August 9, 2019

SonarQube Docker Composer

Prerequisite:

Postgresql - [postgresql-docker-using-docker-compose]

Create a docker-compose.yml file as follows:

version: "3"

services:
  sonarqube:
    image: sonarqube
    expose:
      - 9000
    ports:
      - "127.0.0.1:9000:9000"
    networks:
      - sonarnet
    environment:
      - SONARQUBE_JDBC_URL=jdbc:postgresql://db:5432/sonar
      - SONARQUBE_JDBC_USERNAME=sonar
      - SONARQUBE_JDBC_PASSWORD=sonar
    volumes:
      - sonarqube_conf:/opt/sonarqube/conf
      - sonarqube_data:/opt/sonarqube/data
      - sonarqube_extensions:/opt/sonarqube/extensions
      - sonarqube_bundled-plugins:/opt/sonarqube/lib/bundled-plugins

  db:
    image: postgres
    networks:
      - sonarnet
    environment:
      - POSTGRES_USER=sonar
      - POSTGRES_PASSWORD=sonar
    volumes:
      - postgresql:/var/lib/postgresql
      - postgresql_data:/var/lib/postgresql/data

networks:
  sonarnet:

volumes:
  sonarqube_conf:
  sonarqube_data:
  sonarqube_extensions:
  sonarqube_bundled-plugins:
  postgresql:
  postgresql_data:

Use below command to start docker compose:

docker-compose up

Go to below URL in your browser:

http://localhost:9000/

Insert below default username and password if required:

Username:  admin
Password: admin

Thursday, July 25, 2019

PostgreSQL docker using Docker Compose

Create a docker-compose.yml file like below:

version: '3'

services:
  db:
    image: postgres:latest
    restart: always
    ports:
      - 5432:5432
    environment:
      POSTGRES_PASSWORD: 'postgres'
    volumes:
      - database_data:/var/lib/postgresql/data

volumes:
  database_data:
    driver: local

User below command to start docker compose:

docker-compose up

Install pgAdmin client to connect started PostgreSQL docker:







Wednesday, July 24, 2019

Vault Docker CLI commands


  • Create app role:
curl -X POST -H "X-Vault-Token:${vault-token}" -d '{"type":"approle"}' http://127.0.0.1:8200/v1/sys/auth/approle
  • Add policies:
curl -X POST -H "X-Vault-Token:${vault-token}" -d '{"policies":"dev-policy,test-policy"}' http://127.0.0.1:8200/v1/auth/approle/role/testrole
  • Get role id and secret:
curl -X GET -H "X-Vault-Token:${vault-token}" http://127.0.0.1:8200/v1/auth/approle/role/testrole/role-id | jq .

curl -X POST -H "X-Vault-Token:${vault-token}" http://127.0.0.1:8200/v1/auth/approle/role/testrole/secret-id | jq .
  • Get client token:
curl -X POST -d '{"role_id":"${role-id}","secret_id":"${secret-id}"}' http://127.0.0.1:8200/v1/auth/approle/login | jq .
  • Create kv engine mount:
tee payload.json <<EOF
{
  "type": "kv",
  "options": {
    "version": "1"
  }
}
EOF

curl --header "X-Vault-Token:${vault-token}" --request POST --data @payload.json http://127.0.0.1:8200/v1/sys/mounts/secret

  • Store data:
tee payload.json <<EOF
{
  "value": "localhost"
}
EOF

curl --header "X-Vault-Token:${vault-token}" --request POST --data @payload.json http://127.0.0.1:8200/v1/secret/dev/esb.host

tee payload.json <<EOF
{
  "value": "9443"
}
EOF

curl --header "X-Vault-Token:${vault-token}" --request POST --data @payload.json http://127.0.0.1:8200/v1/secret/dev/esb.port


  • Retrieve data:
curl -H "X-Vault-Token:${vault-token}" http://127.0.0.1:8200/v1/secret/dev/esb.host | jq .data.value | sed 's/"//g'

curl -H "X-Vault-Token:${vault-token}" http://127.0.0.1:8200/v1/secret/dev/esb.port | jq .data.value | sed 's/"//g'