14

I have an Azure AppService (Web-Site microservice) created from an ARM template. It contains a drupal app. I have configured it to read from a git server in bitbucket. When I create for first time it sucessfully pull the files from bitbucket (master branch). All good :-) The App Service is created from a PowerShell script that uses ARM templates launched from Jenkins project. The project is called ReCreateXXXAppService and executes a PowerShell that detects if AppService is there, delete it if that is the case, and deploy it again.

This is the summary of my code around New-AzureRmResourceGroupDeployment:

    $repoUrl = "https://"+$AppServiceUsername+":"+$AppServicePassword+"@bitbucket.org/XXX/as-cms.git"
    $params = @{siteName=$AppServiceName ; hostingPlanName="$($AppServiceName)-HP"; siteLocation=$AppServiceLocationName; repoUrl=$repoUrl; branch="master";}
    $templateFile = Join-Path $scriptDir "templates\$TemplateName"
    Write-Host "Using template file $TemplateFile"
    New-AzureRmResourceGroupDeployment -Mode Complete -Force -TemplateParameterObject $params -Name "$($AppServiceName)-dn" -ResourceGroupName $azureResourceGroupName -TemplateFile $templateFile

When I change something in master branch I have two options:

  1. Automated: Execute RecreateXXXAppService again in Jenkins, wait around 1-2 mins (while App Service is detected, deleted and created) and I have the change deployed.
  2. Manually: Go to azure portal, select App Service, Continuous Deployment and click Sync. It takes 15-20 secs only. (Check screenshot)enter image description here

My question is:

How can I automate from PowerShell the equivalent of clicking "Sync" button?

NOTE1: There is a similar question here, with no answer.

NOTE2: The template part for source control creation is this one:

      {
          "apiVersion": "2014-04-01",
          "name": "web",
          "type": "sourcecontrols",
          "dependsOn": [
            "[resourceId('Microsoft.Web/Sites', parameters('siteName'))]",
            "[concat('Microsoft.Web/Sites/', parameters('siteName'), '/config/web')]"
          ],
          "properties": {
            "RepoUrl": "[parameters('repoUrl')]",
            "branch": "[parameters('branch')]",
            "IsManualIntegration": true
          }
        }

NOTE3: I tried @MichaelB answer with no luck. It seems working but doesn't update the files. Output is

Name              : as-xxxx-dev01
ResourceId        : /subscriptions/a303bbb8-8c07-wq10-8a6a-6c1eceef81bb/resourceGroups/as-rg-xxxx-EUN-DEV01/providers/Microsoft.Web/sites/as-cms-dev01/sourcecontrols/web
ResourceName      : as-xxxx-dev01/web
ResourceType      : Microsoft.Web/sites/sourcecontrols
ResourceGroupName : as-rg-xxxx-EUN-DEV01
Location          : North Europe
SubscriptionId    : a303ibb8-7i77-41d0-8a2s-6c1aaaaf81aa
Tags              : {System.Collections.Hashtable}
Properties        : @{RepoUrl=https://deployments:*******@bitbucket.org/project/as-xxxx.git; Branch=master; IsManualIntegration=False; DeploymentRollbackEnabled=False; 
                    IsMercurial=False; ProvisioningState=Succeeded}
Community
  • 1
  • 1
Oscar Foley
  • 6,817
  • 8
  • 57
  • 90
  • Thanks. I almost lost the hope and was thinking to change to local-git or FTP. Will give another try... – Oscar Foley Jan 29 '16 at 12:29
  • I've just managed to force a resync on my deployment, See rewritten answer. – Michael B Jan 29 '16 at 13:20
  • Why not just setup continues deployment? then every time there is a push even, kudu (the engine behind Azure App Service) will build and deploy your site. – Xiaomin Wu Jan 30 '16 at 01:00
  • @XiaominWu my presumption from the question was that usually there was a Jenkins build that deployed, hence `"IsManualIntegration": true` and 'sometimes' he wanted a manual sync - but reading your question with that thought, I'm curious of the answer too now! – Michael B Jan 30 '16 at 17:10

3 Answers3

5

Having just come across a similar situation myself, it seems this is the solution (or at least, a solution)

If you initially delete the repo, and then re-add it, it will - obviously - force a resync.

Remove-AzureRmResource -ResourceGroupName $AppServiceResourceGroupName `
                -ResourceType Microsoft.Web/sites/SourceControls `
                -Name $AppServiceWebAppName/Web `
                -ApiVersion 2015-08-01 `
                -Force


$props = @{
    RepoUrl = "https://github.com/{account}/{repo}"
    Branch = "master"
    isManualIntegration = "false" 
}
########## -- Configure Source Control --##########
New-AzureRmResource -ResourceGroupName $AppServiceResourceGroupName `
                -ResourceType Microsoft.Web/sites/SourceControls `
                -Name $AppServiceWebAppName/Web `
                -PropertyObject $props `
                -ApiVersion 2015-08-01 `
                -Force
Michael B
  • 11,887
  • 6
  • 38
  • 74
  • Interesting... I will try tomorrow! – Oscar Foley Jan 25 '16 at 22:26
  • Your code seems to work but files are not being updated. I edited question with the template parte for sourcecontrol (NOTE2) and the output of your command (NOTE3) – Oscar Foley Jan 26 '16 at 15:39
  • 1
    if you look in [Resource Explorer](https://resources.azure.com) and see what the syntax is to put in the $props (configure it from the portal first) that might get you closer - I've never synced from bitbucket – Michael B Jan 26 '16 at 15:47
  • Still doesn't work. In Resource Explorer there is a PowerShell example that uses **Set-AzureRmResource** instead of **New-AzureRmResource**. It also uses **-ResourceName** instead of **-Name**. Tried both and still doesn't update... – Oscar Foley Jan 26 '16 at 16:25
4

What the Sync button does is git pull from BitBucket to Azure. You can accomplish the same thing by pushing to Azure directly.

First, setup:

  1. Copy the Git clone url in the Azure Portal (back up two blades to the main web app portal page). Mine looks like https://robrich@thedescriptivename.scm.azurewebsites.net:443/thedescriptivename.git
  2. Set / get Git deployment credentials. Go to the "Deployment Credentials" blade in the Azure site, and set the credentials you'd like to use. If you've done this previously (which I think you have) then you can just use the credentials you set previously.
  3. Open a command prompt or powershell in the project's working directory (where the .git folder is).
  4. Add a second remote (like origin) named "azure": git remote add azure https://{that_url_you_copied_above}.

Now let's experiment from the command line:

  1. Change and commit something that isn't pushed to Jenkins.
  2. Open a command prompt or powershell in the project's working directory (where the .git folder is). This can be the same cmd you used above.
  3. Push the changes: git push origin azure.
  4. It'll invite you to login if you haven't pushed this way before. Use the credentials you created / remembered from above.
  5. Watch the portal notice a new change, and deploy the new code.

Now that it works, let's add it to powershell:

  1. git push origin azure

Note that you'll either need to modify the URL above to include the password or find another way to authenticate from within the script -- you probably don't want the pop-up in the middle of each run.

Why is this better or worse? You just jumped around Jenkins, so you're not running your test suite before deploying. You are deploying much faster though. Weigh these carefully.

robrich
  • 13,017
  • 7
  • 36
  • 63
4

Here's how to mimic the "Sync" button with an API call*. Site hooked up with "External Repository" deployment method.

Request:

POST /deploy HTTP/1.1

Host: $SiteLevelUsername:SiteLevelPassword@WebAppName.scm.azurewebsites.net
Content-Type: application/json
Accept: application/json
X-SITE-DEPLOYMENT-ID: WebAppName
Cache-Control: no-cache

{
    "format":"basic",
    "url":"https://username:password@example.com/git/reponame.git"
} 

You’ll also need a Content-Length header in there. You can get away with Transfer-encoding: chunked instead, if in a hurry.

Response (empty body):

200 OK

* Source: I figured it out looking at https://github.com/projectkudu/kudu/blob/master/Kudu.Services/ServiceHookHandlers/GenericHandler.cs and a Kudu trace of a successful "Sync" from the portal.

D:\home\LogFiles\kudu\trace>head 2016-04-08T10-43-27_2a1598_086_POST_deploy_200_3s.xml

<step title="Incoming Request" date="2016-04-08T10:43:27.636" instance="2a1598" 
url="/deploy?scmType=ExternalGit" method="POST" type="request"
pid="35604,2,68" Connection="Keep-Alive" Content-Length="107"
Content-Type="application/json; charset=utf-8" Accept="application/json"
Accept-Language="en-US" Expect="100-continue"
Host="WebAppName.scm.azurewebsites.net"
User-Agent="Azure-Portal/5.16.00298.15"
x-ms-client-request-id="xxxxxxxxxxxx"
x-ms-client-session-id="xxxxxxxxxxx"
X-SITE-DEPLOYMENT-ID="WebAppName"

Same request with Azure PowerShell:

# Action sync
Invoke-AzureRmResourceAction -ResourceGroupName <ResourceGroupName> `
                             -ResourceType Microsoft.Web/sites `
                             -ResourceName <WebAppName> `
                             -Action sync `
                             -ApiVersion 2015-08-01 `
                             -Force -Verbose

# Expected output:
# ----------------
# VERBOSE: Performing the operation "Invoking the 'sync' action
# on the resource." on target 
# subscriptions/xx-xx-xx-xx/resourceGroups/xxxx/providers/Microsoft.Web/sites/xxxx".

and curl:

:: cmd.exe uses ^ (caret) to escape new lines (the equivalent of \ in bash)

C:\>curl -k -v https://$siteLevelUsername:SiteLevelPassword@WebAppName.scm.azurewebsites.net/deploy ^
     -H "Transfer-encoding: chunked" -H "X-SITE-DEPLOYMENT-ID: WebAppName" ^
     -H "Content-type: application/json" -H "Accept: application/json" ^
     --data-ascii "{ \"format\":\"basic\", \"url\":\"http://user:pass@example.com/git/repo.git\" }"

> POST /deploy HTTP/1.1
> Authorization: Basic xxxxxxxxxxxxxxxxxxx=
> User-Agent: curl/7.28.1
> Host: WebAppName.scm.azurewebsites.net
> Transfer-encoding: chunked
> X-SITE-DEPLOYMENT-ID: WebAppName
> Content-type: application/json
> Accept: application/json
>
> 66
* upload completely sent off: 109 out of 102 bytes

< HTTP/1.1 200 OK
< Cache-Control: private
< Content-Length: 0
evilSnobu
  • 24,582
  • 8
  • 41
  • 71