もちゅろぐ

iOSやSwift、モバイル設計だったりRailsについてまとめていく

古いPCにLinux(CentOS 7)をUSBメモリでインストールしてプリンターサーバーとして再生させる

こないだ断捨離してたら独身の頃買ったネットブックを発見。 長らく使っておらず今後も予定なかったので、破棄も考えたのですが比較的使っているプリントサーバとして勉強がてら復活させました。

色々ネットで調べながら構築したのですが、ネットでは見つからなかったり、躓いたり、情報が散らばって進めにくかったのでまとめました。

環境

機器 名称
PC acer の Aspire 1410
プリンター iP2700
OS Windows 7 64bits版
作業PC Mac
USBメモリ 4GB

構築したプリントサーバ

Windows 7 がインストールされてる 内部HDD を CentOS 7 64bits Minimal で上書き。 GUIはなしです。 プリンターはPCにUSBケーブルで接続します。 system-config-printer は GUI なのでそれ以外の方法で構築します

注意

PC内のデータやOSは全て削除されます。

イメージファイルをダウンロード

特別記載することはないですね。 CentOS のページからダウンロードするだけです。 Download CentOS ちなみに Minimal にした理由は2つあって

  1. 手持ちのUSBフラッシュメモリの容量不足
  2. 足りないパッケージや環境などを自分で構築するため

のためなので、特にそういった目的不要であれば フルパッケージ版を入れてもいいと思います。

イメージファイルをUSBフラッシュメモリに書き込む

USBメモリの初期化

ディスク一覧を確認

$ diskutil list

MS_DOS(FAT)形式で初期化 ディスク一覧で確認したパーティション/dev/disk2 だとしたら

$ diskutil eraseDisk MS-DOS UNTITLED /dev/disk2

マウント解除

$ diskuntil unmountDisk /dev/disk2

ISOイメージをUSBメモリに書き込む ここで Finder 上でisoイメージファイルをコピペしても認識されません。 ddコマンド使って書き込む。

以下は isoイメージファイルが ~/Downloads/centos.iso とした場合

$ sudo dd if=~/Downloads/centos.iso of=/dev/disk2 bs=4028

ディスク取り出し

$ diskutil eject /dev/disk2

BIOSのブート順序を変える

  1. PCの電源を入れてF2を押しておき、F12が押せるように設定を変更
  2. 再起動してF12を押しておき、ブートディスクをUSBメモリを1番上に移動

yum を使う準備

$ yum update
$ yum install epel-release
$ yum install wget

権限エラーの場合はsudo つけてください

CUPSをインストール

$ yum install cups cups-devel

権限エラーの場合はsudo つけてください

次のような必要ファイルが見つからない場合は

エラー: 依存性の欠如:
    libcups.so.2 は cnijfilter-common-3.30-1.i386 に必要とされています
    libpopt.so.0 は cnijfilter-common-3.30-1.i386 に必要とされています
$ yum provides libcups.so.2

のようにすることで内包してるパッケージ名を確認できます。

PCからプリンタのUSBケーブルを抜くとCUPSの設定が無効になる

CUPSウェブ管理上では変化ないが印刷しても反応しない 再設定すると印刷される

Macのプリンタ設定で見つからない場合

プリンターサーバーに avahi をインストールしてみてください。

CUPSを設定

vi /etc/cups/cupsd.conf

Listen localhost:631

# Listen localhost:631
Listen 631

にする

<Location /></Location>

の間に Allow From All 末尾を追加

<Location /admin></Location>

の間に Allow From All 末尾を追加

<Location /admin/conf></Location>

の間に Allow From All 末尾を追加

CUPS起動

プリンタ電源を入れておこう

USBにプリンタが接続されているか確認

lsusb
$ systemctl start cups

Firewalld で IPP のポートを開ける

サービス確認

$ firewall-cmd --get-services

IPP が定義されてれば追加

$ firewall-cmd --add-service=ipp --permanent
$ firewall-cmd --reload

Linux用プリンタードライバーをインストール

キヤノン:ダウンロード|IJ Printer Driver Ver.3.30 for Linux から rpm をダウンロードします

$ wget http://pdisp01.c-wss.com/gdl/WWUFORedirectTarget.do?id=MDEwMDAwMjcxNjAx&cmp=ACM&lang=JA

ダウンロードしたファイルはホームフォルダにあります。 適宜名前を変更してください。

$ rpm -vhU --nodeps --force <rpm name>

CentOSの再起動が必要です。

CUPS設定

ブラウザで http://サーバーアドレス:631 にアクセス サーバーアドレスは

$ ip a

で確認できる

  1. 管理者向けの「プリンターとクラスの追加」
  2. プリンターの「プリンターの追加」
  3. 権限エラーページが出るので表示されたURLにアクセス
  4. 再度「プリンターの追加」
  5. rootアカウント情報を入力
  6. プリンターに接続しているローカルプリンターを選択
  7. 「このプリンターを共有する」をONにする

PCのスリープをOFF

vi /etc/systemd/logind.conf を編集する

#HandleLidSwitch=suspend
#HandlePowerKey=poweroff
#HandleSuspendKey=suspend
#HandleHibernateKey=hibernate

# PCを閉じた
HandleLidSwitch=ignore
# パワーキーを押した
HandlePowerKey=ignore
# サスペンドキーを押した
HandleSuspendKey=ignore
# ハイバネートキーを押した
HandleHibernateKey=ignore

再起動する

$ systemctl restart systemd-logind.service

プリンタの自動電源OFF機能を無効化

iP2700だと自動電源がデフォルトでONになってる 調べた感じCUI上からだと変更はできなさそう。

少しセキュリティを強固にする

yum-cron で定期 yum update 実行

$ yum install yum-cron

除外設定 vi /etc/yum.conf

[main] より下に除外したい項目を追加

[main]
exclude=kernel*

自動更新を設定 /etc/yum/yum-cron.conf

apply_updates = no

を yes にする

セキュリティ関連に限定するために

update_cmd = default

を security にする

自動起動にする

$ systemctl start yum-cron
$ systemctl enable yum-cron

不要サービスを止める

起動中サービスを確認

$systemctl list-unit-files -t service 

サービスを止める

$ systemctl disable <service name>

root ユーザーのログイン無効化

/etc/ssh/sshd_config 内の

#PermitRootLogin yes

PermitRootLogin no

に変更する

再起動する

$ systemctl reload sshd.service

何かインストールしても変わらない場合

OSの再起動を試してみてください。

参考URL

Mac OSX上でISOイメージからBootable USBを作成する - 1日ひとつだけ強くなる SambaとCUPSと各種プリンター(CUPS・プリンタ編) - Qiita 【丁寧解説】Linuxのファイアウォール firewalld の使い方

CUPS 設定 - CentOS プリンタ 管理

CircleCIで別途SSHキーを追加して使う方法

最近CircleCIを使って定期実行的なことをするために弄り始めました。

CircleCI が自動で生成&登録してる鍵は read-only

CircleCIを使ってサーバーにデプロイしたい場合やGitHubへpushしたい場合は、 自動生成&登録されるSSH Keyでは権限が足りずエラーになります。

別途SSH Keyを登録して利用することで上記のような目的を達成できるようになります。

手順

  1. ssh-keygen -m PEM -t rsa などで鍵生成
  2. GitHubのrepository設定のdeploy keyに公開鍵を登録
  3. repository毎の設定 > PERMISSIONS > SSH Permissions へ移動
  4. Add SSH Key を押下
  5. ホスト名を github.com
  6. Private Keyに秘密鍵を登録
  7. .circleci/config.yml の steps 内で add_ssh_key コマンドを記入

add_ssh_key に関してはこちら参照。 記事中に出てくる Fingerprint は GitHubかCircleCIのrepository設定ページで確認可能。

関連

CircleCIにSSH Key登録が失敗する場合はこちらをどうぞ mothulog.hateblo.jp

CircleCIでSSH Key登録が失敗する場合の原因特定方法と自分が見つけた解決方法

最近CircleCIを使って定期実行的なことをするために弄り始めました。

CircleCIの簡単な説明

CircleCIはGitHubのレポジトリベースで管理されており、セットアップすると自動でread-onlyの鍵がGitHubの対象レポジトリに登録されてます。 これによりCircleCIがGitHubのレポジトリをgit pullして取得したコードのテストを実行できるようになります。

自分が試したかったのは少し違う

自分がやりたかったのはgit pull後にテストではなくバッヂスクリプトを走らせた後に 成果物を再度対象レポジトリにgit push することでした。

自動で登録される read-only な鍵では足りないので新たに鍵を追加する必要があります。 そのさいに何故か秘密鍵が登録できず失敗になって躓いたのでその時に調べたことを紹介しようと思います。

SSH Key 追加画面 f:id:motom552:20181126162504p:plain

エラーはブラウザコンソールに出る

f:id:motom552:20181126163343p:plain

エラーになると失敗しか表示されず一見まったく原因が分からないですが、 ここでエラーになったらブラウザコンソールでエラーログに失敗要因が表示されてます。 Chromeであればoption+command+iで呼び出せます。

自分が躓いたのはエラーログでは分からず

しかし自分が躓いたのはエラーログが単純に400が変えるだけで詳しい原因が分からなかったのですが、 次の方法で解決できました。

SSH Keyを登録する時に

$ ssh-keygen -t rsa -b 4096 -C "メールアドレスなど"

のようなコマンドだと思いますが、これに -m PEM をつけて強制的にPEM形式にすることで無事登録できました。

$ ssh-keygen -m PEM -t rsa -b 4096 -C "メールアドレスなど"

参考

discuss.circleci.com discuss.circleci.com

クラス名にSimpleやEasyがついててもクラス内コードが単純なわけではない

クラス名は目的やできることや塊を表現する。
そのためクラス名にSimpleやEasyがついてる場合

  1. 提供してる機能自体がシンプル
  2. 提供してる機能の使い方がシンプル
  3. 保持してるデータ構造の名前が「シンプル」とネーミングされている

と少なくとも3つの解釈ができる。

ここで、クラス名にSimpleだからといってクラス内コードがシンプルと思うのは、
設計において

  • 「できること」とその「実現方法」の隠蔽化による関心ごとの分離を理解できていない
  • クラス名の活用意図を間違えている

と言える。どの解釈においてもコードがシンプルと断言には至らない。

「3.がそうじゃないのか?」と思っても、仕様・要件上「シンプルな方」だからシンプルと名付けてるだけであって 絶対にコードがシンプルになるわけではない。

データ構造がシンプルだからコードもシンプルと言うのは、偶然コードもシンプルになりやすいだけである。

提供してる機能自体がシンプル

何か高機能なサービスをラッパーして使いたい機能のみを提供するクラスなどによく見かける。

提供してる機能の使い方がシンプル

スレッド操作や並列処理、直接扱おうとするとコードが複雑になり、ボイラープレートコードなどで埋め尽くされるのを1つのクラスに隠蔽化することで、手段を簡単に扱えるようにさせる場合に使われやすい。

保持してるデータ構造の名前がシンプル

データクラスにおいて保持するデータ構造の名前が「シンプル」とついてる。つまりドメイン用語でシンプルとついてる。

RailsのController内におけるエラーハンドリングのベストプラクティスについて調べてみた

概要

  • 各APIControllerでエラー検知とエラーレスポンスを書くのDRY違反してる
  • エラーレスポンスは構造が統一できていないとクライアント側が死んでしまう
  • Applicationで一律例外検知してエラー内容をハンドリングしたほうが楽

C#のASP.NET MVC5ではController毎に例外キャッチなどはせずApplicationで一律ハンドリングするので、 Railsにも同様の機能は提供されていると思う。

その方法を調べると同時にRailsにおけるベストプラクティスを知っておこうって思った。

Applicationで一律例外検知してハンドリングする方法

  • ApplicationController で rescue_from メソッドを使う
  • 404や500は 専用Controller用意とroutes.rb更新してconfig.exceptions_app = routesでカスタマイズする

ベストプラクティス

  • ExceptionではなくStandardErrorをキャッチする
  • 各ControllerではなくApplicationControllerでハンドリングする
  • エラーハンドリング処理はApplicationControllerから分離する
  • Custom Errorでエラー情報の詳細化を助ける
  • アプリケーションエラーとシステムエラーは分けるハンドリングする
  • アプリケーションエラーはユーザーフレンドリーを目指す
  • システムエラーはデベロッパーフレンドリーを目指す

  • 参考サイトA

  • 参考サイトB

XcodeのPlaygroundが動かないとか遅いとか不安定な場合は新しく作り直すといい

過去に作ったPlaygroundのままだと動作が変だよって話。

自分もだいぶ前に作ったPlaygroundをちょっとしたコード動かしたい時にXcodeプロジェクトが立ち上がった状態 Playground を立ち上げてコード書いてた。

だけど以前から Playgroundがずっと何かを処理中のまま止まって、再起動しないと動かないことが頻発してた。

試しに現バージョンのXcodeから新しくPlaygroundを作り直したら、今までの不安定な動きは見せず快適になった。

Playgroundが重いな、動かないな、不安定だなって感じる人がいたら試してみるといいです。

Optional<String>をExtension化したのにエラーになって役に立たない

事の発端

nil結合演算子コンパイルが重くなる要因だし、見た目としてもよくないから解決したいと考えてた。

そこで Optional を拡張してそのコードを次のようにカプセル化した。 これなら nil結合演算子も使わずにコード量も抑えられる。

extension Optional where Wrapped == String {
    var orEmpty: String {
        guard let value = self else { return "" }
        return value
    }
}

だけど実際のコードではエラーになる

let url: URL? = URL(string: "https://hogehogex.jp")
url?.absoluteString.orEmpty // Value of type 'String' has no member 'orEmpty'

エラー説明見ると String に orEmpty がないと言われてるので試しに用意してもダメ。

extension String {
    var orEmpty: String {
        return self
    }
}

let url: URL? = URL(string: "https://hogehogex.jp")
url?.absoluteString.orEmpty // Value of optional type 'String?' not unwrapped; did you mean to use '!' or '?'?

こっちみたいに一度格納すると認識する。

let value: String? = url?.absoluteString
value.orEmpty // OK

結局これだとほとんどのケースで無駄にコード量が増えるので役に立たなかった。

言語不具合

Swiftコードを見たことないけど、これバグだよな。 nilの伝搬とメソッドの評価順が逆なんじゃないかと思う。