Network Cards and Device Names

I know there’s a page on the Red Hat website that explains the new network device names and how they’re created. But, for me, a concrete example that I worked with is always much better. I set up a new server yesterday and had some issues with a fiber network card, so I thought I’d write up what I learned.

The system has two built-in ethernet cards and I added a fiber card as well. The first thing I want to mention is that this server has space for two cpus, but we’re only using one. And on my first attempt at adding the fiber card, I put it in a slot that was for things for cpu2, which we’re not using. After I moved the card to a slot for cpu1, it showed up. So here is the info on my cards:


# lspci|grep Eth
65:00.0 Ethernet controller: Realtek Semiconductor Co., Ltd. RTL8111/8168/8411 PCI Express Gigabit Ethernet Controller (rev 06)
b5:00.0 Ethernet controller: Intel Corporation Ethernet Connection X722 for 10GBASE-T (rev 09)
b5:00.1 Ethernet controller: Intel Corporation Ethernet Connection X722 for 10GBASE-T (rev 09)

The Realtek card is the fiber one and the other two are built in. Note the numbers for the built-in cards, b5:00.0 and b5:00.1. This number is the basis for how the device names are made. If you convert b5 from hex to decimal, you get 181. Now if I look in /etc/sysconfig/network-scripts, I see two device files: ifcfg-enp181s0f0 and ifcfg-enp181s0f1. These devices all start with en. Then they’re followed by the numbers from the lspci command.

enp#s#f#

For b5:00.0, the p is b5 in decimal, the s is 00 (though you only need one 0) and since there are two cards .0 and .1, add the f with 0 or 1.

Now the device for my fiber card didn’t show up. But if I want to make my own device, I can. The hex number 65 in decimal is 101. So I created enp101s0. I don’t need the f because there’s only one card here. And I created the file /etc/sysconfig/network-scripts/ifcfg-enp101s0 with the information needed for the fiber card.

The other thing that I needed to do is to assign the mac address of the card to that device. I ran this command:


# ifconfig enp101s0 hw ether aa:bb:cc:dd:ee:ff
# ifup enp101s0

I found a number on the actual card that is the length of the mac address, so I used that in my command. After the ifup command, the card showed with the ifconfig command.

The big question was did it work. Right now, I don’t know. I didn’t have a fiber cable to test things out. I hope that next week the student who is using this card will get back to me and let me know how things go.

My other issue is that this card doesn’t come up automatically at boot. I’m not sure why I have to manually assign the hw address to it with the ifconfig command. This makes me think that perhaps I did something wrong as there’s no reason for it not to come up automatically. I’ll find out next week when things are actually set up so I can test it.

Ruby Gem Error

I’ve been doing a bit more work with Sinatra and I got the following error. I’m just documenting how I fixed it.

yo:digital_signs $ ruby display.rb 
Traceback (most recent call last):
	10: from display.rb:2:in `
' 9: from /Users/maryh/Software/rubies/2.5.7/lib/ruby/2.5.0/rubygems/core_ext/kernel_require.rb:39:in `require' 8: from /Users/maryh/Software/rubies/2.5.7/lib/ruby/2.5.0/rubygems/core_ext/kernel_require.rb:128:in `rescue in require' 7: from /Users/maryh/Software/rubies/2.5.7/lib/ruby/2.5.0/rubygems.rb:217:in `try_activate' 6: from /Users/maryh/Software/rubies/2.5.7/lib/ruby/2.5.0/rubygems.rb:224:in `rescue in try_activate' 5: from /Users/maryh/Software/rubies/2.5.7/lib/ruby/2.5.0/rubygems/specification.rb:1440:in `activate' 4: from /Users/maryh/Software/rubies/2.5.7/lib/ruby/2.5.0/rubygems/specification.rb:1458:in `activate_dependencies' 3: from /Users/maryh/Software/rubies/2.5.7/lib/ruby/2.5.0/rubygems/specification.rb:1458:in `each' 2: from /Users/maryh/Software/rubies/2.5.7/lib/ruby/2.5.0/rubygems/specification.rb:1472:in `block in activate_dependencies' 1: from /Users/maryh/Software/rubies/2.5.7/lib/ruby/2.5.0/rubygems/specification.rb:1438:in `activate' /Users/maryh/Software/rubies/2.5.7/lib/ruby/2.5.0/rubygems/specification.rb:2325:in `raise_if_conflicts': Unable to activate dm-serializer-1.2.2, because json-2.1.0 conflicts with json (~> 1.6) (Gem::ConflictError)

I couldn’t start my Sinatra app due to this json error. My first idea was to just uninstall the json v2.1.0 gem.

yo:2.5.7 $ gem list json

*** LOCAL GEMS ***

json (default: 2.1.0, 1.8.6)
json_pure (1.8.6)
multi_json (1.13.1)

yo:2.5.7 $ gem uninstall json -v 2.1.0
ERROR:  While executing gem ... (Gem::InstallError)
    gem "json" cannot be uninstalled because it is a default gem

I’ve compiled my own version of ruby because I have a bunch of different versions on my computer. So I went to the directory for the version I wanted to use and searched for 2.1.0.

yo:2.5.7 $ find . -name '*2.1.0*' -print
./lib/ruby/gems/2.5.0/cache/chromedriver-helper-2.1.0.gem
./lib/ruby/gems/2.5.0/cache/sassc-rails-2.1.0.gem
./lib/ruby/gems/2.5.0/cache/spring-2.1.0.gem
./lib/ruby/gems/2.5.0/doc/chromedriver-helper-2.1.0
./lib/ruby/gems/2.5.0/doc/sassc-rails-2.1.0
./lib/ruby/gems/2.5.0/doc/spring-2.1.0
./lib/ruby/gems/2.5.0/gems/chromedriver-helper-2.1.0
./lib/ruby/gems/2.5.0/gems/sassc-rails-2.1.0
./lib/ruby/gems/2.5.0/gems/spring-2.1.0
./lib/ruby/gems/2.5.0/specifications/chromedriver-helper-2.1.0.gemspec
./lib/ruby/gems/2.5.0/specifications/default/json-2.1.0.gemspec
./lib/ruby/gems/2.5.0/specifications/sassc-rails-2.1.0.gemspec
./lib/ruby/gems/2.5.0/specifications/spring-2.1.0.gemspec


yo:2.5.7 $ rm ./lib/ruby/gems/2.5.0/specifications/default/json-2.1.0.gemspec

Once I found the gemspec file, I deleted it and things worked as expected.

My First Sinatra Project

I have a wufoo form that I’m using and I want to automatically see the results on a webpage. One of the hangups of this process is that I can’t put any script on the webserver. But what I can do is embed an iframe. So I could download the information that I wanted from my form to another server and then display that page in the iframe. My question was what to run on my second server, which I’m going to call my results server. All it really needed to do was get the results and then show them. So using a ruby on rails app for this seemed to be overkill. After reading about it, sinatra seemed to be the perfect fit. I could still use ruby and just show the results I wanted. This seemed to be the perfect project to test out sinatra.

The only gems that I needed were sinatra and wuparty. Wuparty is a gem specifically written for wufoo. I installed it with gem install and found that it didn’t install correctly. I looked at the source code on git and saw that everything except the /lib/wuparty/* files got installed. If I knew how to use git better, I’d submit a ticket. But it was easy for me to just fix manually.

Anyway, ignoring all the files I need to deploy or set things up, here’s what I needed.

Gemfile

source 'https://rubygems.org'
git_source(:github) { |repo| "https://github.com/#{repo}.git" }

ruby '>= 2.5.0'

gem 'wuparty' # For using wufoo API
gem 'capistrano' # For deployment
gem 'rake', '12.3.2'
gem 'rack', '2.0.7'
gem 'sinatra', '2.0.5'

config.ru

require 'rubygems'
require 'sinatra'
require File.expand_path '../display_results.rb', __FILE__

run Sinatra::Application

entry.rb (this is where I define which fields are for what)

Entry = Struct.new(:firstname, :lastname, :institution, :attending, :guestfirstname, :guestlastname, :guestattending)

module Entries

end

if __FILE__ == $0
x = Entry.new('George', "Washington", "White House", "Dinner and Talks", "Martha", "Washington", "Dinner").to_h
puts x[:firstname]
end

display_results.rb

require 'rubygems'
require 'sinatra'
require 'wuparty'
require_relative 'entry'

config = YAML.load_file("config/wufoo.yml")
account = config["ACCOUNT"]
api_key = config["API_KEY"]

get '/results.html' do
erb `cat public/results.html`, layout: false
end

post '/results' do
@entries = []
wufoo = WuParty.new(account, api_key)
form = wufoo.form('FormName')
count = form.count.to_i
pageSize = 100
times = (count / pageSize).to_i
(0..times).each do |l|
form.entries(limit: pageSize, pageSize: pageSize, pageStart: (pageSize * l)).each do |e|
@entries << Entry.new(e["Field1"], e["Field2"], e["Field4"], e["Field6"], e["Field215"], e["Field216"], e["Field218"]).to_h
end
end
output = erb :'results.html'
File.open("public/results.html", "w") do |f|
f.puts(output)
end
end

That’s basically it. It’s really simple, but does exactly what I want it to do. And wufoo has webhooks that you can set up. I use those to send a post request each time someone signs up. This post request generates a new results.html file for me. And that’s the file that I put in an iframe on the website where I’m very limited in what I can do. I store a few things in a config file that I don’t want to store in my repo.

This is pretty simple, that I’m pretty sure it would be easy for me to add another get/post combo for another wufoo form when I add it.

This was a fun project and I like being able to set up sinatra to handle simple things like this. Rails would have been overkill here.

cmake

I haven’t been doing much with writing/compiling c programs of late. So I didn’t really notice the move from using make to using cmake for the build environment. We’ve been having some issues at work with this, so I’ve spent a few days trying to learn it. I’m not at expert at this at all, but I have picked up a few things. So I want to document them here.

Here’s a simple hello.c program.

#include <stdio.h>

int main() {
printf("Hello world!\n");
return 0;
}

It can be compiled with:

yo:hello $ gcc hello.c -o hello
yo:hello $ ./hello
Hello world!

How would I do this using cmake?

yo:hello $ mkdir build
yo:hello $ touch CMakeLists.txt
yo:hello $ ll
total 32
-rw-r--r--  1 maryh  staff     0 Apr 24 10:23 CMakeLists.txt
drwxr-xr-x  2 maryh  staff    68 Apr 24 10:23 build
-rwxr-xr-x  1 maryh  staff  8432 Apr 24 10:09 hello
-rw-r--r--  1 maryh  staff    73 Apr 24 10:06 hello.c

The file that cmake looks for is called CMakeLists.txt. Edit this file so it looks like this:

cmake_minimum_required(VERSION 3.0 FATAL_ERROR)
project(hello)
add_executable(hello hello.c)

All this does is check that we’re using at least version 3 of cmake. Not necessary for this, but for some other work programs, I needed that. The project line sets up the project and stores the name in the variable PROJECT_NAME. And if it’s the top-level CMakeLists.txt file, it also stores it in CMAKE_PROJECT_NAME. And the add_executable line adds an executable target (for us called hello) that’s built from the source file(s) (for us we only have hello.c).

That’s all that is needed. It’s nice to make the build directory and run the cmake program there because it makes things much easier to delete all the files if you’re doing various iterations on things.

To compile then, go to the build directory and run:

yo:hello $ cd build
yo:build $ cmake ../
-- The C compiler identification is AppleClang 9.1.0.9020039
-- The CXX compiler identification is AppleClang 9.1.0.9020039
-- Check for working C compiler: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/cc
-- Check for working C compiler: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/c++
-- Check for working CXX compiler: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /Users/maryh/Documents/C/hello/build

Now use make to compile the program.

yo:build $ make
Scanning dependencies of target hello
[ 50%] Building C object CMakeFiles/hello.dir/hello.c.o
[100%] Linking C executable hello
[100%] Built target hello
yo:build $ ll
total 80
-rw-r--r--   1 maryh  staff  13521 Apr 24 10:33 CMakeCache.txt
drwxr-xr-x  15 maryh  staff    510 Apr 24 10:34 CMakeFiles
-rw-r--r--   1 maryh  staff   4751 Apr 24 10:33 Makefile
-rw-r--r--   1 maryh  staff   1373 Apr 24 10:33 cmake_install.cmake
-rwxr-xr-x   1 maryh  staff   8432 Apr 24 10:34 hello
yo:build $ ./hello
Hello world!

This is definitely overkill for such a simple program, but those are the basic steps for more elaborate programs. And the key file to edit is basically CMakeLists.txt.

Ideas

It’s weird. I’ve just spent the past two hours making myself a calendar. I was wondering how to design it and it just popped into my head that I have pictures from the early 2000s to now. Why don’t I use some of my own pictures on my calendar? And then find some quotes I like and put them over the picture. It’s a really simple idea, but I love it. I’m going to get a calendar that has motivational or inspirational quotes and I can look at pictures of things I’ve done which brings back those memories. Totally going to make me happy.

I had wanted to read a book tonight, but I finally got my bluetooth speaker working with my laptop. So I felt that I had to listen to music. I can’t really read when there’s music playing that I can sing along to, so I gave up reading pretty quickly. Then I was thinking that I need to start tracking that I’m eating vegetables, so I need a calendar. And making calendar on the computer is something I can easily do while listening to music. I don’t know why, but now that I don’t have a tv, I feel like I’m getting more and more good ideas for projects. Or maybe it’s just that I have the time to do them, since I’m not sitting in front of a tv. All I know is that I’m loving getting more and more ideas, so I hope they keep coming.

UPDATE: Just printed the calendar. I have a cheap printer and it says it prints on 13×19 paper, which technically it does. But on a few pages, everything was a little skewed. So I think it has a hard time handling paper that big. But it’s printed and hanging on my wall and I love it!

Getting Started with the Google API for Reading Public Calendars

I have a few public calendars at work that we use to show events taking place in various departments. I am creating a digital sign for one of our buildings and I’d like to be able to grab the events for the current day and display them on the digital sign. I’m most familiar with ruby right now, so I’m writing a ruby script to do this.

The first thing is I need to install the ruby google-api-client.

$ gem install google-api-client

Since all of the calendar data that I want to grab is on public calendars, I can use an API key to get all this data. Instructions for generating an API key are here: https://support.google.com/cloud/answer/6158862. You also need the calendarid for the calendars you want to grab data from.

In order to see if I have things set up correctly, the following script will grab all the entries from the calendar specified by the calendarid.

require 'google/apis/calendar_v3'

Google::Apis.logger.level = Logger::DEBUG

calendar = Google::Apis::CalendarV3::CalendarService.new
calendar.key='YOUR_API_KEY'
puts calendar.list_events('GOOGLE_CALENDAR_ID')

$ ruby simple_test.rb
...all calendar events show...

With the key working correctly, how can I limit the results to just a single day? And only see the fields that I’m interested in? For us, these are the summary, description, start date_time and location.

require 'google/apis/calendar_v3'

calendar = Google::Apis::CalendarV3::CalendarService.new
calendar.key='YOUR_API_KEY'

events = calendar.list_events('GOOGLE_CALENDAR_ID',
	always_include_email: false,
	time_min: '2018-04-23T00:00:00-05:00',
 	time_max: '2018-04-23T23:59:59-05:00'
)

events.items.each do |item|
	puts item.summary
	puts item.description
	puts item.start.date_time
	puts item.location
	puts "====="
end

I hope to have this script do a bit more. So I’ve put it on my github page. The repository is here: https://github.com/maryheintz/google-calendar-api-ruby

Root Logins with Key Required

I love the fact that I still have so much to learn. I was thinking that I should set things up so that root can ssh in to a computer but only if they have keys set up. One very quick google search and I had my answer.

[[email protected] ~]# grep PermitRoot /etc/ssh/sshd_config
PermitRootLogin without-password

I had just assumed the settings for PermitRootLogin were yes or no. It’s great that the programmers also had thought of this other use. People are so much smarter than me.

Splitting a PDF File

I had a pdf file that was too large to email, but I needed to email.  So I quickly broke it up into two smaller files.  I used this command:

$ gs -dNOPAUSE -dBATCH -dFirstPage=1 -dLastPage=34 -sDEVICE=pdfwrite -sOutputFile=physics1.pdf -f Physics\ Faculty.pdf 
$ gs -dNOPAUSE -dBATCH -dFirstPage=35 -dLastPage=68 -sDEVICE=pdfwrite -sOutputFile=physics2.pdf -f Physics\ Faculty.pdf