Category: Technology

ADO Notifications

I’ve been underwhelmed with the notifications I get from Azure DevOps – there are a lot of build-centric notifications, but I don’t use ADO for builds or deployment apart from playing around. And I really don’t care if the silly test project I set up to build and deploy a website worked, failed, or whatever. I was thinking about hooking whatever they’re calling Flow this week up to ADO and building notification workflows.

Fortunately, a coworker mentioned that you can customize notifications in ADO … which, I’d spent a few seconds poking around and didn’t see anything. But I spent more than a few seconds this time and happened across this little ellipsis on the card that pops up when I click the circle with my initials in it. More options!

A new menu flies out; and, look, there’s “Notifications”

Exactly as I’ve observed, there are a lot of build-centric alerts. So I created a new subscription.

Here’s a subscription that I hope will notify me when items assigned to me have updates to activity or comments.

Discourse in Docker on Fedora 32

I had to make a few tweaks in order to run the Discourse base Docker image. First, I got the following very clear error:

discourse docker this version of runc doesn't work on cgroups v2: unknown

I had to switch from cgroupv2 to cgroup

grubby --update-kernel=ALL --args="systemd.unified_cgroup_hierarchy=0"

At which point I was at least able to run through the configuration. This yielded an access denied error attempting to create /shared/postgres:

Configuration file at updated successfully!

Updates successful. Rebuilding in 5 seconds.
Building app
Ensuring launcher is up to date
Fetching origin
Launcher is up-to-date
cd /pups && git pull && /pups/bin/pups --stdin
Already up to date.
I, [2020-08-11T18:15:03.664400 #1] INFO -- : Loading --stdin
I, [2020-08-11T18:15:03.672609 #1] INFO -- : > locale-gen $LANG && update-locale
I, [2020-08-11T18:15:03.746912 #1] INFO -- : Generating locales (this might take a while)...
Generation complete.

I, [2020-08-11T18:15:03.747838 #1] INFO -- : > mkdir -p /shared/postgres_run
mkdir: cannot create directory ‘/shared/postgres_run’: Permission denied
I, [2020-08-11T18:15:03.754890 #1] INFO -- :

FAILED
--------------------
Pups::ExecError: mkdir -p /shared/postgres_run failed with return #<Process::Status: pid 21 exit 1>
Location of failure: /pups/lib/pups/exec_command.rb:112:in `spawn'
exec failed with the params "mkdir -p /shared/postgres_run"
d98ee8471413ad77ab27ed3506f12c5c94a2b6902622faf4d88d5dbb51a10f63
** FAILED TO BOOTSTRAP ** please scroll up and look for earlier error messages, there may be more than one.
./discourse-doctor may help diagnose the problem.

Gut was that I encountered an SELinux problem. Turns out I was right. There’s a lot of reading you can do about SELinux and Docker — this, for one — but the quick and simple solution is to run the docker container in privileged mode (note: this may not be a good idea in your specific scenario. understand what privileged mode is and the risks it entails). To do so, edit the launcher script (/var/discourse/launcher in my case) and add  “–privileged” to user_args:

And finally (and this may well be a RTFM thing) — you’ve got to have your public DNS set up & whatever firewall rules to get traffic to the http:// website you are trying to build in order to use the LetsEncrypt SSL cert and configure HTTPS. It uses the file-based verification (i.e. create a file named xyz in /path/to/xyz.whatever on your web server, lets encrypt grabs the file and verifies it exists) which fails quite spectacularly when the Internet at large cannot access your about-to-be-a-discourse-server.

Exporting Microsoft Stream Transcript

Microsoft has changed the interface on Stream slightly, so my code to export the Stream transcript needed an update. since copy/paste doesn’t seem to work for everyone, the script is also available as a text file.

var objTranscriptionLines = window.angular.element(window.document.querySelectorAll('.transcript-list')).scope().$ctrl.transcriptLines;
var strRunningText = "";
for(var i = 0; i < objTranscriptionLines.length; i++){
    if( objTranscriptionLines[i] ){
        var strLineText = objTranscriptionLines[i].eventData.text;
        strRunningText = strRunningText + "\n" + strLineText;
    }
}
console.log(strRunningText);

Building LIB_MYSQLUDF_SYS On Fedora 31

I moved my MariaDB server to a new host and could not follow my previously working instructions to build lib_mysqludf_sys. The error indicated that my_atomic.h was not found.

[lisa@server03 lib_mysqludf_sys]# make
gcc -fPIC -Wall -I/usr/include/mysql/server -I. -shared lib_mysqludf_sys.c -o /usr/lib64/mariadb/plugin//lib_mysqludf_sys.so
In file included from /usr/include/mysql/server/my_sys.h:34,
from lib_mysqludf_sys.c:41:
/usr/include/mysql/server/my_pthread.h:26:10: fatal error: my_atomic.h: No such file or directory
26 | #include <my_atomic.h>
| ^~~~~~~~~~~~~
compilation terminated.
make: *** [Makefile:4: install] Error 1

The missing file is located in /usr/include/mysql/server/private … so I had to include that file in the gcc command as well. My new Makefile reads as follows:

[lisa@server03 lib_mysqludf_sys]# cat Makefile
LIBDIR=/usr/lib64/mariadb/plugin/

install:
gcc -fPIC -Wall -I/usr/include/mysql/server -I/usr/include/mysql/server/private -I. -shared lib_mysqludf_sys.c -o $(LIBDIR)/lib_mysqludf_sys.so

I was then able to make and use install.sh to load it into MariaDB.

HTML Checkbox Adding and Removing Table Row

Here’s the JavaScript code I ended up using to add and remove rows from a table based on a checkbox selection (and only allowing one checkbox per group to be selected). The biggest change is that I added a name and ID to my TR for easier identification.

$(document).on("change", "input[type='checkbox']", function () {
    var $objCheckbox = $(this);
    if ($objCheckbox.is(":checked")) {			// When checked, deactivate other checkboxes and add to sets to create table
        var objCheckboxGroup = "input:checkbox[tableselector='" + $objCheckbox.attr("tableselector") + "']";

        $(objCheckboxGroup).prop("disabled", true);
        $objCheckbox.prop("disabled", false);		// Allow checked box to be unchecked

        addSetToCreatingTable($objCheckbox.attr("setname"), $objCheckbox.attr("settype"), $objCheckbox.attr("goodcircuits") + "|" + $objCheckbox.attr("value"), $objCheckbox.attr("tableselector"));

    }
    else {							// When unchecked, active checkboxes and remove from sets to create table
        var objCheckboxGroup = "input:checkbox[name='" + $objCheckbox.attr("name") + "']";
        $(objCheckboxGroup).prop("disabled", false);	

        $("#" + $objCheckbox.attr('tableselector')).each(function(){ $(this).remove();})
}
});

What Can I sudo?

Some 90% of my Linux experience is on servers where I have root or root-equivalent access (i.e. I can sudo anything). In those cases, ‘what can I run under sudo’ was never a question. And I’d use something like “sudo less /etc/sudoers” to inspect what someone else was able to run when they questioned their access. In my new position, we have a lot of servers that we own too — the Engineering IT support group lets us spin up our own VMs, do whatever we want (within reason). But we have a few IT-managed servers with very restricted rights. And the commands I would use to perform functions (think systemctl restart httpd) aren’t in my sudoers access list. Luckily you can list out what you can run under sudo:

$ sudo -l
[sudo] password for useraccount:
Matching Defaults entries for useraccount on this host:
syslog=auth, loglinelen=0, syslog_goodpri=info, syslog_badpri=err,
logfile=/var/log/sudo.log

User useraccount may run the following commands on this host:
(ALL) /opt/lampp/lampp start, (ALL) /opt/lampp/lampp stop, (ALL)
/opt/lampp/lampp restart, (ALL) /usr/sbin/apachectl

And that is how I know to use apachectl instead of systemctl.

HTML Checkboxes To Add and Remove Values from Table

I am creating a web form where the user input sometimes cannot be resolved to a unique value. In those cases, I present the user a set of checkboxes with the options (yes, a radio button makes more sense because you can only select one. But I hate that radio buttons change selection when you hit an arrow key.).

When a selection is made, I need to (1) deactivate the checkboxes for the other options when a checkbox in the group is selected and (2) add information to a data table that is used in subsequent activities.

When a selection is cleared, I need to (1) activate the checkboxes within the group and (2) remove the right row from the data table.

Below is the HTML code that achieves this. Now I just need to map this test page into the actual web code. There’s a post with the actual code I ended up using in production too.

<html>
<head><title>Adding And Removing From Table</title></head>
<body>

<div name="divCircuitClarifications" id="divCircuitClarifications">
  <h3>My-Sample-Circuit-A</h3>
    <input type="checkbox" value="123" tableselector="SampleCircuitA" name="SampleCircuitA[]" /><label>123</label>
    <input type="checkbox" value="234" tableselector="SampleCircuitA" name="SampleCircuitA[]" /><label>234</label>
    <input type="checkbox" value="345" tableselector="SampleCircuitA" name="SampleCircuitA[]" /><label>345</label>
<P>
  <h3>My-Sample-Circuit-B</h3>
    <input type="checkbox" value="abc" tableselector="SampleCircuitB" name="SampleCircuitB[]" /><label>abc</label>
    <input type="checkbox" value="bcd" tableselector="SampleCircuitB" name="SampleCircuitB[]" /><label>bcd</label>
    <input type="checkbox" value="cde" tableselector="SampleCircuitB" name="SampleCircuitB[]" /><label>cde</label>
<P>
  <h3>My-Sample-Circuit-C</h3>
    <input type="checkbox" value="Cabc" tableselector="SampleCircuitC" name="SampleCircuitC[]" /><label>abc</label>
    <input type="checkbox" value="Cbcd" tableselector="SampleCircuitC" name="SampleCircuitC[]" /><label>bcd</label>
    <input type="checkbox" value="Ccde" tableselector="SampleCircuitC" name="SampleCircuitC[]" /><label>cde</label>
<P>
</div>

<div id="divResultTable" name="divResultTable">
<table border="1" padding="1" name="tableSetsToCreate" id="tableSetsToCreate">
	<thead><tr><th>ECCKT</th><th>Circuit ID</th></tr></thead>
	<tbody></tbody>
</table>


<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

<script>
	$("input:checkbox").on('click', function() {
	  	var $objCheckbox = $(this);
	  	if ($objCheckbox.is(":checked")) {			// When checked, deactivate other checkboxes and add to sets to create table
	    		var objCheckboxGroup = "input:checkbox[tableselector='" + $objCheckbox.attr("tableselector") + "']";
	
	    		$(objCheckboxGroup).prop("disabled", true);
	    		$objCheckbox.prop("disabled", false);		// Allow checked box to be unchecked

	                var strTableRowString = '<tr><td>' + $objCheckbox.attr("tableselector") + '</td><td>' + $objCheckbox.val() + '</td>\n';
	                $('#tableSetsToCreate tbody').append(strTableRowString);
	  	}
		else {							// When unchecked, active checkboxes and remove from sets to create table
	    		var objCheckboxGroup = "input:checkbox[name='" + $objCheckbox.attr("name") + "']";
	    		$(objCheckboxGroup).prop("disabled", false);	

			$("tr:contains('" + $objCheckbox.attr('tableselector') + "')").each(function(){ $(this).remove();})
  		}
	});
</script>
</body>



Web Stats

Since my website has a lot of information about Microsoft Teams, I can see when a lot of new Teams users came online during the lockdown. Now that people are returning to offices (and, I expect, are more familiar with the platform), I’m starting to see fewer search engine referrals. But I’m still 3-4x the numbers I’d seen pre-lockdown.

Oracle – LISTAGG

I needed to collapse multiple rows into a single row — the circuits within a diversity set are stored within the ds_dvrsty_set_circuit table as individual rows & the ds_dvrsty_set_id links the multiple rows. What I wanted was a set ID, set name, and the list of circuits within the set.

To accomplish this, I found LISTAGG which is a little bit like STUFF in MSSQL. This query produces a single row for each diversity set that contains the set ID, the set name, and a comma delimited list of set members.

SELECT
     ds_dvrsty_set_circuit.ds_dvrsty_set_id,
     (select ds_dvrsty_set.ds_dvrsty_set_nm from ds_dvrsty_set where ds_dvrsty_set_id = ds_dvrsty_set_circuit.ds_dvrsty_set_id) as set_name,
     LISTAGG(ds_dvrsty_set_circuit.circuit_design_id,  ',') WITHIN GROUP(ORDER BY ds_dvrsty_set_circuit.ds_dvrsty_set_id) AS member_circuits
FROM
     ds_dvrsty_set_circuit
     left outer join ds_dvrsty_set on ds_dvrsty_set.ds_dvrsty_set_id = ds_dvrsty_set_circuit.DS_DVRSTY_SET_ID
WHERE
     ds_dvrsty_set_circuit.ds_dvrsty_set_id in (select distinct ds_dvrsty_set_id from ds_dvrsty_set_circuit where circuit_design_id in (14445678, 5078901) )
AND
     ds_dvrsty_set.ds_dvrsty_set_nm like '43%'
GROUP BY
     ds_dvrsty_set_circuit.ds_dvrsty_set_id
ORDER BY
     ds_dvrsty_set_circuit.ds_dvrsty_set_id;

Voila — exactly what I needed. If the searched circuit design IDs appear in more than one set, there is a new row for each set ID.

NVIDIA Driver Installation Issue – Fedora 30

NVIDIA finally released an updated driver for Scott’s laptop — one that should be compatible with the 5.x kernel. Ran through the normal process and got the following error:

     Unable to load the nvidia-drm kernel module

Which … was at least new. Tried running through the installation again but not registering the driver with the kernel. Installation completed successfully, and he’s able to boot the 5.8.100 kernel.