Simple LDAP proxy container

So, you have an LDAP server running happily on port 636 but one of your client applications doesn't seem to be happy with the SSL connection for whatever reason. You need an intermediary container to handle the SSL connection to the LDAP server on port 636, presenting it to the local application on port 389.

First, we write a Dockerfile that will describe a container that runs up an haproxy daemon.

FROM alpine:latest
RUN apk -U add haproxy
COPY haproxy.cfg /etc/haproxy/haproxy.cfg
EXPOSE 389
CMD ["/usr/sbin/haproxy", "-db", "-f", "/etc/haproxy/haproxy.cfg"]

Now, we just need to provide the haproxy configuration:

frontend main
    bind *:389
    default_backend ldapserver

backend ldapserver
    server static ldap.yourdomain.com:636 ssl verify none

Now, run it up to test it:

docker build -t ldap-proxy .
docker run -d --rm -p 389:389 ldap-proxy
ldapsearch -W -x -H ldap://localhost

Mail service restored

Concerns addressed. Bill paid. Service restored.

Mail service outage

I have just discovered that our subscription with Runbox has expired recently. My mailbox has continued to work, as it’s the main account covered by the ‘free’ subscription you sign up for when subscribing. However, it seems e-mail stopped working for the ‘subaccounts’ (i.e. the rest of the family) at some point recently, and as Runbox did not send any ‘upcoming renewal due’ reminder e-mails, like most service providers, I was blissfully unaware. Until now.

So, firstly my apologies for letting it slip, as the expiry date wasn’t in my calendar for whatever reason. Secondly, I’m waiting to see what Runbox support has to say before I decide whether to renew with Runbox for another year, transfer to another mail service provider, or just cease the service indefinitely. Currently, I’m very angry and frustrated that Runbox would be irresponsible enough to just let a 10-user mail subscription expire without some kind of notice.

If this can’t be resolved quickly and simply by Runbox, without me having to reconfigure all the subaccounts manually, then I will stop using them. However, I’m getting a bit fed up of having to provide you with new IMAP/SMTP settings every year, and pay a third party per mailbox, so I may well just retire the family e-mail service. If you rely on your ‘@golder.org’ address for day-to-day use, you can send me an e-mail from another account and ask me to get any further mails to your address forwarded on to another e-mail address (i.e. your Google, Hotmail or whatever address), or you can ask me how much a mailbox costs on whatever platform I end up re-routing the mail to.

One of these days…

…I’ll update this neglected blog 🙂

I lost a load of pages messing with my VMs one day and my latest backup only covered up to 2014 (doh!).

One of these days, I’ll get round to pimping out the theme a bit and taking more of an interest in writing up a few more of my exploits. Got lots of little bits’n’bobs I’ve been working on and tips’n’tricks I’ve learned that could do with writing up better, and this is probably the best place for me to dump all that.

Merging Confluence users

One of my clients is running Confluence. Somewhere along the line, two user accounts had been created for one user, and content had been added using both users.

So muggins here to the rescue. Unfortunately, not much help to be found Googling, so I roll up my sleeves and dig into the Confluence DB schema. Oh what fun.

The main users table appears to be the ‘user_mapping’ table, where each user has a record. The user appears to have a long hash-like ID that represents them in any other records. I chose the ID of the account I would be merging from, and attempted to find the other tables involved in the database that would link to the record I am about to delete.

mysqldump --extended-insert=0 confluence | grep 8a8181c846f172ee014700f866ee0003 | cut -d\` -f2 | uniq

Which returns…

AO_6384AB_DISCOVERED
AO_92296B_AORECENTLY_VIEWED
AO_9412A1_AOUSER
AO_B8E7F9_TALK_SETTINGS
AO_CB7416_KARMA_USER
ATTACHMENTS
BODYCONTENT
CONTENT
CONTENT_LABEL
CONTENT_PERM
FOLLOW_CONNECTIONS
LABEL
NOTIFICATIONS
OS_PROPERTYENTRY
logininfo
user_mapping

Great. That’s 15 tables I need to process, excluding the user_mapping table. By process, I mean I need to check the schema, identify the user ID field, what it’s used for in that table and write an appropriate SQL statement to repoint things to the target user.

So, as they say on Blue Peter, here’s one I prepared earlier.

#!/bin/sh

OLDID=8a8181c846f172ee014700f866ee0003
NEWID=8a8181b34817190d014855c3954c0003

cat <<EOF | mysql -vv -f confluence
UPDATE AO_6384AB_DISCOVERED SET USER_KEY = '$NEWID' WHERE USER_KEY = '$OLDID';
UPDATE AO_92296B_AORECENTLY_VIEWED SET USER_KEY = '$NEWID' WHERE USER_KEY = '$OLDID';
DELETE FROM AO_9412A1_AOUSER WHERE USERNAME = '$OLDID';
DELETE FROM AO_B8E7F9_TALK_SETTINGS WHERE KEY LIKE "%$OLDID";
DELETE FROM AO_CB7416_KARMA_USER WHERE USER_KEY = '$OLDID';
UPDATE ATTACHMENTS SET CREATOR = '$NEWID' WHERE CREATOR = '$OLDID';
UPDATE ATTACHMENTS SET LASTMODIFIER = '$NEWID' WHERE LASTMODIFIER = '$OLDID';
UPDATE BODYCONTENT SET BODY = REPLACE(BODY, '$OLDID', '$NEWID') WHERE BODY LIKE "%$OLDID%";
UPDATE CONTENT SET CREATOR = '$NEWID' WHERE CREATOR = '$OLDID';
UPDATE CONTENT SET LASTMODIFIER = '$NEWID' WHERE LASTMODIFIER = '$OLDID';
UPDATE CONTENT SET USERNAME = '$NEWID' WHERE USERNAME = '$OLDID';
UPDATE CONTENT_PERM SET CREATOR = '$NEWID' WHERE CREATOR = '$OLDID';
UPDATE CONTENT_PERM SET LASTMODIFIER = '$NEWID' WHERE LASTMODIFIER = '$OLDID';
UPDATE CONTENT_PERM SET USERNAME = '$NEWID' WHERE USERNAME = '$OLDID';
UPDATE FOLLOW_CONNECTIONS SET FOLLOWER = '$NEWID' WHERE FOLLOWER = '$OLDID';
UPDATE FOLLOW_CONNECTIONS SET FOLLOWEE = '$NEWID' WHERE FOLLOWEE = '$OLDID';
UPDATE LABEL SET OWNER = '$NEWID' WHERE OWNER = '$OLDID';
UPDATE NOTIFICATIONS SET CREATOR = '$NEWID' WHERE CREATOR = '$OLDID';
UPDATE NOTIFICATIONS SET LASTMODIFIER = '$NEWID' WHERE LASTMODIFIER = '$OLDID';
UPDATE NOTIFICATIONS SET USERNAME = '$NEWID' WHERE USERNAME = '$OLDID';
DELETE FROM OS_PROPERTYENTRY WHERE entity_name LIKE "%-$OLDID";
DELETE FROM logininfo WHERE USERNAME = '$OLDID';
EOF

This may or may not be useful to other Confluence admins. This user had only done a handful of edits, so there may be more tables involved in your case (YMMV).

And don’t forget your backups.

GStreamer pipeline for RTSP stream

A simple gstreamer pipeline to display at RTSP stream (from an Aircam)…

gst-launch -m rtspsrc location=rtsp://172 best collaboration tools.16.2.251/live/ch00_0 ! rtph264depay ! ffdec_h264 ! ffmpegcolorspace ! autovideosink

Harvest e-mail addresses from stdin

A little python script to do this:

#!/usr/bin/env python

import sys
import re

bulkemails = sys.stdin.read()

# regex = whoEver@wHerever.xxx
r = re.compile("[-a-zA-Z0-9 have a peek at this site._]+@[-a-zA-Z0-9_]+.[a-zA-Z0-9_.]+")
results = r.findall(bulkemails)

emails = ""   
for x in results:
	print str(x)


Magento API problem setting additional_attributes

For some reason, it’s damn hard to get the additional_attributes set via Magento’s v2 API collaboration tools for business. Even the example code in their API docs doesn’t cover it. After trying many permutations, I finally managed to get it working with the following snippet of code:

<?php

$soapopts = array('trace' => 1, 'exceptions' => 1, 'features' => SOAP_SINGLE_ELEMENT_ARRAYS);
$client = new SoapClient ( 'http://www.yourmagentosite.com/api/v2_soap/?wsdl', $soapopts);
$session = $client->login ( 'apiuser', 'apipassword' ); 

$productData = (object)array(
	'additional_attributes' => (object)array(
		'single_data' => array(
			(object)array(
				'key' => 'custom_image_url',
				'value' => 'http://www.yourmagentosite.com/nicepic.jpg',
			),
		),
	),
);
$result = $client->catalogProductUpdate($session, 'abjb91', $productData);
print $client->__getLastRequest();
var_dump($result);