Skip to content

Commit

Permalink
✨ : parse provider from module code
Browse files Browse the repository at this point in the history
  • Loading branch information
juwit committed Jan 29, 2020
1 parent 3ca6f20 commit 5517dde
Show file tree
Hide file tree
Showing 13 changed files with 194 additions and 9 deletions.
12 changes: 11 additions & 1 deletion src/main/antlr4/io/codeka/gaia/hcl/antlr/hcl.g4
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,20 @@ file
;

directive
: variableDirective
: providerDirective
| resourceDirective
| variableDirective
| outputDirective
;

providerDirective
: 'provider' STRING object
;

resourceDirective
: 'resource' STRING STRING object
;

variableDirective
: 'variable' STRING variableBlock
;
Expand Down
6 changes: 6 additions & 0 deletions src/main/java/io/codeka/gaia/hcl/HclParserImpl.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ interface HclParser {
fun parseContent(content: String): HclVisitor
fun parseVariables(content: String): List<Variable>
fun parseOutputs(content: String): List<Output>
fun parseProvider(fileContent: String): String
}

@Service
Expand Down Expand Up @@ -45,4 +46,9 @@ class HclParserImpl : HclParser {
val hclVisitor = parseContent(content)
return hclVisitor.outputs
}

override fun parseProvider(content: String): String {
val hclVisitor = parseContent(content)
return hclVisitor.provider
}
}
20 changes: 20 additions & 0 deletions src/main/java/io/codeka/gaia/hcl/HclVisitor.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,14 @@ class HclVisitor : hclBaseVisitor<Unit>() {

var variables: MutableList<Variable> = LinkedList()
var outputs: MutableList<Output> = LinkedList()
var provider: String = "unknown"

private val IGNORED_PROVIDERS = setOf("null", "random", "template", "terraform")

private var currentVariable: Variable = Variable(name = "")
private var currentOutput: Output = Output()


override fun visitVariableDirective(ctx: hclParser.VariableDirectiveContext) {
currentVariable = Variable(name = ctx.STRING().text.removeSurrounding("\""))
variables.add(currentVariable)
Expand Down Expand Up @@ -49,4 +53,20 @@ class HclVisitor : hclBaseVisitor<Unit>() {
override fun visitOutputSensitive(ctx: hclParser.OutputSensitiveContext) {
currentOutput.sensitive = ctx.BOOLEAN().text.removeSurrounding("\"")
}

override fun visitProviderDirective(ctx: hclParser.ProviderDirectiveContext) {
val parsedProvider = ctx.STRING().text.removeSurrounding("\"")
if (! IGNORED_PROVIDERS.contains(parsedProvider)) {
provider = parsedProvider
}
}

override fun visitResourceDirective(ctx: hclParser.ResourceDirectiveContext) {
// provider already found !
if (provider != "unknown") return

// check first part of the resource type
provider = ctx.STRING(0).text.removeSurrounding("\"")
.substringBefore("_")
}
}
9 changes: 9 additions & 0 deletions src/main/java/io/codeka/gaia/modules/bo/TerraformModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ public class TerraformModule {

private RegistryDetails registryDetails;

private String mainProvider;

public String getId() {
return id;
}
Expand Down Expand Up @@ -152,4 +154,11 @@ public void setModuleMetadata(ModuleMetadata moduleMetadata) {
this.moduleMetadata = moduleMetadata;
}

public String getMainProvider() {
return mainProvider;
}

public void setMainProvider(String mainProvider) {
this.mainProvider = mainProvider;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ class RegistryServiceImpl(
val variablesFile = registryApis[registryType]?.getFileContent(user, projectId, "variables.tf")!!
module.variables = hclParser.parseVariables(variablesFile)

// find main provider
val mainFile = registryApis[registryType]?.getFileContent(user, projectId, "main.tf")!!
module.mainProvider = hclParser.parseProvider(mainFile)

// saving module !
return moduleRepository.save(module)
}
Expand Down
69 changes: 61 additions & 8 deletions src/test/java/io/codeka/gaia/hcl/HCLParserTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ package io.codeka.gaia.hcl
import io.codeka.gaia.modules.bo.Output
import io.codeka.gaia.modules.bo.Variable
import org.apache.commons.io.IOUtils
import org.assertj.core.api.Assertions
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Nested
import org.junit.jupiter.api.Test
import org.springframework.core.io.ClassPathResource
import java.io.IOException
Expand All @@ -23,11 +24,11 @@ class HCLParserTest {
val variables = hclParser.parseVariables(fileContent)

// then
Assertions.assertThat(variables).hasSize(3)
assertThat(variables).hasSize(3)
val stringVar = Variable("string_var", "string", "a test string var", "foo")
val numberVar = Variable("number_var", "number", "a test number var", "42")
val boolVar = Variable("bool_var", defaultValue = "false")
Assertions.assertThat(variables).contains(stringVar, numberVar, boolVar)
assertThat(variables).contains(stringVar, numberVar, boolVar)
}

@Test
Expand All @@ -40,7 +41,7 @@ class HCLParserTest {
val variables = hclParser.parseVariables(fileContent)

// then
Assertions.assertThat(variables).hasSize(49)
assertThat(variables).hasSize(49)
}

@Test
Expand All @@ -53,7 +54,7 @@ class HCLParserTest {
val variables = hclParser.parseVariables(fileContent)

// then
Assertions.assertThat(variables).hasSize(282)
assertThat(variables).hasSize(282)
}

@Test
Expand All @@ -66,10 +67,10 @@ class HCLParserTest {
val outputs = hclParser.parseOutputs(fileContent)

// then
Assertions.assertThat(outputs).hasSize(2)
assertThat(outputs).hasSize(2)
val output1 = Output("instance_ip_addr", "\${aws_instance.server.private_ip}", "The private IP address of the main server instance.", "false")
val output2 = Output("db_password", "aws_db_instance.db[1].password", "The password for logging in to the database.", "true")
Assertions.assertThat(outputs).contains(output1, output2)
assertThat(outputs).contains(output1, output2)
}

@Test
Expand All @@ -82,6 +83,58 @@ class HCLParserTest {
val outputs = hclParser.parseOutputs(fileContent)

// then
Assertions.assertThat(outputs).hasSize(27)
assertThat(outputs).hasSize(27)
}

/**
* Tests for the provider part
*/
@Nested
inner class ProviderTest {

@Test
@Throws(IOException::class)
fun parsing_provider_shouldWork_withMainFile_includingProviderDirective() {
// given
val fileContent = IOUtils.toString(ClassPathResource("hcl/terraform_docker_mongo_main_with_provider.tf").url, Charset.defaultCharset())
// when
val provider: String = hclParser.parseProvider(fileContent)
// then
assertThat(provider).isEqualTo("docker")
}

@Test
@Throws(IOException::class)
fun parsing_provider_shouldWork_withMainFile_withoutProviderDirective() {
// given
val fileContent = IOUtils.toString(ClassPathResource("hcl/terraform_docker_mongo_main_without_provider.tf").url, Charset.defaultCharset())

// when
val provider: String = hclParser.parseProvider(fileContent)

// then
assertThat(provider).isEqualTo("docker")
}

@Test
@Throws(IOException::class)
fun parsing_provider_shouldReturn_unknown_ifNoProviderFound() {
// given
val fileContent = IOUtils.toString(ClassPathResource("hcl/variables.tf").url, Charset.defaultCharset())

// when
val provider: String = hclParser.parseProvider(fileContent)

// then
assertThat(provider).isEqualTo("unknown")
}

@Test
fun dummyProvidersShouldBeIgnored() {
assertThat(hclParser.parseProvider("""provider "null" {} """)).isEqualTo("unknown")
assertThat(hclParser.parseProvider("""provider "template" {} """)).isEqualTo("unknown")
assertThat(hclParser.parseProvider("""provider "random" {} """)).isEqualTo("unknown")
assertThat(hclParser.parseProvider("""provider "terraform" {} """)).isEqualTo("unknown")
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,10 @@ class GithubRegistryControllerIT{
.andExpect(MockRestRequestMatchers.header("Authorization", "Bearer Tok'ra"))
.andRespond(MockRestResponseCreators.withSuccess(ClassPathResource("/rest/github/selmak-terraform-docker-mongo-content-variables.json"), MediaType.APPLICATION_JSON))

server.expect(requestTo("https://api.github.com/repos/selmak/terraform-docker-mongo/contents/main.tf?ref=master"))
.andExpect(MockRestRequestMatchers.header("Authorization", "Bearer Tok'ra"))
.andRespond(MockRestResponseCreators.withSuccess(ClassPathResource("/rest/github/selmak-terraform-docker-mongo-content-main.json"), MediaType.APPLICATION_JSON))

val selmak = User("Selmak", null)
selmak.oAuth2User = OAuth2User("GITHUB", "Tok'ra", null)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,10 @@ class GitlabRegistryControllerIT{
.andExpect(MockRestRequestMatchers.header("Authorization", "Bearer Tok'ra"))
.andRespond(MockRestResponseCreators.withSuccess(ClassPathResource("/rest/gitlab/selmak-terraform-docker-mongo-content-variables.json"), MediaType.APPLICATION_JSON))

server.expect(requestTo("https://gitlab.com/api/v4/projects/16181047/repository/files/main.tf?ref=master"))
.andExpect(MockRestRequestMatchers.header("Authorization", "Bearer Tok'ra"))
.andRespond(MockRestResponseCreators.withSuccess(ClassPathResource("/rest/gitlab/selmak-terraform-docker-mongo-content-main.json"), MediaType.APPLICATION_JSON))

val selmak = User("Selmak", null)
selmak.oAuth2User = OAuth2User("GITLAB", "Tok'ra", null)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ class RegistryServiceImplTest {
whenever(gitlabRegistryApi.getFileContent(user, "15689", "variables.tf")).thenReturn(variablesFileContent)
whenever(hclParser.parseVariables(variablesFileContent)).thenReturn(listOf(Variable("dummy")))

whenever(gitlabRegistryApi.getFileContent(user, "15689", "main.tf")).thenReturn(variablesFileContent)
whenever(hclParser.parseProvider(variablesFileContent)).thenReturn("docker")

val module = registryService.importRepository("15689", RegistryType.GITLAB, user)

verify(gitlabRegistryApi).getRepository(user, "15689")
Expand All @@ -88,6 +91,8 @@ class RegistryServiceImplTest {
assertThat(module.cliVersion).isEqualTo("1.12.8")
assertThat(module.moduleMetadata.createdBy).isEqualTo(user)

assertThat(module.mainProvider).isEqualTo("docker")

assertThat(module.variables).containsExactly(Variable("dummy"))
}

Expand All @@ -107,6 +112,9 @@ class RegistryServiceImplTest {
whenever(githubRegistryApi.getFileContent(user, "juwit/terraform-docker-mongo", "variables.tf")).thenReturn(variablesFileContent)
whenever(hclParser.parseVariables(variablesFileContent)).thenReturn(listOf(Variable("dummy")))

whenever(githubRegistryApi.getFileContent(user, "juwit/terraform-docker-mongo", "main.tf")).thenReturn(variablesFileContent)
whenever(hclParser.parseProvider(variablesFileContent)).thenReturn("docker")

val module = registryService.importRepository("juwit/terraform-docker-mongo", RegistryType.GITHUB, user)

verify(githubRegistryApi).getRepository(user, "juwit/terraform-docker-mongo")
Expand All @@ -126,6 +134,8 @@ class RegistryServiceImplTest {
assertThat(module.cliVersion).isEqualTo("1.12.8")
assertThat(module.moduleMetadata.createdBy).isEqualTo(user)

assertThat(module.mainProvider).isEqualTo("docker")

assertThat(module.variables).containsExactly(Variable("dummy"))
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# use local docker as provider
provider "docker" {
host = "unix:///var/run/docker.sock"
}

# get the mongo docker image
resource "docker_image" "mongo" {
name = "mongo"
keep_locally = true
}

# start a container and expose the 27017 port
resource "docker_container" "mongo" {
name = var.mongo_container_name
image = docker_image.mongo.latest
ports = {
internal = 27017
external = var.mongo_exposed_port
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# get the mongo docker image
resource "docker_image" "mongo" {
name = "mongo"
keep_locally = true
}

# start a container and expose the 27017 port
resource "docker_container" "mongo" {
name = var.mongo_container_name
image = docker_image.mongo.latest
ports = {
internal = 27017
external = var.mongo_exposed_port
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"name": "main.tf",
"path": "main.tf",
"sha": "0a5cc012309c07f639bf522dec2dab19783608c9",
"size": 360,
"url": "https://api.github.com/repos/selmak/terraform-docker-mongo/contents/main.tf?ref=master",
"html_url": "https://github.com/selmak/terraform-docker-mongo/blob/master/main.tf",
"git_url": "https://api.github.com/repos/selmak/terraform-docker-mongo/git/blobs/0a5cc012309c07f639bf522dec2dab19783608c9",
"download_url": "https://raw.githubusercontent.com/selmak/terraform-docker-mongo/master/main.tf",
"type": "file",
"content": "IyBnZXQgdGhlIG1vbmdvIGRvY2tlciBpbWFnZQpyZXNvdXJjZSAiZG9ja2Vy\nX2ltYWdlIiAibW9uZ28iIHsKICBuYW1lICAgICAgICAgPSAibW9uZ28iCiAg\na2VlcF9sb2NhbGx5ID0gdHJ1ZQp9CgojIHN0YXJ0IGEgY29udGFpbmVyIGFu\nZCBleHBvc2UgdGhlIDI3MDE3IHBvcnQKcmVzb3VyY2UgImRvY2tlcl9jb250\nYWluZXIiICJtb25nbyIgewogIG5hbWUgID0gIiR7dmFyLm1vbmdvX2NvbnRh\naW5lcl9uYW1lfSIKICBpbWFnZSA9ICIke2RvY2tlcl9pbWFnZS5tb25nby5s\nYXRlc3R9IgogIHBvcnRzID0gewogICAgaW50ZXJuYWwgPSAyNzAxNwogICAg\nZXh0ZXJuYWwgPSAiJHt2YXIubW9uZ29fZXhwb3NlZF9wb3J0fSIKICB9Cn0K\n",
"encoding": "base64",
"_links": {
"self": "https://api.github.com/repos/selmak/terraform-docker-mongo/contents/main.tf?ref=master",
"git": "https://api.github.com/repos/selmak/terraform-docker-mongo/git/blobs/0a5cc012309c07f639bf522dec2dab19783608c9",
"html": "https://github.com/selmak/terraform-docker-mongo/blob/master/main.tf"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"file_name": "main.tf",
"file_path": "main.tf",
"size": 360,
"encoding": "base64",
"content_sha256": "179816b847fa491f6a9b4d7eff54d6be640b397d8f0ec02a62ad6ed6220057b6",
"ref": "master",
"blob_id": "0a5cc012309c07f639bf522dec2dab19783608c9",
"commit_id": "91ee4feddf2d3c489f8ea1b2489027bb05839ac1",
"last_commit_id": "e01d6f909cd078253d6ef557769fc27c5df5d1e7",
"content": "IyBnZXQgdGhlIG1vbmdvIGRvY2tlciBpbWFnZQpyZXNvdXJjZSAiZG9ja2VyX2ltYWdlIiAibW9uZ28iIHsKICBuYW1lICAgICAgICAgPSAibW9uZ28iCiAga2VlcF9sb2NhbGx5ID0gdHJ1ZQp9CgojIHN0YXJ0IGEgY29udGFpbmVyIGFuZCBleHBvc2UgdGhlIDI3MDE3IHBvcnQKcmVzb3VyY2UgImRvY2tlcl9jb250YWluZXIiICJtb25nbyIgewogIG5hbWUgID0gIiR7dmFyLm1vbmdvX2NvbnRhaW5lcl9uYW1lfSIKICBpbWFnZSA9ICIke2RvY2tlcl9pbWFnZS5tb25nby5sYXRlc3R9IgogIHBvcnRzID0gewogICAgaW50ZXJuYWwgPSAyNzAxNwogICAgZXh0ZXJuYWwgPSAiJHt2YXIubW9uZ29fZXhwb3NlZF9wb3J0fSIKICB9Cn0K"
}

0 comments on commit 5517dde

Please sign in to comment.