Vinod Kurup

Hospitalist/programmer in search of the meaning of life

Aug 21, 2020 - 2 minute read - Comments - homelab phone

Using an OBi110 for VOIP service

I set up an OBi110 device to provide a landline at home. OK, it’s not a land line, it’s a VOIP (Voice Over Internet Protocol) line, but it performs a similar function. We’ve always had a landline. Our cell phone coverage is spotty at times and ever since Mala started working from home, she needs to have a reliable phone line for her global conference calls.

The problem is that Spectrum was charging us $44.95 per month plus taxes, which took it near $50 every month. I considered a few options including:

  • MagicJack
  • Ooma
  • I looked at a few others… can’t remember them all

In the end, I settled on buying an ATA device and then connecting it to a cheaper VOIP service. I chose voip.ms which has been great so far.

One Time Costs:

  • OBi110 ATA device: $19.90
  • voip.ms setup fee: $0.40
  • voip.ms e911 setup fee: $1.50

Monthly Costs:

  • voip.ms fee for an incoming phone number: $0.85
  • voip.ms e911 monthly fee: $1.50

Per-Minute Costs:

  • voip.ms incoming: $0.009 per minute

I’ll have to keep an eye on my monthly per-minute costs because there is an unlimited plan that is $4.25 per month, which I’ll switch to if I use more than that per month. In any case, this is MUCH cheaper than Spectrum.

Now, if you do any research about the OBi110 device, you’ll see everyone telling you not to buy it because it is out of service and doesn’t support Google Voice. This is true, ObiTalk doesn’t support the device anymore. When it was supported by the company, you could just dial a special code on your phone and it would do all the set up for you. Since it’s not supported, that procedure doesn’t work anymore. But you can manually configure the device with the excellent docs from voip.ms, and for a geek like me that was not bad. And yes, you can’t link a Google Voice number to the device, but I didn’t want to do that anyway. I think if you wanted to keep using a google voice number, you could probably get pretty close by putting a different number on your device (through voip.ms) and then pointing Google Voice at that number. Incoming calls would work fine in that way, but I’m not sure about outgoing calls. If you want to seamlessly use Google Voice on an ATA device, then OBi110 isn’t for you. You’ll need the OBI202 (which was out of stock when I was looking).

Aug 17, 2020 - 2 minute read - Comments - django programming

Django forms have 2 modes

I worked on adding tests to some Django forms today and I was reminded that Django forms operate in two modes. I think of them as the GET mode and the POST mode. The GET mode displays the form and the POST mode processes the data that you supply to the form. I don’t know why, but I often forget that. Instead, I sometimes treat them as a normal Python class, especially when I’m creating automated tests for them. I instantiate the class (form = MyForm()) and then just call any of its methods and make sure they return the right values or achieve the correct side effects. The form that I was working with today had a couple features. The first was that it provided some helper functions to the template so that the template could display the form properly. Those are in the GET mode. So I did something like:

user = create_my_special_user()
form = MyForm(user=user)
self.assertTrue(form.is_user_special())

And that worked as I expected. The second feature of my custom form was that it cleaned the data in a particular way. So I did:

form = MyForm(user=user)
cleaned_data = form.clean()
self.assertEqual(cleaned_data, expected_data)

Instead of passing, the test blew up:

AttributeError: 'MyForm' object has no attribute 'cleaned_data'

Why? Because the clean() method is called when you provide it with POST data (normally… there are also other ways to populate forms). If you don’t supply it data, then cleaned_data doesn’t get populated. The answer is to provide data to the form:

form = MyForm(user=user, data={})
cleaned_data = form.clean()
self.assertEqual(cleaned_data, expected_data)

And that works as expected. The reminder to myself is to always identify which mode of the form you are testing, GET or POST.

Jan 27, 2020 - 1 minute read - Comments - cheatsheet aws

AWS Xray brain dump

These are very rough notes on how I got AWS Xray working in a kubernetes deployment. Posting this mainly for my auxiliary brain.

First, set up an IAM role that allows nodes to access xray.

Following this blog post: https://aws.amazon.com/blogs/compute/application-tracing-on-kubernetes-with-aws-x-ray/

I cloned this repo: https://github.com/aws-samples/aws-xray-kubernetes

Build the AWS Xray image:

cd xray-daemon/
docker build -t xray-daemon:latest .

THIS OUT OF DATE! try this: https://docs.aws.amazon.com/xray/latest/devguide/xray-daemon-ecs.html#xray-daemon-ecs-image

Create an AWS ECR repo:

aws ecr create-repository --repository-name xray-daemon

Login via docker:

aws ecr get-login --no-include-email

That command spits out a command which you can run that will log you into docker ^

Tag and push the image there:

docker tag xray-daemon:latest AWS-ACCOUNT-ID.dkr.ecr.us-east-1.amazonaws.com/xray-daemon:latest
docker push AWS-ACCOUNT-ID.dkr.ecr.us-east-1.amazonaws.com/xray-daemon:latest

You should now be able to see the image in the AWS ECR console

Update aws-xray-kubernetes/xray-daemon/xray-k8s-daemonset.yaml:

Change the image value to the image you just pushed

deploy it:

kubectl apply -f xray-k8s-daemonset.yaml

Dec 11, 2019 - 3 minute read - Comments - book-review

We have always lived in the castle

At school, Kavi is reading “We have always lived in the castle”, by Shirley Jackson. I read her short story, “The Lottery”, in high school. I recall the main plot of the story, but I’m sure I have forgotten many details. What I haven’t forgotten is the sense of shock I felt as the plot finally became clear. As I’m typing this, I wonder if that was more because I was young and new to being shocked, or whether it was really shocking. In any case, that feeling of being shocked by that story is deeply embedded inside me.

So I checked this book from the library and finished it today. It was dark and disturbing, reminiscent of “The Lottery”. There were many elements of foreshadowing. From the start, you wonder what Mary Katherine or her family did to sow such discontent among the villagers, and the answer comes slowly, in bits and pieces. I wondered why they had library books that they would never be able to return. In the end, I was sucked in and couldn’t put the book down until I figured it all out. Thankfully, it’s a short book.

Some random thoughts that my brain generated while reading this book (and that I’d prefer to remember someday):

  • When Merrikat and Connie first enter their house after it was trashed by the village, Merrikat is not surprised that the library books are intact because it’s against the law to damage library property. I smiled.
  • The absurdity of Merrikat’s behavior at times struck me hard. The first time was when she threw a glass pitcher on the floor because she was upset by a visitor talking to her sister too much. I had to re-read that section a few times because it was written in an almost off-hand way, as if this was normal behavior. She continues to behave like that in bursts, and then the more absurd part becomes Connie’s calm reaction to these behaviors. Piece by piece, you get to understand more about how disturbed they are, and why.
  • Merrikat’s belief in magical powers that keep her safe are both hard to believe and comforting. I kept waiting for someone to say one of her three magic words, as if that was the only way that anything could go wrong.
  • I wanted Charles to be taught a lesson. I guess it happened, but a part of me wanted it to be more dramatic and more crushing. I’m a sucker for an evil character doing clearly evil things and then getting caught red-handed and punished. I know that’s simplistic, but I still like it and am a little disappointed when I don’t get that satisfaction.

I love the fact that I’m finding books to enjoy, thanks to my kids. Life is good.

Nov 27, 2019 - 1 minute read - Comments - book-review

Open Borders

I just finished Open Borders, a graphic novel about immigration policy. (Not 2 things that normally occupy the same sentence)

It was an excellent presentation of a position that I’ve always felt to be morally correct, in my heart of hearts. I am one of the few lucky ones who gets to be an American citizen just because of the fact that my parents took it on themselves to forge a better life for us. Why shouldn’t everyone have this opportunity? This book shatters many of the myths that allowing open borders makes things “worse” in any way for natives.

Nov 18, 2019 - 2 minute read - Comments - book-review

Deep Survival Déjà Vu

Whenever I come across a book that I want to read, I add it to my Goodreads to-read list. This list, of course, is always growing. I’m very slowly coming to terms with the fact that I will never make it through this list and that someday I will die, with unread books on my to-read list. Horrors! The other major problem with this simple approach to a reading list is that I can never remember why I added a book to my list. If it was a recent addition, I might recall, but in most cases I just can’t remember why I wanted to read the book in the first place.

In that way, the book Deep Survival made it to my to-read list last year, and I picked it up for my Kindle when it went on sale recently:

Knocking off a to-read Knocking off a to-read

I’ve gotten through the first few chapters so far. I have been enjoying it, but something about it is bothering me. It felt very familiar. Maybe that is what happened… I read a teaser for the book in a magazine article or something, and that is why I added it to my to-read list last year.

And then yesterday, while I was converting the blog from Octopress to Hugo, I had to fix up some posts, so I ended up looking through a bunch of my old posts, including…. my book review of Deep Survival.

It’s a weird feeling to read a review about a book that I’ve been wanting to read for over a year, written by a 12 year younger version of yourself.

Nov 17, 2019 - 2 minute read - Comments - family programming

Ports and networks

Kavi was looking over my shoulder as I tried to get my blog working in a local Docker container. I’ve gotten to the point that the site seems to be up and running in the container, but I can’t seem to get to it from my laptop. So, he wondered why I was putting port 1313 in my URL bar (“localhost:1313”) and then I showed the results of netstat -ant to prove that something should be listening on that port. And we got the IP address for google.com and then put that in Chrome’s URL bar with :80 at the end of it, and magically, it worked. (Other websites did not work, and I explained that most sites will not allow their sites to be accessed via IP address).

I still haven’t figured out why I can’t access the blog running in my container, but I think Kavi’s learning more about networking than I ever did (and I’m hoping that he’ll be able to debug these issues for me… soon enough)

UPDATE: I figured it out. Hugo’s server was listening on localhost inside the container, when it needed to be listening on 0.0.0.0. Adding that as a --bind parameter fixed the issue (though I had to also add --baseURL and --appendPort=false params, which saddened me.)

Nov 17, 2019 - 2 minute read - Comments - blog

Hugo

I moved my blog from Octopress to Hugo today. I had been slightly unhappy with Octopress for a while now, but mainly I just wanted something new to play with. Hugo is MUCH faster than Octopress was:

vkurup@caktus020:~/dev/kurup.org(master) $ hugo

                   | EN   
+------------------+-----+
  Pages            | 669  
  Paginator pages  |  29  
  Non-page files   |   0  
  Static files     | 426  
  Processed images |   0  
  Aliases          |   1  
  Sitemaps         |   1  
  Cleaned          |   0  

Total in 808 ms

It is nice to generate my entire site in less than a second.

But I still liked the style and theme of my old site, so I was happy to find that someone had already built an Octopress theme for Hugo. I promptly stole his work and customized a few things here and there to make it look (nearly) exactly like my old site did. Yay! Thanks to Parsia for building that theme. I’ve also subscribed to his RSS feed because his site looks pretty interesting.

Moving my content wasn’t easy, but it wasn’t hard. I mainly just copied the old markdown posts over, changed the front matter, and then fixed a few octopress plugins I was using to work with Hugo.

Future steps:

  • Switch from Disqus to something self-hosted
  • Generate the HTML on the server rather than having the HTML in git
  • Update my About page and Computers page
  • … oh, maybe write more!

Apr 8, 2019 - 1 minute read - Comments - family poetry

Avik 7:30

“Here it comes!” His eyes light up.
Slurps one last sip from his small cup.

Then bounding from the kitchen table,
Fast as lighting, he is able

To trash his scraps and stow his dishes.
He yells to Mom, “It was delicious!”

One more breath then on the couch he lands.
“What’s up?” says Mom. Dad shrugs his hands.

Big brother also has no idea.
Big sister sighs, “He’s a weird one I fear.”

We gather round to be sure he’s fine.
Eyes glued to his wrist, “It’s 7:29!”

And then the beeping fills the room.
The smile confirms he’s over the moon.

The source of this happiness, on his arm,
His brand new watch, and a 7:30 alarm.

(A real-life story, barely embellished)

A kid with a watch A kid with a watch

Dec 20, 2018 - 2 minute read - Comments - running family

Triangle Race Series

When we made our 2018 goals last year, Kavi, Anika and I all had some running-related goals. I don’t remember offhand exactly what each of our goals were, but I think we all wanted to run more races, because well, races are fun! I somehow stumbled on the Triangle Race Series. It’s a series of a couple dozen races throughout the year around the Triangle, so we signed up for a few. They keep standings based on participation and placement. You get 5 points for running a race, and more if you place in your age/gender division. We ran about 4 or 5 of the races. I hadn’t really thought about the series at all recently since I injured my right Achilles in July and haven’t run at all since then. Getting old really is a bummer. Anyways, I checked the website today and they have posted the final 2018 results. I got 6th place in my “not-quite-old-fogey” division! Not bad, huh? Yeah, I know… it’s mostly a participation award, but still, I’m proud. But wait! That’s not even the best part. I’m even more proud of Kavi and Anika. They are both in the 0-19 age group, so get to compete against teenagers. Kavi got 3rd place in the male 0-19 division, and Anika got 1st place in the female 0-19 division!

Oak City Mile 2018 Oak City Mile 2018