Cleaning up private docker registry

The solution to cleaning the unused docker registry layers is not straightforward, there is nothing readily available from docker. As more and more docker layers are pushed and tagged, it may be possible that there are image layers that may not be required. These unnecessary layers will consume a lot of storage space. This page describes the way to delete unused layers without disturbing the registry.
I am going to explain how to clean up unused layers from docker registry using HTTP API V2
Docker HTTP API V2
The current version of the docker provides an option to interact with the images in the remote private registry using HTTP API version 2.
Few useful Digest APIs
List all the repositories available in the private registry
CATALOG
$ curl reg-server:5000/v2/_catalog

Output
------
{"repositories":["alpine","1_ubuntu_16.04","centos","centos6-build-test","centos6-build-qa","centos6-build-build","centos6-jenkins-agent","jenkins","squid-deb-proxy","ubuntu","ubuntu-build","ubuntu-build-agent","ubuntu_16.04"]}
Getting a list of layers used, and other metadata of a repository (image)
GET DETAILS
$ curl -k -v --silent -H "Accept: application/vnd.docker.distribution.manifest.v2+json" -X GET http://reg-server:5000/v2/ubuntu-jenkins-agent/manifests/latestrl reg-server:5000/v2/_catalog
OUTPUT
Output
------
* Trying 10.0.93.36...
* Connected to reg-server (12.0.33.1) port 5000 (#0)
> GET /v2/ubuntu-jenkins-agent/manifests/latest HTTP/1.1
> Host: reg-server:5000
> User-Agent: curl/7.47.0
> Accept: application/vnd.docker.distribution.manifest.v2+json
> 
< HTTP/1.1 200 OK
< Content-Length: 5540
< Content-Type: application/vnd.docker.distribution.manifest.v2+json
< Docker-Content-Digest: sha256:d00e05048b4ef3d7e175d233a306f64175f1c716c755224984099c7e8cf0948
< Docker-Distribution-Api-Version: registry/2.0
< Etag: "sha256:d00e05048b4ef3d7e175d233a306f64175f1c716c7552245e14099c7e8cf0948"
< X-Content-Type-Options: nosniff
< Date: Fri, 06 Apr 2018 08:39:42 GMT
< 
{
"schemaVersion": 2,
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"config": {
"mediaType": "application/vnd.docker.container.image.v1+json",
"size": 17980,
"digest": "sha256:6c4e6280d347be4762dd77a20845ec69c4c1da3424195523765dfaeeecbffa22"
},
"layers": [
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"size": 67103213,
"digest": "sha256:5d890c53be21ea2d7c417960dfdb8edf87f623bfd016751261fac26943a0b188"
},
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"size": 72628,
"digest": "sha256:f775b856e1997836995617cf691ea4ffb0b1ef967ac73db661666ba3a216d432"
},
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"size": 363,
"digest": "sha256:552c4f407d99f5ff4e96e79430bae55c4ff1154824dab3945ef4bb0482c826d5"
},
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"size": 676,
"digest": "sha256:fda304b96f8a99052eacb6ce515f26d8ff10fc78cbb6a9f09e996faaadabdaaa"
},
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"size": 162,
"digest": "sha256:2b033adb904af1b663e78cf33f513fc2f98730b9c0dcab4a3ad4cd85eb825880"
},
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"size": 69424905,
"digest": "sha256:3b93b65608a04bbd902b73d76e61f52a28b2a0b0faca95b8303dbe9a3397a688"
},
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"size": 76466711,
"digest": "sha256:8ccd40bb9dd1bb2dfbc16a0ab661b817ce9b6af0617ae679cfabaa80a74414c5"
},
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"size": 1066,
"digest": "sha256:0cf16c8ac4188b500ccbdf405c1288c298c4a50e40f0aafe485cd2d58f81ee8f"
},
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"size": 4606,
"digest": "sha256:5670062ffd23e300b2fa32af6d9763211372ae919801c1ee98d1827aec24b57c"
},
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"size": 1020,
"digest": "sha256:ce7a2ec46384b5e5cf94f6bdded1c8a46c1614b4e5216101e706a5a47dd1a8b5"
},
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"size": 38402,
"digest": "sha256:73dd7e155ea00edcb02adc94f271aa07924faac30b4413fba823cbb7be51541c"
},
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"size": 175,
"digest": "sha256:46094570601896ddccb7446c48fd64e7089fb3fb826b747e6db4c971da4f2d9a"
},
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"size": 28176,
"digest": "sha256:2a4b48722514ef189776665fa00e98b24296117db359b491c83d995c53d4a3c1"
},
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"size": 47021,
"digest": "sha256:55c8e005550e7be9ea7f990696b6b863a270f7a43a059b8e52af9e84a745403d"
},
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"size": 415368,
"digest": "sha256:9cbcf4bfa6017c078eb8e2f20da1593e91cb0b5d271538c480c2a847fd0453ea"
},
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"size": 98274,
"digest": "sha256:4e6638ed8398ca234d28dad09047ffba24fa96961497d8975ea20fe89738fe7e"
},
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"size": 1133119,
"digest": "sha256:cffca1cea7728d2f65b29956c5f4ca46e3130e7c5eca2a8e74ceee7760f75227"
},
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"size": 465660,
"digest": "sha256:586d6232925d2948926e1c0697657ddeb8daf63840f50d14e75a5d80a140f53f"
},
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"size": 114104,
"digest": "sha256:329692f820b7a8f115763b238025b0021eeebfa83f9ba5ba94d09e4d30ab0443"
},
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"size": 11356,
"digest": "sha256:8b948376919e9027aed5fb110f827e29b5d5b89faa249dd5e96d9f322f16671d"
},
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"size": 233,
"digest": "sha256:280ed15840b101f31d36195774dbc64a0756b10445ac86a7d56c9323b254d3ab"
},
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"size": 177,
"digest": "sha256:8b3430dea5aa62d32f1afa524062c8842b69f4e4c6c206c506096d61b86cf9aa"
},
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"size": 5397987,
"digest": "sha256:940f81402bbb4f7cd2fc2e27ad60243ee352594d2d347d4cc7d061543a645579"
},
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"size": 265,
"digest": "sha256:f22d1b75d0776f7b50c189b5f902411a16f1e558bb182eaa50d87970a783c3ed"
},
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"size": 573,
"digest": "sha256:9d201349e9cab134e816a063bcbf18d1a23ff854a953492b9d9aa4165cf059ec"
}
]
* Connection #0 to host reg-server left intact
Deleting an image tag using the Docker-Content-Digest
Using this API, any given tag of an image can be deleted remotely. This will delete the layers associated with this tag. But one has to identify the tags that should be deleted. After deleting a tag remotely, one has to run the garbage-collector to take the depletion effect. Please note that the DELETE API requires a digest of an image tag. The digest can be obtained using a tag as bellow (for an image which is tagged).
The tag name in the below snippet is latest. It will work with any other named tag
DELETE
$ curl -k -v --silent -H "Accept: application/vnd.docker.distribution.manifest.v2+json" -X GET http://reg-server:5000/v2/ubuntu-jenkins-agent/manifests/latest 2>&1 | grep Docker-Content-Digest | awk '{print ($3)}'
To get the digest of an untagged image, go to the storage of the docker registry inside the registry container. If the registry container has configured with volume, a digest can be obtained from this location as well.
Suppose if 966fcf31b8a2 is a container id of a private registry and /var/lib/registry is the registry storage inside the container
DELETE
$ sudo docker exec -it 966fcf31b8a2 sh
$ cd /var/lib/registry/docker/registry/v2/repositories/alpine/_manifests/revisions/sha256

## below listed sha256 are the manifest whihc reference the image tag This is called a digest. These digests are used while deleting an image tag.
## there are 3 unamed tags here and the latest is always tagged as :latest
$ ls
xr-xr-x 2 root root 18 Apr 4 06:02 ef04ea6e2324b2e1f2b1a25a56defc92d24f6b364e14ddd081241426af82aa2d
xr-xr-x 2 root root 18 Apr 4 10:06 b978ab300d84b859181fbf8c579315e709d22bb47e25b448952e6dfdc79be1f5
xr-xr-x 2 root root 6 Apr 4 10:10 c62d369018e25c79c651cdebc10d380e585acbda33340476d9f85d34c4a37b0d

To delete a tag using a Digest (which you got in the previous step)
Note:
  1. stop the running container and start again with additional ENV variable -e REGISTRY_STORAGE_DELETE_ENABLED=true. The run command looks like
    docker run -d -p 5000:5000 -v /home/sanjeeva/registry_vol:/var/lib/registry -e REGISTRY_STORAGE_DELETE_ENABLED=true --name registry registry:2
  2. By editing the config file inside the registry container.
    vi /etc/docker/registry/config.yml
    Under 
    storage: add these 2 lines
    delete:
    enabled: true
    Run the below command
    $ sudo docker restart >
DELETE
$ curl -k -v --silent -X DELETE http://localhost:5000/v2/alpine/manifests/sha256:934c25b1f1c266e31ee3693890b08f67cf0b05c162561edc779150c0ece7d872
DELETE OUTPUT
* Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 5000 (#0)
> DELETE /v2/alpine/manifests/sha256:934c25b1f1c266e31ee3693890b08f67cf0b05c162561edc779150c0ece7d872 HTTP/1.1
> Host: localhost:5000
> User-Agent: curl/7.47.0
> Accept: */*
> 
< HTTP/1.1 202 Accepted
< Docker-Distribution-Api-Version: registry/2.0
< X-Content-Type-Options: nosniff
< Date: Fri, 30 Mar 2018 10:58:18 GMT
< Content-Length: 0
< Content-Type: text/plain; charset=utf-8
< 
* Connection #0 to host localhost left intact
Garbage-collection
After deleting a tag of an image using API, run the garbage collection inside the container.
DELETE
## dry run with -d
$ /bin/registry garbage-collect -d /etc/docker/registry/config.yml
## actual run without -d
$ /bin/registry garbage-collect /etc/docker/registry/config.yml
Summary of steps to clean up a registry
  1. Enabling a layer deletion in docker registry (there are 2 ways to do this 1.b is the preferred method)
    1. by stopping and deleting the registry container
      1. Stop and delete the registry container
    2.  
      1. This may delete all the images in the registry unless it was started with a volume with -v option
      2. Start the registry container with
      3. REGISTRY_STORAGE_DELETE_ENABLED=true as
      4. docker run -d -p 5000:5000 -v /home/sanjeeva/registry_vol:/var/lib/registry -e REGISTRY_STORAGE_DELETE_ENABLED=true --name registry registry:2
    3. by restarting the container after editing the config file
      1. $ vi /etc/docker/registry/config.yml
      2. Under storage: add these 2 lines
        delete:
        enabled: true
      3. Run the below command
      4. $ sudo docker restart
  2. inside the registry container, for each repository
    1. List all the manifests except the latest tag.
  3. Run the API V2 command to delete the non-latest manifests
    1. $ curl -k -v --silent -X DELETE http://reg-server:5000/v2/alpine/manifests/sha256:249c714c688541c83ca2c9b2a8c30dd77b5c45c836e6c69632815ee3614ccbd2
  4. Run the garbage-collector inside the registry container
    1. It will delete the image layers which are no more referenced by any tag(manifest) except the latest tag
    2. We may see a few folders left undeleted.


How to use Jenkins docker image to run Jenkins master

How to use Jenkins docker image as a master and as a build node.
In the recent past, Containerization is becoming very popular. Docker is a very prominent player in the field of containerization.
Today I am going to show step by step procedure on how to use a docker image for both Jenkins master and node. Also, I am going to address a few known issues and how to find a workaround for them. In the tutorial, I will use the Jenkins version jenkins/jenkins:2.107.3.
Pull the image from docker hub
$ docker pull jenkins/Jenkins:2.107.3
Note that the dockerized Jenkins will use /var/jenkins_home as Jenkins home. If you want to change this you have to edit the docker file provided by the docker hub, which was used to build the image jenkins/jenkins:2.107.3. I will not cover that in the tutorial.
The additional steps we are doing on top of the base image Jenkins/jenkins:2.107.3
1.     Customize the Jenkins docker image with additional packages and new users
2.     Use different user other than the default jenkins user.
3.     Use a different home directory for a different user but use the same jenkins_home folder
4.     Use a host-volume to map to Jenkins_home inside the container
5.     Use the host machine ssh keys on the container as also
Let us see one by one and what are the issues we have.
In most cases you will not want to use the default user called Jenkins, you need to use the user which is specific to your organization or company. I will call the new user as user_jenkins, this user is already present in my host machine and it needs to be created in the new image.
Below docker file will add the new user, declares 2 arguments for ssh private and public key, copy the plugins.txt file and install them, finally copies the necessary ssh keys from host to the container.  

from jenkins/jenkins:2.107.3
ARG priv
ARG pub
USER root

COPY plugins.txt /usr/share/jenkins/ref/plugins.txt
RUN /usr/local/bin/install-plugins.sh < /usr/share/jenkins/ref/plugins.txt

# Add user user_jenkins using static UID/GID from AD, home /var/lib/jenkins, adequate shell
RUN groupadd -g 215 group_jenkins && \
    useradd -u 1396 -g group_jenkins -d /var/jenkins_home_tmp -s /bin/bash -m user_jenkins

USER user_jenkins

# insert ssh keys
RUN mkdir -p ~/.ssh && \
    echo "$priv" > ~/.ssh/id_rsa && \
    echo "$pub" > ~/.ssh/id_rsa.pub && \
    chmod 644 ~/.ssh/id_rsa.pub && chmod 600 ~/.ssh/id_rsa && chmod 700 ~/.ssh 

Now try to build the docker image using docker build command. We need to keep the plugins.txt in the build context and ssh keys to be passed as a build parameter. 

The format of the plugins.txt file should as below 

mask-passwords:2.8
workflow-step-api:2.2
external-monitor-job:1.4
accelerated-build-now-plugin:1.0.1
pam-auth:1.1
ssh-credentials:1.10
plot:1.11
configurationslicing:1.47
active-directory:2.2
git-parameter:0.6.1
disk-usage:0.28
structs:1.2
envinject:1.92.1
release:2.5.4
custom-tools-plugin:0.4.4
coverity:1.7.1
elastic-axis:1.2
run-condition:1.0
slave-status:1.6
groovy-label-assignment:1.2.0
matrix-project:1.4.1
scm-api:1.2
warnings:4.56
docker-plugin:0.16.2
ssh-agent:1.13
maven-plugin:2.7.1
periodic-reincarnation:1.10
icon-shim:2.0.3
docker-slaves:1.0.6
mapdb-api:1.0.9.0
throttle-concurrents:1.9.0
analysis-core:1.79
jquery:1.11.2-0
slave-setup:1.10
subversion:1.54
postbuild-task:1.8
artifactdeployer:0.33
timestamper:1.8.8
gerrit-trigger:2.21.1
bouncycastle-api:1.648.3
translation:1.10
monitoring:1.59.0
credentials:2.1.13
javadoc:1.1
build-name-setter:1.6.5
antisamy-markup-formatter:1.1
PrioritySorter:3.4
extended-choice-parameter:0.74
workflow-scm-step:2.2
cvs:2.11
authentication-tokens:1.3
ldap:1.11
unreliable-slave-plugin:1.2
description-setter:1.10
parameterized-trigger:2.31
project-stats-plugin:0.4
token-macro:1.12.1
ant:1.2
script-security:1.29
leastload:1.0.3
junit:1.2-beta-4
ssh-slaves:1.9
repo:1.10.2
email-ext:2.44
purge-build-queue-plugin:1.0
git:2.5.2
matrix-auth:1.1
keepSlaveOffline:1.0
preSCMbuildstep:0.3
mailer:1.11
docker-commons:1.6
conditional-buildstep:1.3.5
jobConfigHistory:2.16
dashboard-view:2.9.10
durable-task:1.13
git-client:1.19.7

build-failure-analyzer:1.16.0

Passing ssh keys to the image during the build time is necessary for various reasons. One such reason is to clone from git or Github, which requires ssh keys to connect to the servers. Copying ssh keys is also tricky because we are copying both private and public keys. Earlier I used to keep the ssh keys in a plain text inside the docker file. But that is very dangerous. Now I am trying to pass them as a build parameter. The only concern with the approach is that the keys are available in the docker layer. There is an experimental option available in the docker engine to squash the layers so the layers are which are exposing the security information, can be merged into other layers. This can be achieved using –squash option in the docker build command.
The docker build command
$ docker build --build-arg priv="$(cat ~/.ssh/id_rsa)" --build-arg pub="$(cat ~/.ssh/id_rsa.pub)" -t jenkins_2 --no-cache  -f docker .
The key thing to be noted here is the --build-arg parameters. I am reading the existing ssh keys from the host machine and passing them as a parameter. Note that here 2 separate –-build-arg parameters one each for the private key and public key. The parameters are handled by ARG instruction in the docker file
Once the image is built successfully we can start the container.
Run command
$ docker run -d  -p 8082:8080  -p 5002:5000  jenkins_2
I am using different ports. You will get the error message as shown below or similar.  

17:46:34 root dev ~ → docker logs 4s6yuknv568
touch: cannot touch ‘/var/jenkins_home/copy_reference_file.log’: Permission denied
Can not write to /var/jenkins_home/copy_reference_file.log. Wrong volume permissions?
Note that the ‘/var/jenkins_home/’ is the default home directory from where the Jenkins runs. If you are using a user other than default user Jenkins, you will get permission denied error.
To overcome this error there should be a proper folder created before running the container. The new folder created will be mapped as host volume as in the below command.  
$ su user_jenkins
$ mkdir -p /opt/my_jenkins_home
$ docker run -d  -p 8082:8080  -p 5002:5000 -v /opt/my_jenkins_home:/var/jenkins_home  jenkins_2

Why some mobile phones does not support screen mirroring?

On my Youtube channel, I have posted a video that shows how to mirror your mobile screen onto LED or LCD TV which is equipped with Wi-Fi and Miracast. To clarify what is Miracast, it is a hardware device built into your TV. If your TV is equipped with Miracast, then you don't have to use any additional dongles like Google ChromeCast to cast your mobile screen onto the TV. Please note that the Miracast feature and Google Chromecast may work differently.

I got lots of comments asking questions like whether the TV is smart, whether the TV is used as a monitor with a CPU, is there any dongle connected to the TV, whether it requires internet, etc.  To clarify all these questions, it is a basic LED TV with Wi-FI and Miracst enabled. No internet, no dongle connected and it is not a smart TV.

The most important question I am trying to clarify here is why some mobile phones do not have mirroring options.

First, you need to understand that screen mirroring works on a Wi-Fi network.  That means there will be a Wi-Fi network set up between your mobile phone and your TV. There is no intermediate Wi-Fi router. There will be an active connection between your phone and TV. This will not allow you to connect to any other Wi-Fi network for the internet. You have to completely rely on your carrier provided mobile data. It may incur a lot of data usage. So, some mobile manufacturers disabled this option from the design itself. This is the case with single-band Wi-Fi-enabled mobiles.

But the newer mobile phones from different manufacturers support dual-band Wi-Fi.  That means simultaneously you can connect to the TV and to another WI-Fi network for the internet. You do not have to rely on your mobile data. Most of the MI Redmi phone supports the dual-band Wi-Fi and they support screen mirroring out of the box.

The solution for those who do not have a screen mirroring option is to use apps or third-party mirroring devices like Google Chrome cast, Miracast, or even Amazon stick. You can also use specific MHL cables which are similar to HDMI cable. Each app may work differently and some apps may require root mobile phones.





How to install Apps in Android TV

As Android TVs are becoming famous, it's obvious to know whether it will allow us to install apps on Android TV the way we do it on Android mobile and to know how to install the apps on TV. The same version of a particular app may not support all the TVs and you might not get all the apps available for Mobile. But certainly, there are plenty of apps for various purpose and it can be installed on Android TV.

There are two ways to install an app on Android TV. Please note that this procedure is specific to MI Android TV. A similar procedure can be used for other Android TV.

Install using .apk file

The first option is to install it from a .apk file. The apk file has to be downloaded and copied into a USB using a computer. Insert the USB drive into TV, go to the location of the apk file inside the USB drive. Open the selected apk file, it will ask you to enable or trust the 'third party app' installation. If you have not done this before, got to settings and enable it. Please note that it may be a security violation if you install it from an unauthorized source. Before installing an app from an unknown source, understand the consequences, and proceed. 

Install using an App Store

The second option is to install from Android TV-specific App Store. The App Store has to be installed using the first method - apk installation from USB.

There is one App store called AptoideTV. It has all the major apps which are more than enough to get all the required apps for your Smart TV 

AptoideTV

Download the apk for AptoideTV-3.2.5.apk from the below link. Copy it into a USB drive and insert it into your TV. Browse to the location, where the apk is present and click on the apk file. It will ask you to enable the Third-Party App installation.


Once the App Store is installed, you can use it like any other App Store. Browse or search for an app from different categories and install. 

Check out this video which shows how to install the Chrome App on 32 inch MI TV 




VBA Macro to copy Excel data into MS Word table

The below code will help you to copy the MS Excel data into MS Word. The main thing to note here is, the Excel data is copied into Word in a table format. This is a very basic VBA code, you can extend this to add other features.

To add this code to your excel, Open VBA editor in Excel or you can press F11. Insert a module, paste this code. Come back to excel by pressing F11 again. Under macros you can see the name of subroutine 'CopyFromExcelToWord' appearing, this is your macro.

Sub CopyFromExcelToWord()
   Dim objWord
   Dim objDoc
   Dim objRange
   Dim total_rows
   Dim total_cols
   Dim objTable
   Dim tmp_row
   Dim tmp_col
    total_rows = Cells(1, 10).Value
    total_cols = Cells(2, 10).Value
    Set objWord = CreateObject("Word.Application")

  Set objDoc = objWord.Documents.Add
  Set objRange = objDoc.Range
  objWord.Visible = True

  objDoc.Tables.Add objRange, total_rows, total_cols
  'objWord.SaveAs ("C:\Users\sanjeeva\Documents\krishna\personal\videos\a.docm")
  Set objTable = objDoc.Tables(1)
    objTable.Borders.Enable = True
  For tmp_row = 1 To total_rows
     For tmp_col = 1 To total_cols
        objTable.Cell(tmp_row, tmp_col).Range.Text = Cells(tmp_row, tmp_col)
     Next
  Next
End Sub

How to create MS Word document automatically with Text file

This VBA code will help you to import data from a text file and insert it into the MS word document. This is useful when you have to create a report or formats in MS Word format, reading the data from a text file. The VBA code can be extended import extra data from the text file, and also you can add additional format as per your needs.

Please note that VBA macros can cause harm to your computer. First, open them in a disabled mode. To disable macros, to Developer tab, select macro security and then select Macro settings on the left side pane. In the right pane, select the second radio button, 'Disable all macros with notification'. The second option is better because it will notify you if there are any macros associated with your file. So you will not miss any document features that may be available after running a macro. But you can decide whether to allow the macros to run or not.

Please click on the below link to download the MS Word Template file. You can also download the text file used to import the data. I remind you that this is a sample file. You may have to modify the VBA code according to your requirement. You may have to rename the input file.

Please leave a comment below if you have any concerns.
MS word template

The VBA Code
-------------------
Sub Document_Open()
If (ActiveDocument.Name = "Template.docm") Then
With ActiveDocument
 
   On Error Resume Next
    .Variables.Add Name:="1", Value:="1"
    .Variables.Add Name:="2", Value:="2"
    .Variables.Add Name:="3", Value:="3"
    .Variables.Add Name:="4", Value:="4"
    .Variables.Add Name:="5", Value:="5"
    .Variables.Add Name:="6", Value:="6"
   
    Dim ReadData As String
    Dim myarray() As String
   
    Open ActiveDocument.Path & "\text.txt" For Input As #1

    Do Until EOF(1)
       Line Input #1, ReadData
    If Not Left(ReadData, 1) = "*" Then
    myarray = Split(ReadData, ",")
    End If

    Loop

    Close #1

    i = 1
    For Each f In myarray
       .Variables(i).Value = f
       i = i + 1
    Next f
    .Fields.Update
End With

With ActiveDocument
strFileName = "Agreement Between " & myarray(5) & " and " & myarray(0)
strPath = .Path

.SaveAs2 (strPath & "\" & strFileName)
'.Close SaveChanges:=wdDoNotSaveChanges
Application.Quit SaveChanges:=wdDoNotSaveChanges
'.Application.
End With
End If
End Sub
-------------------

MS Excel Currency converter VBA code

To convert numbers into text, there is no builtin function in MS Excel as of now. Using the below VBA code you can overcome this issue. There are situations like writing a cheque leaf, printing a rent agreement, or writing contract documents that may require printing the transaction amount in the text. Make use of this code to convert numbers into text automatically. 

Copy and paste this VBA code into your Excel VBA editor module. Or Insert an empty module and paste this code.
  1. Attribute VB_Name = "Module1"
  2. 'Attribute VB_Name = "Module2"
  3. ' ****  Author          : Krishna S
  4. ' ****  Tittle          : Converting Hindu Arabic Currency(Indian System) to Words
  5. ' ****  Copyright Owner : Krishna S
  6. ' ****  Description     : This utility converts currencies in Indian numbering system to words.
  7. ' ****  Limitations     : Converts only upto 10,00,00,000( Ten Crores)

  8. Function ConvertCurrencyToEnglish(ByVal MyNumber)
  9. Dim Temp
  10.          Dim Rupees, Paise
  11.          Dim DecimalPlace, Count
  12.          ReDim Place(9) As String
  13.          Place(2) = " Thousand "
  14.          Place(3) = " Lac "
  15.          Place(4) = " Core "
  16.       '   Place(5) = " Hundred Core "
  17.          ' Convert MyNumber to a string, trimming extra spaces.
  18.          MyNumber = Trim(Str(MyNumber))
  19.          ' Find decimal place.
  20.          DecimalPlace = InStr(MyNumber, ".")
  21.          ' If we find decimal place...
  22.          If DecimalPlace > 0 Then
  23.             ' Convert Paise
  24.             Temp = Left(Mid(MyNumber, DecimalPlace + 1) & "00", 2)
  25.             Paise = ConvertTens(Temp)
  26.             ' Strip off Paise from remainder to convert.
  27.             MyNumber = Trim(Left(MyNumber, DecimalPlace - 1))
  28.          End If
  29.          Count = 1
  30.          
  31.          Do While MyNumber <> ""
  32.                  If Count = 1 Then
  33.                 
  34.                    Temp = ConvertHundreds(Right(MyNumber, 3))
  35.                      
  36.                     If Temp <> "" Then Rupees = Temp & Place(Count) & Rupees
  37.                     If Len(MyNumber) > 3 Then
  38.                        ' Remove last 3 converted digits from MyNumber.
  39.                        MyNumber = Left(MyNumber, Len(MyNumber) - 3)
  40.                     Else
  41.                        MyNumber = ""
  42.                     End If
  43.                     Count = Count + 1
  44.                  Else
  45.                  ' Convert last 3 digits of MyNumber to English Rupees.
  46.                  If Len(MyNumber) = 1 Then
  47.                  Temp = ConvertDigit(MyNumber)
  48.                  Else
  49.                  Temp = ConvertTens(Right(MyNumber, 2))
  50.                  End If
  51.                     If Temp <> "" Then Rupees = Temp & Place(Count) & Rupees
  52.                     If Len(MyNumber) >= 3 Then
  53.                        ' Remove last 3 converted digits from MyNumber.
  54.                        MyNumber = Left(MyNumber, Len(MyNumber) - 2)
  55.                     Else
  56.                        MyNumber = ""
  57.                     End If
  58.                     Count = Count + 1
  59.                     End If
  60.          Loop
  61.          ' Clean up Rupees.
  62.          Select Case Rupees
  63.             Case ""
  64.                Rupees = ""
  65.             Case "One"
  66.                Rupees = "One Rupee"
  67.             Case Else
  68.                Rupees = Rupees & " Rupees"
  69.          End Select
  70.          ' Clean up Paise.
  71.          Select Case Paise
  72.             Case ""
  73.                Paise = ""
  74.             Case "One"
  75.                Paise = " And One Cent"
  76.             Case Else
  77.                Paise = " And " & Paise & " Paise"
  78.          End Select
  79.          ConvertCurrencyToEnglish = Rupees & Paise
  80. End Function
  81. Private Function ConvertHundreds(ByVal MyNumber)
  82. Dim Result As String
  83.          ' Exit if there is nothing to convert.
  84.          If Val(MyNumber) = 0 Then Exit Function
  85.          ' Append leading zeros to number.
  86.          MyNumber = Right("000" & MyNumber, 3)
  87.          ' Do we have a hundreds place digit to convert?
  88.          If Left(MyNumber, 1) <> "0" Then
  89.             Result = ConvertDigit(Left(MyNumber, 1)) & " Hundred "
  90.          End If
  91.          ' Do we have a tens place digit to convert?
  92.          If Mid(MyNumber, 2, 1) <> "0" Then
  93.             Result = Result & ConvertTens(Mid(MyNumber, 2))
  94.          Else
  95.             ' If not, then convert the ones place digit.
  96.             Result = Result & ConvertDigit(Mid(MyNumber, 3))
  97.          End If
  98.          ConvertHundreds = Trim(Result)
  99. End Function
  100. Private Function ConvertTens(ByVal MyTens)
  101. Dim Result As String
  102.          ' Is value between 10 and 19?
  103.          If Val(Left(MyTens, 1)) = 1 Then
  104.             Select Case Val(MyTens)
  105.                Case 1: Result = "One"
  106.                Case 10: Result = "Ten"
  107.                Case 11: Result = "Eleven"
  108.                Case 12: Result = "Twelve"
  109.                Case 13: Result = "Thirteen"
  110.                Case 14: Result = "Fourteen"
  111.                Case 15: Result = "Fifteen"
  112.                Case 16: Result = "Sixteen"
  113.                Case 17: Result = "Seventeen"
  114.                Case 18: Result = "Eighteen"
  115.                Case 19: Result = "Nineteen"
  116.                Case Else
  117.             End Select
  118.          Else
  119.             ' .. otherwise it's between 20 and 99.
  120.             Select Case Val(Left(MyTens, 1))
  121.                Case 2: Result = "Twenty "
  122.                Case 3: Result = "Thirty "
  123.                Case 4: Result = "Forty "
  124.                Case 5: Result = "Fifty "
  125.                Case 6: Result = "Sixty "
  126.                Case 7: Result = "Seventy "
  127.                Case 8: Result = "Eighty "
  128.                Case 9: Result = "Ninety "
  129.                Case Else
  130.             End Select
  131.             ' Convert ones place digit.
  132.             Result = Result & ConvertDigit(Right(MyTens, 1))
  133.          End If
  134.          ConvertTens = Result
  135. End Function
  136. Private Function ConvertDigit(ByVal MyDigit)
  137. Select Case Val(MyDigit)
  138.             Case 1: ConvertDigit = "One"
  139.             Case 2: ConvertDigit = "Two"
  140.             Case 3: ConvertDigit = "Three"
  141.             Case 4: ConvertDigit = "Four"
  142.             Case 5: ConvertDigit = "Five"
  143.             Case 6: ConvertDigit = "Six"
  144.             Case 7: ConvertDigit = "Seven"
  145.             Case 8: ConvertDigit = "Eight"
  146.             Case 9: ConvertDigit = "Nine"
  147.             Case Else: ConvertDigit = ""
  148.          End Select
  149. End Function