PowerShell Gallery の Module の利用方法 (よく使うコマンド集)

完全な自分のためのメモ。

PowerShell Gallery の Module を探したり (Find)、持って来たり (Install)、使えるようにしたり (Import) といった、最低限おぼえておくべき、よく使うコマンドを列挙する。

PowerShell Gallery から希望する Module を探す場合

Find-Module | Where-Object { $_.Name -match "{search string}" }

探した Module で、利用可能な Version (すべて) を表示する場合

Find-Module -Name {module name} -AllVersions

見つけた Module をマシンに Install する (ローカルに持ってくる) 場合

Install-Module {module name}

特定の Version を決めうちで Install する場合

Install-Module {module name} -RequiredVersion {version}

マシンに Install 済の使用可能な Module の一覧を取得する場合

Get-Module -ListAvailable

Install された Module (つまり、その Module 内の Command) を使える状態にする場合
(ただし、Windows PowerShell のウィンドウを閉じてセッションを終了したら終わり。いつも使う場合は、毎回 Windows PowerShell 起動時に、このコマンドを実行すること。)

Import-Module {module name}

Import 済の有効な (使える) Module の一覧を取得する場合

Get-Module

その Module 内で使える Command (Cmdlet) の一覧を取得する場合

Get-Command -Module {module name}

利用可能な Command を文字列で絞り込む場合

Get-Command *{search string}* -Module {module name}

Module をマシンから Uninstall する場合

Uninstall-Module {module name}

ただし、上記は単一の Module だけを追加・削除するので注意。
例えば、Web PI などインストーラー経由で複数の Module をまとめてインストールするケースでは、[プログラムと機能] (programs and features) などから Uninstall するほうが良い。そうすると、Install 時に入れた関連する Module すべてを削除してくれるためだ。(例えば、Azure PowerShell など)

Advertisements

Azure で Docker Cluster を構成するさまざまな方法

ここでは、Azure を使ってマルチ インスタンスや Cluster を構成するさまざまな方法をまとめたい。(Swarm, Mesos, Kubernetes 自体の構成方法の話ではなく、Azure に構成する際の考え方。)
いろいろと使える情報 (サンプルの構成ファイルなど) もあるので、それらの紹介 (リンク) もあわせて以下に記載する。

Azure + Docker の超基本

クラスタの話をする前に、まず、Azure で Docker を使う場合の超基本的な話を整理しておく。(知らない人のために)

Azure 上で Docker を使う場合、ざっくり下記の 2 つが使える。
(この他に、Docker 社が提供している Docker Cloud、Mesosphere が提供している DCOS でも、Azure を正式サポートしているが、これらについては本投稿の対象外とする。)

  • 普通に Azure Virtual Machine (IaaS, VM) を立ち上げて Container を立てる方法
  • Azure Container Service (ACS) と呼ばれるコンテナのホスティングを管理するサービス型の Azure リソースを使って Container 作成と管理をおこなう方法。
    やや乱暴な説明だが、AWS, Google を使っている人は、Amazon EC2 Container Service (ECS), Google Container Engine (GCE) と同じ位置づけのいわゆる「サービス」型のホスティング環境と思えば良い。(内部的な話は後述)

前者の VM (Azure Virtual Machine) を使うケースについて、Azure Virtual Machine (IaaS 環境) に docker container を構成するには、直球で Virtual Machine に docker のダウンロード・インストールをおこなっても良いが、Azure の場合は、Virtual Machine Extension と呼ばれる「VM に対する追加の構成要素 (リソースの 1 つ)」を使って docker のインストールと構成が可能だ。(よって、Azure 上で Docker を扱う場合、この “Extension” という言葉は良く出てくることになる。)
この構成をおこなうには、大きく下記の 3 通りの方法がある。

まずもっとも一般的な方法として、Azure CLI (Command-line Interface) のコマンド ユーティリティ (Azure 専用のコマンド ユーティリティ) を使う方法がある。(Azure CLI の azure vm docker create コマンドですぐに構成できる。)

Azure CLI を使って Docker VM Extension を構成する方法 :
https://azure.microsoft.com/en-us/documentation/articles/virtual-machines-docker-with-xplat-cli/

VM + Docker の 2 番目の方法として、ARM (Azure Resource Manager) の Resource template と呼ばれる展開用の json ファイルを使って、Virtual Machine Extension を (json で) 記述する方法がある。
VM Extension にはさまざまな種類があるが、その 1 つとして Docker Extension と呼ばれるものがあるので、これを使えば簡単に構成できるようになっている。(なお、sh を実行するための VM Extension も用意されているので、この sh を使って Docker を構成する方法もある。)
展開をコード化して自動化したい場合にはすごく使える方法なので、上記 (コマンド ユーティリティ) で展開がうまくいったら、さいごに ARM の template としてコード化してみると良いだろう。(なお、このあと紹介する template を見る前に、最低限、ここで紹介している How-to 程度は理解できるようにしておいてほしい。)

Docker を構成した resource template の例 :
(下記の azuredeploy.json が開始点だ。以降も同様。。。)
https://github.com/Azure/azure-quickstart-templates/tree/master/docker-simple-on-ubuntu

抜粋すると以下のような感じだ。(ハイライト部分が DockerExtension)

. . .

{
  "apiVersion": "2015-06-15",
  "type": "Microsoft.Compute/virtualMachines",
  "name": "vmtest01",
  "location": "East US",
  . . . (途中省略)
},
{
  "type": "Microsoft.Compute/virtualMachines/extensions",
  "name": "testvm01/dockerex01",
  "apiVersion": "2015-06-15",
  "location": "East US",
  "dependsOn": [
    "Microsoft.Compute/virtualMachines/vmtest01"
  ],
  "properties": {
    "publisher": "Microsoft.Azure.Extensions",
    "type": "DockerExtension",
    "typeHandlerVersion": "1.0",
    "autoUpgradeMinorVersion": true,
    "settings": {}
  }
}

. . .

VM + Docker のおまけとして、docker 標準の client でも構成可能だ。
Azure の Docker サポートは MS が勝手に対応しているのではなく、Azure と Docker の双方が対応している形で、docker driver の 1 つとして azure がサポートされているからだ。上述の ARM のような “Azure かぶれ” な方法ではなく、オープンなツールやフレームワークなどから呼び出す場合は、この方法が使えるだろう。
(この具体的方法はここでは省略するが、下記ブログを参照してほしい。)

Docker client のみを使って Azure 上の Docker container を作成する例 :
https://blogs.msdn.microsoft.com/tsmatsuz/2015/10/08/azure-docker-machine-on-linux-from-pc-mac/

また、Azure Container Service (ACS) については、本投稿でテーマとしている「Cluster」の話と大きく関連しているので後述する。

Compose

まずは、IaaS v2 (Azure Virtual Machine) を使った構成を中心に整理しよう。

最初に、クラスタ (Cluster) ではなく、単なるマルチインスタンス (複数台) 構成の話だが、Azure では docker compose も柔軟に扱えるようになっている。

Azure の ARM (Azure Resource Manager) template の場合は、上述の Docker Extension で Compose の記述がサポートされていて、下記の通り ARM template の json に混ぜて構成が可能だ。(なお、コマンドを使った場合は「Azure VM Docker Compose Quickstart」で記載しているように普通に Compose を構成するだけ。)

Docker Compose を使って WordPress と MySQL を構成する template の例 :
https://github.com/Azure/azure-quickstart-templates/tree/master/docker-wordpress-mysql

抜粋すると以下のような感じだ。

. . .
{
  "apiVersion": "2015-06-15",
  "type": "Microsoft.Compute/virtualMachines",
  "name": "testvm01",
  "location": "East US",
  . . .
},
{
  "type": "Microsoft.Compute/virtualMachines/extensions",
  "name": "testvm01/dockerex01",
  "apiVersion": "2015-06-15",
  "location": "East US",
  "dependsOn": [
    "Microsoft.Compute/virtualMachines/rtestvm01"
  ],
  "properties": {
    "publisher": "Microsoft.Azure.Extensions",
    "type": "DockerExtension",
    "typeHandlerVersion": "1.0",
    "autoUpgradeMinorVersion": true,
    . . .
    "settings": {
      "compose": {
        "db": {
          "image": "mysql",
          "ports": [
            "3306:3306"
          ],
          "volumes": [
            "/var/lib/mysql:/var/lib/mysql"
          ],
          "environment": [
            "MYSQL_ROOT_PASSWORD"
          ]
        },
        "wordpress": {
          "image": "wordpress",
          "ports": [
            "80:80"
          ],
          "links": [
            "db:mysql"
          ]
        }
      }
    }
  }
}
. . .

Docker Compose の scale コマンドで、起動する container の数も柔軟に制御できる。

分散クラスタ

Production を考える場合、単に複数のコンテナが起動していれば良いというわけではない。
複数の物理マシンに点在する複数のコンテナを柔軟に管理するために、Swarm、Mesos などのオーケストレーション エンジンを使うのが一般的だ。

Azure VM (IaaS v2) を使って Docker + Swarm, Mesos, Marathon 等で分散クラスタを構成する場合は、専用の Extension はないので、上述の Compose を使うか、sh の実行をおこなうことになる。(コマンドの場合の例は「Azure Virtual Machine : How to use docker with swarm」参照。)

例えば、下記は、ARM (Azure Resource Manager) template で、上述した Compose を使って Swarm をインストールしている例だ。

Docker Compose と使って Swarm を構成する template の例 :
https://github.com/Azure/azure-quickstart-templates/tree/master/docker-swarm-cluster

Azure VM Extension には Linux の sh を実行する Extension (CustomScriptForLinux Extension) もあるので、Compose を使わずにすべて sh だけで構成する方法もある。
例えば、下記は mesos, zookeeper 等も含む構成を sh で記述しているが (適宜パラメータ化をおこなっている)、こうした sh を CustomScriptForLinux Extension を使って実行すれば良い。(下記では docker 自体も sh でインストールしている。)

#!/bin/bash

###########################################################
# Configure Mesos One Box
#
# This installs the following components
# - zookeepr
# - mesos master
# - marathon
# - mesos agent
###########################################################

set -x

echo "starting mesos cluster configuration"
date
ps ax

SWARM_VERSION="1.0.0-rc2"

#############
# Parameters
#############

MASTERCOUNT=$1
MASTERMODE=$2
MASTERPREFIX=$3
SWARMENABLED=$4
MARATHONENABLED=$5
CHRONOSENABLED=$6
ACCOUNTNAME=$7
set +x
ACCOUNTKEY=$8
set -x
AZUREUSER=$9
SSHKEY=${10}
HOMEDIR="/home/$AZUREUSER"
VMNAME=`hostname`
VMNUMBER=`echo $VMNAME | sed 's/.*[^0-9]\([0-9]\+\)*$/\1/'`
VMPREFIX=`echo $VMNAME | sed 's/\(.*[^0-9]\)*[0-9]\+$/\1/'`

echo "Master Count: $MASTERCOUNT"
echo "Master Mode: $MASTERMODE"
echo "Master Prefix: $MASTERPREFIX"
echo "vmname: $VMNAME"
echo "VMNUMBER: $VMNUMBER, VMPREFIX: $VMPREFIX"
echo "SWARMENABLED: $SWARMENABLED, MARATHONENABLED: $MARATHONENABLED, CHRONOSENABLED: $CHRONOSENABLED"
echo "ACCOUNTNAME: $ACCOUNTNAME"

###################
# setup ssh access
###################

SSHDIR=$HOMEDIR/.ssh
AUTHFILE=$SSHDIR/authorized_keys
if [ `echo $SSHKEY | sed 's/^\(ssh-rsa \).*/\1/'` == "ssh-rsa" ] ; then
  if [ ! -d $SSHDIR ] ; then
    sudo -i -u $AZUREUSER mkdir $SSHDIR
    sudo -i -u $AZUREUSER chmod 700 $SSHDIR
  fi

  if [ ! -e $AUTHFILE ] ; then
    sudo -i -u $AZUREUSER touch $AUTHFILE
    sudo -i -u $AZUREUSER chmod 600 $AUTHFILE
  fi
  echo $SSHKEY | sudo -i -u $AZUREUSER tee -a $AUTHFILE
else
  echo "no valid key data"
fi

###################
# Common Functions
###################

ensureAzureNetwork()
{
  # ensure the host name is resolvable
  hostResolveHealthy=1
  for i in {1..120}; do
    host $VMNAME
    if [ $? -eq 0 ]
    then
      # hostname has been found continue
      hostResolveHealthy=0
      echo "the host name resolves"
      break
    fi
    sleep 1
  done
  if [ $hostResolveHealthy -ne 0 ]
  then
    echo "host name does not resolve, aborting install"
    exit 1
  fi

  # ensure the network works
  networkHealthy=1
  for i in {1..12}; do
    wget -O/dev/null http://bing.com
    if [ $? -eq 0 ]
    then
      # hostname has been found continue
      networkHealthy=0
      echo "the network is healthy"
      break
    fi
    sleep 10
  done
  if [ $networkHealthy -ne 0 ]
  then
    echo "the network is not healthy, aborting install"
    ifconfig
    ip a
    exit 2
  fi
  # ensure the host ip can resolve
  networkHealthy=1
  for i in {1..120}; do
    hostname -i
    if [ $? -eq 0 ]
    then
      # hostname has been found continue
      networkHealthy=0
      echo "the network is healthy"
      break
    fi
    sleep 1
  done
  if [ $networkHealthy -ne 0 ]
  then
    echo "the network is not healthy, cannot resolve ip address, aborting install"
    ifconfig
    ip a
    exit 2
  fi
}
ensureAzureNetwork
HOSTADDR=`hostname -i`

ismaster ()
{
  if [ "$MASTERPREFIX" == "$VMPREFIX" ]
  then
    return 0
  else
    return 1
  fi
}
if ismaster ; then
  echo "this node is a master"
fi

isagent()
{
  if ismaster ; then
    if [ "$MASTERMODE" == "masters-are-agents" ]
    then
      return 0
    else
      return 1
    fi
  else
    return 0
  fi
}
if isagent ; then
  echo "this node is an agent"
fi

zkhosts()
{
  zkhosts=""
  for i in `seq 1 $MASTERCOUNT` ;
  do
    if [ "$i" -gt "1" ]
    then
      zkhosts="${zkhosts},"
    fi

    IPADDR=`getent hosts ${MASTERPREFIX}${i} | awk '{ print $1 }'`
    zkhosts="${zkhosts}${IPADDR}:2181"
    # due to mesos team experience ip addresses are chosen over dns names
    #zkhosts="${zkhosts}${MASTERPREFIX}${i}:2181"
  done
  echo $zkhosts
}

zkconfig()
{
  postfix="$1"
  zkhosts=$(zkhosts)
  zkconfigstr="zk://${zkhosts}/${postfix}"
  echo $zkconfigstr
}

######################
# resolve self in DNS
######################

echo "$HOSTADDR $VMNAME" | sudo tee -a /etc/hosts

################
# Install Docker
################

echo "Installing and configuring docker and swarm"

time wget -qO- https://get.docker.com | sh

# Start Docker and listen on :2375 (no auth, but in vnet)
echo 'DOCKER_OPTS="-H unix:///var/run/docker.sock -H 0.0.0.0:2375"' | sudo tee /etc/default/docker
# the following insecure registry is for OMS
echo 'DOCKER_OPTS="$DOCKER_OPTS --insecure-registry 137.135.93.9"' | sudo tee -a /etc/default/docker
sudo service docker restart

ensureDocker()
{
  # ensure that docker is healthy
  dockerHealthy=1
  for i in {1..3}; do
    sudo docker info
    if [ $? -eq 0 ]
    then
      # hostname has been found continue
      dockerHealthy=0
      echo "Docker is healthy"
      sudo docker ps -a
      break
    fi
    sleep 10
  done
  if [ $dockerHealthy -ne 0 ]
  then
    echo "Docker is not healthy"
  fi
}
ensureDocker

############
# setup OMS
############

if [ $ACCOUNTNAME != "none" ]
then
  set +x
  EPSTRING="DefaultEndpointsProtocol=https;AccountName=${ACCOUNTNAME};AccountKey=${ACCOUNTKEY}"
  docker run --restart=always -d 137.135.93.9/msdockeragentv3 http://${VMNAME}:2375 "${EPSTRING}"
  set -x
fi

##################
# Install Mesos
##################

sudo apt-key adv --keyserver keyserver.ubuntu.com --recv E56151BF
DISTRO=$(lsb_release -is | tr '[:upper:]' '[:lower:]')
CODENAME=$(lsb_release -cs)
echo "deb http://repos.mesosphere.io/${DISTRO} ${CODENAME} main" | sudo tee /etc/apt/sources.list.d/mesosphere.list
time sudo add-apt-repository -y ppa:openjdk-r/ppa
time sudo apt-get -y update
time sudo apt-get -y install openjdk-8-jre-headless
if ismaster ; then
  time sudo apt-get -y --force-yes install mesosphere
else
  time sudo apt-get -y --force-yes install mesos
fi

#########################
# Configure ZooKeeper
#########################

zkmesosconfig=$(zkconfig "mesos")
echo $zkmesosconfig | sudo tee /etc/mesos/zk

if ismaster ; then
  echo $VMNUMBER | sudo tee /etc/zookeeper/conf/myid
  for i in `seq 1 $MASTERCOUNT` ;
  do
    IPADDR=`getent hosts ${MASTERPREFIX}${i} | awk '{ print $1 }'`
    echo "server.${i}=${IPADDR}:2888:3888" | sudo tee -a /etc/zookeeper/conf/zoo.cfg
    # due to mesos team experience ip addresses are chosen over dns names
    #echo "server.${i}=${MASTERPREFIX}${i}:2888:3888" | sudo tee -a /etc/zookeeper/conf/zoo.cfg
  done
fi

#########################################
# Configure Mesos Master and Frameworks
#########################################
if ismaster ; then
  quorum=`expr $MASTERCOUNT / 2 + 1`
  echo $quorum | sudo tee /etc/mesos-master/quorum
  hostname -i | sudo tee /etc/mesos-master/ip
  hostname | sudo tee /etc/mesos-master/hostname
  echo 'Mesos Cluster on Microsoft Azure' | sudo tee /etc/mesos-master/cluster
fi

if ismaster  && [ "$MARATHONENABLED" == "true" ] ; then
  # setup marathon
  sudo mkdir -p /etc/marathon/conf
  sudo cp /etc/mesos-master/hostname /etc/marathon/conf
  sudo cp /etc/mesos/zk /etc/marathon/conf/master
  zkmarathonconfig=$(zkconfig "marathon")
  echo $zkmarathonconfig | sudo tee /etc/marathon/conf/zk
  # enable marathon to failover tasks to other nodes immediately
  echo 0 | sudo tee /etc/marathon/conf/failover_timeout
  #echo false | sudo tee /etc/marathon/conf/checkpoint
fi

#########################################
# Configure Mesos Master and Frameworks
#########################################
if ismaster ; then
  # Download and install mesos-dns
  sudo mkdir -p /usr/local/mesos-dns
  sudo wget https://github.com/mesosphere/mesos-dns/releases/download/v0.2.0/mesos-dns-v0.2.0-linux-amd64.tgz
  sudo tar zxvf mesos-dns-v0.2.0-linux-amd64.tgz
  sudo mv mesos-dns-v0.2.0-linux-amd64 /usr/local/mesos-dns/mesos-dns
  RESOLVER=`cat /etc/resolv.conf | grep nameserver | tail -n 1 | awk '{print $2}'`

  echo "
{
  \"zk\": \"zk://127.0.0.1:2181/mesos\",
  \"refreshSeconds\": 1,
  \"ttl\": 0,
  \"domain\": \"mesos\",
  \"port\": 53,
  \"timeout\": 1,
  \"listener\": \"0.0.0.0\",
  \"email\": \"root.mesos-dns.mesos\",
  \"resolvers\": [\"$RESOLVER\"]
}
" > mesos-dns.json
  sudo mv mesos-dns.json /usr/local/mesos-dns/mesos-dns.json

  echo "
description \"mesos dns\"
# Start just after the System-V jobs (rc) to ensure networking and zookeeper
# are started. This is as simple as possible to ensure compatibility with
# Ubuntu, Debian, CentOS, and RHEL distros. See:
# http://upstart.ubuntu.com/cookbook/#standard-idioms
start on stopped rc RUNLEVEL=[2345]
respawn
exec /usr/local/mesos-dns/mesos-dns -config /usr/local/mesos-dns/mesos-dns.json" > mesos-dns.conf
  sudo mv mesos-dns.conf /etc/init
  sudo service mesos-dns start
fi


#########################
# Configure Mesos Agent
#########################
if isagent ; then
  # Add docker containerizer
  echo "docker,mesos" | sudo tee /etc/mesos-slave/containerizers
  # Add resources configuration
  if ismaster ; then
    echo "ports:[1-21,23-4399,4401-5049,5052-8079,8081-32000]" | sudo tee /etc/mesos-slave/resources
  else
    echo "ports:[1-21,23-5050,5052-32000]" | sudo tee /etc/mesos-slave/resources
  fi
  hostname -i | sudo tee /etc/mesos-slave/ip
  hostname | sudo tee /etc/mesos-slave/hostname

  # Add mesos-dns IP addresses at the top of resolv.conf
  RESOLV_TMP=resolv.conf.temp
  rm -f $RESOLV_TMP
  for i in `seq $MASTERCOUNT` ; do
      echo nameserver `getent hosts ${MASTERPREFIX}${i} | awk '{ print $1 }'` >> $RESOLV_TMP
  done

  cat /etc/resolv.conf >> $RESOLV_TMP
  mv $RESOLV_TMP /etc/resolv.conf
fi

##############################################
# configure init rules restart all processes
##############################################

echo "(re)starting mesos and framework processes"
if ismaster ; then
  sudo service zookeeper restart
  sudo service mesos-master start
  if [ "$MARATHONENABLED" == "true" ] ; then
    sudo service marathon start
  fi
  if [ "$CHRONOSENABLED" == "true" ] ; then
    sudo service chronos start
  fi
else
  echo manual | sudo tee /etc/init/zookeeper.override
  sudo service zookeeper stop
  echo manual | sudo tee /etc/init/mesos-master.override
  sudo service mesos-master stop
fi

if isagent ; then
  echo "starting mesos-slave"
  sudo service mesos-slave start
  echo "completed starting mesos-slave with code $?"
else
  echo manual | sudo tee /etc/init/mesos-slave.override
  sudo service mesos-slave stop
fi

echo "processes after restarting mesos"
ps ax

# Run swarm manager container on port 2376 (no auth)
if ismaster && [ "$SWARMENABLED" == "true" ] ; then
  echo "starting docker swarm:$SWARM_VERSION"
  echo "sleep to give master time to come up"
  sleep 10
  echo sudo docker run -d -e SWARM_MESOS_USER=root \
      --restart=always \
      -p 2376:2375 -p 3375:3375 swarm:$SWARM_VERSION manage \
      -c mesos-experimental \
      --cluster-opt mesos.address=0.0.0.0 \
      --cluster-opt mesos.port=3375 $zkmesosconfig
  sudo docker run -d -e SWARM_MESOS_USER=root \
      --restart=always \
      -p 2376:2375 -p 3375:3375 swarm:$SWARM_VERSION manage \
      -c mesos-experimental \
      --cluster-opt mesos.address=0.0.0.0 \
      --cluster-opt mesos.port=3375 $zkmesosconfig
  sudo docker ps
  echo "completed starting docker swarm"
fi
echo "processes at end of script"
ps ax
echo "Finished installing and configuring docker and swarm"
date
echo "completed mesos cluster configuration"

Kubernetes

上記では技術計算等で扱う大規模分散構成のようなクラスタを想定したが、例えば、同一構成の展開・管理では Kubernetes クラスタと組み合わせた Scaling も組み合わせたくなるだろう。(通常、Azure Virtual Machine で Web や AP の負荷分散をおこなう場合には Azure 標準の Load Balancer リソースが使えるが、ここに Docker が入ってきた場合には話が変わってくる。)
この場合も上記と同じ話で、compose か sh で書いて展開することになる。

なお、残念ながら Azure Quickstart Templates にこのサンプルはあがっていないが、下記の Kubernetes の Github に Azure の場合の構成方法について書かれているので、これを参考にスクリプト化などしてほしい。

[Kubernetes on Azure] Start Guide :
https://github.com/kubernetes/kubernetes/blob/release-1.1/docs/getting-started-guides/coreos/azure/README.md

Azure Container Service (ACS)

※ 以降、2016/02/18 追記

冒頭で述べた Azure Container Service (ACS) を使うと、自身で明示的に VM を立てずに Service のクラスタを立ち上げて管理できる。Swarm、Apache Mesos、さらに Marathon などに対応しているので、上述の分散クラスタを扱う場合にもって来いなサービスだ。(むしろ、クラスタを立てずに使うようなシンプルな使い方はできない。)

現在、下記の ARM template を使ってクラスタ (サービス インスタンス) を配置 (作成) するが、内部では結果的に、Virtual Machine Scale Sets (VM Scale Sets) や Load Balancer のリソース が起動している。(利用者にとって単一のサービス インスタンスとして管理できるだけで、実際には VM などの IaaS 環境が使われているということ。ECS 同様、GCE のような Full Managed なサービスではない。)
Amazon EC2 Container Service (ECS)、Google Container Engine (GCE) 同様、今後は Auto Scale に対応しようということだろう。

Mesos による ACS (Azure Container Service) クラスタの配置
https://github.com/Azure/azure-quickstart-templates/tree/master/acs-mesos

Swarm による ACS (Azure Container Service) クラスタの配置
https://github.com/Azure/azure-quickstart-templates/tree/master/acs-swarm

クラスタを作成した後は、Mesos UI などの標準のツールで管理できるという点は相当 魅力的だ。いったん配置してしまえば、Apache Mesos、Swarm の利用者にとって説明の必要はないだろう。(ただし、プログラムから管理する場合は、ACS が提供する REST API も使用可能。)

Red Hat を Microsoft Azure (IaaS v2) で動かす

[2016/02/18 追記] Red Hat Enterprise が Azure Marketplace (Gallery) から選択可能になったので、今後はこれを使用できます ! (以下の投稿は、Red Hat の Repository から Image を持ち込んで使う方法を記載)

azure_redhat

Red Hat Enterprise が Microsoft Azure にようやく対応したが、Azure Resource Manager (ARM) ベースの仮想マシンで動かす方法に悩んだのでメモしておく。(いま動かすなら、当然、v2 で動かしたい。)

なお、下記の細かなコマンドの中身などは、概ね、「Prepare a Red Hat-based Virtual Machine for Azure」に記載されているので、ここではどのようなことするかステップややっていることを述べておく。

まず必ず最初にハマるポイントだが、現在、Azure Marketplace (Gallery) に Red Hat のイメージはない。(今後提供される予定のようだが、少なくとも 2016 年 01 月時点では。。。)
後述する Document や Channel 9 (動画) で紹介されているが、自分で image を取得して構成し、Azure 上に展開する必要がある。

下記は、Linux の Host (Client) から作業している想定で記載する。

  1. Red Hat Enterprise のイメージを取得する
    (例えば、https://access.redhat.com/ から KVM Guest Image などを取得すると良い)
  2. 上記で取得した Red Hat の Virtual Machine (image) を起動して接続 (ログイン) する。
  3. まず、構成ファイルなどを編集して Network 関連の構成をおこなう。
    詳細は「Prepare a Red Hat-based Virtual Machine for Azure」に書かれているので参考にしてほしい。
  4. 下記の手順で Azure Linux VM Agent (WALinuxAgent) のインストールをおこなう。
    1. そのために、まず Package のインストールができるよう、Red Hat Enterprise を Subscribe しておく
      (sudo subscription-manager register)
    2. EPEL Repository の取得と有効化をおこなう
    3. Azure Linux VM Agent (WALinuxAgent) をインストールする (yum コマンド)
    4. Red Hat Enterprise を UnSubscribe する
      (sudo subscription-manager unregister)
  5. インストールした Azure Linux VM Agent を使って Generalize (Azure の展開に備えた Clean-up) を実行
    (sudo waagent -force -deprovision)
  6. Virtual Machine を shutdown する
  7. 上記で作成されたマシン イメージ ( .raw .qcow2 .vmdk など) を qemu-img コマンドを使って .vhd ファイルに変換する (qemu-img コマンドの -O オプションに vpc と指定する)。
    ただし、Azure に展開する vhd の Virtual Size は 1 MB で Round されている必要があるので要注意。.qcow2 などの場合、いったん .raw に変換した後で、qemu-img resize コマンドで 1 MB 単位に Round して、そのあとで .vhd に変換する。(Hyper-V などで作ったイメージの Virtual Size は必ず Round されているが、Linux 上の VM はそうとは限らない。)
  8. Azure CLI や Azure Resource Manager (ARM) の template を使って、上記のカスタム イメージ (vhd ファイル) を Azure に配置し、ARM ベースの Virtual Machine (VM v2) を作成する。
    この具体的手順や注意点は「Azure Resource Manager の template の How-to」の「custom image の利用」に書かれているようなので参考。(上記のように作成した vhd を、この方法で展開することが可能。)
  9. さいごに、展開された Red Hat Enterprise の VM (v2 image) にログインして Subscribe
    (sudo subscription-manager register)

結論を書くと、 上記の 8 以外 (上記の 1 – 7, 9) はドキュメントや Channel9 でも紹介されている内容と同じ。要は、作った .vhd を ただ ARM Base で展開すれば良いということのようだ。

 

※ 参考情報

Document : Prepare a Red Hat-based Virtual Machine for Azure

Channel9 : Uploading a Red Hat Enterprise Linux (RHEL) 7.1 image to Microsoft Azure

 

Office Add-ins の add-in command (カスタム Ribbon ボタン)

de:code 2015 の「Office 開発/Office 365 開発の新機能紹介」でもデモしていたアドイン コマンド (リボン コマンド) が、まずは Outlook の Mail Add-in で試せるようになったので紹介したい。

追記 : Office Add-in Command は、Excel Add-in、Word Add-in、PowerPoint Add-in でも可能になった。Outlook 以外で追加した場合、「個人用アドイン」(My Add-in) に登録されている間、常にアプリ (Excel、Word、PowerPoint) に表示される。(ドキュメント単位ではなく、アプリ単位の挿入。)
PowerPoint Add-in の “Pickit Presentation Images” などで確認できるので、是非試してみてほしい。

平たく書くと、Office Add-ins の Mail Add-ins (Mail Add-in for Outlook) で下図のような ribbon command (ボタンを押すと実行できる処理) が使えるようになったというもので、動作させるには、今のところ Windows 版の Outlook 2016 (現在 Preview) が必要だ。(いずれ Outlook Web App やその他の Native の Outlook などでも対応されるだろう。)

addin_command

これまでの Mail Add-ins では、一度、Taskpane などの形で何某かの Window (Pane) を表示して、そこに必要なボタンなどのコントロールを配置してアプリを作るしかなかったが、こうした Window (Pane) が不要なストレートな処理は、今後は上述の Add-in Command を使って作ることが可能だ。

Manifest の記述方法

今回の新機能では、Manifest (Office Add-ins で作成する .xml ファイル) の記述も大幅に拡張されているが、Office Add-ins (および、JavaScript Library) 自体のバージョンがあがるわけではなく、既存のバージョンの拡張として実装されているらしく、上述の通り、この機能が使えないプラットフォームもあるという点に注意が必要だ。例えば、Outlook 2013 から使用した際に、不明な XML 要素によりエラーが発生するようなケースは避ける必要がある。

そこで、Manifest 作成のアプローチとして、そのまま Add-in Command 用の記述を入れるのではなく、いったん過去のプラットフォーム互換な Manifest を作成し、新しいプラットフォーム (Outlook 2016 など) で使用された場合には、その内容を override するというアプローチで Manifest を記述する。

この際 必要になるのが、VersionOverrides 要素だ。
Manifest には下記の通り記述し、この VersionOverrides の中に Add-in Command 用の設定を書いていく。(この中身は、このあと作成する。)

<?xml version="1.0" encoding="UTF-8"?>
<OfficeApp
  xmlns="http://schemas.microsoft.com/office/appforoffice/1.1"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:bt="http://schemas.microsoft.com/office/officeappbasictypes/1.0"
  xmlns:mailappor="http://schemas.microsoft.com/office/mailappversionoverrides"
  xsi:type="MailApp">
  <Id>{9AADFD5D-49A0-47C8-897F-1BB59D5116B5}</Id>
  <Version>1.0</Version>
  <ProviderName>Microsoft</ProviderName>
  <DefaultLocale>en-us</DefaultLocale>
  <DisplayName DefaultValue="My App Test"></DisplayName>
  <Description DefaultValue="This is a test"></Description>
  <Requirements>
    <Sets DefaultMinVersion="1.1">
      <Set Name="Mailbox" />
    </Sets>
  </Requirements>
  <FormSettings>
    <Form xsi:type="ItemRead">
      <DesktopSettings>
        <SourceLocation
          DefaultValue="https://addintest01.azurewebsites.net/app1.html" >
        </SourceLocation>
        <RequestedHeight>150</RequestedHeight>
      </DesktopSettings>
    </Form>
    <Form xsi:type="ItemEdit">
      <DesktopSettings>
        <SourceLocation
          DefaultValue="https://addintest01.azurewebsites.net/app2.html" >
        </SourceLocation>
      </DesktopSettings>
    </Form>
  </FormSettings>
  <Permissions>ReadWriteItem</Permissions>
  <Rule xsi:type="RuleCollection" Mode="Or">
    <Rule xsi:type="ItemIs"
      ItemType="Message"
      FormType="Edit" />
    <Rule xsi:type="ItemIs"
      ItemType="Appointment"
      FormType="Edit" />
  </Rule>
  <DisableEntityHighlighting>true</DisableEntityHighlighting>
  <VersionOverrides
    xmlns="http://schemas.microsoft.com/office/mailappversionoverrides"
    xsi:type="VersionOverridesV1_0">
    <!-- we will write here later -->
  </VersionOverrides>
</OfficeApp>

例えば、ボタンを押したら、ある JavaScript 関数を実行する場合は、以下の通りプログラミングする。

まず、下記の JavaScript 関数を含む html ファイルをどこかインターネット上の見える場所に配置しておく。(今回、これを myfunc.html という名前で公開する。)
なお、下記では単にメールの返信画面を起動しているが、JavaScript API for Office の Mail 関連の API では、アイテム変更 (Compose の際)、EWS の呼び出しなど多くのことが可能なので、COM アドインに匹敵する細かな処理を記述することが可能だ。

<meta http-equiv="X-UA-Compatible" content="IE=9" >
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
  <title>My Test Page</title>
  <script type="text/javascript"
    src="https://appsforoffice.microsoft.com/lib/1.1/hosted/office.debug.js">
  </script>
  <script type="text/javascript">
  Office.initialize = function (reason) 
  {
    //// you can initialize here
    //_Om = Office.context.mailbox;
    //_Item = _Om.item;
    //_UserProfile = _Om.userProfile;
  }

  function showTest(event)
  {
    //// if you need source control, do below
    //var buttonId = event.source.id;

    // if in compose, displayReplyForm does not work ...
    Office.context.mailbox.item.displayReplyForm('reply test !');
	
    //// when compose mode, you can do below
    //
    //_Item.setSubjectAsync('Hello World!');
    //
    //Office.context.mailbox.item.body.prependAsync(
    //  'test!',
    //  {
    //    coercionType: Office.CoercionType.Text,
    //    asyncContext: { ... }
    //  },
    //  function(asyncResult) {
    //    event.completed(true);
    //  });
    
    event.completed();
  }
  </script>
</head>
<body>
</body>
</html>

そして、前述の Manifest 内の VersionOverrides に以下の通り記述する。
ここでは、Ribbon Button を配置し、このボタンが押された際に、上記の関数 showTest を呼び出している。

<VersionOverrides
  xmlns="http://schemas.microsoft.com/office/mailappversionoverrides"
  xsi:type="VersionOverridesV1_0">

  <Description resid="residDesc" />

  <Requirements>
    <bt:Sets DefaultMinVersion="1.3">
      <bt:Set Name="Mailbox" />
    </bt:Sets>
  </Requirements>

  <Hosts>
    <Host xsi:type="MailHost">

      <DesktopFormFactor>
        <FunctionFile resid="residFuncUrl" />

        <ExtensionPoint xsi:type="MessageReadCommandSurface">
          <OfficeTab id="TabDefault">
            <Group id="msgreadTabMessage.grp1">
              <Label resid="residLabel" />
              <Tooltip resid="residLabelTip" />
 
              <Control xsi:type="Button" id="button1id">
                <Label resid="residUILessButton" />
                <Tooltip resid="residTip" />
                <Supertip>
                  <Title resid="residSuperTipTitle" />
                  <Description resid="residSuperTipDesc" />
                </Supertip>
                <Icon>
                  <bt:Image size="16" resid="icon1" />
                  <bt:Image size="32" resid="icon2" />
                  <bt:Image size="80" resid="icon3" />
                </Icon>
                <Action xsi:type="ExecuteFunction">
                  <FunctionName>showTest</FunctionName>
                </Action>
              </Control>

            </Group>
          </OfficeTab>
        </ExtensionPoint>
      </DesktopFormFactor>
    </Host>
  </Hosts>

  <Resources>
    <bt:Images>
      <bt:Image id="icon1"
        DefaultValue="https://addintest01.azurewebsites.net/myimg16.bmp" >
      </bt:Image>
      <bt:Image id="icon2"
        DefaultValue="https://addintest01.azurewebsites.net/myimg32.bmp" >
      </bt:Image>
      <bt:Image id="icon3"
        DefaultValue="https://addintest01.azurewebsites.net/myimg80.bmp">
      </bt:Image>
    </bt:Images>
    <bt:Urls>
      <bt:Url id="residFuncUrl"
        DefaultValue="https://addintest01.azurewebsites.net/myfunc.html" >
      </bt:Url>
    </bt:Urls>
    <bt:ShortStrings>
      <bt:String id="residLabel"
        DefaultValue="Test App">
      </bt:String>
      <bt:String id="residUILessButton"
        DefaultValue="Do Func">
      </bt:String>
      <bt:String id="residSuperTipTitle"
        DefaultValue="SuperTip Title">
      </bt:String>
    </bt:ShortStrings>
    <bt:LongStrings>
      <bt:String id="residDesc"
        DefaultValue="This is an add-in test.">
      </bt:String>
      <bt:String id="residLabelTip"
        DefaultValue="This is an add-in test.">
      </bt:String>
      <bt:String id="residTip"
        DefaultValue="Run Test app">
      </bt:String>
      <bt:String id="residSuperTipDesc"
        DefaultValue="Run Test App">
      </bt:String>
    </bt:LongStrings>
  </Resources>

</VersionOverrides>

この Add-in を登録して Outlook 2016 で開くと、下図の通り、Mail の Read の際に Custom の Button が表示される。

execute01

このボタンをクリックすると、下図の通り、選択したメールの Reply 画面が起動する。

mail_popup

ExtensionPoint の type に指定している MessageReadCommandSurface は、「Mail の Read の画面にボタンを配置」という意味だ。ここに別の type を指定することで、Compose (メール作成・変更) の画面にボタンを配置したり、予定 (Appointment) の作成や閲覧の画面にボタンを配置することが可能だ。
また、command button ではなく、従来通りの custom pane を配置する場合、今後は、この type に CustomPane と指定して内容を記述できるようになっている。(過去のバージョンにも対応させる場合は、上述のような VersionOverrides の外の定義と、この定義の両方を書いておく必要があるだろう。)

また、Action の type に注目してほしい。
上記では ExecuteFunction を指定しているが、ここに下記の通り ShowTaskpane と指定すると、ボタンを押した際に Taskpane を表示させることが可能だ。

<VersionOverrides
  xmlns="http://schemas.microsoft.com/office/mailappversionoverrides"
  xsi:type="VersionOverridesV1_0">

  <!-- skip here ... (same as above) -->

  <Hosts>
    <Host xsi:type="MailHost">

      <DesktopFormFactor>
        <FunctionFile resid="residFuncUrl" />

        <ExtensionPoint xsi:type="MessageReadCommandSurface">
          <OfficeTab id="TabDefault">
            <Group id="msgreadTabMessage.grp1">
              <Label resid="residLabel" />
              <Tooltip resid="residLabelTip" />
 
              <Control xsi:type="Button" id="button1id">
                <Label resid="residUILessButton" />
                <Tooltip resid="residTip" />
                <Supertip>
                  <Title resid="residSuperTipTitle" />
                  <Description resid="residSuperTipDesc" />
                </Supertip>
                <Icon>
                  <bt:Image size="16" resid="icon1" />
                  <bt:Image size="32" resid="icon2" />
                  <bt:Image size="80" resid="icon3" />
                </Icon>
                <Action xsi:type="ExecuteFunction">
                  <FunctionName>showTest</FunctionName>
                </Action>
              </Control>

              <Control xsi:type="Button" id="button2id">
                <Label resid="residTaskpaneButton" />
                <Tooltip resid="residTip" />
                <Supertip>
                  <Title resid="residSuperTipTitle" />
                  <Description resid="residSuperTipDesc" />
                </Supertip>
                <Icon>
                  <bt:Image size="16" resid="icon1" />
                  <bt:Image size="32" resid="icon2" />
                  <bt:Image size="80" resid="icon3" />
                </Icon>
	              <Action xsi:type="ShowTaskpane">
	                <SourceLocation resid="residTaskpaneUrl" />
	              </Action>
              </Control>
              
            </Group>
          </OfficeTab>
        </ExtensionPoint>
      </DesktopFormFactor>
    </Host>
  </Hosts>

  <Resources>
    <bt:Images>
      <bt:Image id="icon1"
        DefaultValue="https://addintest01.azurewebsites.net/myimg16.bmp" >
      </bt:Image>
      <bt:Image id="icon2"
        DefaultValue="https://addintest01.azurewebsites.net/myimg32.bmp" >
      </bt:Image>
      <bt:Image id="icon3"
        DefaultValue="https://addintest01.azurewebsites.net/myimg80.bmp">
      </bt:Image>
    </bt:Images>
    <bt:Urls>
      <bt:Url id="residFuncUrl"
        DefaultValue="https://addintest01.azurewebsites.net/myfunc.html" >
      </bt:Url>
      <bt:Url id="residTaskpaneUrl"
        DefaultValue="https://addintest01.azurewebsites.net/mypane.html" >
      </bt:Url>
    </bt:Urls>
    <bt:ShortStrings>
      <bt:String id="residLabel"
        DefaultValue="Test App">
      </bt:String>
      <bt:String id="residUILessButton"
        DefaultValue="Do Func">
      </bt:String>
      <bt:String id="residTaskpaneButton"
        DefaultValue="Show Pane">
      </bt:String>
      <bt:String id="residSuperTipTitle"
        DefaultValue="SuperTip Title">
      </bt:String>
    </bt:ShortStrings>
    <bt:LongStrings>
      <bt:String id="residDesc"
        DefaultValue="This is an add-in test.">
      </bt:String>
      <bt:String id="residLabelTip"
        DefaultValue="This is an add-in test.">
      </bt:String>
      <bt:String id="residTip"
        DefaultValue="Run Test app">
      </bt:String>
      <bt:String id="residSuperTipDesc"
        DefaultValue="Run Test App">
      </bt:String>
    </bt:LongStrings>
  </Resources>

</VersionOverrides>

[Show Pane] ボタンを押すと、下図の通り、指定した Url のページが Pane として表示される。
もちろん、この Web ページに、これまでの Mail Add-in のように、メールや予定と連携して動作する何某かの処理 (JavaScript) を埋め込んで使うことが可能だ。

execute02

最終的に作成した Manifest のサンプルを以下に掲載しておくので、コピーして、是非試してみていただきたい。(ただし、下記の Id などは変更しておくこと。)

なお、つい最近、この新機能に関する ドキュメントがリリースされたようなので、是非、参考にされたし !

Office Dev Center : Overview of add-in commands for mail

Office Dev Center : Create a manifest for add-in commands

<?xml version="1.0" encoding="UTF-8"?>
<OfficeApp
  xmlns="http://schemas.microsoft.com/office/appforoffice/1.1"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:bt="http://schemas.microsoft.com/office/officeappbasictypes/1.0"
  xmlns:mailappor="http://schemas.microsoft.com/office/mailappversionoverrides"
  xsi:type="MailApp">
  <Id>{9AADFD5D-49A0-47C8-897F-1BB59D5116B5}</Id>
  <Version>1.0</Version>
  <ProviderName>Microsoft</ProviderName>
  <DefaultLocale>en-us</DefaultLocale>
  <DisplayName DefaultValue="My App Test"></DisplayName>
  <Description DefaultValue="This is a test"></Description>
  <Requirements>
    <Sets DefaultMinVersion="1.1">
      <Set Name="Mailbox" />
    </Sets>
  </Requirements>

  <FormSettings>
    <Form xsi:type="ItemRead">
      <DesktopSettings>
        <SourceLocation
          DefaultValue="https://addintest01.azurewebsites.net/app1.html" >
        </SourceLocation>
        <RequestedHeight>150</RequestedHeight>
      </DesktopSettings>
    </Form>
    <Form xsi:type="ItemEdit">
      <DesktopSettings>
        <SourceLocation
          DefaultValue="https://addintest01.azurewebsites.net/app2.html" >
        </SourceLocation>
      </DesktopSettings>
    </Form>
  </FormSettings>
  <Permissions>ReadWriteItem</Permissions>
  <Rule xsi:type="RuleCollection" Mode="Or">
    <Rule xsi:type="ItemIs"
      ItemType="Message"
      FormType="Edit" />
    <Rule xsi:type="ItemIs"
      ItemType="Appointment"
      FormType="Edit" />
  </Rule>
  <DisableEntityHighlighting>true</DisableEntityHighlighting>

  <VersionOverrides
    xmlns="http://schemas.microsoft.com/office/mailappversionoverrides"
    xsi:type="VersionOverridesV1_0">

    <Description resid="residDesc" />

    <Requirements>
      <bt:Sets DefaultMinVersion="1.3">
        <bt:Set Name="Mailbox" />
      </bt:Sets>
    </Requirements>

    <Hosts>
      <Host xsi:type="MailHost">

        <DesktopFormFactor>
          <FunctionFile resid="residFuncUrl" />

          <ExtensionPoint xsi:type="MessageReadCommandSurface">
            <OfficeTab id="TabDefault">
              <Group id="msgreadTabMessage.grp1">
                <Label resid="residLabel" />
                <Tooltip resid="residLabelTip" />
 
                <Control xsi:type="Button" id="button1id">
                  <Label resid="residUILessButton" />
                  <Tooltip resid="residTip" />
                  <Supertip>
                    <Title resid="residSuperTipTitle" />
                    <Description resid="residSuperTipDesc" />
                  </Supertip>
                  <Icon>
                    <bt:Image size="16" resid="icon1" />
                    <bt:Image size="32" resid="icon2" />
                    <bt:Image size="80" resid="icon3" />
                  </Icon>
                  <Action xsi:type="ExecuteFunction">
                    <FunctionName>showTest</FunctionName>
                  </Action>
                </Control>
                
                <Control xsi:type="Button" id="button2id">
                  <Label resid="residTaskpaneButton" />
                  <Tooltip resid="residTip" />
                  <Supertip>
                    <Title resid="residSuperTipTitle" />
                    <Description resid="residSuperTipDesc" />
                  </Supertip>
                  <Icon>
                    <bt:Image size="16" resid="icon1" />
                    <bt:Image size="32" resid="icon2" />
                    <bt:Image size="80" resid="icon3" />
                  </Icon>
	                <Action xsi:type="ShowTaskpane">
	                  <SourceLocation resid="residTaskpaneUrl" />
	                </Action>
                </Control>

              </Group>
            </OfficeTab>
          </ExtensionPoint>
        </DesktopFormFactor>
      </Host>
    </Hosts>

    <Resources>
      <bt:Images>
        <bt:Image id="icon1"
          DefaultValue="https://addintest01.azurewebsites.net/myimg16.bmp" >
        </bt:Image>
        <bt:Image id="icon2"
          DefaultValue="https://addintest01.azurewebsites.net/myimg32.bmp" >
        </bt:Image>
        <bt:Image id="icon3"
          DefaultValue="https://addintest01.azurewebsites.net/myimg80.bmp">
        </bt:Image>
      </bt:Images>
      <bt:Urls>
        <bt:Url id="residFuncUrl"
          DefaultValue="https://addintest01.azurewebsites.net/myfunc.html" >
        </bt:Url>
        <bt:Url id="residTaskpaneUrl"
          DefaultValue="https://addintest01.azurewebsites.net/mypane.html" >
        </bt:Url>
      </bt:Urls>
      <bt:ShortStrings>
        <bt:String id="residLabel"
          DefaultValue="Test App">
        </bt:String>
        <bt:String id="residUILessButton"
          DefaultValue="Do Func">
        </bt:String>
        <bt:String id="residTaskpaneButton"
          DefaultValue="Show Pane">
        </bt:String>
        <bt:String id="residSuperTipTitle"
          DefaultValue="SuperTip Title">
        </bt:String>
      </bt:ShortStrings>
      <bt:LongStrings>
        <bt:String id="residDesc"
          DefaultValue="This is an add-in test.">
        </bt:String>
        <bt:String id="residLabelTip"
          DefaultValue="This is an add-in test.">
        </bt:String>
        <bt:String id="residTip"
          DefaultValue="Run Test app">
        </bt:String>
        <bt:String id="residSuperTipDesc"
          DefaultValue="Run Test App">
        </bt:String>
      </bt:LongStrings>
    </Resources>

  </VersionOverrides>
</OfficeApp>

Add-in for Outlook.com (旧 Hotmail における Web Add-in 対応)

既に春にアナウンスされたが、outlook.com (旧 Hotmail) でも Mail Add-in (旧 App for Outlook の Mail App) が扱えるようになる。

Hotmail_App

Option メニューから [Manage Add-in] を選択すると Add-in の管理画面が表示され、

Manage_Addin

通常の (Exchange 版 Outlook の) Mail Add-in 同様、ここから Add-in のファイル (拡張子 .app) やオンライン上で公開されている URL を入力すれば登録が可能だ。
(正式リリースの際には、おそらく、ストアからのダウンロードも可能になるのだろう。)

Add_Addin

outlook.com で扱えるようになったことによる、もう 1 つの隠れたメリット (開発者のメリット) として、Napa で動かしやすくなったことだ。

このブログでも紹介したように、Tenant-less Napa を使うと Microsoft Account だけで Office Add-in が簡単に開発できるが、これまで、Mail Add-in (Add-in for Outlook) の展開 (配置) の際には Exchange (Exchange Online 含む) に登録する必要があり、再度、Office 365 のアカウントなどで入りなおす必要があった。
これが、この outlook.com の Add-in 対応で、Microsoft Account でログインしたまま、Add-in の動作確認まで可能になった

なお、現時点では、Preview に申し込んだ Developer のみが試せるようになっている。

Browser Only, Office 365 不要の Office Add-in 開発 – Tenant-less Napa

「Napa」という名前のブラウザ ベースの Office Add-in 開発環境があるが、これまで、Napa を使うには以下の面倒な手続きが必要だった。

  1. Office 365 アカウントを取得する (お金がかかるので、1 ヶ月試用版など)
  2. Office 365 にログインして、SharePoint の developer site を構築する
  3. 作成した site の Site Contents として、Office Store から Napa をインストールする
  4. ようやく Napa を使える

特に、昨今、Mac を利用している人も多いので Napa のような Browser ベースの開発環境は重宝するが、ただ Office Add-in 開発をするだけなのに、1 ヶ月限定の Office 365 trial を契約し、SharePoint の使い方をおぼえるなど、意味のないハードルを超える必要があった。

今後は、Napa だけ使うなら、Office 365 や SharePoint が不要で Microsoft Account さえあれば、将来に渡ってタダで利用可能 になった。(厳密には、Napa は、Live Services のアプリとして提供されるようになった。)
以下にアクセスして Microsoft Account で SignIn すれば、すぐに Napa を使い始めることができる。

Tenant-less Napa
https://www.napacloudapp.com

napa

Visual Studio Online “Monaco” さながらの Browser Editor で開発をおこなえる。

edit

そして、Run Project] を実行すると、アプリに応じて、Excel Online、Word Online、Outlook Web App などが起動して動作をすぐに確認できる。
裏側では OneDrive が使用されている

run

完成したら、Visual Studio のプロジェクトとして出力も可能だ。

Add-in for Outlook (旧 メール・アプリ) の場合のみ、「@IT – Office 用アプリの作り方と、できること/できないこと」で解説したように Exchange (サーバー) が必要となるため、結局、実行時に Office 365 アカウントにログインする必要があるが、今後 (もうすぐ)、Add-in for Outlook も Outlook.com (旧 Hotmail) で動かすことができるので、こうなると、すべての Add-in 開発で Office 365 へのログインは不要になる。(この Outlook.com 対応は、現在、限定的な Preview として提供されている。)

Office Add-in Context Highlighting

最近開催された MS の大きなイベント (BUILD, Ignite) にあわせて、Office Add-ins (旧 App for Office) にいくつか Preview を含む機能が追加されている。
そんなわけで、ちょっと自分の整理のためにも、ここ数か月で Update された Office Add-ins の内容についてメモしておきたい。

まず、少し前に提供された OWA の Context Highlighting について。

「Office用アプリ」の作り方と、できること/できないこと』で解説したように、Mail Add-ins for Outlook (旧 メール アプリ) では正規表現などの Rule (ItemHasKnownEntity, ItemHasRegularExpressionMatch を使用した Rule) を持つ Contextual Add-in では、その条件 (正規表現など) とマッチングしている場合に下図の通り Add-ins のリンクが表示されるが、まあ正直、これに気付いてクリックしてくれる人は実際なかなかいなかったのではないかと思う。。。

dt-officestoreapp_01_10

今後は、Outlook Web App で参照した際に、マッチングしている箇所に下図の通りリンクが表示されて、このリンクをクリックすることで Add-ins (アプリ) がポップアップで表示されるようになった。(下図のような感じ)

Click 前
Content_Highlighting01

Click 後
Content_Highlighting02

この機能 (Context Highlighting) は、下記のいずれかの条件に合致する場合には適用されない (その場合には、従来通りの表示方法になる) ので注意してほしい。

  • ItemHasKnownEntity として、Url か EmailAddress の Entity が使われた場合
  • type が ItemHasRegularExpressionMatch で、Property が NameBodyAsHTML か SenderSMTPAddress の Rule がある場合
  • 以下の条件に合致する OR の RuleCollection がある場合
    • 最初の Rule の type が ItemIs で、itemType が Appointment か Message
    • 次の Rule の type が ItemHasKnownEntity か ItemHasRegularExpressionMatch
  • e-mail の body が複雑な場合

例えば、下記のような Rule では、下図のように表示される。

<Rule xsi:type="RuleCollection" Mode="And">
  <Rule xsi:type="ItemIs" ItemType="Message" FormType="Read" />
  <Rule xsi:type="ItemHasRegularExpressionMatch" 
    PropertyName="BodyAsPlaintext" RegExName="highlighttest"
    RegExValue="This is [a-zA-Z0-9_-]*" />
</Rule>

Custom_Sample