Category: Technology

GitLab – Using the built-in Docker Registry

GitLab has a built-in Docker registry that you can use for projects. With the Omnibus install (or a container based on the official Docker image), enabling the registry is as simple as adding a config line to your gitlab.rb (this assumes you have a SSL key at /etc/gitlab/ssl named with the fully qualified hostname and using .crt for the public key and .key for the private key

registry_external_url ‘https://gitlab.example.com:4567’

Then just tag an image to a project’s repository URL

docker tag ossautomation/cent68php56 gitlab.example.com:4567/lisa/ljtestproject-dockerexecutor

Log in and push the image:

D:\git\ljtestproject-dockerexecutor>docker login gitlab.example.com:4567
Username: lisa
Password:
Login Succeeded

D:\git\ljtestproject-dockerexecutor>docker push gitlab.example.com:4567/lisa/ljtestproject-dockerexecutor
The push refers to repository [gitlab.example.com:4567/lisa/ljtestproject-dockerexecutor]
45c3e2f5d139: Pushing [=> ] 33.31MB/1.619GB

GitLab SSH Deployment Setup

Preliminary stuff – before setting up SSH deployment in your pipeline, you’ll need a user on the target box with permission to write to the files being published. You will need a public/private key pair.

On the target server, the project needs to be cloned into the deployment directory. The public key will need to be added to authorized_keys (or authorized_keys2 on older versions of Linux) file so the private key can be used for authentication.

To set up your GitLab project for SSH-based deployment, you need to add some variables to the project. In the project, navigate to Settings ==> CI/CD

Expand the “Variables” section. You will need to add the following key/value variable pairs:

Key Value
SSH_KNOWN_HOSTS Output of ssh-keyscan targetserver.example.com
SSH_PRIVATE_KEY Content of your private key
DEPLOYMENT_HOST Target hostname, e.g. targetserver.example.com
DEPLOYMENT_USER Username on target server
DEPLOYMENT_PATH Path to which project will be deployed on target server

Save the variables

I am managing both a production and development deployment within the pipeline, so I’ve got prod and dev specific variables. We use the same username for prod and dev; but the hostname, path, and target server public key are different.

If your repository is publicly readable, this is sufficient. If you have a private repository, you’ll need a way to authenticate and fetch the data. In this example, I am using a deployment token. Under Settings Repository, expand the “Deployment Tokens” section and create a deployment token. On my target servers, the remote is added as https://TokenUser:TokenSecret@gitlab.example.com/path/to/project.git instead of just https://gitlab.example.com/path/to/project.git

Once you have defined these variables within the project, use the variables in your CI/CD YAML. In this example, I am deploying PHP code to a web server. Changes to the development branch are deployed to the dev server, and changes to the master branch are deployed to the production server.

In the before_script, I set up the key-based authentication by adding the private key to my runner environment and adding the prod and dev target server’s public key to the runner environment.

- 'which ssh-agent || ( apt-get update -y && apt-get install openssh-client -y )'
- eval $(ssh-agent -s)
- echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add - > /dev/null
- mkdir -p ~/.ssh
- chmod 700 ~/.ssh
- echo "$SSH_KNOWN_HOSTS_DEV" > ~/.ssh/known_hosts
- echo "$SSH_KNOWN_HOSTS_PROD" >> ~/.ssh/known_hosts
- chmod 644 ~/.ssh/known_hosts

In the deployment component, username and host variables are used to connect to the target server via SSH. The commands run over that SSH session change directory into the deployment target path and use “git pull” to fetch and merge the updated code. This ensures the proper branch is pulled to the production and down-level environments.

production-deployment:
 stage: deploy
  script:
    - ssh $DEPLOYMENT_USER@$DEPLOYMENT_HOST_PROD "cd '$DEPLOYMENT_PATH_PROD'; git pull origin master"
  only:
    - master

development-deployment:
 stage: deploy
 script:
   - ssh $DEPLOYMENT_USER@$DEPLOYMENT_HOST_DEV "cd '$DEPLOYMENT_PATH_DEV'; git pull origin development"
 only:
   - development

Now when I make changes to the project code,

Assuming the tests still pass, the deployment will run

If you click on the deployment component, you can see what changes were pulled to the target server

And, yes, the updated files are on my target server.

 

VSCode Tab Key Not Working

Tab suddenly stop tabbing in VSCode? Try hitting ctrl+m — evidently there’s another ‘mode’ for the tab key where it changes focus instead of tabbing. Very cool and useful when used deliberately. Very “huh?!?!” when you accidentally hit ctrl+m 🙂

From https://code.visualstudio.com/docs/getstarted/keybindings

Ctrl+M Toggle Use of Tab Key for Setting Focus editor.action.toggleTabFocusMode

Of course if that wasn’t your problem … focus mode is turned on now & you’ll want to hit ctrl+m again to change back to tab mode!

Corrupted Spreadsheets From PHPSpreadsheet (andPHPExcel)

I need to deliver Excel files to the browser, so used php://output as the save location. Does exactly what I want except …

Excel says it has a problem with some of the file content. It’s recoverable – click “Yes” and you’ll see all of the spreadsheet data. But no one is going to want to run a repair on every single file they download from my site!

I confirmed the buffer was being cleared, that I didn’t have any extraneous PHP errors getting inserted into the spreadsheet data. My output was clean – it was also corrupt. I’d actually started using the old PHPExcel module, installed and changed over to PHPSpreadsheet because I know PHPExcel is not maintained. But the problem persisted. I started reading through the docs for PHPSpreadsheet to see if I could find a hint.

https://phpspreadsheet.readthedocs.io/en/latest/topics/recipes/#redirect-output-to-a-clients-web-browser

Caution:

Make sure not to include any echo statements or output any other contents than the Excel file. 
There should be no whitespace before the opening <?php tag and at most one line break after the closing ?> tag 
(which can also be omitted to avoid problems). 
Make sure that your script is saved without a BOM (Byte-order mark) because this counts as echoing output. 
The same things apply to all included files. 
Failing to follow the above guidelines may result in corrupt Excel files arriving at the client browser, 
and/or that headers cannot be set by PHP (resulting in warning messages).

Do I have more than one newline after the closing “?>” tag? Sure do!

Got rid of the extra newline, and the downloaded file is fine.

 

Create a New Exchange Account with Powershell

We use unique e-mail addresses every time we give out our address. Because that occasionally means I need to reply to someone using that address, I set up a quick web form to send e-mail from any arbitrary address in my domain. Every now and again, though … we need to actually reply to a message (attach pictures, get some really specific formatting without wasting a lot of time coming up with the appropriate HTML, etc).

If the Exchange powershell snap-in is not loaded (the new-mailbox command is not found), load the snap-in:

Add-PSSnapIn -Name Microsoft.Exchange.Management.PowerShell.SnapIn

Then create a new Exchange account and granting full access to the person who wants to send mail from that address.

New-Mailbox -Name "NewAccount" -Alias NewAccount -LastName "NewAccount" -UserPrincipalName NewAccount@example.com -Password (ConvertTo-SecureString -String 'haW29oihOI#192QHe983QHR9' -AsPlainText -Force)
Add-MailboxPermission -Identity "NewAccount@example.com" -User "me@example.com" -AccessRights FullAccess -InheritanceType All

Or adding a new primary SMTP address to an existing account:

set-mailbox -Identity NewAccount@example.com -PrimarySmtpAddress "ANewAddress@example.com" -EmailAddressPolicyEnabled $false

When adding a new address, the existing primary SMTP address becomes a secondary proxy address.

Oracle Query Returns JSON

I’m using Oracle a lot in my new job; and, in the process, I am learning about a lot of neat Oracle database features. Today, I discovered JSON_OBJECT:

SELECT JSON_OBJECT
(KEY 'CDID" VALUE C1.circuit_design_id,
KEY 'NODE_STATUS' VALUE circuit_position.CIRCUIT_NODE_STATUS, KEY "CDID3' VALUE circuit_position.circuit_design_id_3) jsonCircuitResults
FROM circuit C1
LEFT OUTER JOIN circuit_position on C1.circuit_design_id = circuit_position.circuit_design_id
WHERE C1.circuit_design_id = '54535525' and circuit_position.circuit_design_id_3 is not null;

The response is JSON –

 

SSL Trust On Fedora

I have a CA on one of our Fedora boxes, and I use it to sign some of the internal certificates. I’ll probably stop doing that since the LetsEncrypt certs are free … but, for now, I’ve still got to set up a trust to my CA.

In /etc/pki/ca-trust/source/anchors, put a PEM file with the CA public key. Run update-ca-trust … the cert gets added to /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem and your system will trust the CA.

Accessing MobyVM (And adding an exposed port to an existing Docker container)

I needed to map an addition port into an existing Docker container. Now I know the right thing to do is to create a new container and do it right this time but GitLab’s container has problems running on the Windows Docker Desktop. Permission-based problems that I’m not particularly included to attempt to sort out just to run a simple sandbox. Which means I’d need to drop my config file back in place & recreate my sandbox projects. And since I’m using CI/CD variables which don’t export … recreating the sandbox projects is a bit of a PITA.

On Linux, I can fix this by editing the config.v2.json and hostconfig.json files … but this is Windows running a funky Hyper-V Linux. And it turns out you can access the files on this MobyVM.

docker run -it --rm --privileged --pid=host justincormack/nsenter1

Now I’m able to cd into /var/lib/docker/containers, find the full ID for my GitLab container and cd into it, and edit the two config files. If it is running, you need to stop the container prior to editing the config files.

config.v2.json — add the port to “ExposedPorts”

chStdin”:false,”AttachStdout”:false,”AttachStderr”:false,”ExposedPorts”:{“22/tcp”:{},”443/tcp”:{},”80/tcp”:{},”4567/tcp”:{}},”Tty”:fal…

hostconfig.json — add the port to “PortBindings”

ult”,”PortBindings”:{“22/tcp”:[{“HostIp”:””,”HostPort”:”22″}],”443/tcp”:[{“HostIp”:””,”HostPort”:”443″}],”80/tcp”:[{“HostIp”:””,”HostPort”:”80″}],”4567/tcp”:[{“HostIp”:””,”HostPort”:”4567″}]},”Res…

 

Stop the Windows Docker service, start it, then start the container again. Voila! The new port for the container registry is there without recreating the container.

Using File System As A Git Repository

I’ve used GitLab for quite some time, and as a full featured CI/CD platform that also provides git functionality … it’s awesome. But it’s also serious overkill for someone who wants to coordinate code with another developer or two. Or just keep history for their code. Or a backup. To accomplish this, all you need is drive space. If you’ve got a file server, any folder on the share can be a git repository.

On the server, create a git repository and add something to it.

Z:\Temp\test>git init
Initialized empty Git repository in Z:/Temp/test/.git/

Z:\Temp\test>notepad testfile.txt

Z:\Temp\test>git add testfile.txt

Z:\Temp\test>git commit -m "Initial file upload"
[master (root-commit) 9a3ebe7] Initial file upload
1 file changed, 1 insertion(+)
create mode 100644 testfile.txt

Then on your client, either clone the repo from the drive path

C:\Users\lisa>git clone file://z:/temp/test
Cloning into 'test'...
remote: Enumerating objects: 3, done.
remote: Counting objects: 100% (3/3), done.
remote: Total 3 (delta 0), reused 0 (delta 0)
Receiving objects: 100% (3/3), done.

Or from the UNC path

C:\Users\lisa>git clone file://server01.example.com/data/temp/test
Cloning into 'test'...
remote: Enumerating objects: 3, done.
remote: Counting objects: 100% (3/3), done.
remote: Total 3 (delta 0), reused 0 (delta 0)
Receiving objects: 100% (3/3), done.

I prefer to use the UNC paths – if my drive letter fails to map for some reason, the UNC path is still available.

If you’ve got pre-existing code, there’s a bit of a different process. On the server, create an empty folder and use “git init” to initialize the empty repo. On the client where the code exists, run:

git init
git add *
git commit -m “Initial code upload”
git remote add origin git clone file://server01.example.com/data/temp/test
git push origin master