Monday, December 31, 2018

Finding the IP address for a KVM guest (in bridge mode)

I have a Windows 10 vm guest, testdesktop, in my KVM vm host I want to remote in.

raub@vmhost:~$ virsh list
 Id    Name                           State
----------------------------------------------------
 1     desktop                        running
 16    testdesktop                    running

raub@vmhost:~$

Thing is I did not set it up to support VNC as console, so I cannot just do virsh vncdisplay testdesktop and go from there. Well, I really just want to connect to it using RDP because that is what I want to do. But to do that I need to know its hostname or IP. I thought it was testdesktop.in.example.com, but I am wrong. So, what can I do?

As far as I know (if I am wrong, do let me know!), I cannot get the IP of a guest directly using virsh unless KVM is acting as the DCHP server. In my case, that is not the case; I am using the domain's DHCP and DNS servers since this guest is in bridge mode:

virsh dumpxml testdesktop
[...[
    &linterface type='bridge'>
      &lmac address='c0:ff:ee:83:eb:ed'/>
      &lsource bridge='br0'/>
      <arget dev='vnet1'/>
      &lmodel type='rtl8139'/>
      <alias name='net0'/>

I found an interesting thread that does offer great suggestions for finding the IP address of a KVM Virtual Machine. Let's see if any of them will help me.

  1. Use my ARP table. The idea here is that since I am in the vm host, vmhost (yes, that is its name, really) testdesktop is a guest of, vmhost's ARP table should see it from time to time. All I need is the MAC address, which I have thanks to previously runnning virsh dumpxml testdesktop:

    raub@vmhost:~$ arp -n|grep c0:ff:ee:83:eb:ed
    raub@vmhost:~$

    Hmmm, don't know why but it ain't there. Next?

  2. Nmap. Yes, it's main use is network security scanner, but Nmap can be used as a glorified ping, where it returns amongst other things the MAC address. Let me show you what I mean by running it against the vmhost (I will be using desktop for that). First we cheat since we know the IP address:

    raub@desktop:/tmp$ sudo nmap -sn -n 192.168.10.19
    
    Starting Nmap 7.01 ( https://nmap.org ) at 2018-12-31 10:45 EST
    Nmap scan report for 192.168.10.19
    Host is up (0.000082s latency).
    MAC Address: BC:5F:F4:54:D7:8D (ASRock Incorporation)
    Nmap done: 1 IP address (1 host up) scanned in 0.22 seconds
    raub@desktop:/tmp$

    Then we use the MAC address to find the IP.

    raub@desktop:/tmp$ sudo nmap -sn 192.168.10.* | grep -B 3 BC:5F:F4:54:D7:8D
    Nmap scan report for vmhost.in.example.com (192.168.10.19)
    Host is up (-0.10s latency).
    MAC Address: BC:5F:F4:54:D7:8D (ASRock Incorporation)
    raub@desktop:/tmp$
    Note: If you want to look cooler, use 192.168.10.0/24 instead of 192.168.10.*. Also, grep -i helps to cover our asses.

    Looks like we have a plan here. So, let's look for testdesktop:

    raub@desktop:~$ nmap -sn 192.168.10.0/24 | grep -i c0:ff:ee:83:eb:ed -B 3
    raub@desktop:~$

    All I got back was was a nice cup of nothing. Next!

  3. What about virsh domifaddr?. Not holding my breath. Remember testdesktop is in bridge mode. But, just to be sure:

    raub@vmhost:~$ virsh domifaddr testdesktop
     Name       MAC address          Protocol     Address
    -------------------------------------------------------------------------------
    raub@vmhost:~$
  4. Well, the arp command should have been deprecated. What about ip neighbour? Er, nope.

    raub@vmhost:~$ ip neighbour | grep -i c0:ff:ee:83:eb:ed
    raub@vmhost:~$
  5. You are making this too complicated! Why not login to the console of this guest and then type ipconfig since it is a Windows box? What if vmhost is run headless? So, I would have to install a windows manager in vmhost, then VNC with all the extra cruft that GUIs require just so I can vnc into it and then use the gui console thingie to get into testdesktop to type one command? Can you say overkill and convoluted? I think we can do better thank you verymuch.

  6. OK, smartguy. Since you are making an article you have found a solution. What did you do?. Well, I like solutions that do not require me to keep installing extra programs; note I used nmap in desktop as it is where I run it. Here is my thought process: vmhost should have the network traffic for testdesktop since it is his guest. Why not then look for traffic matching its MAC address? We can do that using tcpdump which is there to begin with.

    Since I am lazy, I told it to probulate tcpdump the physical network interface, eno1 instead of the bridge I created for KVM. This way I cannot use the excuse that I missed something.

    raub@vmhost:~$ sudo tcpdump -i eno1 | grep c0:ff:ee:83:eb:ed
    [sudo] password for raub:
    tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
    listening on eno1, link-type EN10MB (Ethernet), capture size 262144 bytes
    23:19:09.835884 IP testdesktop.dhcp.example.com.68 > ns.in.example.com.67: BOOTP/DHCP, Request from c0:ff:ee:83:eb:ed (oui Unknown), length 327
    00:49:09.846907 IP testdesktop.dhcp.example.com.68 > ns.in.example.com.67: BOOTP/DHCP, Request from c0:ff:ee:83:eb:ed (oui Unknown), length 327
    02:19:09.857254 IP testdesktop.dhcp.example.com.68 > ns.in.example.com.67: BOOTP/DHCP, Request from c0:ff:ee:83:eb:ed (oui Unknown), length 327
    03:49:09.868670 IP testdesktop.dhcp.example.com.68 > ns.in.example.com.67: BOOTP/DHCP, Request from c0:ff:ee:83:eb:ed (oui Unknown), length 327
    05:19:09.882066 IP testdesktop.dhcp.example.com.68 > ns.in.example.com.67: BOOTP/DHCP, Request from c0:ff:ee:83:eb:ed (oui Unknown), length 327
    06:49:09.895852 IP testdesktop.dhcp.example.com.68 > ns.in.example.com.67: BOOTP/DHCP, Request from c0:ff:ee:83:eb:ed (oui Unknown), length 327
    ^C2384605 packets captured
    2385524 packets received by filter
    914 packets dropped by kernel
    186 packets dropped by interface
    
    raub@vmhost:~$

    So the guest is seen by DNS as testdesktop.dhcp.example.com (I don't want to know why), from which I can get the IP if I so want.

The beauty of the above solution is that it did not really require any special feature from KVM, meaning it should work with VirtualBox, ESXi, HyperV, or even Xen. I like generic solutions.

Friday, November 30, 2018

VMWare ESXI Gripes: How not to set a ESXi host in maintenance mode

So I want to patch a ESXi host (it is by itself instead of part of a cluster). First thing I do is to tell it to go to maintenance mode:

[root@vmhost2:~] esxcli system maintenanceMode set --enable on


[crickets]

and Then I wait and wait and wait and wait some more. And then 35 minutes passed since I started that and nothing seems to be happening, which is why I decided to take the time while waiting and start typing this article. It does feel like it is trying to pause all the running guests in some convoluted way (more on that later). I checked the Place a Host in Maintenance Mode chapter in the official ESXi and vCenter docs, and this is what it says about this:

The host is in a state of Entering Maintenance Mode until all running virtual machines are powered down or migrated to different hosts.

Lovely. But, this is taking way too long. I mean, the script I wrote to save/suspend and resume ESXi guests is much faster than whatever the maintenance mode is doing. Maybe I should have done that first.

It is now almost an hour and it still have not finished doing whatever it is trying to do. So, I got annoyed:

[root@vmhost2:~] /etc/init.d/hostd restart
watchdog-hostd: Terminating watchdog process with PID 66942
hostd stopped.
hostd started.
[root@vmhost2:~] /etc/init.d/vpxa  restart
watchdog-vpxa: Terminating watchdog process with PID 67479
vpxa stopped.
[root@vmhost2:~] /etc/init.d/vpxa  status
vpxa is running
[root@vmhost2:~] vim-cmd /hostsvc/maintenance_mode_exit
The operation is not allowed in the current state.
[root@vmhost2:~]

See how it is giving me a hard time? I can play that game: time to unleash my script:

[root@vmhost2:/vmfs/volumes/5b7a0d7d-7f2b6678-68c8-00224d98ad4f/var/tmp] ./save
_runningvms.sh save
Suspending VM...
Suspending VM...
Suspending VM...
Suspending VM...
Suspending VM...
Suspending VM...
[root@vmhost2:/vmfs/volumes/5b7a0d7d-7f2b6678-68c8-00224d98ad4f/var/tmp]

and now I know I can safely do a Windows on this vm host:

[root@vmhost2:~] reboot
[root@vmhost2:~]

And now the vms are saved, I have no problem whatsoever putting this host in maintenance more. In fact, doing

[root@vmhost2:~] esxcli system maintenanceMode set --enable on
[root@vmhost2:~] 

took longer to type than to run it.

Moral of the Story

Save/quit/whatever your guests before setting maintenance mode. At least if you do not have a way to move the guests to the other nodes (if you have any), like vmotion.

Wednesday, October 03, 2018

Creating and mounting a fileshare as a file in a KVM Windows guest

Yeah, the title is a mouthfull.

So, let's get it done.

  1. Create the disk, which is henceforth called foretest.iso. I made it to be 1G because, as the name says, it is a test.
    raub@vmhost:~$ dd if=/dev/zero of=foretest.iso bs=1G count=1
    1+0 records in
    1+0 records out
    1073741824 bytes (1.1 GB, 1.0 GiB) copied, 2.29044 s, 469 MB/s
    raub@vmhost:~$
    NOTE: Some people would complain that I am using the .iso extension for my image file instead of, say, .img. Well, this is my article; deal with it.
  2. Now let's feed it to the vm.
    raub@vmhost:~$ virsh attach-disk desktop dev/foretest.iso hda --type raw --mode readwrite                 
    error: No support for readwrite in command 'attach-disk'
    
    raub@vmhost:~$

    Well, I did not know my KVM host does not have attach-disk. I guess I need to use attach-device instead. But, we will need to use a config file to describe how we want the storage to look like. If it looks familiar, we have used attach-disk to mount a USB device, namely an APC UPS.

    So, here is the .xml file:

    cat > dev/foretest.xml << 'EOF'
    <disk type='file' device='disk'>
       <driver name='qemu' type='raw' cache='none'/>
       <source file='/home/raub/dev/foretest.iso'/>
    <target dev='hdc'/>
    </disk >
    EOF

    And here we are feeding it into the guest:

    raub@vmhost:~$ sudo virsh attach-device --config testdesktop dev/foretest.xml
    Device attached successfully
    
    raub@vmhost:~$

    So we should be able to go to the guest and see the drive waving at us, right? Er, not quite. it is being listed here

    <disk type='file' device='disk'>
    
          <source file='/home/raub/dev/foretest.iso'/>
          <target dev='vdd' bus='virtio'/>
          <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/>
       </disk>

    But not in the GUI thingie nor inside the guest. And, yes, I have 2 virtual CD drives in this guest.


On a second thought, maybe I am doing this wrong. You see, the --config option tells it to add the drive to the config file. Only way to enable that is to completely shut down the vm guest (rebooting is not enough) and then restart it. What if I use --live instead, which does the deed in real time, as if I just pop the computer on and add the drive to an unused sata port?

raub@vmhost:~$ sudo virsh attach-device --live testdesktop dev/foretest.xml
error: Failed to attach device from dev/foretest.xml
error: internal error unable to execute QEMU command '__com.redhat_drive_add': Device 'drive-virtio-disk3' could not be initialized

raub@vmhost:~$

I guess it does not like me to add hard drives to a running guest. We need to try something else.

Attempt #2: USB

What if we pretend our disk is really a removable device like a USB drive? We begin by rewriting our .xml file:

cat > dev/foretest.xml << 'EOF'
<disk type='file' device='disk'>
  <driver name='qemu' type='raw'/>
  <source file='/home/raub/dev/foretest.iso'/>
  <target dev='sdd' bus='usb'/>
</disk>
EOF

Now let's mount it:

raub@desktop:~$ sudo virsh attach-device --live testdesktop dev/foretest.xml
Device attached successfully

raub@desktop:~$

So far so good. Can our guest see it this time? When I use Windows Explorer (do notice I disabled one of the CD drives as I was doing something else between the last screen capture and this one) I do not see the drive there; I kinda expected Windows to say something like "Hey! You just connected an unformatted drive! I need to format it!" Oh well; there are more than one way to get this done:

There it is! And we can format it!

And then, we can put things into it.

Now, let's unmount it

raub@desktop:~$ sudo virsh detach-device --live testdesktop dev/foretest.xml
Device detached successfully

raub@desktop:~$

Now let's make it a physical drive!

Stupid question: since we pretend our foretest.iso file is a USB drive, can we make it a real USB drive? We would test that question by first grabbing a USB drive which is at least 1GB in size (I had a 16GB one doing nothing), which was mounted into my KVM host as /dev/sdh.And now we need to copy the file to the drive.

raub@desktop:~$ sudo dd if=dev/foretest.iso of=/dev/sdh
raub@desktop:~$

Then grab USB drive and then mount it in a windows physical desktop. And it will look just like how it looks in the testdesktop guest down to be able to write to it.

The next step will be to see if we can make it a system disk, a disk we can boot a computer from. But, that will be for another article.

Monday, September 24, 2018

Using ldapsearch and ldapmodify to talk to Active Directory

Why?

Great question! Here are a few lame excuses I was able to come with:

  • I like to use command line. This is a lame excuse because Windows have powershell. But,
  • I am more comfortable with Linux than Windows. Lame excuse since
    1. How many posts in this very blog I have made about using Windows?
    2. How many of said posts I have used the GUI when I could take care of business with Powershell?
    3. What is wrong with Powershell, at least of the applications I have used it for here so far?
I do have a couple of not so lame ones though:
  • I like to be able to access the network resources from any machine in the network running any OS. If I have a Linux box in an Active Directory-controlled network, chances are I will need to authenticate the Linux box against Active Directory (AD so I can save some keytaps). AD is Kerberos + ldap + sprinkles, so I better be able to use the usual kerberos/ldap Linux tools as one day I will need to figure out why things are boink.
  • It feels like I get more info using ldapsearch than the Windows tools, which is good when I do not know the name of an attribute, or how many instaces of said attribute are in use.

Using ldapsearch

Before we go mindlessly typing things, we need some data.
We need to know the name of the ldapserver.
Yes, if you have it configured in your ldap.conf file, you should not need it. But I prefer to assume nothing. If the domain was setup properly, we can ask it directly by typing nslookup -type=srv _ldap._tcp.DOMAIN where DOMAIN is the Active Directory domain name, not the DNS one; that caught me off guard. So, if our DNS dmain is example.com and the AD domain (we are very original) is ad.example.com, we have
raub@desktop:/tmp$ nslookup -type=srv _ldap._tcp.ad.example.com
Server:         192.168.0.10
Address:        192.168.0.10#53

Non-authoritative answer:
_ldap._tcp.ad.example.com   service = 0 100 389 ADDC0.ad.example.com.
_ldap._tcp.ad.example.com   service = 0 100 389 ADDC2.ad.example.com.
_ldap._tcp.ad.example.com   service = 0 100 389 ADDC1.ad.example.com.

Authoritative answers can be found from:
ad.example.com      nameserver = addc1.ad.example.com.
ad.example.com      nameserver = ns.example.com.
ad.example.com      nameserver = ns2.example.com.
ad.example.com      nameserver = addc0.ad.example.com.
ad.example.com      nameserver = addc2.ad.example.com.
ADDC0.ad.example.com        internet address = 192.168.1.100
ADDC1.ad.example.com        internet address = 192.168.1.102
ADDC2.ad.example.com        internet address = 192.168.1.101
ns.example.com      internet address = 192.168.0.10
ns2.example.com     internet address = 192.168.0.10

raub@desktop:/tmp$
and we can use any of the ADDCN.ad.example.com (where N=0,1,2). Notice in my setup, just using ad.example.com also worked. I found out by using netcat to see if port 636 was open (I will leave the answer for "why port 636?" as an exercise to the reader)
raub@desktop:~$ nc -v ad.example.com 636
Connection to ad.example.com 636 port [tcp/ldaps] succeeded!
^C
raub@desktop:~$ 
We need to be able to authenticate against AD somehow.
For this discussion I will be using a username and password; we can also do it using a Kerberos TGT ticket.

Fun Fact: I have a user account, my normal one, which can look into some things in LDAP/AD but then I have another ("admin") account I can see more and edit stuff in AD. You will see later on me forgetting completely about that and how it affects me. But we are getting ahead of ourselves.

With that taken care of, we are going to begin by looking for some user: me

raub@desktop:~$ ldapsearch -H "ldaps://addc0.ad.example.com:636" 
-D "raub@ad.example.com" -W -b "dc=ad,dc=example,dc=com" -LLL -s sub "(CN=raub)" 
Enter LDAP Password:
dn: CN=raub,OU=Users,OU=Identity,DC=ad,DC=example,DC=com
objectClass: top
objectClass: posixAccount
objectClass: person
objectClass: organizationalPerson
objectClass: user
cn: Wrong Droid
sn: Droid
title: Entropy Creators
description: Orthodontics
givenName: Wrong
initials: B 
distinguishedName: CN=raub,OU=Users,OU=Identity,DC=ad,DC=example,DC=com
instanceType: 4
whenCreated: 20080109142820.0Z
whenChanged: 20180905201157.0Z
displayName: Droid, Wrong
uSNCreated: 243336
memberOf: CN=cookie_recipes,OU=Distribution Groups,OU=Special Users,DC=ad,DC=example,DC=com
memberOf: CN=servers,OU=Groups,OU=APE,OU=EXAMPLE,DC=ad,DC=example,DC=com
memberOf: CN=third_floor_printers,OU=Groups,OU=APE,OU=EXAMPLE,DC=ad,DC=example,DC=com
[...]
proxyAddresses: sip:raub@ad.example.com
proxyAddresses: smtp:raub@ad.example.com
proxyAddresses: X500:/o=UNC Exchange/ou=Exchange Administrative Group (FYDIBOH
 F23SPDLT)/cn=Recipients/cn=raub
proxyAddresses: SMTP:raub@email.example.com
displayNamePrintable: Wrong Droid
name: Wrong Droid
[...]
sExchPoliciesExcluded: {26491cfc-9e50-4857-861b-0cb8df22b5d7}
msExchUserAccountControl: 0
msExchELCMailboxFlags: 2
msRTCSIP-PrimaryHomeServer:
[...]
msExchOWAPolicy: CN=Default,CN=OWA Mailbox Policies,CN=Exchange,CN=Microsoft Exchange,CN=Services,CN=Configuration,DC=ad,DC=example,DC=com

# refldaps://ForestDnsZones.ad.example.com/DC=ForestDnsZones,DC=ad,DC=example,DC=com

# refldaps://DomainDnsZones.ad.example.com/DC=DomainDnsZones,DC=ad,DC=example,DC=com

# refldaps://ad.example.com/CN=Configuration,DC=ad,DC=example,DC=com

raub@desktop:~$

That is probably more info than you wanted to know about someone, but this has its applications. Since we now know every attribute associated with a given user (I should not be that special, at least as far as AD is concerned), we can build customized queries looking for only a specific bit of info. For instance, let's just get the groups I belong to or am a member of (hint hint):

raub@desktop:~$ ldapsearch -H "ldaps://addc0.ad.example.com:636" 
-D "raub@ad.example.com" -W -b "dc=ad,dc=example,dc=com" -LLL -s sub "(CN=raub)" memberOf 
dn: CN=raub,OU=Users,OU=Identity,DC=ad,DC=example,DC=com
memberOf: CN=cookie_recipes,OU=Distribution Groups,OU=Special Users,DC=ad,DC=example,DC=com
memberOf: CN=servers,OU=Groups,OU=APE,OU=EXAMPLE,DC=ad,DC=example,DC=com
memberOf: CN=third_floor_printers,OU=Groups,OU=APE,OU=EXAMPLE,DC=ad,DC=example,DC=com

Fancy, huh? Now, if instead of doing (CN=raub) we did (CN=*raub*), it would return every entry that has a CN with raub in it. In my case that would mean two entries, raub and raub.admin (if you remember our Fun Fact you will know about it), but it could also have returned a device whose name matches that. And, they would have been printed one after the other (I do wonder if the order depends on the order they were added to LDAP/AD).

Using ldapmodify

Ok, we established we can probulate Active Directory using common household Linux/UNIX query tools. What if we want to change something? Let's say we have an AD group (specifically a distribution list) called moustache_operators (for those who own and operate moustaches) and want to add a member and delete another.

Why I do like ldapmodify to edit LDAP/AD

Main reason is because I can create a file (in the LDIF format) at my leisure (i.e. think about what I want to do) with pretty commands and comments describing what I want to do. If I like what I did, I can then document it and maybe even save the file in a wiki or somewhere that can be fed to Ansible/Puppet/Chef/Docker and reused.

Our little LDIF file, let's call it change.ldif, could look like this:

# Let's define the entity we will be fiddling with
dn: CN=moustache_operators,OU=Distribution Lists,OU=Special Users,DC=ad,DC=example,DC=com
# And then what we will be doing with it
changetype: modify
delete: member
member: CN=baldone,OU=Users,OU=Identity,DC=ad,DC=example,DC=com
# Separator because we will be doing another change
-
add: member
member: CN=raub,OU=Users,OU=Identity,DC=ad,DC=example,DC=com

So let's try it:

raub@desktop:~$ ldapmodify -H "ldaps://addc0.ad.example.com:636" -D "raub@ad.example.com" -x -W -f change.ldif
Enter LDAP Password:
modifying entry "CN=moustache_operators,OU=Distribution Lists,OU=Special Users,DC=ad,DC=example,DC=com"
ldap_modify: Insufficient access (50)
        additional info: 00002098: SecErr: DSID-03150F93, problem 4003 (INSUFF_ACCESS_RIGHTS), data 0

raub@desktop:~$ 

Why is it not working? Well, do you remember the Fun Fact I mentioned earlier in this article? This is how it shows it's ugly head. I should have used my raub.admin@ad.example.com account instead of raub@ad.example.com. If we do it right, it then works. I will not show the output of a successful connection here; what matters is verifying the deed is done, and we can do it using dear ol' ldapsearch:

raub@desktop:~$ ldapsearch -H "ldaps://addc0.ad.example.com:636" 
-D "raub@ad.example.com" -W -b "dc=ad,dc=example,dc=com" -LLL -s sub "(CN=raub) memberOf" dn: CN=raub,OU=Users,OU=Identity,DC=ad,DC=example,DC=com
memberOf: CN=cookie_recipes,OU=Distribution Groups,OU=Special Users,DC=ad,DC=example,DC=com
memberOf: CN=servers,OU=Groups,OU=APE,OU=EXAMPLE,DC=ad,DC=example,DC=com
memberOf: CN=third_floor_printers,OU=Groups,OU=APE,OU=EXAMPLE,DC=ad,DC=example,DC=com
memberOf: CN=moustache_operators,OU=Distribution Lists,OU=Special Users,DC=ad,DC=example,DC=com

What about Mac/OSX?

They too have ldapsearch; just use the terminal and off you go.

Wednesday, August 29, 2018

Customizing the prompt in OSX (or anything running bash)

Quick and dirty article whose only claim to fame is to show another example of treating a Mac running OSX a UNIX box: I have two Mac, an old Mini and a MacBook Air (I think I talked about it before). If you have been reading this blog, you expect me to use the shell a lot in them, and you would be right. One thing that annoys me is the default prompt used in both. The old, slow mini has the most useless one:

bash-3.2$ bash --version
GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin15)
Copyright (C) 2007 Free Software Foundation, Inc.
bash-3.2$

Why would I care about knowing at all times which bash version I am running, and even then it is incomplete info (compared to bash --version)? The MacBook Air is just slightly better, showing (in order) the name of the machine, the path, and then the username.

littleguy:~ raub$

It is similar in content to what I would see in my Linux boxes,

raub@desktop:~$
but I do not like the order; it does not flow right in my eyes. So I am going to change both to look more like Linux.

First let's see how those prompts are defined in both machines; that is found by looking at the content of the environment variablePS1:

bash-3.2$ echo $PS1
\s-\v\$
bash-3.2$
and
littleguy:~ raub$ echo $PS1
\h:\W \u\$
littleguy:~ raub$

From the official gnu page on controlling the Bash prompt, we know that

  • \h : hostname
  • \s : shell name
  • \u : username
  • \v : shell version
  • \w : current working directory
  • \$ : the generic symbol for users (as opposite to # for root)
Based on the above, what I really want is something like PS1="\u@\h:\w\$ ". So let's try it out without permanently committing to it

bash-3.2$ PS1="\u@\h:\w\$ "
raub@slowmac:~$ 

That seems to be exactly what I want. And, since it only exists in memory (i.e. did not commit it), if I did not like it, restarting the shell or opening a new tab in iTerm would brought it back to the original config. So, how do we make it permanent? In the slowmac, we have

raub@slowmac:~$ cat ~/.bash_profile
# .bash_profile

# Get the aliases and functions
if [ -f ~/.bashrc ]; then
        . ~/.bashrc
fi

# User specific environment and startup programs

PATH=$PATH:$HOME/bin:/opt/local/bin:/opt/local/sbin

export PATH

raub@slowmac:~$

So we might as well put it in the .bashrc file the lazy way.

cat >> ~/.bashrc << "EOF"
PS1="\u@\h:\w\$ "
EOF

Interestingly enough, the MacBook Air does not have a ~/.bash_profile. Maybe the slowmac did not have it either and I added it because I was developing programs in it a while ago. No problem, we can solve the MacBook Air problem by creating a ~/.bash_profile or just appending the proper lines to it, which is done the same was as we did to add the prompt lines to the slowmac's .bashrc:

cat >> ~/.bash_profile << "EOF"

# Get the aliases and functions
if [ -f ~/.bashrc ]; then
        . ~/.bashrc
fi
EOF

Why do we put the prompt in the .bashrc instead of .bash_profile. You see, while ~/.bash_profile is executed when you login, ~/.bashrc is run whenever you start a new shell. By having our prompt defined in ~/.bashrc and then having ~/.bashrc called by ~/.bash_profile we cover our bases.

I am happy, but if you want to make your prompt fancier with colour and cows (really), I would suggest you to check a few more articles such as

In addition to the gnu page I mentioned above. Incidentally, everything I mentioned above should work with any Linux and UNIX distro using bash

Monday, August 27, 2018

VMWare ESXI Gripes: service-control error message not particularly useful

I posted this at the vmware support forum, whose sophisticated text processing interface decided that it knew better than me and reimagineered my pure html post into a rather flat one. I feel like venting and will do so by posting here what it should have looked like there. Note that right now it is just a bunch of WTF-like questions.

We begin this by stating the ESXi cluster in question uses Windows vcenter server; that is not by my choice. I would rather use the appliance

C:\Users\raub> "C:\Program Files\VMware\vCenter Server\bin\service-control" --status --all
Running:
 VMWareAfdService VMWareCertificateService VMWareDirectoryService VMwareComponentManager VMwareDNSService VMwareIdentityMgmtService VMwareSTS rhttpproxy vmon vmonapi vmware-cis-config vmware-license vmwareServiceControlAgent
Stopped:
 EsxAgentManager VMWareCAMService VServiceManager content-library mbcs vPostgres vapiEndpoint vimPBSM vmsyslogcollector vmware-autodeploy-waiter vmware-imagebuilder vmware-network-coredump vmware-perfcharts vpxd vpxd-svcs vsan-health vsphere-ui vspherewebclientsvc

C:\Users\raub>

C:\Users\raub> "C:\Program Files\VMware\vCenter Server\bin\service-control" --start vspherewebclientsvc
Operation not cancellable. Please wait for it to finish...
Performing start operation on service vsphere-client...
Error executing start on service vsphere-client. Details {
    "detail": [
        {  
            "id": "install.ciscommon.service.failstart",
            "translatable": "An error occurred while starting service '%(0)s'",
            "localized": "An error occurred while starting service 'vsphere-client'",
            "args": [
                "vsphere-client"
            ]
        }
    ],
    "resolution": null,
    "problemId": null,
    "componentKey": null
}
Service-control failed. Error: {
    "detail": [
        {
            "id": "install.ciscommon.service.failstart",
            "translatable": "An error occurred while starting service '%(0)s'",
            "localized": "An error occurred while starting service 'vsphere-client'",
            "args": [
                "vsphere-client"
            ]
        }
    ],
    "resolution": null,
    "problemId": null,
    "componentKey": null
}

C:\Users\raub>

I understand that "An error occurred while starting service 'vsphere-client'", but what is it? Maybe the log file is more helpful. https://kb.vmware.com/s/article/2121043 claims log dir is
C:\ProgamData\VMware\vCenterServer\logs\vsphere-client\logs\
But I can see lots of directories in there but the log one:
C:\Users\raub>dir  "C:\Program Files\VMware\vCenter Server\"
 Volume in drive C has no label.
 Volume Serial Number is F020-F58F

 Directory of C:\Program Files\VMware\vCenter Server

05/21/2018  07:36 PM    <DIR>          .
05/21/2018  07:36 PM    <DIR>          ..
05/21/2018  07:11 PM    <DIR>          apachetomcat
05/21/2018  07:15 PM    <DIR>          autodeploy
05/21/2018  07:17 PM    <DIR>          bin
05/21/2018  07:13 PM    <DIR>          cis-license
05/21/2018  07:10 PM    <DIR>          cis_upgrade_runner
05/21/2018  07:13 PM    <DIR>          cm
05/21/2018  07:10 PM    <DIR>          common-jars
05/21/2018  07:10 PM    <DIR>          common-libs
05/21/2018  07:15 PM    <DIR>          content-library
05/21/2018  07:15 PM    <DIR>          eam
05/21/2018  07:36 PM    <DIR>          eula
05/21/2018  07:12 PM    <DIR>          fips
05/21/2018  07:21 PM    <DIR>          firstboot
05/21/2018  07:15 PM    <DIR>          imagebuilder
05/21/2018  07:10 PM    <DIR>          jmemtool
05/21/2018  07:10 PM    <DIR>          jre
05/21/2018  07:12 PM    <DIR>          jre_ext
05/21/2018  07:15 PM    <DIR>          mbcs
05/21/2018  07:13 PM    <DIR>          netdump
05/21/2018  07:10 PM    <DIR>          openSSL
04/09/2018  01:24 PM         7,398,602 open_source_license.txt
05/21/2018  07:16 PM    <DIR>          perfcharts
05/21/2018  07:11 PM    <DIR>          python
05/21/2018  07:16 PM    <DIR>          python-modules
05/21/2018  07:13 PM    <DIR>          rhttpproxy
05/21/2018  07:12 PM    <DIR>          ruby
05/21/2018  07:15 PM    <DIR>          rvc
05/21/2018  07:13 PM    <DIR>          sca
05/21/2018  07:09 PM    <DIR>          TlsReconfigurator
05/21/2018  07:13 PM    <DIR>          vapi
04/09/2018  01:24 PM            25,214 vcs.ico
05/21/2018  07:14 PM    <DIR>          virgo
05/21/2018  07:12 PM    <DIR>          visl-integration
05/21/2018  07:12 PM    <DIR>          vmafdd
05/21/2018  07:12 PM    <DIR>          vmcad
05/21/2018  07:15 PM    <DIR>          vmcamd
05/21/2018  07:12 PM    <DIR>          vmdird
05/21/2018  07:13 PM    <DIR>          vmdns
05/21/2018  07:13 PM    <DIR>          vmon
05/21/2018  07:15 PM    <DIR>          vmsyslogcollector
05/21/2018  07:13 PM    <DIR>          VMware Identity Services
05/21/2018  07:11 PM    <DIR>          vmware-sasl
04/25/2018  01:20 PM    <DIR>          vmware-sps
05/21/2018  07:13 PM    <DIR>          vmware-sso
05/21/2018  07:14 PM    <DIR>          vPostgres
05/21/2018  07:25 PM    <DIR>          vpxd
05/21/2018  07:14 PM    <DIR>          vpxd-svcs
05/21/2018  07:32 PM    <DIR>          vsan-health
05/21/2018  07:34 PM    <DIR>          vsm
05/21/2018  07:16 PM    <DIR>          vsphere-client
05/21/2018  07:17 PM    <DIR>          vsphere-ui
               2 File(s)      7,423,816 bytes
              51 Dir(s)  69,727,727,616 bytes free

C:\Users\raub>

C:\Users\raub>dir  "C:\Program Files\VMware\vCenter Server\logs"
 Volume in drive C has no label.
 Volume Serial Number is F020-F58F

 Directory of C:\Program Files\VMware\vCenter Server

File Not Found

C:\Users\raub>

Where can I find where vcenter thinks the log files are at?

If you want to see how the ticket looks like at vmware, https://communities.vmware.com/message/2796432#2796432. Try to read the version posted at vmware and you will understand why I am frustrated.

Wednesday, August 22, 2018

Scheduling Time Machine backups from the command line

So I have an old Mac Mini which will just not start a backup to my time machine server. We could go over the reason but that is the subject for another article. The point is running it from the GUI does not work. However, I can go to the terminal window and do

raub@slowmac:~$ tmutil startbackup

all day and it works fine. In fact, I have been doing that manually to have a semblance of a backup:

dalek@strangepork:~$ tmutil latestbackup
/Volumes/Time Machine Backups/Backups.backupdb/strangepork/2018-07-16-234250
dalek@strangepork:~$ tmutil listbackups
[...]
/Volumes/Time Machine Backups/Backups.backupdb/strangepork/2018-05-01-130725
/Volumes/Time Machine Backups/Backups.backupdb/strangepork/2018-05-24-032218
/Volumes/Time Machine Backups/Backups.backupdb/strangepork/2018-06-21-001720
/Volumes/Time Machine Backups/Backups.backupdb/strangepork/2018-07-08-201058
/Volumes/Time Machine Backups/Backups.backupdb/strangepork/2018-07-16-234250
/Volumes/Time Machine Backups/Backups.backupdb/strangepork/2018-08-22-131023
dalek@strangepork:~$ 

But that is a bit of a drag. As you can see I am not manually doing it as often as I should. We need to automate this. Hmmm... recurring job... if this was Linux, Solaris, FreeBSD, or AIX, I would use a cronjob. But this is a Mac... running OSX. What should I do? Look for some App?

Wait a minute. OSX is UNIX with some sprinkles on the top. So, let's cron this out!

I am going to start the task off my normal account since I do not have to run startbackup from root. First let's see cronjobs I have right now:

dalek@strangepork:~$ crontab -l
#
dalek@strangepork:~$

Nothing at all, which is as good place to start as any. Now we need to add the entry. I like to specify the path of the program I am using in case there are old versions. So from

I will be using /usr/bin/tmutil. Now let's edit the crontab, which is done by typing crontab -e. That put me in a vim session (that can be configured); if you do not know it, it is a good time to learn. Here are a few quick pointers:

  • When in doubt, press the escape key a lot.
  • After you press esc a lot, if you want to save your changes and quit, type :wq, but if you do not want to save, type :q!
I do not know how often timemachine usually runs, so I will guess every two hours and will tell my cronjob to start at 15 minutes past the hour every 2 hours. In cron-lese, that looks like this

15  */2  * * *  /usr/bin/tmutil startbackup

After we save it, let's verify that our little work is committed:

dalek@strangepork:~$ crontab -l
#
15  */2  * * *  /usr/bin/tmutil startbackup
dalek@strangepork:~$

Then, give it a few hours and run tmutil listbackups to see if the backup cron jobs are being run every two hours.

Saturday, June 02, 2018

Finding disk space hogs in a Windows server/workstation

If you have any doubts, we will be doing it from the command line. Just want to put that out before we start. Also, it turned out this is a long and boring article; deal with it.

So, where were we? Disk space and what is using it. That is a problem common to all OS: you have a partition without infinite disk space (sorry ZFS, it happens sometimes) and is running out of space:

  • Sometimes it is a careless user; some OS allow you to tell non-system programs, like the ones run by a user, can only use up to 95% of the disk. This way we have some space to fix things.
  • Sometimes it is actually a program being run as a system/root/admin account, which is trouble since it can use up the entire partition.

If the machine in question is a server, a Windows server since that is what we wrote in the name of the article, we might not be able to just ignore it; others will be affected by this. So, how to take care of this problem? The lazy fix is to throw more space at it and move on. The proper solution is to find out who is hoarding all the space and why. I would like to talk about doing the right thing.

The standard Windows approach would be to search for some app online, which must have a graphics interface and ideally from some site with a name like "finddiskusage.com" because such domain names do inspire confidence, right? Specially when the site's text is pretty much "You do not know what is using your disk space? Click here to download the solution!" Any relationship with a phishing email is merely coincidental.

So, after downloading this shady program from the suspicious website, we then install it and make sure to turn off the firewall and run it with admin rights. And after it does what we hope it is supposed to do, we then take a screenshot of the output and paste it to our documentation.

I do not know about you but I really do not like to install programs in any server, be it windows/linux/mac/solaris/aix/whatever. I think they should have only the bare minimum to do their job; you should see my Linux servers. Since I am the one writing this article, I will put my dictator hat and look for something that fits my style.

In Unix in general and Linux as a special case there is a program called du which allows you to check the disk usage at a given location. You can be short and only show, say, how much all the files and directories (folders in Windows) inside a given directory, or go recursively and show detailed views for every single directory inside the original one. Output is text, which means you can feed it to something else like sort or some program that will make a decision based on the data.

It would be really cool if there was something like that in Windows. One can dream...

Thing is, we do not have to wait for unicorns and fairies to come up with a solution. Nor we have to reinvent the wheel. You see,

  1. There is something like that natively for windows. I do like cygwin but that requires installing yet another collection of packages that need to be patched and upgraded. Kinda wasteful if all you want is little du. I believe less is more.
  2. It is called du just like the unix one.
  3. You do not need to look for it in some shady or just compromised site. You can find it right at Microsoft as part of the sysinternals package(s).
  4. You do not even need to install anything. Just put its directory somewhere you want to use it, including a USB or network drive, and run it from there.
Not bad if you ask me. Enough talk, let's use it.

Using du

The most common way I use du in Windows is like I use in Linux:

C:\Documents and Settings\raub>"\Documents and Settings\raub\My Documents\DU\du.exe" -l 1 \windows >> du.log

Du v1.5 - report directory disk usage
Copyright (C) 2005-2013 Mark Russinovich
Sysinternals - www.sysinternals.com


C:\Documents and Settings\raub>

Ok, it is old but it is not like it is getting more and more useless features to make it bloated. Like interfacing with your bluetooth-enabled IoT-based massage chair. Let me show it in action with a real (!) example: at work I have a Windows 10 vm for desktop. And as you can see, it ran out of disk disk space:

That's not much free space left! If you know Windows, it will get really slow when its boot/OS disk is that full. I am going to assume I should first check the Users directory. If I am wrong, I would then check the Windows one, First I would like to make a point I will be running du.exe off a network fileshare, strongbadia

PS C:\Users\raub> ls \\spacemoose\users\raub\bin


    Directory: \\strongbadia\users\raub\bin


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----        5/21/2018   9:32 AM         169072 du.exe
-a----        5/21/2018   9:32 AM         191616 du64.exe
-a----        6/28/2018   4:06 PM            543 GetDirSize4DateRange.ps1
-a----        7/18/2017  10:12 AM         854072 putty.exe


PS C:\Users\raub>

You are now getting to learn a few secret things about me! Yes I have a bin dir. Inside it you can see the du.exe and du64.exe. Both are very tiny compared to the crazy GUI programs you can get off suspicious sites to do the very same thing. And, that is all you need: those two files. Well, I will be running du.exe even though my guest is a 64bit windows vm. Because I can. So, let's see what is in the root dir for the users dir:

PS C:\Users\raub> \\strongbadia\users\raub\bin\du.exe -l 1 c:\users\

DU v1.61 - Directory disk usage reporter
Copyright (C) 2005-2016 Mark Russinovich
Sysinternals - www.sysinternals.com

      31,480  c:\users\bob.adm
       2,665  c:\users\Default
  51,390,386  c:\users\raub
     629,717  c:\users\raub.adm
       2,727  c:\users\raub.tst
       2,768  c:\users\Public
     129,592  c:\users\windows-user
Files:        2429983
Directories:  9581
Size:         54,003,166,071 bytes
Size on disk: 59,917,407,544 bytes

PS C:\Users\raub>

Man! My homedir is full of junk. What is that and where is it? Let's check it:

PS C:\Users\raub> \\strongbadia\users\raub\bin\du.exe -l 1 c:\users\raub\

DU v1.61 - Directory disk usage reporter
Copyright (C) 2005-2016 Mark Russinovich
Sysinternals - www.sysinternals.com

  46,023,020  c:\users\raub\AppData
           0  c:\users\raub\Contacts
           1  c:\users\raub\Desktop
           3  c:\users\raub\dev
   1,836,295  c:\users\raub\Documents
   3,551,535  c:\users\raub\Downloads
           0  c:\users\raub\eqlgroupmgr
           0  c:\users\raub\Favorites
           1  c:\users\raub\Links
           0  c:\users\raub\Music
           0  c:\users\raub\OneDrive
       5,012  c:\users\raub\Pictures
           0  c:\users\raub\Saved Games
           3  c:\users\raub\Searches
           0  c:\users\raub\Videos
Files:        2425559
Directories:  3976
Size:         52,663,166,132 bytes
Size on disk: 58,521,224,472 bytes

PS C:\Users\raub>

AppData! A conveniently normally invisible source of many out of space drives. Not to du it is. Let's keep going in:

PS C:\Users\raub> \\strongbadia\users\raub\bin\du.exe -l 1 c:\users\raub\appdata\

DU v1.61 - Directory disk usage reporter
Copyright (C) 2005-2016 Mark Russinovich
Sysinternals - www.sysinternals.com

  45,780,916  c:\users\raub\appdata\Local
       2,588  c:\users\raub\appdata\LocalLow
     198,212  c:\users\raub\appdata\Roaming
Files:        2424970
Directories:  3898
Size:         47,085,278,621 bytes
Size on disk: 52,935,700,880 bytes

PS C:\Users\raub> \\strongbadia\users\raub\bin\du.exe -l 1 c:\users\raub\appdata\local\
[...]
PS C:\Users\raub> \\strongbadia\users\raub\bin\du.exe -l 1 C:\users\raub\appdata\local\Microsoft\Windows\INetCac
he\\

DU v1.61 - Directory disk usage reporter
Copyright (C) 2005-2016 Mark Russinovich
Sysinternals - www.sysinternals.com

         239  c:\users\raub\appdata\local\microsoft\windows\inetcache\Content.MSO
         878  c:\users\raub\appdata\local\microsoft\windows\inetcache\Content.Outlook
       5,207  c:\users\raub\appdata\local\microsoft\windows\inetcache\Content.Word
      18,852  c:\users\raub\appdata\local\microsoft\windows\inetcache\IE
  39,825,165  c:\users\raub\appdata\local\microsoft\windows\inetcache\Low
           0  c:\users\raub\appdata\local\microsoft\windows\inetcache\Virtualized
           0  c:\users\raub\appdata\local\microsoft\windows\inetcache\WebTempDir
Files:        2410022
Directories:  55
Size:         40,806,752,248 bytes
Size on disk: 46,635,979,024 bytes

PS C:\Users\raub> \\strongbadia\users\raub\bin\du.exe -l 1 C:\users\raub\appdata\local\Microsoft\Windows\INetCache\low\

DU v1.61 - Directory disk usage reporter
Copyright (C) 2005-2016 Mark Russinovich
Sysinternals - www.sysinternals.com

  39,819,877  c:\users\raub\appdata\local\microsoft\windows\inetcache\low\IE
Files:        2408915
Directories:  34
Size:         40,780,969,849 bytes
Size on disk: 46,606,749,696 bytes

PS C:\Users\raub>

That smells like that other nemesis of web browsers: Internet Explorer or Edge. What is inside that dir?

PS C:\Users\raub> ls C:\users\raub\appdata\local\Microsoft\Windows\INetCache\Low\IE\
PS C:\Users\raub> dir C:\users\raub\appdata\local\Microsoft\Windows\INetCache\Low\IE\
PS C:\Users\raub>

WTF? Why can't I see what is inside it? Let me du inside it:

PS C:\Users\raub> \\strongbadia\users\raub\bin\du.exe -l 1 C:\users\raub\appdata\local\Microsoft\Windows\INetCache\low\

DU v1.61 - Directory disk usage reporter
Copyright (C) 2005-2016 Mark Russinovich
Sysinternals - www.sysinternals.com

   1,237,378  c:\users\raub\appdata\local\microsoft\windows\inetcache\low\ie\10EAXOSV
   1,246,204  c:\users\raub\appdata\local\microsoft\windows\inetcache\low\ie\145KIAQM
   1,235,782  c:\users\raub\appdata\local\microsoft\windows\inetcache\low\ie\2F8FLUJD
   1,241,300  c:\users\raub\appdata\local\microsoft\windows\inetcache\low\ie\2VB3GL0K
   1,250,215  c:\users\raub\appdata\local\microsoft\windows\inetcache\low\ie\5BZQD406
   1,244,360  c:\users\raub\appdata\local\microsoft\windows\inetcache\low\ie\5IVFOAV9
[...]
   1,251,347  c:\users\raub\appdata\local\microsoft\windows\inetcache\low\ie\TQ26RPSG
   1,236,991  c:\users\raub\appdata\local\microsoft\windows\inetcache\low\ie\VQH18R7G
   1,240,357  c:\users\raub\appdata\local\microsoft\windows\inetcache\low\ie\VYHW6URF
   1,239,508  c:\users\raub\appdata\local\microsoft\windows\inetcache\low\ie\XYKKE45S
Files:        2408912
Directories:  33
Size:         40,775,554,697 bytes
Size on disk: 46,601,322,496 bytes

PS C:\Users\raub>

Before you ask, I am using a powershell window, where ls and dir behave the same. I came from unix so you can understand which one I prefer. So we have a ton (33) of stupid cache folders that the browser could not be bothered to delete after it quit. Thanks, Microsoft, for not cleaning after itself. Really. And, everything below c:\users\raub\appdata\local\microsoft\windows\inetcache\low is hidden (?). Alright then, off it goes! Command line cares not about hidden paths! Note: get-help can be seen as the powershell equivalent of the Unix/linux man.

PS C:\Users\raub> get-help rm

NAME
    Remove-Item

SYNOPSIS
    Deletes files and folders.


SYNTAX
    Remove-Item [-Confirm] [-Credential ] [-Exclude ] [-Filter ] [-Force] [-Include
    ] -LiteralPath  [-Recurse] [-Stream ] [-UseTransaction] [-WhatIf]
    []

    Remove-Item [-Path]  [-Confirm] [-Credential ] [-Exclude ] [-Filter ]
    [-Force] [-Include ] [-Recurse] [-Stream ] [-UseTransaction] [-WhatIf] []
   
    Remove-Item [-Stream ] []
   

DESCRIPTION
    The Remove-Item cmdlet deletes one or more items. Because it is supported by many providers, it can delete many
    different types of items, including files, folders, registry keys, variables, aliases, and functions.
    In file system drives, the Remove-Item cmdlet deletes files and folders.
   
    If you use the Stream dynamic parameter, it deletes the specified alternate data stream, but does not delete the
    file.
   
    Note: This custom cmdlet help file explains how the Remove-Item cmdlet works in a file system drive. For
    information about the Remove-Item cmdlet in all drives, type "Get-Help Remove-Item -Path $null" or see Remove-Item
    at http://go.microsoft.com/fwlink/?LinkID=113373.
   

RELATED LINKS 
    Online version: http://technet.microsoft.com/library/jj628241(v=wps.630).aspx
    Remove-Item (generic); http://go.microsoft.com/fwlink/?LinkID=113373
    FileSystem Provider
    Clear-Content
    Get-Content
    Get-ChildItem
    Get-Content
    Get-Item
    Remove-Item
    Set-Content
    Test-Path


REMARKS
    To see the examples, type: "get-help Remove-Item -examples".
    For more information, type: "get-help Remove-Item -detailed".
    For technical information, type: "get-help Remove-Item -full".
    For online help, type: "get-help Remove-Item -online"


PS C:\Users\raub> rm -force -recurse C:\users\raub\appdata\local\Microsoft\Windows\INetCache\low\IE

Note that since we are running this from the command line, I did not have to do the usual screenshot Windows blog and articles love so much. I could cut and paste the real output and put it here. I could also have piped it into some other script to use the output for its nefarious uses. FYI, the above command has been running for 38 minutes now and has not finished yet.

So, what I have done above in this real example can be also used with servers since

  1. We are using Microsoft published program.
  2. The program is self-contained and requires no installation.
  3. The program fears no hidden directories.
  4. The program has very small footprint.
  5. The program can be run locally, off a USB, or from a network drive.
If you can put up with not having a cute window with some animation, I think sysinternals' version of du is a nice tiny add-on to a Windows server manager arsenal.

Monday, May 14, 2018

Converting a .ovf file to work on an older/different VMWare ESXi (maybe also player) setup

I will be using ESXi because that is what I have; I do not see why it would not work in Player or Workstation.

As you know, the way vmware likes to export/import vm guests is using a ovf format. So, let's say we are supposed to add a guest called strangeguest. We get it as a directory called strangeguest, which contains the disk (strangeguest-disk1.vmdk in our case), the config file strangeguest.ovf and a mysterious file called strangeguest.mf (.mf extension for Mysterious File?). When we try to import it we get an error message that complains we cannot import the OVF. A quick look indicates that strangeguest expects to be of SystemType vmx-12 or better:

admin@fileserver:/export/public/ISOs/strangeguest$ fgrep vmx- strangeguest.ovf         vmx-12
admin@fileserver:/export/public/ISOs/strangeguest$

Thing is our ESXi setup does not support vmx-12 guest in our ESXi as is a bit old and needs to be upgraded (which will be subject of another article). However, right now we need to make this work.

So we cheat.

We know the latest systemtype our ESXi support is vmx-10 by looking at the properties of the guests currently in place. So, how about if we tell strangeguest that it is vmx-10?

admin@fileserver:/export/public/ISOs/strangeguest$ sed -i -e 's/vmx-12/vmx-10/' strangeguest.ovf
admin@fileserver:/export/public/ISOs/strangeguest$ fgrep vmx- strangeguest.ovf         vmx-10
admin@fileserver:/export/public/ISOs/strangeguest$

So we try again and we get a different error (note to myself: get that error message). What did we do wrong? Well, do you remember the mysterious file? Let's see what is inside it:

admin@fileserver:/export/public/ISOs/strangeguest$ cat strangeguest.mf
SHA1(strangeguest.ovf)= 7b11b4aacead791f8aaf76e5ed3c2354349b3b20
SHA1(strangeguest-disk1.vmdk)= 9ccd4817ac2f943f7f29be970b76461850460d18
admin@fileserver:/export/public/ISOs/strangeguest$

So it has the checksum (as SHA1, which is a step about MD5 but still not to be used as it can be lied to, but I digress). Remember we edited strangeguest.ovf!

admin@fileserver:/export/public/ISOs/strangeguest$ sha1sum strangeguest.ovf
f14befc1e790b0043dd5f8e22fd8d601637997bd  strangeguest.ovf
admin@fileserver:/export/public/ISOs/strangeguest$

So, we need to update strangeguest.mf:

sed: -e expression #1, char 83: unterminated `s' command
admin@fileserver:/export/public/ISOs/strangeguest$ sed -i -e \
's/7b11b4aacead791f8aaf76e5ed3c2354349b3b20/f14befc1e790b0043dd5f8e22fd8d601637997bd/' \
strangeguest.mf
admin@fileserver:/export/public/ISOs/strangeguest$ !cat
cat strangeguest.mf
SHA1(strangeguest.ovf)= f14befc1e790b0043dd5f8e22fd8d601637997bd
SHA1(strangeguest-disk1.vmdk)= 9ccd4817ac2f943f7f29be970b76461850460d18
admin@fileserver:/export/public/ISOs/strangeguest$

And we should be rewarded with strangeguest being properly imported.

Saturday, April 28, 2018

Using sed Capture Groups (Linux/Mac)

This will be a short one and belongs to the TIL bin: until 2 days ago I did not even know about capture groups and how to use it. So, I knew how to replace a matching string/pattern in sed

bash-3.2$ echo "As of today swallow_v=23kph at STD" | sed -e 's/swallow_v/swallow_speed/' 
As of today swallow_speed=23kph at STD
bash-3.2$ 
And how to replace from a given pattern all the way to the end of the line. Or starting from the beginning of the line to said pattern:

bash-3.2$ echo "As of today swallow_v=23kph at STD" | sed -e 's/swallow_v=.*/swallow_speed=42/' 
As of today swallow_speed=42
bash-3.2$ echo "As of today swallow_v=23kph at STD" | sed -e 's/^.*swallow_v=/Can you believe that swallow_speed=/' 
Can you believe that swallow_speed=23kph at STD
bash-3.2$ 

If you are curious, the .* in the search pattern means "any character or list of characters here, be it zero or a lot of characters". The dot (.) does the any part and the asterisk (*) the how many. I think this is from regex, but don't quote me on that. Fine, what if I want to replace everything between two patterns, but leaving the second pattern alone? Tricky. You see, replacing everything between the two patterns, inclusive is not that hard

raub@desktop:~$ echo "As of today swallow_v=23kph at STD" | sed -e 's/swallow_v=.*k/swallow_v=25/'
As of today swallow_v=25ph at STD
raub@desktop:~$ 

But to preserve the second pattern we need to use the Capture Groups mentioned in the title of this article. And that makes sense because if it is on the title I better use it. So, we are supposed to surround the capture group pattern with parenthesis and then we can refer to them. If it does not make sense, I too was confused, so let's keep on using our test string:

raub@desktop:~$ echo "As of today swallow_v=23kph at STD" | sed -e 's/swallow_v=.*(k)/swallow_v=25$1/'
As of today swallow_v=23kph at STD
raub@desktop:~$ 

Er, it does not seem to have worked according to the plan. In fact, it was supposed to at least grab swallow_v=23k but as you can see it did not find the pattern. Is $1 the proper way to output the captured string? Going nowhere slowly.

After much soul searching, I found the -e requires the parenthesis to be escaped. And, the capture group pattern is output using \1 instead of $1.So we try again:

raub@desktop:~$ echo "As of today swallow_v=23kph at STD" | sed -e "s/swallow_v=.*\(k\)/swallow_v=25\1/"
As of today swallow_v=25kph at STD
raub@desktop:~$ 

much better!

What about the Mac? Same thing (the bash-3.2$ you have seen all day is it; the raub@desktop:~$ is the Linux box):

bash-3.2$ echo "As of today swallow_v=23kph at STD" | sed -e 's/swallow_v=.*\(k\)/swallow_v=25\1/' 
As of today swallow_v=25kph at STD
bash-3.2$ 

I am not going to say it is perfect though:

bash-3.2$ echo "As of today swallow_v=23kph at STD" | sed -e 's/swallow_v=.*\([[:blank:]]\)/swallow_v=25\1/' 
As of today swallow_v=25 STD
bash-3.2$ echo "As of today swallow_v=23kph at    STD" | sed -e 's/swallow_v=.*\([[:blank:]]\)/swallow_v=25\1/' 
As of today swallow_v=25 STD
bash-3.2$ 

References

  • A site I think has lots of interesting sed examples.

Thursday, March 22, 2018

Thoughts on creating a large iso using dd

Let's see if I can avoid being long winded as usual:

So I wanted to create a .iso file that was going to be treated like a disk (more of that part in a future thread). Nothing better to do the deed but that old friend, dd:

raub@desktop:/export/scratch$ dd if=/dev/zero of=olddrive.iso bs=44G count=1
dd: memory exhausted by input buffer of size 47244640256 bytes (44 GiB)
raub@desktop:/export/scratch$

It so happens that dd is trying to create a 44G file by first allocating that in the RAM. And that will not work for me as I only have 32G total of memory.

The solution is rather obvious if you stop to think about it (which, I must admit, I did not): just don't use all the RAM! Instead, use smaller chunks and repeat that a lot. How about 1G chunks 44 times?

raub@desktop:/export/scratch$ dd if=/dev/zero of=olddrive.iso bs=1G count=44
44+0 records in
44+0 records out
47244640256 bytes (47 GB, 44 GiB) copied, 354.018 s, 133 MB/s
raub@desktop:/export/scratch$

Much better!

Monday, February 26, 2018

Testing for multiple strings without much clutter using powershell

Yes, this hopefully will be quick, and yes it is powershell, which does not make me feel as dirty as if it was Windows. So hear me out.

I wrote a script a while ago that I needed to look for a pattern inside a string and then do something. In its simplest form, the code could look like this (second line is there to show the entire string):

$the_string = "There are pickles in a jar"
$the_string

if ($the_string -match "pickles")
{
        "Found me pickles"
}
else
{
        "nothing to declare"
}

If you wonder why I am using -match instead of -contains, there is a nice discussion you want to check. At least I learned a lot from it. When we run the script, which is henceforth called switchtest.ps1, we get

PS C:\Users\dalek> powershell -file .\dev\switchtest.ps1
There are pickles in a jar
Found me pickles
PS C:\Users\dalek>

So far so good. But, what if we want to do things based on whether other substrings are in the string? After all, instead of one single string we might be looping over a list of them, or reading a file and doing things based on what we find on a line-by-line-basis. We could add more if statements but that gets nasty quickly:

$the_string = "There are pickles in a jar"
$the_string

if ($the_string -match "pickles")
{
        "Found me pickles"
}

elseif ($the_string -match "there")
{
        "There is here"
}
else
{
        "nothing to declare"
}

Notes:

  • By default powershell is case insensitive; this is consistent with how DOS and Windows behaves, which is exactly the opposite of UNIX in general and Linux specifically.
  • If you have used other programming languages like python or C, you might remember switch statements (switch, then case-this and case-that). And, they are also implemented in powershell without the case word being explicitly used but the behavior is there for all to see.
  • -match looks for the substring anywhere in the string. So, it would find there in:
    • $the_string = "There are pickles in a jar"
    • $the_string = "Are there pickles in a jar?"
    • $the_string = "Pickles are in a jar over there"
Let's now redo switchtest.ps1 using case:
$the_string = "There are pickles in a jar"
$the_string

switch -wildcard ($the_string)
{
        "*pickles*" {"Found me pickles"}
        "there*" {"There is here"}
        default {"nothing to declare"}
}

and then run it

PS C:\Users\dalek> powershell -file .\dev\switchtest.ps1
There are pickles in a jar
Found me pickles
There is here
PS C:\Users\dalek>

The -wildcard option is where the main magic is. It allows me to enter a string as the search pattern, such as "pickles". The more astute of you probably noticed the asterisk (*) surrounding the search string. Without the first, it would only look for a string that starts with "pickles"; Since we only want to look for there when it begins the string we do not need the leading *. There is a thread in the Spiceworks forum showing another example of looking for strings that begin with a, in their case, specific letter using a case statement. The second one is so it will not look only for string ending with that substring.

There is nothing forcing each case statement to be a one-liner. In fact, it would be clearer to write the second one as

// Do something if the string begins with "there" 
        "there*" 
             {
                   "There is here"
             }

specially if we are going to do more than just write out a string.

Another thing you might also have noticed is the behaviour of the output does not match the one we did using the if statement. Reason is unless we specifically tell the switch statement to stop testing once it finds a match, it will keep going down to the list (the default is only done if nothing matches. Sometimes that is exactly what you want to do, but let's assume that is not the case. Just as in other languages, the command we need to give it is break. Let's add them

$the_string = "There are pickles in a jar"
$the_string

switch -wildcard ($the_string)
{
        "*pickles*" {"Found me pickles"; break}
        "there*" {"There is here"; break}
        default {"nothing to declare"}
}

and try it once more

PS C:\Users\dalek> powershell -file .\dev\switchtest.ps1
There are pickles in a jar
Found me pickles 
PS C:\Users\dalek>

Now the output looks just like the original script, but it is much cleaner and easier to expand.