Deploy Multiple Projects

I have two projects. App-1 and App-2. Both have different Environment, life Cycle and Channels. I want project App-1 to be deployed before App-2. App-2 will be deployed only if App-1 deployed successfully. Both projects have their own version numbering and their own packages

How can I do this in Octopus?

Hi @endashaw.adane,

Thanks for reaching out. I think the best way to go about this would be to have a Meta project thats deployment process is to deploy a release from the other 2 projects, and then make App2’s deploy mandatory that the release for App1 was a success.

A quick diagram would be
Meta Project’s Deployment Process:
Deploy a Release (Project App1)
Deploy a Release (Project App2) - Previous step must be successful.

Please let me know if that will work for you or if you need further help.

Thanks,
Jeremy

Hi @jeremy.miller,
Thanks for your reply. As you said I’ve created a new project i.e. MasterApp that has two steps: Deploy a release (Project App1) and Deploy a Release (Project App2). When I create a release, the Master project will have 0.0.1 release. As I said before the two projects have their own package version. After creating the release, 0.0.1 the first project deployed successfully. However, the second one expecting guided failure. I’ve attached some screen shotsDeploy Multiple Project.docx (351.4 KB)

Hi @endashaw.adane,

Sorry about that. I missed the part about differing lifecycles the first time and didn’t think about the potential for issue there.

I think the path forward is to use the step template here: https://library.octopus.com/step-templates/18392835-d50e-4ce9-9065-8e15a3c30954/actiontemplate-chain-deployment

It has a bit more setup than just a regular Deploy a Release step, but it also has more granularity. It should be able to get you where you need to go.

Please give it a look and test it and let me know if you’re able to get it working.

Let me know if you have any questions on it.

Thanks,
Jeremy

Hi @jeremy.miller,

Thanks again. I created Chain Deployment step on first project for the second. little bit confused what to fill for API Key, Project Name, Channel Name etc. I think I’ve to use the Restful API. can you give me an example for some of parameters?

Hi @endashaw.adane,

You are correct, for api key you will use one from your profile. I would create a sensitive variable within the project then use the variable in that spot instead of copy pasting the api key to that field.

The project name would be Project for App1 for step 1, project for app 2 for step 2, whatever the names of the projects that house the 2 apps you want to deploy are called in your octopus instance.

For channel, you would just input the name of your channel in the projects you want to deploy a release from. You can leave it blank for default channel.

You will just type the names of the objects not the IDs. You could also store the names within variables in the project then call those variables in the parameter fields.

Please let me know if that works or if you need any more help with the fields.

Edit: it looks like you’ve just added chain deployment to the end of project 1, which is probably the easier way to do it. So you would just need to do the above for project 2 within that chain deployment step.

You could also create some output variables within your project 1 then use those to determine environment/channel for project 2 if you can make the logic automated. https://octopus.com/docs/projects/variables/output-variables#:~:text=Output%20variables%20can%20be%20set,scripting%20languages%20supported%20by%20Octopus.

You may also be able to scope variables to help with automation of those parameters as well. For example project 1 could have a scoped variable for environment development which tells the chain template step which environment to use for the second project based on the first project going to development.

Let me know if that makes sense.

Thanks,
Jeremy

Hi @jeremy.miller trying to use Chain Deployment. however, go

t connection issue as attached here with.

Hi @endashaw.adane,

How have you configured the step to execute? On the deployment target, or on the server itself/default worker pool?

This points to a connection problem getting back to the server. Could you please download a full task log and privately message it to me so I can take a look?

Thanks,
Jeremy

Hi @jeremy.miller,

I selected Octopus Server as execution location. I’ve captured the log but want to make sure your email address. I’ve sent a test message. let me know if you have received it

Hi @jeremy.miller,

sent you the log file

Hi @jeremy.miller,

we have implemented OKTA for single sign on. does it matter?

Hi @endashaw.adane,

It doesn’t seem like it should matter, because the octopus server itself is running the call.

Is there anything in the Octopus Server logs around the time that the GET calls are failing in the script? The default location is C:\Octopus\Logs.

As a test, can we have you remote into the Octopus Server and run a PowerShell API call as the service account that runs the Octopus service and see if it succeeds or fails?

Here is some sample code. You just need to fill in the top fields and run it as the Octopus service’s service account.

$OctopusServerUrl = ""  #PUT YOUR SERVER LOCATION HERE. (e.g. http://localhost)
$ApiKey = ""   #PUT YOUR API KEY HERE
$spaceName = ""   #PUT SPACE NAME HERE
$projectName = "" #PUT PROJECT NAME HERE
$runbookName = "" #PUT RUNBOOK NAME HERE

Function Get-SpaceId {
    # Define parameters
    param(
        $Space
    )
    $spaceName = $Space
    $spaceList = Invoke-RestMethod "$OctopusServerUrl/api/spaces?Name=$spaceName" -Headers @{"X-Octopus-ApiKey" = $ApiKey }
    $spaceFilter = @($spaceList.Items | Where { $_.Name -eq $spaceName })
    $spaceId = $spaceFilter[0].Id
    return $spaceId
}
Function Get-OctopusProject {
    # Define parameters
    param(
        $OctopusServerUrl,
        $ApiKey,
        $ProjectName,
        $SpaceId
    )
    # Call API to get all projects, then filter on name
    $octopusProject = Invoke-RestMethod -Method "get" -Uri "$OctopusServerUrl/api/projects/all" -Headers @{"X-Octopus-ApiKey" = "$ApiKey" }

    # return the specific project
    return ($octopusProject | Where-Object { $_.Name -eq $ProjectName -and $_.SpaceId -eq $SpaceId})
}
Function Get-RunbookId {
    # Define parameters
    param(
        $Runbook,
        $ProjectId,
        $SpaceId
    )
    $runbookname = $runbook
    $runbookList = Invoke-RestMethod "$OctopusServerUrl/api/runbooks?Name=$runbookName" -Headers @{"X-Octopus-ApiKey" = $ApiKey }
    $runbookFilter = @($runbookList.Items | Where { $_.Name -eq $runbookName -and $_.ProjectId -eq $ProjectId -and $_.SpaceId -eq $spaceId })
    $runbookId = $runbookFilter[0].Id
    return $runbookId
}


$spaceId = Get-SpaceId -space $spaceName
$projectId = Get-OctopusProject -OctopusServerUrl $OctopusServerUrl -ApiKey $ApiKey -ProjectName $projectName -SpaceId $spaceid
$projectId = $projectId.Id
$runbookId = Get-RunbookId -Runbook $runbookName -ProjectId $projectId -SpaceId $spaceId
$runbook = Invoke-RestMethod "$OctopusServerUrl/api/$spaceId/runbookProcesses/RunbookProcess-$runbookId" -Headers @{"X-Octopus-ApiKey" = $ApiKey }
$json = $null
$json = $runbook | convertto-json -depth 10
write-host $json

Please let me know if there is anything in the logs and the results of the above test.

Thanks,
Jeremy

hi @jeremy.miller
I RDP to Octopus server, run powershell ISE as different user (i.e. service account). past the above test script, change the values as you said except runbook …as I dont use it. When I run it I got the following. Regarding, the log file, I tried to run the deployment process again but could not find anything in the log file related to that.

Invoke-RestMethod : The underlying connection was closed: An unexpected error occurred on a receive.
At line:13 char:18

  • … spaceList = Invoke-RestMethod "$OctopusServerUrl/api/spaces?Name=$spa …
  •             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    • CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebException
    • FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand

Invoke-RestMethod : The underlying connection was closed: An unexpected error occurred on a receive.
At line:27 char:23

  • … usProject = Invoke-RestMethod -Method “get” -Uri "$OctopusServerUrl/a …
  •             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    • CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebException
    • FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand

Invoke-RestMethod : The underlying connection was closed: An unexpected error occurred on a receive.
At line:40 char:20

  • … nbookList = Invoke-RestMethod "$OctopusServerUrl/api/runbooks?Name=$r …
  •             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    • CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebException
    • FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand

Invoke-RestMethod : The underlying connection was closed: An unexpected error occurred on a receive.
At line:51 char:12

  • $runbook = Invoke-RestMethod "$OctopusServerUrl/api/$spaceId/runbookP …
  •        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    • CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebException
    • FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand

Hi,

Which version of .NET is the server running? It appears this error could be caused by running an old version.

Thanks,
Jeremy

Hi.

here is the screenshot for .net framework. according to https://docs.microsoft.com/en-us/dotnet/framework/migration-guide/how-to-determine-which-versions-are-installed,
528049 is .net Framework 4.8
image.png

Hi,

Thanks for the information.

This could also be due to TLS. In the example I gave you above, could you put this line of code at the top of the script and run it again?

[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12

Please let me know if that gives us different results.

Thanks,
Jeremy

Hi,

yes this gives a different result. I don’t have a runbook. do I need to define one and put both steps?

Invoke-RestMethod : The remote server returned an error: (404) Not Found.
At D:\test.ps1:52 char:12

  • $runbook = Invoke-RestMethod "$OctopusServerUrl/api/$spaceId/runbookP …
  • CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebException
  • FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand

Regards,

Hi,

This was actually just a test to see if we could figure out what type of problem we had going here.

Now that we know that this is likely the issue, could you please go to the Chain Deployment code in the Step Template Library and add that same line of code after the comments stop at line 82, and then save the template as a copy, and attempt to use that version of Chain Deployment and see if the deployment works?

Please let me know if that fixes the Chain Deployment step for you.

Thanks,
Jeremy

hI @jeremy.miller,

This is cool! The deployment is successful. However, there was manual intervention in the project that the chain deployment executes. In the task log it shows the manual intervention and its action as warning. As a result the overall deployment shows success with warning. I’ve attached screenshot.

chain deployment-2

Hi @endashaw.adane,

I’m glad to hear it worked for you, thanks for letting me know. Manual interventions generating a warning is intentional, but you could definitely edit the code in the template to change it to not be a warning if that’s what you would prefer.

Please let me know if you have any other questions.

Thanks,
Jeremy