Skip to content

Commit

Permalink
Initial commit for retrieving Azure config values. (#100)
Browse files Browse the repository at this point in the history
  • Loading branch information
JargoonPard authored and Matt Duftler committed May 25, 2016
1 parent a636d6d commit 5eb055a
Show file tree
Hide file tree
Showing 8 changed files with 354 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ class BakeRequest {
Map extended_attributes

static enum CloudProviderType {
aws, docker, gce, openstack
aws, azure, docker, gce, openstack
}

static enum Label {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/*
* Copyright 2016 Microsoft, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License")
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.netflix.spinnaker.rosco.providers.azure

import com.netflix.spinnaker.rosco.api.Bake
import com.netflix.spinnaker.rosco.api.BakeOptions
import com.netflix.spinnaker.rosco.api.BakeRequest
import com.netflix.spinnaker.rosco.providers.CloudProviderBakeHandler
import com.netflix.spinnaker.rosco.providers.azure.config.RoscoAzureConfiguration
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Component

@Component
public class AzureBakeHandler extends CloudProviderBakeHandler{

private static final String BUILDER_TYPE = "azure-arm"
private static final String IMAGE_NAME_TOKEN = "OSDiskUri:"

@Autowired
RoscoAzureConfiguration.AzureBakeryDefaults azureBakeryDefaults

@Override
def getBakeryDefaults() {
return azureBakeryDefaults
}

@Override
BakeOptions getBakeOptions() {
new BakeOptions(
cloudProvider: BakeRequest.CloudProviderType.azure,
baseImages: azureBakeryDefaults?.baseImages?.collect { it.baseImage }
)
}

@Override
boolean isProducerOf(String logsContentFirstLine) {
logsContentFirstLine =~ BUILDER_TYPE
}

@Override
Bake scrapeCompletedBakeResults(String region, String bakeId, String logsContent) {
String imageName

// TODO(duftler): Presently scraping the logs for the image name. Would be better to not be reliant on the log
// format not changing. Resolve this by storing bake details in redis.
logsContent.eachLine { String line ->
if (line =~ IMAGE_NAME_TOKEN) {
imageName = line.split("/").last()
}
}

return new Bake(id: bakeId, image_name: imageName)
}

@Override
def findVirtualizationSettings(String region, BakeRequest bakeRequest) {
return null
}

@Override
Map buildParameterMap(String region, Object virtualizationSettings, String imageName, BakeRequest bakeRequest) {
return null
}

@Override
String getTemplateFileName() {
return azureBakeryDefaults.templateFile
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/*
* Copyright 2016 Microsoft, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License")
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.netflix.spinnaker.rosco.providers.azure.config

import com.netflix.spinnaker.rosco.api.BakeOptions
import com.netflix.spinnaker.rosco.api.BakeRequest
import com.netflix.spinnaker.rosco.providers.azure.AzureBakeHandler
import com.netflix.spinnaker.rosco.providers.registry.CloudProviderBakeHandlerRegistry
import groovy.transform.AutoClone
import groovy.transform.AutoCloneStyle
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.ComponentScan
import org.springframework.context.annotation.Configuration

import javax.annotation.PostConstruct

@Configuration
@ConditionalOnProperty('azure.enabled')
@ComponentScan('com.netflix.spinnaker.rosco.providers.azure')
class RoscoAzureConfiguration {

@Autowired
CloudProviderBakeHandlerRegistry cloudProviderBakeHandlerRegistry

@Autowired
AzureBakeHandler azureBakeHandler

@Bean
@ConfigurationProperties('azure.bakeryDefaults')
AzureBakeryDefaults azureBakeryDefaults() {
new AzureBakeryDefaults()
}

@PostConstruct
void init() {
cloudProviderBakeHandlerRegistry.register(BakeRequest.CloudProviderType.azure, azureBakeHandler)
}

static class AzureBakeryDefaults {
String azureClientId
String azureClientSecret
String azureResourceGroup
String templateFile
List<AzureOperatingSystemVirtualizationSettings> baseImages = []
}

static class AzureOperatingSystemVirtualizationSettings {
BakeOptions.BaseImage baseImage
List<AzureVirtualizationSettings> vitualizationSettings = []
}

@AutoClone(style = AutoCloneStyle.SIMPLE)
static class AzureVirtualizationSettings {
String region
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
/*
* Copyright 2016 Microsoft, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License")
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.netflix.spinnaker.rosco.providers.azure

import com.fasterxml.jackson.databind.ObjectMapper
import com.netflix.spinnaker.rosco.api.Bake
import com.netflix.spinnaker.rosco.api.BakeOptions
import com.netflix.spinnaker.rosco.api.BakeRequest
import com.netflix.spinnaker.rosco.providers.azure.config.RoscoAzureConfiguration
import spock.lang.Shared
import spock.lang.Specification
import spock.lang.Subject

class AzureBakeHandlerSpec extends Specification{

@Shared
String configDir = "/some/path"

@Shared
RoscoAzureConfiguration.AzureBakeryDefaults azureBakeryDefaults

void setupSpec() {
def azureBakeryDefaultsJson = [
templateFile: "azure-linux.json",
baseImages: [
[
baseImage: [
id: "ubuntu",
detailedDescription: "Ubuntu Server 14.04.4-LTS",
packageType: "DEB",
]
],
[
baseImage: [
id: "centos",
detailedDescription: "OpenLogic CentOS 7.1.20150731",
packageType: "RPM",
]
]
]
]

azureBakeryDefaults = new ObjectMapper().convertValue(azureBakeryDefaultsJson, RoscoAzureConfiguration.AzureBakeryDefaults)
}

void 'can scrape packer logs for image name'() {
setup:
@Subject
AzureBakeHandler azureBakeHandler = new AzureBakeHandler()

when:
def logsContent =
"==> azure-arm: Deleting the temporary OS disk ...\n" +
"==> azure-arm: -> OS Disk : 'https://lgpackervms.blob.core.windows.net/images/pkroswfvmtp50x8.vhd'\n" +
"==> azure-arm:\n" +
"==> azure-arm: Cleanup requested, deleting resource group ...\n" +
"==> azure-arm: Error deleting resource group. Please delete it manually.\n" +
"==> azure-arm:\n" +
"==> azure-arm: Name: packer-Resource-Group-wfvmtp50x8\n" +
"==> azure-arm: Error: azure#updatePollingState: Azure Polling Error - Unable to obtain polling URI for DELETE : StatusCode=0\n" +
"==> azure-arm: Resource group has been deleted.\n" +
"Build 'azure-arm' finished.\n" +
"\n" +
"==> Builds finished. The artifacts of successful builds are:\n" +
"--> azure-arm: Azure.ResourceManagement.VMImage:\n" +
"\n" +
"StorageAccountLocation: westus\n" +
"OSDiskUri: https://lgpackervms.blob.core.windows.net/system/Microsoft.Compute/Images/images/packer-osDisk.0425d8dd-45a0-4f2e-aabb-b5f9a03b08c9.vhd\n" +
"OSDiskUriReadOnlySas: https://lgpackervms.blob.core.windows.net/system/Microsoft.Compute/Images/images/packer-osDisk.0425d8dd-45a0-4f2e-aabb-b5f9a03b08c9.vhd?se=2016-06-24T18%3A16%3A46Z&sig=RHZXFGD3gZq6BGo%2BOb09FXHW6BAYULVJ8thlBEblkmo%3D&sp=r&sr=b&sv=2015-02-21"


Bake bake = azureBakeHandler.scrapeCompletedBakeResults(null, "123", logsContent)

then:
with (bake) {
id == "123"
!ami
image_name == "packer-osDisk.0425d8dd-45a0-4f2e-aabb-b5f9a03b08c9.vhd"
}
}

void 'template file name data is serialized as expected'() {
setup:
@Subject
AzureBakeHandler azureBakeHandler = new AzureBakeHandler(azureBakeryDefaults: azureBakeryDefaults)

when:
String templateFileName = azureBakeHandler.getTemplateFileName()

then:
templateFileName == "azure-linux.json"
}

void 'image config data is serialized as expected'() {
setup:
@Subject
AzureBakeHandler azureBakeHandler = new AzureBakeHandler(azureBakeryDefaults: azureBakeryDefaults)

when:
BakeOptions bakeOptions = azureBakeHandler.getBakeOptions()

then:
with(bakeOptions) {
baseImages.size() == 2
cloudProvider == BakeRequest.CloudProviderType.azure.toString()
}
}
}
56 changes: 56 additions & 0 deletions rosco-web/config/packer/azure-linux.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
{
"variables": {
"azure_client_id": "",
"azure_client_secret": "",
"azure_resource_group": "",
"azure_storage_account": "",
"azure_subscription_id": "",
"azure_tenant_id": "",
"azure_image_publisher": "",
"azure_image_offer": "",
"azure_image_sku": "",
"azure_location": "",
"azure_vm_size": "",
"azure_image_name": "",

"appversion": "",
"build_host": "",
"repository": "",
"package_type": "",
"packages": "",
"upgrade": "",
"configDir": null
},
"builders": [{
"type": "azure-arm",

"client_id": "{{user `client_id`}}",
"client_secret": "{{user `client_secret`}}",
"resource_group_name": "{{user `resource_group`}}",
"storage_account": "{{user `storage_account`}}",
"subscription_id": "{{user `subscription_id`}}",
"tenant_id": "{{user `tenant_id`}}",

"capture_container_name": "images",
"capture_name_prefix": "{{user `appversion`}}",

"os_type": "Linux",
"image_publisher": "{{user `azure_image_publisher`}}",
"image_offer": "{{user `azure_image_offer`}}",
"image_sku": "{{user `azure_image_sku`}}",

"location": "{{user `azure_location`}}",
"vm_size": "{{user `azure_vm_size`}}"
}],
"provisioners": [{
"type": "shell",
"script": "{{user `configDir`}}/install_packages.sh",
"environment_vars": [
"repository={{user `repository`}}",
"package_type={{user `package_type`}}",
"packages={{user `packages`}}",
"upgrade={{user `upgrade`}}"
],
"pause_before": "30s"
}]
}
16 changes: 16 additions & 0 deletions rosco-web/config/rosco.yml
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,22 @@ aws:
sourceAmi: ami-37501207
sshUserName: ubuntu

azure:
enabled: ${AZURE_ENABLED:false}
bakeryDefaults:
templateFile: azure-linux.json
baseImages:
- baseImage:
id: ubuntu
shortDescription: v14.04
detailedDescription: Ubuntu Server 14.04.4-LTS
packageType: deb
- baseImage:
id: centos
shortDescription: 7
detailedDescription: OpenLogic CentOS 7.1.20150731
packageType: rpm

docker:
enabled: ${DOCKER_ENABLED:false}
bakeryDefaults:
Expand Down
1 change: 1 addition & 0 deletions rosco-web/rosco-web.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ ospackage {
configurationFile('/opt/rosco/config/rosco.yml')
configurationFile('/opt/rosco/config/packer/aws-chroot.json')
configurationFile('/opt/rosco/config/packer/aws-ebs.json')
configurationFile('/opt/rosco/config/packer/azure-linux.json')
configurationFile('/opt/rosco/config/packer/gce.json')
configurationFile('/opt/rosco/config/packer/install_packages.sh')

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package com.netflix.spinnaker.rosco

import com.netflix.spinnaker.rosco.providers.aws.config.RoscoAWSConfiguration
import com.netflix.spinnaker.rosco.providers.azure.config.RoscoAzureConfiguration
import com.netflix.spinnaker.rosco.providers.docker.config.RoscoDockerConfiguration
import com.netflix.spinnaker.rosco.providers.google.config.RoscoGoogleConfiguration
import com.netflix.spinnaker.rosco.providers.openstack.config.RoscoOpenstackConfiguration
Expand Down Expand Up @@ -44,7 +45,7 @@ import javax.servlet.Filter
"com.netflix.spinnaker.rosco.rush",
"com.netflix.spinnaker.config"
])
@Import([RoscoAWSConfiguration, RoscoDockerConfiguration, RoscoGoogleConfiguration, RoscoOpenstackConfiguration])
@Import([RoscoAWSConfiguration, RoscoAzureConfiguration, RoscoDockerConfiguration, RoscoGoogleConfiguration, RoscoOpenstackConfiguration])
@EnableAutoConfiguration(exclude = [BatchAutoConfiguration, GroovyTemplateAutoConfiguration])
@EnableScheduling
class Main extends SpringBootServletInitializer {
Expand Down

0 comments on commit 5eb055a

Please sign in to comment.