Variables and Variable sets

resolved
cloud
usability
support
known
(Ggiacalone) #1

Hello Octopus Community.
I am wondering if anyone here has come across this scenario before, and found a solution for it. This involves two projects one of which a variable is dependent on setting a variables value from a different projects (name,environment,release number) for a path. This is to search and replace application.json for a web application.

I was given these two links from Support, but I havent the first clue how to integrate an api call in the variable sets of a project.

Examples: https://github.com/OctopusDeploy/OctopusDeploy-Api
API Wiki: https://github.com/OctopusDeploy/OctopusDeploy-Api/wiki
Example of what you want to do: https://github.com/OctopusDeploy/OctopusDeploy-Api/blob/master/REST/PowerShell/Releases/GetLastSuccessfulForProjectAndEnvironment.ps1

Does anyone have an example?

Thanks in advance.

(Jeremy Miller) #3

Hi ggiacalone,

If you ever get a response from us in support that you need further explanation or help with, please don’t hesitate to reply and ask more questions, that’s what we’re here for!

I can get you started with your API calls. I will give you an example of a script with API calls to get another project’s last successful release version.

These instructions are assuming you are needing a static project and environment. If the script needs to dynamically pick a project and environment that would be more work.

First on your server you would want to go to these web pages to find the Space Id, Project Id and the Environment ID.

http://YOUR_OCTOPUS_URL/api/Spaces
Find the Space # where your project is and use it in the following URLs.

http://YOUR_OCTOPUS_URL/api/Spaces-#/projects (Change the # to the space you found in the first URL)
Find the project name, then scroll up to find the Id. It will be something like “Projects-2”.

http://YOUR_OCTOPUS_URL/api/Spaces-#/environments (Change the # to the space you found in the first URL)
Find the environment name, then grab the environment ID. It will be something like “Environments-1”.

Once you have these two IDs, you can insert the following code into your PowerShell script step. I have put comments in to try to explain the important lines.

##CONFIG for later API calls.
$OctopusURL = "http://YOUR_OCTOPUS_URL" #Octopus URL (change it to your octopus location)
$OctopusAPIKey = "" #Octopus API Key (for info getting an API key, go to (https://octopus.com/docs/octopus-rest-api/how-to-create-an-api-key)

##PROCESS##
$header = @{ "X-Octopus-ApiKey" = $OctopusAPIKey } #This is used for API Calls to pass the API Key
$ProjectID = "Projects-2"  #You got this variable earlier
$EnvironmentID = "Environments-1" #You got this variable earlier

#This is an API call getting the releases of the project we have identified.
$ProjectDashboardReleases = (Invoke-WebRequest $OctopusURL/api/progression/$ProjectID -UseBasicParsing -Method Get -Headers $header).content | ConvertFrom-Json

#This is us setting a variable to the last successful release
$LastSuccessfullRelease = $ProjectDashboardReleases.Releases.Deployments.$EnvironmentId | ?{$_.state -eq "Success"} | select -First 1

#This is the variable call that will give us the latest successful release version.
$LastSuccessfullRelease.ReleaseVersion

You can then use the last variable in your script to do what you need to do. Hopefully this is enough to get you going. If you need more help please reach out.

(Ggiacalone) #4

Thank you Jeremy I am on board with using these API’s. I am not stranger to them, however where I need these values are in your applications variable sets, to be used to search and replace key value pair in application.json files. The variable set is a project, and that project is needing some values from another project on that server. I am no stranger to ansible or python, but unfortunately powershell is not my forte. Are you suggesting to run a script separate from the variable sets in that project using these api’s to set this value?

(Jeremy Miller) #5

Hi ggiacalone,

I think the best way to achieve this is by using PowerShell to modify/retrieve values from another project. I have written two scripts in the past for someone else to do something similar. The first script will allow you to modify/add variables to a project’s variable set. The second one will allow you to retrieve a value from a variable set in a project. You will only need to put in a few pieces of information and then call the function in the desired way. I have examples in both scripts on how to call the functions. Please let me know if you have any questions, or if I misunderstood what you were trying to accomplish. As always with scripts like these, please read them carefully and do testing in a dummy project to make sure you are getting your desired results.

Modify/Add Variable.ps1

Function Get-OctopusProject
{
    # Define parameters
    param(
        $OctopusServerUrl,
        $ApiKey,
        $ProjectName
    )

    # 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})
}

Function Get-OctopusProjectVariables
{
    # Define parameters
    param(
        $OctopusDeployProject,
        $OctopusServerUrl,
        $ApiKey
    )

    # Get reference to the variable list
    return (Invoke-RestMethod -Method "get" -Uri "$OctopusServerUrl/api/variables/$($OctopusDeployProject.VariableSetId)" -Headers @{"X-Octopus-ApiKey"="$ApiKey"})
}

#Code to go find the spaceId
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-EnvironmentId{
    # Define parameters
    param(
        $EnvironmentName,
        $Space
    )
    $environmentName = $EnvironmentName
    $environmentList = Invoke-RestMethod "$OctopusServerUrl/api/$spaceId/environments?skip=0&take=1000&name=$environmentName" -Headers @{"X-Octopus-ApiKey"=$ApiKey}
    $environmentFilter = @($environmentList.Items | Where {$_.Name -eq $environmentName})
    $environmentId = $environmentFilter[0].Id
    return $environmentId
}


Function Modify-Variable{

    # Define parameters
    param(
        $VariableSet,
        $VariableName,
        $VariableValue,
        $VariableEnvScope,
        $Space
    )

    #If given a scope parameter, find the matching variable with scope and modify the value
    if ($VariableEnvScope){
    $spaceId = Get-SpaceId -Space $Space
    write-host "has scope"
    #Code to transform the environment name to environment ID.
    $environmentId = Get-EnvironmentId -EnvironmentName $VariableEnvScope -Space $spaceId

    #loop through all variables and change the value if the name and environment ID match
    ForEach ($variable in $VariableSet.Variables){
    if ($variable.Name -eq $VariableName -and $variable.Scope.Environment -eq $environmentId){
    $variable.Value = $VariableValue
    }
    }

    }
    #When a scope parameter is not given
    else{
    #Find the variable you want to edit by name, then edit the value. Only edit if the variable is unscoped.
    ForEach ($variable in $VariableSet.Variables){
    if ($variable.Name -eq $VariableName -and !$variable.Scope.Environment){
    $variable.Value = $VariableValue
    }
    }
    }

}



Function Add-Variable{

    # Define parameters
    param(
        $VariableSet,
        $VariableName,
        $VariableValue,
        $VariableEnvScope,
        $VariableRoleScope

    )
    #Find the environment ID based on the name given by the parameter.
    $environmentObj = $VariableSet.ScopeValues.Environments | Where { $_.Name -eq $VariableEnvScope } | Select -First 1
        #If there is no Env or Role scope, add variable this way
        if (!$VariableEnvScope -and !$VariableRoleScope){
            $tempVariable = @{
                Name = $VariableName
                Value = $VariableValue
                Scope = @{
                }
            }
        }
        #If there is an Env but no Role scope, add variable this way
        if ($VariableEnvScope -and !$VariableRoleScope){
            $tempVariable = @{
                Name = $VariableName
                Value = $VariableValue
                Scope = @{ 
                    Environment = @(
                        $environmentObj.Id
                    )
                }
            }
        }
        #If there is a Role Scope but no Env scope, add the variable this way
        if ($VariableRoleScope -and !$VariableEnvScope){
            $tempVariable = @{
                Name = $VariableName
                Value = $VariableValue
                Scope = @{ 
                    Role = @(
                        $VariableRoleScope
                    )
                }
            }
        }
        #If both scopes exis, add the variable this way
        if ($VariableEnvScope -and $VariableRoleScope){
            $tempVariable = @{
                Name = $VariableName
                Value = $VariableValue
                Scope = @{
                    Environment = @(
                        $environmentObj.Id
                    )
                    Role = @(
                        $VariableRoleScope
                    )
                }
            }
        }
    #add the variable to the variable set
    $VariableSet.Variables += $tempVariable
}

### INPUT THESE VALUES ####

$OctopusServerUrl = ""  #PUT YOUR SERVER LOCATION HERE. (e.g. http://localhost)
$ApiKey = ""   #PUT YOUR API KEY HERE
$ProjectName = ""   #PUT THE NAME OF THE PROJECT THAT HOUSES THE VARIABLES HERE

### INPUT THESE VALUES ####
try
{
    # Get reference to project
    $octopusProject = Get-OctopusProject -OctopusServerUrl $OctopusServerUrl -ApiKey $ApiKey -ProjectName $ProjectName

    # Get list of existing variables
    $octopusProjectVariables = Get-OctopusProjectVariables -OctopusDeployProject $octopusProject -OctopusServerUrl $OctopusServerUrl -ApiKey $ApiKey

    #Examples
    
    #If you want to modify an Environmentally scoped variable, you must pass the Environment with -VariableEnvScope and the Space with -Space
    #Modify-Variable -VariableSet $octopusProjectVariables -VariableName "Test" -VariableValue "New"
    #Modify-Variable -VariableSet $octopusProjectVariables -VariableName "Test2" -VariableValue "New2" -VariableEnvScope "Development" -Space "Default"
    #Add-Variable -VariableSet $octopusProjectVariables -VariableName "TestNew1" -VariableValue "Nothing to the right"
    #Add-Variable -VariableSet $octopusProjectVariables -VariableName "TestNewEnv" -VariableValue "Env to the right" -VariableEnvScope "Development"
    #Add-Variable -VariableSet $octopusProjectVariables -VariableName "TestNewRole" -VariableValue "Role to the right" -VariableRoleScope "Web"
    #Add-Variable -VariableSet $octopusProjectVariables -VariableName "TestNewEnvRole" -VariableValue "Both to the right" -VariableEnvScope "Development" -VariableRoleScope "Web"

    ##### PUT ANY MODIFY AND ADD COMMANDS HERE #####

    
    ##### PUT ANY MODIFY AND ADD COMMANDS HERE #####

    # Convert object to json to upload it
    $jsonBody = $octopusProjectVariables | ConvertTo-Json -Depth 10
    # Save the variables to the variable set
    Invoke-RestMethod -Method "put" -Uri "$OctopusServerUrl/api/variables/$($octopusProjectVariables.Id)" -Body $jsonBody -Headers @{"X-Octopus-ApiKey"=$ApiKey}
    

}
catch
{
    Write-Error $_.Exception.Message

    throw
}

Find-Variable.ps1

Function Get-OctopusProject
{
    # Define parameters
    param(
        $OctopusServerUrl,
        $ApiKey,
        $ProjectName
    )

    # 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})
}

Function Get-OctopusProjectVariables
{
    # Define parameters
    param(
        $OctopusDeployProject,
        $OctopusServerUrl,
        $ApiKey
    )

    # Get reference to the variable list
    return (Invoke-RestMethod -Method "get" -Uri "$OctopusServerUrl/api/variables/$($OctopusDeployProject.VariableSetId)" -Headers @{"X-Octopus-ApiKey"="$ApiKey"})
}

    

Function Find-Variable{

    # Define parameters
    param(
        $VariableSet,
        $VariableName
    )
    $OutputVariable = "Variable not found based on name and current env"
    $EnvScopeValueSet = $False
   
    #Loop through the variables
    ForEach ($variable in $VariableSet.Variables){
    #Find matching varable by name
    if ($variable.Name -eq $VariableName){
    #Check if it has an environment scope. If it doesnt, and no EnvScopeValue has been found and set, set it.
    if (!$variable.Scope.Environment -and !$EnvScopeValueSet){

    $OutputVariable = $variable.Value

    }

    #If there is a scoped environment...
    else{
    #check to see if the name and current environment match. Set flag that env scope value found.
     if ($variable.Name -eq $VariableName -and $CurrentEnv -eq $variable.Scope.Environment){
           $OutputVariable = $variable.Value
           $EnvScopeValueSet = $True
        }
        }
    }
    
    }
    return $OutputVariable
}

### INPUT THESE VALUES ####

$OctopusServerUrl = ""  #PUT YOUR SERVER LOCATION HERE. (e.g. http://localhost)
$ApiKey = ""   #PUT YOUR API KEY HERE
$ProjectName = ""   #PUT THE NAME OF THE PROJECT THAT HOUSES THE VARIABLES HERE

#Gets the current environment that the deployment is running from. Hard code this if not running the code from in a deployment.
$CurrentEnv = $OctopusParameters["Octopus.Environment.Id"]




### INPUT THESE VALUES ####

try
{
    # Get reference to project
    $octopusProject = Get-OctopusProject -OctopusServerUrl $OctopusServerUrl -ApiKey $ApiKey -ProjectName $ProjectName

    # Get list of existing variables
    $octopusProjectVariables = Get-OctopusProjectVariables -OctopusDeployProject $octopusProject -OctopusServerUrl $OctopusServerUrl -ApiKey $ApiKey

    #### EXAMPLE ####
    #$tempValue = Find-Variable -VariableSet $octopusProjectVariables -VariableName "Test"
    #Write-Host $tempValue
  
    ##### GET YOUR VARIABLE AND STORE IT HERE #####
 

    ##### GET YOUR VARIABLE AND STORE IT HERE #####

    

}
catch
{
    Write-Error $_.Exception.Message

    throw
}