2017年6月13日火曜日

個人的な動く LINE スタンプの作り方

概要

個人的に動く LINE スタンプを作るときの方法を紹介します
一応全部無料でできます
各ツールの詳細な使い方は説明しないので、公式サイト等を見て勉強してください
今回は Windows 環境のスクリーンショットで説明しています

環境

  • macOS 10.12.5 or Windows 10
  • FireAlpaca 1.7.4
  • アニメ画像に変換する君 1.2.0
  • LINE シミュレータ

FireAlpaca で絵を書く

全てはここから、絵を書かないことにはスタンプはできません
FireAlpaca を開いたら

ファイル -> 新規作成 -> 幅320pixel, 高さ270pixel -> OK

でレイヤを 1 つ作成します
このレイヤに適当に絵を書きます
ペンを選択してマウスの左クリックを押しながら移動すれば線が書けます

そして 1 つのレイヤを書き終えたら更にレイヤを追加します

レイヤ -> 追加

追加したレイヤに次のアニメーションの絵を書きます
こんな感じで画像をたくさん作りコマ送りすることでアニメーションを実現しています

アニメーションスタンプのガイドライン を見ると「イラストは最低5 - 最大20フレーム」とあるのでレイヤも最低限 5 つ以上、最高で 20 個以下にしましょう

とりあえず 5 レイヤ分で作成しました
line_animetaion_stamp1.png

各レイヤに丸を横に並べていって最後に四角が登場する謎のアニメーションです

FireAlpaca で png を連番で書き出す

絵が書けたらこのレイヤたちを連番 png で書き出します

表示 -> オニオンスキンモード

にします
オニオンスキンモードはレイヤの前後が薄緑と薄ピンクで表示される機能です
この機能を使うと前後のアニメーションでどういう動きをするか確認できるのでアニメーションが作成しやすいです

調整できたら、連番で書き出します

ファイル -> レイヤーを連番出力 (オニオンスキンモード)

で連番ファイルを保存するディレクトリを選択するダイアログが表示されるので選択して保存します
その後動画を見るかどうか聞かれますが No で OK です

これで連番ファイルが png で出力されました
ちなみに出力される連番は 000.png から出力されます
レイヤ的には番号の大きい方から 000 になるので注意してください
(図で言うと レイヤ5 の四角が 000.png になり、レイヤ 1 の左の丸が 0005.png になります)

アニメ画像に変換する君で apng を作成する

作成された連番の png を apng という動く LINE スタンプのファイル形式にします
ダウンロードしたアニメ画像に変換する君を開きます

そして「ファイルを選択」もしくはドラッグアンドドロップで作成された連番ファイルを開きます
左メニューの「フレームレート」と「ループ回数」を調整します

今回だとフレームレートを「5」ループ回数を「2」にするといい感じになります
いい感じというのは再生時間の調整の部分でこれもガイドラインに書いているのですが再生時間は「1, 2, 3, 4」秒のどれかでないとダメみたいです
再生する機能もあるので再生しながらどんな感じのアニメーションになるか確認すると良いと思います
line_animetaion_stamp2.png

フレームレートとループ回数を調整したら「アニメ画像を保存する」を選択して apng ファイルを作成します
名前と保存先を決定して出力しましょう

できあがった apng ファイルは拡張子は .png で普通に開いてもただの静止画が表示されるだけだと思います

LINE シミュレータで動作確認する

ただの静止画をシミュレータ上で表示してみましょう

Firefox で https://creator.line.me/ja/simulator/ からマイページにログインし左メニューの「作ったスタンプをチェックしよう!」を選択します
「スタンプシミュレータを使ってみる」を選択すると別ウィンドウでシミュレータが起動します
ここに先程作成した apng ファイルをドラッグアンドドロップで配置してみましょう
すると動く LINE スタンプのようにアニメーションすると思います
line_animetaion_stamp3.png

写真はアニメーション後の状況です

最後に

個人的に動く LINE スタンプを作成する方法を紹介しました
メリットはすべて無料で使えるという点でしょうか
フォトショップなどが使えるのであればそれだけで apng まで作成できると思います
また、絵自体もクオリティの高いものができあがると思います

また、絵を書くのにマウスだと正直辛いので本格的に書きたいのであればペンタブを購入するのをおすすめします
自分はまだそこまで本格的にやっていないのでペンタブを購入していませんが、もし購入してスタンプを作成することになったそのときにレビューや FireAlpaca との連携方法なども紹介したいと思います

参考サイト

2017年6月12日月曜日

Firebase で iOS にプッシュ通知を送信してみた

概要

プッシュ通知を Firebase に移行してみたので設定や流れをメモしておきます
ある程度端折っいる流れもあるのでその点はあしからず
基本は公式ドキュメントを見ることをおすすめします

環境

  • macOS 10.12.5
  • Xcode 8.3.2 (8E2002)
  • Firebase (2017/6/9 時点)
  • プッシュ対象端末 iPhone5 iOS 10.3.2

流れ

AppID にプッシュ通知用の証明書を登録する

作成するときは AppID の一覧から作成することをおすすめします
iOS Certificates にログインして

Identifiers -> App IDs -> 対象の AppID を選択 -> Edit

で編集画面に移動し「Push Notifications」の欄をチェックオンにします
そしてそこから「Create Certificate」でプッシュ通知用の証明書を作成します
作成には CSR が必要になるので事前に作成します
Development, Production 用の証明書の 2 つが作成できれば OK です
firebase_push1.png

作成したプッシュ通知用の証明書から p12 ファイルを書き出す

先ほどの画面から証明書を「Download」できるので Mac 上にダウンロードします
そして、ダブルクリックしてキーチェーンアクセスで開いて p12 ファイルを書き出しましょう
firebase_push3.png

パスワードはなしで書き出しました
後から気づいたのですが、Firebase は p12 ファイルのパスワードも設定できるのでパスワードはありでも大丈夫だと思います

p12 ファイルを Firebase に登録する

Firebase のコンソールにログインしましょう

プロジェクトの設定 -> クラウドメッセージング -> 対象のアプリを選択 -> APNs 証明書

を選択します
同じような項目で「APNs 認証キー」という項目がありますが、そっちじゃないので注意してください
firebase_push4.png

「開発用 APNs 証明書」「本番環境の APNs 証明書」という 2 つの欄があるので書き出した p12 ファイルをそれぞれアップロードしてください
ちゃんと Development 用の証明書から書き出した p12 ファイルは「開発用の APNs 証明書」Production 用の証明書から書き出し p12 ファイルは「本番環境の APNs 証明書」に設定しましょう
当然ですが、間違えるとプッシュ通知が送信されません

アプリ側修正

これで Firebase 側の設定は完了です
アプリ側の修正をしていきましょう

ライブラリのインストールは Cocoapods を使います

pod 'Firebase/Messaging'

プロジェクトのプッシュ通知を有効にします
プロジェクトを選択した状態で Capabilities を選択し「Push Notifications」を ON にします
firebase_push2.png

あとは AppDelete.swift を編集します
今回は Swift3 の文法を使っています
Swift2 だと若干コールするメソッドが違うので気をつけてください
全部紹介すると長いのでポイントを紹介します

import UserNotifications

を import しましょう

// Firebase の初期化
FIRApp.configure()
// プッシュ通知の許可を表示する
if #available(iOS 10.0, *) {
    let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
    UNUserNotificationCenter.current().requestAuthorization(
        options: authOptions,
        completionHandler: {_, _ in })
    // For iOS 10 display notification (sent via APNS)
    UNUserNotificationCenter.current().delegate = self as? UNUserNotificationCenterDelegate
    // For iOS 10 data message (sent via FCM)
    FIRMessaging.messaging().remoteMessageDelegate = self as? FIRMessagingDelegate
} else {
    let settings: UIUserNotificationSettings = UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil)
    application.registerUserNotificationSettings(settings)
}
application.registerForRemoteNotifications()

didFinishLaunchingWithOptions に追加します
これでアプリの初回起動時にプッシュ通知を許可するかどうかのダイアログが出るようになり、許可を押した人にプッシュ通知できるようになります

// メッセージ受信時の処理
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any]) {
    print(userInfo)
}

func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any],
                 fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
    print(userInfo)
    completionHandler(UIBackgroundFetchResult.newData)
}

メッセージを受信したときの処理です
メッセージをカスタマイズしていて何か特別な処理をしたいときはここにロジックを記載します

動作確認

これで OK なはずです
あとは Firebase の Notifications からメッセージを作成して送信すればメッセージが届くはずです

当然ですが実機でないと届きません
なので、Mac に iPhone を接続して Firebase 対応したアプリをビルドしてインストールしてください
アプリ起動時にプッシュ通知の許可拒否のダイアログが表示されるのでそこでも必ず許可を選択してください

最後に

Firebase を使って iOS にプッシュ通知を送信してみました
自分が一番ハマったのは証明書の部分で始め Production 用の証明書と p12 ファイルしか登録しないでやっていたら全然プッシュ通知が届かなく、Development 用の証明書も作成したら届くようになりました

あとはコードの部分ですが、今回のコードは公式のドキュメントに記載されていることとほぼ同様です
でも「firebase ios push」あたりでググると公式ドキュメントが一番最初に出てきません
引っかかった記事のサンプルコードを使っていたのですが、単純にプッシュ通知したいだけなのに setAPNSToken を使っていたりしてうまく動作しませんでした
単純にプッシュ通知を受け取りたいだけなら上記のコードだけで十分だと思います
それ以外にもアプリがアクティブになった場合のプッシュ通知の処理や、通知の開封状況などを解析するためのコードがありますが単純にプッシュ通知したい場合であれば不要です

あともう一点良くわからなかったのは Firebase ではプッシュ通知を送信するときに単一の端末にだけ送信する機能があります
そのときに「FCM 登録トークン」というものを使うのですが、これが Firebase 上のどこで確認できるかさっぱりわかりませんでした
コード上でデバッグする方法はドキュメントに載っていたのですが、コンソール上で確認する方法はわかりませんでした
たぶん、個別配信をするときは FCM 登録トークンを使わないで、トピックを使ってやれということだとは思います
FCM 登録トークンは開発者が知りたい時に直接コードにデバッグコードを埋め込んで取得しましょうというスタンスなんだと思います
それともどっかで確認できるのかもしれませんが、、

参考サイト

2017年6月11日日曜日

Getting Started dozens rubygem

概要

dozens には API があります
Ruby の SDK が公開されているので使ってみました

環境

  • CentOS 7.3
  • Ruby 2.3.3p222
  • dozens 0.0.2

Getting Started

dozens のユーザ ID と API Key を事前に取得しておいてください

ライブラリのインストール

  • gem install dozens

認証

require 'dozens'

api = Dozens::API.new("your_dozens_id" , "your_dozens_api_key")
api.authenticate

ゾーンの一覧表示

p api.zones

ゾーン内のレコード一覧

rs = api.records "your.domain"
rs['record'].each {|r|
  p "id => #{r['id']}, name => #{r['name']}, type => #{r['type']}, prio => #{r['prio']}, content => #{r['content']}, ttl => #{r['ttl']}"
}

ゾーン内のレコードの更新

rs = api.records "your.domain"
rs['record'].each {|r|
  if r['name'] == "site.your.domain"
    target = r
    target['content'] = "1.1.1.1"
    p api.update_record(target['id'], target)
  end
}

とかとか

最後に

dozens の rubygem を試してみました
ドキュメントがほぼないので、ソースをみるか rubydoc を見るしかないですが簡単に使えました

dozens の API 自体に非常にシンプルなので自分で SDK を作ってもいいかもしれません

参考サイト

2017年6月10日土曜日

harbor に SSL 証明書を設定して https でレジストリを使うための手順

概要

harbor を https で使うための手順を紹介します
harbor はデフォルトで http なので、わざわざ docker クライアント側の insecure-registry に登録する処理が必要になります
ドメインと証明書が使える環境であればレジストリ自体 https を使うことが推奨されています
今回はドメインと証明書を用意して harbor を https で使えるようにしてみました

環境

  • Ubuntu 16.04
  • harbor 1.1.1
  • docker 17.05

事前準備

ドメインを取得して A レコードを登録して証明書を取得します
この流れは過去に紹介もしているので過去の手順でも OK です

ドメインの取得

何でも OK です
とりあえずドメインを取得してください

A レコードの追加

取得したドメインのサブドメインを A レコードとして DNS サーバに登録します
今回登録したレジストリのサブドメインは「reg01.harbor.gq」とします

証明書の作成

とりあえず A レコードで登録したサブドメインの証明書を 1 つ作成しましょう
同一ドメインでレジストリを何台も構築する場合はワイルドカード SSL 証明書で作成することをオススメします
そして作成した証明書は harbor をインストールするサーバに転送しておきましょう

  • scp -r /etc/letsencrypt/archive/reg01.harbor.gq 192.168.100.201:~

harbor の設定

事前準備

今回は Ubuntu 上に harbor を構築します
事前に docker と docker-compose が必要になるので準備しておきましょう (参考)

設定ファイルの編集

インストーラをダウンロードして展開し、設定ファイルの証明書を設定する部分を編集します

hostname = reg01.harbor.gq
ui_url_protocol = https
ssl_cert = /root/reg01.harbor.gq/fullchain1.pem
ssl_cert_key = /root/reg01.harbor.gq/privkey1.pem
  • ./prepare

customize_crt = on という項目がありますがこれは on のままにしておかないてください
証明書を転送したときの転送先は /root/reg01.harbor.gq/ に転送しているのでそのパスを指定しています

インストールと起動

設定が変更できたらインストールしましょう

  • ./install

ダラダラとログが流れて最終的にコンテナが上がってきます
同一ディレクトリ内に docker-compose.yml があるので docker-compose ps などでコンテナを確認することができます

これで証明書が設定されて https でアクセスできるようになっているはずです

動作確認

docker クライアントから https でアクセスできるか確認してみましょう

  • docker login reg01.harbor.gq

admin/Harbor12345 でログインしましょう
ちゃんと証明書が設定されていれば怒られないはずです

  • docker pull alpine
  • docker tag alpine reg01.harbor.gq/library/alpine
  • docker push reg01.harbor.gq/library/alpine

https://reg01.harbor.gq/harbor/tags/1/library%2Falpine にアクセスすると alpine の latest が存在することがわかります
pull もできるか確認してみましょう

  • docker rmi reg01.harbor.gq/library/alpine
  • docker pull reg01.harbor.gq/library/alpine:latest
  • docker logout reg01.harbor.gq

ログアウトしてから pull するとできないのが確認できると思います

最後に

harbor に https でアクセスできるようにしてみました
ドメインと証明書が取れれば簡単に設定することができます

以下の証明書のエラーが出た場合は再度コンテナを生成し直してみてください

Error response from daemon: Get https://reg01.harbor.gq/v1/users/: dial tcp 192.168.100.201:443: getsockopt: no route to host
  • docker-compose down
  • docker rmi $(docker images -q)
  • ./prepare
  • docker-compose up -d

参考サイト

2017年6月9日金曜日

govmomi で指定の VApp をフォルダ配下に移動させる

概要

VApp をフォルダ配下に移動する方法を紹介します
1 つの VApp をあるフォルダに移動します

環境

  • Ubuntu 16.04
  • golang 1.8
  • govmomi 0.14.0

ソースコード

  • vim main.go
package main

import (
        "context"
        "flag"
        "fmt"
        "net/url"
        "os"

        "github.com/vmware/govmomi"
        "github.com/vmware/govmomi/find"
        "github.com/vmware/govmomi/property"
        "github.com/vmware/govmomi/vim25/mo"
        "github.com/vmware/govmomi/vim25/types"
)

var envURL = "https://192.168.100.101/sdk"
var urlDescription = fmt.Sprintf("ESX or vCenter URL [%s]", envURL)
var urlFlag = flag.String("url", envURL, urlDescription)

var envInsecure = true
var insecureDescription = fmt.Sprintf("Don't verify the server's certificate chain [%s]", envInsecure)
var insecureFlag = flag.Bool("insecure", envInsecure, insecureDescription)

func main() {
        // vCenter への接続
        ctx, cancel := context.WithCancel(context.Background())
        defer cancel()
        flag.Parse()
        u, err := url.Parse(*urlFlag)
        if err != nil {
                fmt.Println(err)
                os.Exit(1)
        }
        u.User = url.UserPassword("vcenter_user", "vcenter_pass")
        c, err := govmomi.NewClient(ctx, u, *insecureFlag)
        if err != nil {
                fmt.Println(err)
                os.Exit(1)
        }
        fmt.Println(c.Client.Client.Version)

        // データセンターの取得
        f := find.NewFinder(c.Client, true)
        dc, err := f.DefaultDatacenter(ctx)
        if err != nil {
                fmt.Println(err)
                os.Exit(1)
        }
        f.SetDatacenter(dc)
        fmt.Println(dc)

        // フォルダの取得
        folder, err := f.Folder(ctx, "/dc/vm/folder/")
        if err != nil {
                fmt.Println(err)
                os.Exit(1)
        }
        fmt.Println(folder.Common.InventoryPath)
        // VirtualApp の取得
        varefs := []types.ManagedObjectReference{}
        va, err := f.VirtualApp(ctx, "/dc/vm/vapp")
        if err != nil {
                fmt.Println(err)
                os.Exit(1)
        }
        fmt.Println(va.Common.InventoryPath)
        varefs = append(varefs, va.Reference())
        // フォルダへ移動
        t, err := folder.MoveInto(ctx, varefs)
        if err != nil {
                fmt.Println(err)
                os.Exit(1)
        }
        info, err := t.WaitForResult(context.Background(), nil)
        if err != nil {
                fmt.Println(err)
                os.Exit(1)
        }
        fmt.Println(info.State)
}

ポイントはフォルダのオブジェクトに対して実行している MoveInto メソッドになります
この引数に moref を指定することで指定した moref をフォルダに移動するという処理を行っています
対象の VApp に対して移動せよという命令をするわけではなく、フォルダに対してこのフォルダに入れるという処理をしているのがポイントです

実行後に WaitForResult を使って処理が完了するのを待っています
完了後 info.State で結果を表示して終了です

今回のコードの場合、指定するフォルダと VApp のパスが存在しない場合はエラーになります
なので、一度実行したあと再度実行したい場合は対象の VApp を元のパスに戻す必要があります

最後に

govmomi を使って VApp を特定のフォルダに移動してみました
参照系よりか簡潔に書くことができました

参考サイト

2017年6月8日木曜日

govmomi で VApp の情報を取得する方法

概要

vCenter 配下で管理されている VApp の情報を govmomi を使って取得してみます

環境

  • Ubuntu 16.04
  • golang 1.8
  • govmomi 0.14.0

ソースコード

  • vim main.go
package main

import (
        "context"
        "flag"
        "fmt"
        "net/url"
        "os"

        "github.com/vmware/govmomi"
        "github.com/vmware/govmomi/find"
        "github.com/vmware/govmomi/property"
        "github.com/vmware/govmomi/vim25/mo"
        "github.com/vmware/govmomi/vim25/types"
)

var envURL = "https://192.168.100.101/sdk"
var urlDescription = fmt.Sprintf("ESX or vCenter URL [%s]", envURL)
var urlFlag = flag.String("url", envURL, urlDescription)

var envInsecure = true
var insecureDescription = fmt.Sprintf("Don't verify the server's certificate chain [%s]", envInsecure)
var insecureFlag = flag.Bool("insecure", envInsecure, insecureDescription)

func main() {
        // vCenter への接続
        ctx, cancel := context.WithCancel(context.Background())
        defer cancel()
        flag.Parse()
        u, err := url.Parse(*urlFlag)
        if err != nil {
                fmt.Println(err)
                os.Exit(1)
        }
        u.User = url.UserPassword("vcenter_user", "vcenter_pass")
        c, err := govmomi.NewClient(ctx, u, *insecureFlag)
        if err != nil {
                fmt.Println(err)
                os.Exit(1)
        }
        fmt.Println(c.Client.Client.Version)

        // データセンターの取得
        f := find.NewFinder(c.Client, true)
        dc, err := f.DefaultDatacenter(ctx)
        if err != nil {
                fmt.Println(err)
                os.Exit(1)
        }
        f.SetDatacenter(dc)
        fmt.Println(dc)

        // 全 VirtualApp の取得
        pc := property.DefaultCollector(c.Client)
        varefs := []types.ManagedObjectReference{}
        vas, err := f.VirtualAppList(ctx, "*")
        if err != nil {
                fmt.Println(err)
                os.Exit(1)
        }
        for _, va := range vas {
                fmt.Println(va.Common.InventoryPath)
                varefs = append(varefs, va.Reference())
        }
        var vadst []mo.VirtualApp
        err = pc.Retrieve(ctx, varefs, nil, &vadst)
        if err != nil {
                fmt.Println(err)
                os.Exit(1)
        }
        for _, va := range vadst {
                fmt.Println(va.VAppConfig.Annotation)
                fmt.Println(va.VAppConfig.EntityConfig) // VApp 内の VM の情報
                fmt.Println(va.Name)
        }
}

まず vCenter に接続しデータセンターの情報を取得します
その後 f.VirtualAppList を使ってすべての VApp の情報を取得します
取得後は types.ManagedObjectReference に突っ込んで pc.Retrieve することで VApp の情報を取得しています
あとは types.ManagedObjectReference に設定された値をループで回して参照しているだけです

VApp の場合 VApp 内に VM が存在することがあると思います
VApp 内の子の要素を参照するには EntityConfig を使えば参照できそうだったので、そこから VM の情報を取得できると思います

VApp の別の情報を参照したい場合は以下を参照してください
https://godoc.org/github.com/vmware/govmomi/vim25/mo#VirtualApp

最後に

govmomi を使って VApp の情報を参照していました
これまで紹介したフォルダや VM を取得する方法とほぼ同じなので特に躓くところはありませんでした

参考サイト

2017年6月7日水曜日

govmomi でフォルダの情報を取得する方法

概要

vCenter 配下で管理されているフォルダ情報を govmomi を使って取得してみます
すべてのフォルダを取得する方法と単体で取得する方法を紹介します

環境

  • Ubuntu 16.04
  • golang 1.8
  • govmomi 0.14.0

ソースコード

  • vim main.go
package main

import (
        "context"
        "flag"
        "fmt"
        "net/url"
        "os"

        "github.com/vmware/govmomi"
        "github.com/vmware/govmomi/find"
        "github.com/vmware/govmomi/property"
        "github.com/vmware/govmomi/vim25/mo"
        "github.com/vmware/govmomi/vim25/types"
)

var envURL = "https://192.168.100.101/sdk"
var urlDescription = fmt.Sprintf("ESX or vCenter URL [%s]", envURL)
var urlFlag = flag.String("url", envURL, urlDescription)

var envInsecure = true
var insecureDescription = fmt.Sprintf("Don't verify the server's certificate chain [%s]", envInsecure)
var insecureFlag = flag.Bool("insecure", envInsecure, insecureDescription)

func main() {
        // vCenter への接続
        ctx, cancel := context.WithCancel(context.Background())
        defer cancel()
        flag.Parse()
        u, err := url.Parse(*urlFlag)
        if err != nil {
                fmt.Println(err)
                os.Exit(1)
        }
        u.User = url.UserPassword("vcenter_user", "vcenter_pass")
        c, err := govmomi.NewClient(ctx, u, *insecureFlag)
        if err != nil {
                fmt.Println(err)
                os.Exit(1)
        }
        fmt.Println(c.Client.Client.Version)

        // データセンターの取得
        f := find.NewFinder(c.Client, true)
        dc, err := f.DefaultDatacenter(ctx)
        if err != nil {
                fmt.Println(err)
                os.Exit(1)
        }
        f.SetDatacenter(dc)
        fmt.Println(dc)

        // フォルダの取得
        pc := property.DefaultCollector(c.Client)
        frefs := []types.ManagedObjectReference{}
        folder, err := f.Folder(ctx, "/dc/vm/folder_name/")
        if err != nil {
                fmt.Println(err)
                os.Exit(1)
        }
        fmt.Println(folder.Common.InventoryPath)
        frefs = append(frefs, folder.Reference())
        var fdst []mo.Folder
        err = pc.Retrieve(ctx, frefs, nil, &fdst)
        if err != nil {
                fmt.Println(err)
                os.Exit(1)
        }
        for _, f := range fdst {
                fmt.Println(f.Name)
                fmt.Println(f.Tag)
        }
        // 全フォルダの取得
        fsrefs := []types.ManagedObjectReference{}
        folders, err := f.FolderList(ctx, "*")
        if err != nil {
                fmt.Println(err)
                os.Exit(1)
        }
        for _, folder := range folders {
                fmt.Println(folder.Common.InventoryPath)
                fsrefs = append(fsrefs, folder.Reference())
        }
        var fsdst []mo.Folder
        err = pc.Retrieve(ctx, fsrefs, nil, &fsdst)
        if err != nil {
                fmt.Println(err)
                os.Exit(1)
        }
        for _, f := range fsdst {
                fmt.Println(f.Name)
                fmt.Println(f.Tag)
        }
}

まず vCenter に接続しデータセンターの情報を取得します
その後 f.Folder にフォルダのパスを指定することでフォルダ単体を取得しています
取得後は types.ManagedObjectReference に突っ込んで pc.Retrieve することでフォルダの情報を取得しています
あとは types.ManagedObjectReference に設定された値をループで回して参照しているだけです

全件取得の場合には f.FolderList(ctx, "*") とパスの部分をアスタリスクにすることで実現できます
あとは同じ流れで moref に突っ込んで pc.Retrieve で設定し、moref をループで回して参照するだけです

今回は Name と Tag を参照していますが、フォルダの他の情報を参照したい場合は godoc を見てください
https://godoc.org/github.com/vmware/govmomi/vim25/mo#Folder

最後に

govmomi を使ってフォルダを参照する方法を紹介しました
フォルダのオブジェクトが取得できるようになればフォルダに対する操作もできるようになります
例えば削除や名前の変更 VM をフォルダに移動することなどができるようになります

その辺の操作周りに関しても別記事で紹介できればなと思います

参考サイト