Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PMM-8471 use unprivileged ports for PMM #2357

Closed
wants to merge 31 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
e799905
PMM-8471 use unprivileged ports for PMM
ademidoff Nov 3, 2023
402d485
Merge branch 'master' into PMM-8471-run-nginx-as-non-root
ademidoff Nov 26, 2023
65ccba5
Use jammy distro for orchestrator tests (bionic is EOL) (#2383)
eleo007 Nov 27, 2023
8797142
K8SPG-471 Add data-migration-gcs test for sandbox (#2381)
ptankov Nov 27, 2023
ff2f4e2
PSMDB. Upgrade tests for KMIP and PRO repos (#2386)
sandraromanchenko Nov 27, 2023
0dc13f7
PMM-7 dbaas-controller is archived, so we can't tag it. (#2388)
BupycHuk Nov 28, 2023
eb3f956
PMM-7 update pmm2-api-tests pipeline (#2370)
ademidoff Nov 28, 2023
b810539
PSMDB package tests on FIPS-enabled OSs (#2387)
olexandr-havryliak Nov 29, 2023
1a38bcc
ENG-7 Jenkins spot instances price auto updater
vorsel Nov 26, 2023
fef1f06
ENG-7 spot-price-auto-updater: keep 1000 builds
vorsel Nov 29, 2023
c18360b
PS-9016 remove bionic from building jobs for MySQL related products (…
adivinho Nov 29, 2023
3466ddd
PBM e2e tests improvements (#2394)
sandraromanchenko Nov 30, 2023
d6ca181
ENG-7 spot-price-auto-updater: script improvals
vorsel Nov 29, 2023
cc3f2db
RM-1292 ps-8.0.35-27 (#2399)
adivinho Dec 1, 2023
510e656
K8SPG-375 - Rename postgres-postgis image to just postgis (#2398)
tplavcic Dec 1, 2023
250d0c0
CLOUD-817 - Fix Jenkins pipelines for gcloud installation (#2400)
tplavcic Dec 2, 2023
c94d3be
K8SPG-375 - Rename postgis image to postgres-gis (#2401)
tplavcic Dec 2, 2023
cbfee7c
PBM tests changed aws user (#2402)
olexandr-havryliak Dec 4, 2023
079e80b
Adding installMoleculePPG function to enable and install python3.8 on…
Naeem-Akhter Dec 4, 2023
926878a
Updated PPG Release Testing pipelines to use installMoleculePPG funct…
Naeem-Akhter Dec 4, 2023
668584d
Add Scheduler Jobs for PGO,PXC,PS,PSMDB with Parameters (#2395)
panchal-yash Dec 5, 2023
c71525b
PMM-7 get rid of svn usage (#2405)
yurkovychv Dec 6, 2023
959909a
PMM-7 replace svn usage in aws job (#2408)
yurkovychv Dec 6, 2023
3f2fae2
PMM-7 Add debian bookworm build for pmm2-client (#2411)
talhabinrizwan Dec 7, 2023
c4c7275
PSMDB added mongosh version parameter (#2412)
olexandr-havryliak Dec 7, 2023
f3e4f53
RM-1274 PXB-8.2 (#2413)
adivinho Dec 7, 2023
10b0374
RM-1274 PXB-8.2 (#2414)
adivinho Dec 8, 2023
10068d0
ENG-7 remove withCredentials and use default cred provider
vorsel Dec 10, 2023
3b74863
Add PS/PDPS/PXC/PDPXC/PXB tasks to check download links (#2409)
eleo007 Dec 11, 2023
14f4a07
PMM-8471 use unprivileged ports for PMM
ademidoff Nov 3, 2023
140940e
Merge branch 'PMM-8471-run-nginx-as-non-root' of github.com:Percona-L…
ademidoff Dec 11, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
200 changes: 200 additions & 0 deletions IaC/spot-price-auto-updater.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
- job:
name: spot-price-auto-updater
project-type: pipeline
description: |
Checks current AWS spot prices for each AZ
and updates maxBidPrice in all templates: currentAWSSpotPrice + 0.07$
Do not edit this job through the web!
disabled: false
concurrent: false
properties:
- build-discarder:
days-to-keep: -1
num-to-keep: 1000
artifact-days-to-keep: -1
artifact-num-to-keep: 1000
triggers:
- timed: 'H/15 * * * *'
dsl: |
import jenkins.model.Jenkins
import hudson.plugins.ec2.AmazonEC2Cloud
import hudson.plugins.ec2.SlaveTemplate
import hudson.plugins.ec2.SpotConfiguration

import com.amazonaws.auth.InstanceProfileCredentialsProvider
import com.amazonaws.services.ec2.AmazonEC2ClientBuilder
import com.amazonaws.services.ec2.model.DescribeSpotPriceHistoryRequest

// Get the Jenkins instance
def jenkins = Jenkins.instance

// Find all AmazonEC2Cloud instances in Jenkins
def ec2Clouds = jenkins.clouds.findAll { it instanceof AmazonEC2Cloud }

// Create a map to store data
def cloudData = [:]

// Flag to check if there were any price changes
def priceChanges = false

// Multiline output
def dbgOutput = ""

// Iterate through each AmazonEC2Cloud instance
ec2Clouds.each { cloud ->
// Get the region and CloudName
def region = cloud.getRegion()
def CloudName = cloud.getDisplayName()

// Get availability zone
def AvailabilityZone = "${region}${CloudName[-1..-1]}"

// Get all templates for the current cloud
def templates = cloud.getTemplates()

// Initialize a set to track unique instance types per Availability Zone
def uniqueInstanceTypes = new HashSet<String>()

// Iterate through each template
templates.each { template ->
if (template instanceof SlaveTemplate) {
def instanceType = template.type.toString()

// Check if this instance type is already processed for this Availability Zone
if (!uniqueInstanceTypes.contains(instanceType)) {
// Create an entry for the instance type in the AvailabilityZone data
def instanceData = [:]
instanceData.instanceType = instanceType

// Get the SpotConfiguration for the template
def spotConfig = template.spotConfig
if (spotConfig instanceof SpotConfiguration) {
def maxBidPrice = spotConfig.getSpotMaxBidPrice()

// Create an entry for the instance type in the AvailabilityZone data
instanceData.maxBidPrice = maxBidPrice
instanceData.az = null
instanceData.timestamp = null
instanceData.awsCurrentPrice = null
instanceData.newMaxBidPrice = null

// Add the instance data to the AvailabilityZone
if (!cloudData[AvailabilityZone]) {
cloudData[AvailabilityZone] = [:]
cloudData[AvailabilityZone].availabilityZone = AvailabilityZone
cloudData[AvailabilityZone].instanceTypes = []
}

cloudData[AvailabilityZone].instanceTypes << instanceData

// Add the instance type to the set to mark it as processed
uniqueInstanceTypes.add(instanceType)

// Create the EC2 client using the instance profile credentials provider
def ec2Client = AmazonEC2ClientBuilder.standard()
.withRegion(region)
.build()

// Set the product description
def productDescription = "Linux/UNIX"

// Make the necessary API call to AWS to retrieve the spot price history
def request = new DescribeSpotPriceHistoryRequest()
.withInstanceTypes(instanceType)
.withProductDescriptions(productDescription.toString())
.withAvailabilityZone(AvailabilityZone) // Filter by Availability Zone
.withMaxResults(1)

def response = ec2Client.describeSpotPriceHistory(request)
if (response.getSpotPriceHistory().size() > 0) {
def spotPriceHistory = response.getSpotPriceHistory().get(0)
instanceData.az = spotPriceHistory.getAvailabilityZone()
instanceData.timestamp = spotPriceHistory.getTimestamp()
instanceData.awsCurrentPrice = spotPriceHistory.getSpotPrice()
instanceData.newMaxBidPrice = ((instanceData.awsCurrentPrice as Float) + 0.07).toString()[0..7]
}
}
}
}
}

}

// Print the debug data
cloudData.each { availabilityZone, data ->
dbgOutput += "Availability Zone: ${availabilityZone}\n"
data.instanceTypes.each { instanceData ->
dbgOutput += " Availability Zone: ${instanceData.az}\n"
dbgOutput += " Instance Type: ${instanceData.instanceType}\n"
dbgOutput += " Max Bid Price: ${instanceData.maxBidPrice}\n"
dbgOutput += " Current AWS Spot Price: ${instanceData.awsCurrentPrice ?: 'N/A'}\n"
dbgOutput += " New Max Bid Price: ${instanceData.newMaxBidPrice ?: 'N/A'}\n"
dbgOutput += " Timestamp: ${instanceData.timestamp}\n"
dbgOutput += "\n"
}
}

// Iterate through each cloud
ec2Clouds.each { cloud ->
// Get the region and CloudName for the current cloud
def region = cloud.getRegion()
def CloudName = cloud.getDisplayName()
def cloudAvailabilityZone = "${region}${CloudName[-1..-1]}"

// Get all templates for the current cloud
def templates = cloud.getTemplates()

// Iterate through each template
templates.each { template ->
if (template instanceof SlaveTemplate) {
def instanceType = template.type.toString()
def maxBidPrice = template.spotConfig.getSpotMaxBidPrice()
def templateName = template.getDisplayName()

// Iterate through each entry in cloudData to find the corresponding instanceType and AZ
cloudData.each { _, data ->
data.instanceTypes.each { instanceData ->
if (instanceData.instanceType == instanceType && data.availabilityZone == cloudAvailabilityZone) {
// Update only if the newMaxBidPrice is different
if (instanceData.newMaxBidPrice != maxBidPrice) {
template.spotConfig.setSpotMaxBidPrice(instanceData.newMaxBidPrice)
priceChanges = true
dbgOutput += " Price change for ${templateName}(${data.availabilityZone}, ${instanceData.instanceType}):\n"
dbgOutput += " ${maxBidPrice} -> ${instanceData.newMaxBidPrice}\n"
}
}
}
}
}
}
// Remove the existing cloud with the same name
def cloudsToRemove = []
jenkins.clouds.each {
if (it.hasProperty('cloudName') && it['cloudName'] == cloud.getDisplayName()) {
cloudsToRemove.add(it)
}
}
// Remove the clouds outside prev iteration: fixes java.util.NoSuchElementException
// if only 1 cloud is configured
cloudsToRemove.each {
jenkins.clouds.remove(it)
}

// Add the updated cloud configuration
jenkins.clouds.add(cloud)
}
jenkins.save()

// Print output
println dbgOutput

// Set the build result and description based on the priceChanges flag
if (priceChanges) {
currentBuild.result = 'UNSTABLE'
currentBuild.description = 'The prices were changed'
} else {
currentBuild.result = 'SUCCESS'
currentBuild.description = 'No price changes'
}

return
Loading