vue.js使用時にvue-resourceでhttpリクエストを投げてみる

vue-resourceでhttpリクエストを投げてみた
公式では以下のようにvue-resourceは公式推奨からは外すけど、ajaxはVue自身が管理すべき領域でないからということで、使うべきではないとかそういった意味合いではないようだ。
https://jp.vuejs.org/2016/11/03/retiring-vue-resource/

インストール

$ npm install vue-resource

試してみる

jsファイル内に以下の追記を行いvue-resourceを有効化しておく

import VueResource from 'vue-resource'
Vue.use(VueResource)

それからgetリクエストを投げる場合は、以下のようになる。

  this.$http.get(リクエストURL').then(
    response => {
      console.info(response.body)
    }, response => {
      //エラー時の処理    
    })
  }

簡単に動作確認はできた。
Vueの公式ではhttpリクエスト周りは自分で好きなの選んでということだったが、とりあえずはvue-resourceを使っとけば良いのかと思います。

vue.jsにVue Materialを適用してみた

Vue Material(https://vuematerial.github.io/#/)を使用してマテリアルデザインを適用した際のメモ

インストール

公式の手順に従えば簡単に使えるようになる。

https://vuematerial.github.io/#/getting-started

$ npm install vue-material --save
$ yarn add vue-material

vue-materialはyarnでインストールするので、まだ入っていない場合は"npm install -g yarn"でyarnを実行できるようにしておく。

インストールできたらmain.jsなど最初の方で読み込まれるjs内で以下を実行してVue Materialのコンポーネントを使えるようにしておく。

import VueMaterial from 'vue-material'
Vue.use(VueMaterial)

ただこれだけだとコンポーネントに対してcssが適用されないので、以下を追記してnode_module内のcssを読み込ませておく。

require('vue-material/dist/vue-material.css')

または

import 'vue-material/dist/vue-material.css'

使ってみる

Vue Materialを使う準備はできたので実際に使ってみる。試しに以下のようなコンポーネントを準備した。

<template>
  <div id="header">
    <md-toolbar>
      <h1 class="md-title">アプリケーションタイトル</h1>
      <md-button class="md-raised" v-on:click="greet(event)">実行</md-button>
    </md-toolbar>
  </div>
</template>

<script>
export default {
  data () {
    return {
    }
  },
  methods: {
    greet: function (event) {
      alert('Hello !')
    }
  }
}
</script>

<style scoped>
.md-raised {
      margin-left: 30px;
}
</style>

実行してみるとマテリアルデザインが適用されたボタンが表示されたはずである。ボタンを押したらgreetメソッドが実行されると思ったのだが反応がなかった。 これについては公式にドキュメント(https://jp.vuejs.org/v2/guide/components.html)がありまして、どうやらカスタムコンポーネントのルート要素 にネイティブイベントをバインディングする場合.nativeを追記する必要があるようです。 それを踏まえて以下の修正を加えるとボタンクリックでメソッドが実行できることを確認できました。

<md-button class="md-raised" v-on:click="greet(event)">実行</md-button>
 ↓
<md-button class="md-raised" v-on:click.native="greet(event)">実行</md-button>

vue.jsを触ってみた

vue.jsとは

公式ページを引用すると以下のようになっています。

Vue (発音は / v j u ː / 、 view と同様)はユーザーインターフェイスを構築するための
プログレッシブフレームワークです。他の一枚板(モノリシック: monolithic)なフレームワークとは
異なり、Vue は初めから少しづつ適用していけるように設計されています。中核となるライブラリは
view 層だけに焦点を当てているため、Vue.js を使い始めたり、他のライブラリや既存のプロジェクト
に統合したりすることはとても簡単です。一方、モダンなツールやサポートライブラリと併せて利用
することで、洗練されたシングルページアプリケーションを開発することも可能です。

印象

reactの開発を行った際は始める際にgulpやwebpackなど開発用のツールの知識を事前に学んだりする必要があったのですが、vueではvue-cliでテンプレートのプロジェクトから開始できるのがすごい便利でした(reactについても現在ではテンプレートプロジェクト作成ができるようだ"https://facebook.github.io/react/blog/2016/07/22/create-apps-with-no-configuration.html")。一応fluxぽく実装することもできるようですが、それをやるならreactで良さそうな印象。fluxを使うまでもない単純なwebアプリとか作るのであればvue.jsを選べば良さそうに思います。

vue-cliによるプロジェクトの作成

ではvue-cliを使ってvue-cliのテンプレートプロジェクトを作ってみたいと思います。

インストール

$ npm install -g vue-cli

プロジェクト作成

$ vue init テンプレート名 プロジェクト名

vue-cliで使えるテンプレートは以下で確認できる。
https://github.com/vuejs-templates

起動

$ cd プロジェクト名
$ npm install
$ npm run dev

package.jsonを確認してみると"npm run dev"で"node build/dev-server.js"を実行していることがわかります。"webpack-dev-server"のタスクを直接実行するのではなくnode起動時にwebpackを実行するようにしているようです。初期状態でautOpenBroserが有効になっているのでnpm run dev実行で自動でブラウザが開くようになっています。

ビルド

$ npm run build

jsファイルのビルドが行われます。その際の設定などはだいたいconfig/index.jsにまとめられているようです。ビルド後のbase urlを変更したい場合はbuild.assetPublicPathを変更したら良いみたいです。

// see http://vuejs-templates.github.io/webpack for documentation.
var path = require('path')

module.exports = {
  build: {
    env: require('./prod.env'),
    index: path.resolve(__dirname, '../dist/index.html'),
    assetsRoot: path.resolve(__dirname, '../dist'),
    assetsSubDirectory: 'static',
    assetsPublicPath: '/',
    productionSourceMap: true,
    // Gzip off by default as many popular static hosts such as
    // Surge or Netlify already gzip all static assets for you.
    // Before setting to `true`, make sure to:
    // npm install --save-dev compression-webpack-plugin
    productionGzip: false,
    productionGzipExtensions: ['js', 'css'],
    // Run the build command with an extra argument to
    // View the bundle analyzer report after build finishes:
    // `npm run build --report`
    // Set to `true` or `false` to always turn it on or off
    bundleAnalyzerReport: process.env.npm_config_report
  },
  dev: {
    env: require('./dev.env'),
    port: 8080,
    autoOpenBrowser: true,
    assetsSubDirectory: 'static',
    assetsPublicPath: '/',
    proxyTable: {},
    // CSS Sourcemaps off by default because relative paths are "buggy"
    // with this option, according to the CSS-Loader README
    // (https://github.com/webpack/css-loader#sourcemaps)
    // In our experience, they generally work as expected,
    // just be aware of this issue when enabling this option.
    cssSourceMap: false
  }
}

試しにコンポーネントを追加してみる

vueでの開発の流れを把握するためコンポーネントを追加してみる。
まずwebpack起動時にアクセスするページについてだが、これはindex.htmlになる。

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>my-project</title>
  </head>
  <body>
    <div id="app"></div>
    <!-- built files will be auto injected -->
  </body>
</html>

ただindex.html内にはjavascriptを読み込む部分がないのだが、これはnode側がjavascriptを自動で返すようにしているためであり、 該当する設定はbuild/webpack.base.config.jsの以下の箇所になる。

module.exports = {
  entry: {
    app: './src/main.js'
  },

これにより、node側がindex.htmlとともに読み込むjsファイルをまとめて返すようにしている。

それから、main.js内でルータを読み込んでいるのがわかるので対象のルータ(source/router/index.js)を確認して見る。

import Vue from 'vue'
import Router from 'vue-router'
import Hello from '@/components/Hello'

Vue.use(Router)

export default new Router({
  routes: [
    {
      path: '/',
      name: 'Hello',
      component: Hello
    }
  ]
})

今回は最初に読み込むコンポーネントを追加したいと思うので、ここのルータに手を加える。とりあえず以下のように修正して見る。

import Vue from 'vue'
import Router from 'vue-router'
import Hello from '@/components/Hello'
import myApp from '@/components/myApp'

Vue.use(Router)

export default new Router({
  routes: [
    {
      path: '/',
      name: 'myApp',
      component: myApp
    },
    {
      path: '/hello',
      name: 'Hello',
      component: Hello
    }
  ]
})

これで"http://localhost:8080/“でアクセスした際にmyAppコンポーネントが表示されるようになるので、今度はそのmyAppコンポーネントを以下のように定義しておく。
src/components/myApp.js

<template>
  <div >
    {{msg}}
  </div>
</template>

<script>
export default {
  name: 'myApp',
  data () {
    return {
      msg: 'Welcome to my first app'
    }
  }
}
</script>

<style scoped>
h1, h2 {
  font-weight: normal;
}

ul {
  list-style-type: none;
  padding: 0;
}

li {
  display: inline-block;
  margin: 0 10px;
}

a {
  color: #42b983;
}
</style>

これでnodeを再起動したら自作したmyAppコンポーネントが表示されるはずである。初期状態だとvueのロゴが表示されていると思うがこれはmain.jsが最初に読み込んでいるコンポーネントであるApp.vue内で指定されているものなので、消す場合はApp.vueを修正したら良い。
公式ページのドキュメントが豊富なのであとはこれを参考にしたら開発を進めていけると思われます。

jp.vuejs.org

すでに公開されていて良さそうなコンポーネントは以下で探すことができる。

github.com

マテリアルデザインを適用するのであれば、Vue MaterialVue MDL Documentationのあたりが良さそうな気がします。 Vue Materialの方はインストール時にcssが付いてきてそれをimportして使えば良いので自分はそっちの方が楽で使ってたりします。

WSUS構築メモ

WSUSインストール

  1. 更新プログラムを保存するためのフォルダを作っておく
  2. サーバマネージャの"役割と機能の追加"からWSUSを指定
  3. 役割とサービスでデータベースにWIDを選択
  4. 更新プログラムの保存先に事前に用意したフォルダを指定

WSUS設定

  1. WSUSの同期スケジュールを設定 日本では深夜2-3時くらいに更新プログラムの配信が行われるから深夜4時とかに同期するのが多そう
    1回のアップデートでダウンロードに失敗する場合は同期回数を増やしておく

ドメイングループポリシーでWSUS管理対象にする

ドメイングループポリシーを変更してWSUSの管理対象にする
1. ドメインコントローラーで"グループポリシーの管理"を実行
2. WSUS管理対象のOUに以下のグループポリシーオブジェクトを指定
コンピューターの管理-管理用テンプレート-Windowsコンポーネント-WindowsUpdateを表示
“自動更新を構成する"を"有効"にし自動更新の構成を"3-自動ダウンロードしインストールを通知"に変更する
"イントラネットMicrosoft更新サービスの場所を指定する"を有効にするそれからWSUSサーバの場所を指定(ポートはデフォルトだと8530)
3. "ActiveDirectoryユーザとコンピュータ"でWSUS管理対象のOUに管理対象のコンピュータを移する

クライアント端末のグループポリシーでWSUS管理対象にする

クライアント端末のグループポリシーでもWSUS管理対象に変更できる

更新プログラムの自動承認

  1. WSUS管理コンソールのオプション-自動承認をクリック
  2. 自動承認対象のグループ、承認対象の分類を選ぶ等する

更新プログラムの手動承認

更新プログラムのインストール、削除ともに承認を行うことができる 1. WSUS管理コンソールの更新プログラムをクリック 2. 対象のプログラムを選択して承認をクリック 3. インストールまたは削除を指定して承認実行

その他

重くなったらインデックスの構築やキャッシュ削除、メモリ設定とかの調整は必要になりそう

WSUSに困らせられた記録

WSUS管理コンソールに繋がらなくなった

症状
WSUS管理コンソールに繋がらないということで確認したところ"予期しないパケット形式のためハンドシェイクに失敗しました"とのエラー表示で繋がらない

Microsoftのフォーラムに同様の書き込みがあり、どうやら最近WindowsUpdateを行った際にインストールされたKB3159706が原因でWSUSの管理コンソールに繋がらなくなったようだ。
→OS再起動だけではWSUSの管理コンソールに繋がらない、KB3159706アンインストール後はWSUS管理コンソールにつながるようになったことを確認  KB3159706はwindows10がupdateを行う際に必要になるのでインストールが必須になるようなので以下のWSUSサポートチームのブログを参照にインストール対応を実施
https://blogs.technet.microsoft.com/jpwsus/2016/05/26/kb3159706/

とりあえず無事にインストールできたからよかったけど、これはWindowsの不具合ではないのか

WSUS管理コンソールで削除した端末を再度管理対象にできない

症状 WSUS管理コンソールから端末削除後、グループポリシーを編集し再度WSUS管理対象としたが管理コンソールに表示されなくなった

クライアント端末のローカルグループポリシーでアップデートサーバにWSUSを指定していたのだが、ドメインコントローラのグループポリシーでアップデートさーばをWSUSに指定できるか確認するた以下の手順の操作を行った。
1. ローカルグループポリシー変更してWindows Update関連の設定をみ構成に変更
2. WSUS管理コンソールで対象端末を削除 3. ドメインコントローラーのポリシー変更して対象端末がupdate時にWSUSを見にいくように変更

これでWSUSの管理コンソールに端末に対象端末が表示されると思ったけど、表示されない。で、確認したところ以下のページにレジストリ消せな直るとの情報が
https://support.microsoft.com/ja-jp/help/903262/a-windows-2000-based,-windows-server-2003-based,-or-windows-xp-based-computer-that-was-set-up-by-using-a-windows-2000,-windows-server-2003,-or-windows-xp-image-does-not-appear-in-the-wsus-console
で対応してちょっと待ったら治った
グループポリシーとWSUSの管理対象端末が同期できない作りになっているんだろーなーと思いました。ドメインコントローラの端末で管理対象端末に適用されているグループポリシー情報を管理できたら簡単そうな気もするんですがそうはいかないのだろう。せめてWSUS管理コンソールからの削除時間と端末に適用されるグループポリシーの変更時間からとかうまく整合性とってもらいたいとか思ったりする。

Scalaで新しく制御構造を作成する

Scalaで新しい制御構造を自作する

Scala関数型言語にあるため関数が第一級のオブジェクトとなります。そのためJavaなどのオブジェクト指向言語と比べてどんな違いがあるかというと、関数を引数にして別の関数を呼び出すことができます。俗に言う高階関数というやつです。
試しに用意した関数を引数として受け取るサンプルは以下のようになります。

def listFunc(lines: List[String])(op:String => Boolean) = {
  for {
    line <- lines
    if op(line)
  } yield line + "\n"
}

(op:String => Boolean) の部分がStringを引数で受け取りBooleanを受け取る関数を引数で使うように定義している。(op:String => Boolean)の部分は(op: Function[String, Boolean])と書き換えることもできます。それから関数を引数として渡している部分は以下のようになります。

def grepText(fileName: String, text: String): String = {
  val lines = Source.fromFile(fileName).getLines().toList
  val result = listFunc(lines) {
    line => line.contains(text)
  }
  result.mkString
}

高階関数を利用することで処理のみを切り替えるだけということができます。上記の例ではline.contains(text)の部分が異なる関数を利用することで制御の構造はそのままで処理を切り替えることができます。また同一の処理を別の部分でも再利用が行えるためコードの再利用性はjavaなどに比べて大分上がると思います。
参考までに今回用意した高階関数を利用したgrepコマンドの全体像は以下のようになります。

import scala.io.Source

/**
  *
  * @param file ファイル名
  * @param text 検索対象テキスト
  * @param lineNum 行番号を表示するかどうか
  */
case class SGrepArgs(file:String, text: String, lineNum: Boolean )
object SGrep {

  def parseArgs(args: List[String]): Option[SGrepArgs] = {
    var file: String = ""
    var text: String = ""
    var lineNum:Boolean = false

    def parseArgsHelper(args: List[String]): Unit = {
      args match {
        case "-n" :: x  ::rest => {
          lineNum = if(x equals "true"){true} else{false}
          parseArgsHelper(rest)
        }
        case x :: y :: rest => {
          file = x
          text = y
          parseArgsHelper(rest)
        }
        case _ => {}
      }
    }
    parseArgsHelper(args)
    Some(SGrepArgs(file, text, lineNum))
  }

  def main(args:Array[String]): Unit ={
    val sGrepArgs = parseArgs(args.toList)
    sGrepArgs match {
      case Some(x) => grep(x)
      case _ => {}
    }
  }


  def grep(sGrepArgs: SGrepArgs) = {
    println(grepText(sGrepArgs.file, sGrepArgs.text))
  }

  def grepText(fileName: String, text: String): String = {
    val lines = Source.fromFile(fileName).getLines().toList
    val result = listFunc(lines) {
      line => line.contains(text)
    }
    result.mkString
  }

  def listFunc(lines: List[String])(op:String => Boolean) = {
    for {
      line <- lines
      if op(line)
    } yield line + "\n"
  }
}

Ansibleを触ってみた

Ansibleを触ったのでメモ

Ansibleとは

エージェントレス型の構成管理ツール。エージェント型とエージェントレス型では以下のような違いがある。
◯エージェントレス型
管理対象のサーバにエージェントを入れる必要がない
管理対象のサーバへの接続情報が必要になる
 管理端末から構成反映の処理を行う必要がある
◯エージェント型
管理対象のサーバにエージェントを入れる必要がある
起動時などに自動で構成が適用される

複数の設定が異なるサーバを管理する場合は、管理用サーバを別で持てるエージェントレス型の方が扱いやすいような気がします。それからAnsibleはエージェント型のchefやpuppetより後発のため洗練されている部分がありますし、RedHatがAnsibleを買収したため今後も開発が続けられることが期待できます。

0.インストール環境準備

以下のvagrant環境にインストール

Vagrant.configure("2") do |config|

  config.vm.define :node1 do |node|
    node.vm.box = "geerlingguy/centos7"
    node.vm.network "forwarded_port", guest: 22, host: 2001, id: "ssh"
    node.vm.network "private_network", ip: "192.168.33.11"
  end

  config.vm.define :node2 do |node|
    node.vm.box = "geerlingguy/centos7"
    node.vm.network "forwarded_port", guest: 22, host: 2002, id: "ssh"
    node.vm.network "forwarded_port", guest: 80, host: 8000, id: "http"
    node.vm.network "private_network", ip: "192.168.33.12"
  end
end

ssh接続準備

管理用端末が管理対象の端末を操作する際にはsshプロトコルを使用するので、鍵を配置する等の事前準備は必要になると思います。

1.Ansibleインストール

yumを使ってインストールする

# vagrant ssh node1
# sudo yum install epel-release
# sudo yum install ansible

2.管理対象ホストの設定とAnsibleの疎通確認

管理対象ホストの設定

$ echo 192.168.33.12 > hosts

pingでの疎通確認

node1の方で実行
$ ansible -i hosts 192.168.33.12 -m ping

192.168.33.12 | success >> {    
    "changed": false,    
    "ping": "pong"    
}    

ansibleコマンドで連携対象サーバ上で任意のコマンドを実行する

$ ansible -i hosts 192.168.33.12 -a 'uname -r'
192.168.33.12 | success | rc=0 >>
2.6.32-431.el6.x86_64

任意のコマンドを実行

ansible -i hosts 192.168.33.12 -m yum -s -a name=telnet

ansible yumは以下でドキュメントを確認できる

$ ansible-doc yum

3.Playbookの作成から実行まで

Playbookの作成

# vi simple-playbook

---
- hosts: test-servers
  become: yes
  tasks:
    - name: be sure httpd is installed
      yum: name=httpd state=installed

    - name: be sure httpd is running and enabled
      service: name=httpd state=started enabled=yes

Playbookの文法チェック

ansible-playbookに–syntax-checkのオプションをつけて実行する

ansible-playbook -i hosts simple-playbook.yml --syntax-check

Playbookのタスク一覧を確認する

–list-tasksオプションをつけてplyabookのnameを一覧表示してタスクを確認

[vagrant@localhost ~]$ ansible-playbook -i hosts simple-playbook.yml --list-tasks

playbook: simple-playbook.yml

  play #1 (test-servers): test-servers  TAGS: []
    tasks:
      be sure httpd is installed    TAGS: []
      be sure httpd is running and enabled  TAGS: []

Playbookの実行

[vagrant@localhost ~]$ ansible-playbook -i hosts simple-playbook.yml

PLAY [test-servers] ************************************************************

TASK [setup] *******************************************************************
ok: [192.168.33.12]

TASK [be sure httpd is installed] **********************************************
changed: [192.168.33.12]

TASK [be sure httpd is running and enabled] ************************************
changed: [192.168.33.12]

PLAY RECAP *********************************************************************
192.168.33.12              : ok=3    changed=2    unreachable=0    failed=0

ansibleには冪等星性(ある操作を何度実行しても常に結果が同じになる)が備わっており、上記実行例ではchangedの部分が新しく実行された部分になるようです。これでnode2のサーバにPlaybookで指定した通りapacheがインストールされました。
node2内でhttpdが動作しているか確認

[vagrant@localhost ~]$ sudo systemctl status httpd

たったこれだけで、Apacheがインストールできました。chefはほとんど触ったことありませんが、それよりもシンプルで使いやすい気がします。

Playbook入門

yumを使う

tasks:
  - name: be sure httpd is installed
    yum: name=httpd state=installed

nameでインストール対象を指定する。state=installedはインスートールされているか確認し、されていなかったらインストールする。state=latestでは最新が入っているか確認し最新でなければインストールする。

コマンドを実行する

tasks:
  - name: disable selinux
    command: /sbin/setenforce 0

ファイルを編集する

文字列を置換する

tasks:
  - name: set selinux permisive
    replace: >
      dest=/etc/selinux/config
      regexp='SELINUX=enforcing'
      replace='SELINUX=disabled'

http://docs.ansible.com/ansible/replace_module.html

ホスト端末のファイルを送る

事前に転送するファイルを準備

echo hogehoge > copyFile
tasks:
  - name: copy test
    copy: >
      src=/home/vagrant/copyFile
      dest=/home/vagrant/copyFile

http://docs.ansible.com/ansible/copy_module.html