2011年5月19日木曜日

SQL Azure ファイアウォール管理 REST API のアクティビティ化

基本的に前回とほぼ同一ですが、SQL Azure のファイアウォール制御作成列挙削除)もアクティビティ化してみました。ファイアウォール制御 API 自体は特に難しいものでもなく、非常に簡単な形式となっています。メッセージ生成が必要なのも新規作成の際のみです。
前回同様ベースとなるクラスから。

   1: Imports System.Activities
   2: Imports System.IO
   3: Imports System.Net
   4: Imports System.Security.Cryptography.X509Certificates
   5:  
   6: Public MustInherit Class SQLAzureActivityBase
   7:     Inherits AsyncCodeActivity
   8:  
   9:     Protected Const SQL_API_PATH = "https://management.database.windows.net:8443/{0}/servers/{1}/firewallrules"
  10:  
  11:     Public Property SubscriptionID As String
  12:     Public Property CertThumbPrint As String
  13:  
  14:     Public Property ServerName As String
  15:     Public Property RuleName As String
  16:     Public Property StartIP As String
  17:     Public Property EndIP As String
  18:  
  19:     Public Property ResultDocument As OutArgument(Of String)
  20:     Public Property ResultStatus As OutArgument(Of String)
  21:     Public Property RequestID As OutArgument(Of String)
  22:  
  23:     Private Delegate Function AsyncGetWebDataDelegate(ByVal subscription As String,
  24:                                                                                ByVal thumbprint As String) As String()
  25:  
  26:     Protected Overrides Function BeginExecute(context As System.Activities.AsyncCodeActivityContext, callback As System.AsyncCallback, state As Object) As System.IAsyncResult
  27:         Dim asyncExecute = New AsyncGetWebDataDelegate(AddressOf GetWebData)
  28:         context.UserState = asyncExecute
  29:  
  30:         Return asyncExecute.BeginInvoke(Me.SubscriptionID, Me.CertThumbPrint, callback, state)
  31:     End Function
  32:  
  33:     Protected Overrides Sub EndExecute(context As System.Activities.AsyncCodeActivityContext, result As System.IAsyncResult)
  34:         Dim asyncExecute = TryCast(context.UserState, AsyncGetWebDataDelegate)
  35:         Dim getResult = asyncExecute.EndInvoke(result)
  36:  
  37:         context.SetValue(Me.ResultDocument, getResult(0))
  38:         context.SetValue(Me.ResultStatus, getResult(1))
  39:         context.SetValue(Me.RequestID, getResult(2))
  40:     End Sub
  41:  
  42:     Protected Overridable Function GetWebData(ByVal subscription As String,
  43:                                                                   ByVal thumbprint As String) As String()
  44:         Dim resultStrings As String = ""
  45:         Dim resultStatus As String = ""
  46:         Dim resultRequestID As String = ""
  47:         Try
  48:             Dim certificate As X509Certificate2 = CreateCertification(thumbprint)
  49:  
  50:             Dim requestUri As Uri = Me.CreateApiPath(subscription, Me.RuleName)
  51:             Dim localWebRequest = TryCast(HttpWebRequest.Create(requestUri), HttpWebRequest)
  52:             localWebRequest.ClientCertificates.Add(certificate)
  53:             Me.SetHttpMethod(localWebRequest)
  54:             Me.AddRequestHeader(localWebRequest)
  55:  
  56:             Dim bodyString = Me.CreateBodyMessage()
  57:             If bodyString IsNot Nothing Then
  58:                 Dim sendBytes() As Byte = Text.Encoding.UTF8.GetBytes(bodyString)
  59:                 localWebRequest.ContentLength = sendBytes.Length
  60:                 localWebRequest.ContentType = "application/xml; charset=utf-8"
  61:                 Using reqStream = localWebRequest.GetRequestStream
  62:                     reqStream.Write(sendBytes, 0, sendBytes.Length)
  63:                 End Using
  64:             End If
  65:  
  66:             Using webResponse = TryCast(localWebRequest.GetResponse(), HttpWebResponse)
  67:                 resultStatus = webResponse.StatusCode.ToString
  68:                 resultRequestID = webResponse.Headers("x-ms-request-id")
  69:                 Using responseStream = webResponse.GetResponseStream()
  70:                     Using reader As New StreamReader(responseStream)
  71:                         resultStrings = reader.ReadToEnd
  72:                     End Using
  73:                 End Using
  74:             End Using
  75:  
  76:         Catch ex As Exception
  77:             resultStrings = ex.Message
  78:         End Try
  79:         Return New String() {resultStrings, resultStatus, resultRequestID}
  80:     End Function
  81:  
  82:     Protected Overridable Function CreateApiPath(subscript As String, ByVal rule As String) As System.Uri
  83:         Return New Uri(String.Format(SQL_API_PATH, subscript, Me.ServerName) +
  84:                               "/" + rule)
  85:     End Function
  86:  
  87:     Protected Overridable Function CreateCertification(ByVal thumbPrintString As String) As X509Certificate2
  88:         Dim certStore As X509Store = New X509Store(StoreName.My, StoreLocation.CurrentUser)
  89:         certStore.Open(OpenFlags.ReadOnly)
  90:  
  91:         Dim certCollection As X509Certificate2Collection = certStore.Certificates.Find(X509FindType.FindByThumbprint, thumbPrintString, False)
  92:         certStore.Close()
  93:  
  94:         If certCollection.Count <= 0 Then
  95:             Throw New ApplicationException("証明書がありません")
  96:         End If
  97:         Return certCollection(0)
  98:     End Function
  99:  
 100:     Protected Overridable Sub AddRequestHeader(ByVal wq As WebRequest)
 101:         wq.Headers.Add("x-ms-version", "1.0")
 102:     End Sub
 103:  
 104:     Protected Overridable Sub SetHttpMethod(ByVal wq As WebRequest)
 105:         wq.Method = "PUT"
 106:     End Sub
 107:  
 108:     Protected Overridable Function CreateBodyMessage() As String
 109:         Dim xmlBody =
 110:         "<?xml version=""1.0"" encoding=""utf-8""?>" + ControlChars.NewLine +
 111:         "<FirewallRule" + ControlChars.NewLine +
 112:         "  xmlns=""http://schemas.microsoft.com/sqlazure/2010/12/""" + ControlChars.NewLine +
 113:         "  xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance""" + ControlChars.NewLine +
 114:         "  xsi:schemaLocation=""http://schemas.microsoft.com/sqlazure/2010/12/ FirewallRule.xsd"">" + ControlChars.NewLine +
 115:         "  <StartIpAddress>" + Me.StartIP + "</StartIpAddress>" + ControlChars.NewLine +
 116:         "  <EndIpAddress>" + Me.EndIP + "</EndIpAddress>" + ControlChars.NewLine +
 117:         "</FirewallRule>"
 118:         Return xmlBody
 119:     End Function
 120:  
 121: End Class

今回ベースにしている処理はファイアウォールルールの新規追加です。ですので新規追加用アクティビティはこのベースクラス自体を利用してもよかったのですが、あとでリファクタリングを行う事を考えて、そのままにしていますw

   1: Imports System.Activities
   2:  
   3: Public Class CreateSQLAzureFirewallRuleActivity
   4:     Inherits SQLAzureActivityBase
   5:  
   6:     Public Sub New()
   7:         Me.DisplayName = "SQLAzure FW ルール作成"
   8:     End Sub
   9:  
  10: End Class

続いて列挙。

   1: Imports System.Activities
   2:  
   3: Public Class EnumSQLAzureFirewallRuleActivity
   4:     Inherits SQLAzureActivityBase
   5:  
   6:     Public Sub New()
   7:         Me.DisplayName = "SQLAzure FW ルール列挙"
   8:     End Sub
   9:  
  10:     Protected Overrides Sub SetHttpMethod(wq As System.Net.WebRequest)
  11:         wq.Method = "GET"
  12:     End Sub
  13:  
  14:     Protected Overrides Function CreateBodyMessage() As String
  15:         Return Nothing
  16:     End Function
  17:  
  18:     Protected Overrides Function CreateApiPath(subscript As String, rule As String) As System.Uri
  19:         Return New Uri(String.Format(SQL_API_PATH, subscript, Me.ServerName))
  20:     End Function
  21:  
  22: End Class

最後に削除です。

   1: Imports System.Activities
   2:  
   3: Public Class DeleteSQLAzureFirewallRuleActivity
   4:     Inherits SQLAzureActivityBase
   5:  
   6:     Public Sub New()
   7:         Me.DisplayName = "SQLAzure FW ルール削除"
   8:     End Sub
   9:  
  10:     Protected Overrides Sub SetHttpMethod(wq As System.Net.WebRequest)
  11:         wq.Method = "DELETE"
  12:     End Sub
  13:  
  14:     Protected Overrides Function CreateBodyMessage() As String
  15:         Return Nothing
  16:     End Function
  17:  
  18: End Class

なお、これら 3 つのアクティビティにて、実行時に結果が返却されるものは「列挙」のみです。「作成」と「削除」は特に処理結果を返却しませんので、HTTP のステータスコードにより結果を判断するようにしてください。基本的には 200 が返却されれば正常終了です。

これら 3 つのアクティビティを、ワークフロー上で実際に利用した場合のプロパティ設定はこのような形になります。

SQLAzureFWCreate

作成時はほぼすべてのプロパティに設定する必要があります。ただし結果関係のプロパティとして実装している、ResultDocument、ResultStatus、RequestID プロパティについては未設定でも利用可能です。

SQLAzureFWEnum

列挙時はこのように、ルールの設定に関わる部分が未設定となります。

SQLAzureFWEnumResult

実行して返却される結果はこのような感じになります。

SQLAzureFWDelete

削除の際は、削除対象となるルール名が必要ですが、開始~終了の IP アドレスについては未設定で利用できます。

このような形で SQL Azure 管理 REST API をアクティビティ化し利用する事で、ファイアウォールのルール設定が簡易に行えるようになります。

0 件のコメント:

コメントを投稿