Dot Peekser Logo

#Sitecore#XM Cloud#Thoughts

XM Cloud - First steps

by Tobias Demski on

Today we will go through the first steps of how to setup Sitecore XM Cloud.

Before we can work with Sitecore XM Cloud we have to belong to an organization. Ensure you are assigned to at least one organization.

⁠If you are ready, you can create a project and an environment through the following website. https://deploy.sitecorecloud.io/ or optional use the dotnet sitecore cloud plugin.

Creating your project and environment

If you are assigned to an organization you will need to create a project. By creating a new project you have two options:

1. Connect your project with a github repository

When you create a project you can link a single repository which will be used for all your environments within a project (At the moment you can only link to a github repository through the UI).
⁠You can choose between starting from "scratch" or "existing code".
⁠Later you can deploy your code based on the setting "Trigger deployment on commit to branch" or by using the website / cli.

⁠Side note: If you link your environment to a branch you are not able to deploy from the file system. You have to unlink the branch through the environment details menu.

2. No connection - Local deployment

If you don't want to rely on a repository, you can deploy your code from your local filesystem. This requires to use the Sitecore CLI with the cloud plugin.

Sitecore CLI Login

If you want to use the Sitecore CLI we need to login with powershell dotnet sitecore cloud login .
⁠A browser should open where you have to login and grant permission to the device. (Check the code from the browser window with the id in your powershell console)

Organization overview

Based on your chosen option, your overview should like this after the project creation wizard:

xm-cloud-projects-overview.png

Creating a project through the Sitecore CLI cloud plugin with this command: dotnet sitecore cloud project create --name YOUR_PROJECT_NAME

This will create a new project with the provided project name in your current connected organization.

Project details

If you are heading to your created project you are able to create new environments. For each environment you are able to define a name, a boolean if this environment is a production environment, link it to a specific branch* and if a new deployment should be triggered* if a new commit in the selected branch was made.

* if connected with github

Creating an environment through the Sitecore CLI cloud plugin:

Create an environment: dotnet sitecore cloud environment create --project-name YOUR_PROJECT_NAME --name YOUR_ENV_NAME --prod BOOLEAN

With the creation of the environment, Sitecore starts the provisioning process to perform all the required tasks for a valid environment.

Environment

Deployment preparation

Before you start deploying your code in XM Cloud you have to prepare your file system.

Your solution needs a file named xmcloud.build.json.

The XM Cloud build configuration for an environment is defined in the xmcloud.build.json file. The file contains configurations for editing hosts, build targets, serialization modules to deploy to the XM instance for that environment, and more.

XM Cloud build configuration

Also a solution file (.sln) and at least an empty project (.csproj) is required to deploy to XM cloud.

Installing the Sitecore CLI

Before you can work with the sitecore cli and also the cloud plugin you have to initialize your project.
With only a few commands you are ready to go:

dotnet new tool-manifest
dotnet nuget add source -n Sitecore https://sitecore.myget.org/F/sc-packages/api/v3/index.json
dotnet tool install Sitecore.CLI
dotnet sitecore init # Installs the default plugins
dotnet sitecore plugin add -n Sitecore.DevEx.Extensibility.XMCloud # Installs the XM Cloud plugin

If your project already initialized the project for the cli but just started to work on this you only have to call dotnet tool restore.

While executing the command dotnet tool install Sitecore.CLI or dotnet tool restore you could get the error message "dotnet-tools.json came from another computer and might be blocked to help protect this computer. For more information, including how to unblock, see https://aka.ms/motw"

To fix this issue you can execute a powershell script to unblock all files:

Get-ChildItem "C:\YOUR_PROJECT_PATH\" -Recurse | Unblock-File

Install Sitecore Command Line Interface

Deployment with the Sitecore CLI and the cloud plugin

Triggering a deployment with the sitecore cli requires an environment id. One option is to retrieve the environment id through the enviroment overview page (see above "Environment" section) or to query the id with the sitecore cli.

With the cli we need to list our projects with dotnet sitecore cloud project list --json to get all our projects within our organization.

The output should look similar to this output

{
    "organizationName": "dotPeekser",
    "organizationId": "org_AtGBkLvCEzULwvVw",
    "id": "60JLSTSBC4WiZz5VTTA11b",
    "name": "Playground",
    "region": "weu",
    "createdBy": "info@dotpeekser.de",
    "createdAt": "2023-04-04T09:50:30.4217801Z",
    "lastUpdatedBy": "info@dotpeekser.de",
    "lastUpdatedAt": "2023-04-04T09:50:30.4217801Z",
    "sitecoreMajorVersion": 1,
    "environments": [
      "0OiDHAlcdQB80TQoOxE9F",
      "2dnicawejL1Iv4rLgexMhR",
      "4RXtm1XWA5xyKdWPPKxEhB"
    ]
}

You can see in the environments property that we already have three enviroments created. To list all enviroments based on a project we can execute the following command.

dotnet sitecore cloud environment list --project-id PROJECT_NAME --json

[{
    "OrganizationId": "org_AtGBkLvCEzULwvVw",
    "OrganizationName": "dotPeekser",
    "ProjectId": "60JLSTSBC4WiZz5VTTA11b",
    "ProjectName": "Playground",
    "Id": "0OiDHAlcdQB80TQoOxE9F",
    "Name": "DotPeekserEnvOne",
    "Host": "xmc-dotpeekser-playground-dotdfc.sitecorecloud.io",
    "TenantType": "nonprod",
    "CreatedBy": "info@dotpeekser.de",
    "CreatedAt": "2023-04-27T14:15:43.8323202Z",
    "LastUpdatedBy": "info@dotpeekser.de",
    "LastUpdatedAt": "2023-04-27T14:15:43.8323202Z",
    "ProvisioningStatus": 2,
    "ProvisioningLastFailureMessage": null,
    "LastSuccessfulDeploymentId": "2XXHVICqVWXOm5l2Fdg7yh",
    "Health": {
      ...
    },
    ...
  }, {
    "OrganizationId": "org_AtGBkLvCEzULwvVw",
    "OrganizationName": "dotPeekser",
    "ProjectId": "60JLSTSBC4WiZz5VTTA11b",
    "ProjectName": "Playground",
    "Id": "4RXtm1XWA5xyKdWPPKxEhB",
    "Name": "DotPeekserEnvTwo",
    ...
  }, {
    "OrganizationId": "org_AtGBkLvCEzULwvVw",
    "OrganizationName": "dotPeekser",
    "ProjectId": "60JLSTSBC4WiZz5VTTA11b",
    "ProjectName": "Playground",
    "Id": "2dnicawejL1Iv4rLgexMhR",
    "Name": "DotPeekserEnvThree",
    ...
  }
]

Now we have to choose an environment to deploy our code. In this example we will pick the first environment with the id 0OiDHAlcdQB80TQoOxE9F.

The following command can be executed to queue a new deployment without starting it (--no-start). If you want to deploy a different folder than the current folder you can specify the path within the --working-dir parameter.

dotnet sitecore cloud deployment create --environment-id 0OiDHAlcdQB80TQoOxE9F --working-dir . --upload --no-watch --no-start --json

Due to the --json parameter, the result will be in json.

{
  "OrganizationId": "org_DtGBkLvCEzULwvWi",
  "ProjectId": "50JLSMSBC4WiYz5VSTA13b",
  "EnvironmentId": "0OiDHBlceQB80TQoOxE9F",
  "Id": "6DKJn3SKdngJ8IkPNMIOkB",
  "StartedAt": null,
  "CompletedAt": null,
  "ProvisioningStatus": 0,
  "ProvisioningStartedAt": null,
  "ProvisioningCompletedAt": null,
  "ProvisioningLastFailureMessage": null,
  "BuildStatus": 0,
  "BuildStartedAt": null,
  "BuildCompletedAt": null,
  "BuildLastFailureMessage": null,
  "DeploymentStatus": 0,
  "DeploymentStartedAt": null,
  "DeploymentCompletedAt": null,
  "DeploymentLastFailureMessage": null,
  "PostActionStatus": 0,
  "PostActionStartedAt": null,
  "PostActionCompletedAt": null,
  "PostActionLastFailureMessage": null,
  "CalculatedStatus": 0,
  "CreatedBy": "info@dotpeekser.de",
  "CreatedAt": "2023-05-16T13:05:54.069972Z",
  "TriggerMessage": "Deployment created by info@dotpeekser.de",
  "Health": {
    ...
  }
}

If we take a look in our environment through the https://deploy.sitecorecloud.io/ we can see a new deployment is queued.

To start the queued deployment, we can use the id we retrieved from the last response and use it for the -id parameter as follows: dotnet sitecore cloud deployment start -id 6DKJn3SKdngJ8IkPNMIOkB

The deployment will start to kick off after a few seconds.

Deployment details

A deployment consists of 4 parts:

  1. Provisioning
    • Ensures an enviroment exists (Configuring Unified identity, DB creation, Setting up Experience Edge)
  2. Build
    • Build your solution and creating resources as items, uploading artifacts
  3. Deployment
    • Deploying the uploaded artifacts, XDT transformations, Update binding redirects
  4. Post actions
    • Warmup CM, Populate schema, reindex

Connecting to Experience Edge

To generate an edge token we need a working environment. In your root folder of your code repository (if starter kit is used) you should find a powershell script named "New-EdgeToken.ps1" otherwise you can use the script below.
⁠Execute it to generate a new edge token: ⁠.\New-EdgeToken.ps1 -EnvironmentId "YOUR_ENV_ID"

[powershell]: New-EdgeToken.ps1
# parse the sitecore.json file for the XM Cloud plugin version
[CmdletBinding(DefaultParameterSetName = 'FromArgs')]
param (
    [Parameter(Mandatory)]
    [string]$EnvironmentId
)

$ErrorActionPreference = "Stop"

$XmCloudDeployApi = (Get-Content "$PSScriptRoot\.sitecore\user.json" | ConvertFrom-Json).endpoints.xmCloud.host
$XmCloudDeployAccessToken = (Get-Content "$PSScriptRoot\.sitecore\user.json" | ConvertFrom-Json).endpoints.xmCloud.accessToken

$Headers = @{"Authorization" = "Bearer $XmCloudDeployAccessToken" }
$URL = @(
    "$($XmCloudDeployApi)api/environments/v1"
    $EnvironmentId
    'obtain-edge-token'
)

$Response = Invoke-RestMethod ($URL -join '/') -Method 'GET' -Headers $Headers -Verbose
$AccessToken = $Response.apiKey
$EdgeUrl = "$($Response.edgeUrl)/api/graphql/ide"
Write-Host "Launching Edge GraphQL IDE"
Write-Host "Add { ""X-GQL-Token"" : ""$AccessToken"" } to the HTTP HEADERS tab at the bottom-left of the screen to write queries against your content"
Start-Process $EdgeUrl

If you havent logged in yet or your access token is expired you will get an unauthorized error. Response status code does not indicate success: 401 (Unauthorized).

Working with the Experience Edge GraphQL IDE

After retrieving the GQL-Token from the script before, you can publish your content from the CM system to the Edge target and you will be able to query the data from the edge.

From the GraphQL playground can test your queries against the edge: https://edge.sitecorecloud.io/api/graphql/ide

Ensure that the endpoint url should is pointing to this url: https://edge.sitecorecloud.io/api/graphql/v1/

Paste your GQL-Token in the header in the following format:

[json]: HTTP HEADERS
{
  "X-GQL-Token" : "YOUR_GQL_TOKEN"
}

Test your connection with an example query

[graphql]: Retrieve the content item in en
query SitecoreContentItem {
  item(path: "/sitecore/content", language: "en") {
    path
    id
    name
    displayName
  }
}

Your response on the right side should look like this.

{
  "data": {
    "item": {
      "path": "/sitecore/content",
      "id": "0DE95AE441AB4D019EB067441B7C2450",
      "name": "content",
      "displayName": "Content"
    }
  }
}

Connecting to Authoring / Management API

There is also an endpoint for the authoring and management api through your instance endpoint.
⁠With this endpoint you can mutate your content with GraphQL queries. To connect to your GraphQL IDE you have to set at first the Sitecore_GraphQL_ExposePlayground environment variable to true.

You need to redeploy your application so that your variable is taken into account.

To access your GraphQL endpoint you can call either https://YOUR_INSTANCE_NAME.sitecorecloud.io/sitecore/api/authoring/graphql/ide/ or https://YOUR_INSTANCE_NAME.sitecorecloud.io/sitecore/api/authoring/graphql/playground/

Ensure that your endpoint url points to the following url: https://YOUR_INSTANCE_NAME.sitecorecloud.io/sitecore/api/authoring/graphql/v1/

Otherwise you will see the message "Server cannot be reached".

The last step to be able to send queries is to set the correct http headers for the authorization.

You can either use the access token you generated from the dotnet sitecore cloud login (Access token is located in .\sitecore\user.json) or you can create an automation client from the deploy app and generate a new access token.

[powershell]: Generate access token
$clientId="YOUR_CLIENTID"
$clientSecret="YOUR_CLIENTSECRET"
$authUrl="https://auth.sitecorecloud.io"
$audience="https://api.sitecorecloud.io"


$headers=@{}
$headers.Add("Content-Type", "application/x-www-form-urlencoded")
$response = Invoke-WebRequest -Uri "$authUrl/oauth/token" -Method POST -Headers $headers -ContentType "application/x-www-form-urlencoded" -Body "client_id=$clientId&client_secret=$clientSecret&audience=$audience&grant_type=client_credentials"

$accessToken = ($response | ConvertFrom-Json).access_token

Write-Host $accessToken

Set the retrieved access token in the header as follows

[json]: HTTP HEADERS
{
    "Authorization": "Bearer  YOUR_API_TOKEN"
}

Now we can test our connection with an example query

[graphql]: Retrieve the content item in en
query SitecoreContentItem {
  item(where: { path: "/sitecore/content", language: "en" }) {
    itemId
    path
    name
    displayName
  }
}

If you need further informations about the authoring api configuration you can also take a look on the Sitecore documentation.

Serialization with XM Cloud

Because the Sitecore CLI needs a valid login too and Sitecore already stored the login information from the dotnet sitecore cloud login in the .sitecore\user.json we just create an additional "default" entry with a ref to the "xmCloud" configuration: dotnet sitecore login --ref "xmCloud" --cm "https://xmc-dotpeekser-playground-dotdfc.sitecorecloud.io" --allow-write true

allow-write true parameter is important, otherwise you are not able to pull / push and you will get the error message "Environment default is not configured to allow writing data. Use what-if, or set the environment to allow writes in the user.json file."

The next time you need to login, you just have to call the command dotnet sitecore login

After your browser login and device confirmation we can use the ser commands!
⁠Example: dotnet sitecore ser pull

Useful Sources

Tobias Demski

I'm a Software Engineer with 10+ years of experience. Passionate about software development, and I like to get challenged by new stuff.