Skip to content

Commit

Permalink
feat :: 컨테이너 도메인 동기화 기능 추가
Browse files Browse the repository at this point in the history
  • Loading branch information
HyunSu1768 committed Jul 30, 2024
1 parent 4dc6b94 commit c8acadc
Show file tree
Hide file tree
Showing 12 changed files with 207 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import xquare.app.xquareinfra.domain.container.adapter.dto.request.CreateNodeWit
import xquare.app.xquareinfra.domain.container.adapter.dto.request.SetContainerConfigRequest
import xquare.app.xquareinfra.domain.container.adapter.dto.response.GetContainerDeployHistoryResponse
import xquare.app.xquareinfra.domain.container.application.port.`in`.*
import xquare.app.xquareinfra.domain.container.application.service.GetContainerDeployHistoryService
import xquare.app.xquareinfra.domain.container.domain.ContainerEnvironment
import java.util.*

Expand All @@ -19,7 +18,7 @@ class V2ContainerWebAdapter(
private val createNodeWithNginxDockerfileUseCase: CreateNodeWithNginxDockerfileUseCase,
private val createNodeDockerfileUseCase: CreateNodeDockerfileUseCase,
private val getContainerDeployHistoryUseCase: GetContainerDeployHistoryUseCase,
private val getContainerDeployHistoryService: GetContainerDeployHistoryService
private val syncContainerDomainUseCase: SyncContainerDomainUseCase
) {
@PutMapping("/config")
fun setContainerConfig(
Expand Down Expand Up @@ -66,4 +65,11 @@ class V2ContainerWebAdapter(
@RequestParam(name = "environment", required = true)
containerEnvironment: ContainerEnvironment,
): GetContainerDeployHistoryResponse = getContainerDeployHistoryUseCase.getContainerDeployHistory(deployId, containerEnvironment)

@PutMapping("/{deployName}/{containerEnvironment}/sync-domain")
fun syncContainerDomain(
@PathVariable("deployName") deployName: String,
@PathVariable("containerEnvironment") containerEnvironment: ContainerEnvironment,
@RequestParam("domain") domain: String
) = syncContainerDomainUseCase.syncContainerDomain(deployName , containerEnvironment, domain)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package xquare.app.xquareinfra.domain.container.application.port.`in`

import xquare.app.xquareinfra.domain.container.domain.ContainerEnvironment

interface SyncContainerDomainUseCase {
fun syncContainerDomain(deployName: String, containerEnvironment: ContainerEnvironment, domain: String)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package xquare.app.xquareinfra.domain.container.application.service

import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
import xquare.app.xquareinfra.domain.container.application.port.`in`.SyncContainerDomainUseCase
import xquare.app.xquareinfra.domain.container.application.port.out.FindContainerPort
import xquare.app.xquareinfra.domain.container.domain.ContainerEnvironment
import xquare.app.xquareinfra.domain.deploy.application.port.out.FindDeployPort
import xquare.app.xquareinfra.infrastructure.exception.BusinessLogicException
import xquare.app.xquareinfra.infrastructure.exception.XquareException
import xquare.app.xquareinfra.infrastructure.feign.client.cloudflare.CloudflareClient
import xquare.app.xquareinfra.infrastructure.feign.client.cloudflare.dto.request.CreateDnsRecordRequest
import xquare.app.xquareinfra.infrastructure.global.env.cloudflare.CloudflareProperties
import xquare.app.xquareinfra.infrastructure.kubernetes.env.XquareProperties

@Transactional
@Service
class SyncContainerDomainService(
private val findDeployPort: FindDeployPort,
private val findContainerPort: FindContainerPort,
private val cloudflareClient: CloudflareClient,
private val cloudflareProperties: CloudflareProperties,
private val xquareProperties: XquareProperties
) : SyncContainerDomainUseCase{
override fun syncContainerDomain(
deployName: String,
containerEnvironment: ContainerEnvironment,
domain: String
) {
val deploy = findDeployPort.findByDeployName(deployName) ?: throw BusinessLogicException.DEPLOY_NOT_FOUND
val container = findContainerPort.findByDeployAndEnvironment(deploy, containerEnvironment) ?: throw BusinessLogicException.CONTAINER_NOT_FOUND

container.updateDomain(domain)

val listResponse = cloudflareClient.listDnsRecords(
cloudflareProperties.zoneId,
cloudflareProperties.xAuthEmail,
cloudflareProperties.xAuthKey
)

if(listResponse.statusCode.isError) {
throw XquareException.INTERNAL_SERVER_ERROR
}

val records = listResponse.body
if(!records!!.result.any { it.name == domain }) {
val createResponse = cloudflareClient.createDnsRecords(
cloudflareProperties.zoneId,
cloudflareProperties.xAuthEmail,
cloudflareProperties.xAuthKey,
CreateDnsRecordRequest(
content = xquareProperties.gatewayDns,
name = domain,
proxied = false,
type = "CNAME"
)
)

if(createResponse.statusCode.isError) {
throw XquareException.INTERNAL_SERVER_ERROR
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -58,4 +58,8 @@ class Container(
fun updateContainerPort(containerPort: Int) {
this.containerPort = containerPort
}

fun updateDomain(domain: String) {
this.subDomain = domain
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package xquare.app.xquareinfra.infrastructure.feign.client.cloudflare

import org.springframework.cloud.openfeign.FeignClient
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.*
import xquare.app.xquareinfra.infrastructure.feign.client.cloudflare.dto.request.CreateDnsRecordRequest
import xquare.app.xquareinfra.infrastructure.feign.client.cloudflare.dto.response.ListDnsRecordsResponse
import xquare.app.xquareinfra.infrastructure.feign.config.FeignConfig

@FeignClient(
name = "cloudflare-client",
url = "\${url.cloudflare}",
configuration = [FeignConfig::class]
)
interface CloudflareClient {
@GetMapping("/zones/{zone_id}/dns_records")
fun listDnsRecords(
@PathVariable("zone_id") zoneId: String,
@RequestHeader("X-Auth-Email") xAuthEmail: String,
@RequestHeader("X-Auth-Key") xAuthKey: String,
): ResponseEntity<ListDnsRecordsResponse>

@PostMapping("/zones/{zone_id}/dns_records")
fun createDnsRecords(
@PathVariable("zone_id") zoneId: String,
@RequestHeader("X-Auth-Email") xAuthEmail: String,
@RequestHeader("X-Auth-Key") xAuthKey: String,
@RequestBody createDnsRecordRequest: CreateDnsRecordRequest
): ResponseEntity<Any>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package xquare.app.xquareinfra.infrastructure.feign.client.cloudflare.dto.request

data class CreateDnsRecordRequest(
val content: String,
val name: String,
val proxied: Boolean,
val type: String
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package xquare.app.xquareinfra.infrastructure.feign.client.cloudflare.dto.response

import com.fasterxml.jackson.annotation.JsonProperty

data class ListDnsRecordsResponse(
val result: List<Result>,
val success: Boolean,
val errors: List<Any?>,
val messages: List<Any?>,
@JsonProperty("result_info")
val resultInfo: ResultInfo,
)

data class Result(
val id: String,
@JsonProperty("zone_id")
val zoneId: String,
@JsonProperty("zone_name")
val zoneName: String,
val name: String,
val type: String,
val content: String,
val proxiable: Boolean,
val proxied: Boolean,
val ttl: Long,
val locked: Boolean,
val meta: Meta,
val comment: Any?,
val tags: List<Any?>,
@JsonProperty("created_on")
val createdOn: String,
@JsonProperty("modified_on")
val modifiedOn: String,
val priority: Long?,
)

data class Meta(
@JsonProperty("auto_added")
val autoAdded: Boolean,
@JsonProperty("managed_by_apps")
val managedByApps: Boolean,
@JsonProperty("managed_by_argo_tunnel")
val managedByArgoTunnel: Boolean,
@JsonProperty("email_routing")
val emailRouting: Boolean?,
@JsonProperty("read_only")
val readOnly: Boolean?,
)

data class ResultInfo(
val page: Long,
@JsonProperty("per_page")
val perPage: Long,
val count: Long,
@JsonProperty("total_count")
val totalCount: Long,
@JsonProperty("total_pages")
val totalPages: Long,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package xquare.app.xquareinfra.infrastructure.global.env.cloudflare

import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.boot.context.properties.ConstructorBinding

@ConstructorBinding
@ConfigurationProperties(value = "cloudflare")
data class CloudflareProperties(
val zoneId: String,
val xAuthKey: String,
val xAuthEmail: String
)
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package xquare.app.xquareinfra.infrastructure.kubernetes.config

import xquare.app.xquareinfra.infrastructure.kubernetes.env.KubernetesProperty
import xquare.app.xquareinfra.infrastructure.kubernetes.env.XquareAwsProperty
import xquare.app.xquareinfra.infrastructure.kubernetes.env.XquareProperties
import io.kubernetes.client.openapi.Configuration
import io.kubernetes.client.openapi.apis.CoreV1Api
import io.kubernetes.client.openapi.apis.CustomObjectsApi
Expand All @@ -17,12 +17,12 @@ import javax.annotation.PostConstruct

@org.springframework.context.annotation.Configuration
class KubernetesClientConfig(
private val xquareAwsProperty: XquareAwsProperty,
private val xquareProperties: XquareProperties,
private val kubernetesProperty: KubernetesProperty
) {
@PostConstruct
fun initKubernetesConfig() {
configureAWS("default", xquareAwsProperty.accessKey, xquareAwsProperty.secretKey, Region.AP_NORTHEAST_2.toString())
configureAWS("default", xquareProperties.accessKey, xquareProperties.secretKey, Region.AP_NORTHEAST_2.toString())
val decodedBytes = Base64.getDecoder().decode(kubernetesProperty.kubeConfig)
val kubeconfig = String(decodedBytes, Charset.defaultCharset())
val client = ClientBuilder.kubeconfig(KubeConfig.loadKubeConfig(StringReader(kubeconfig))).build()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ import org.springframework.boot.context.properties.ConstructorBinding

@ConfigurationProperties("xquare")
@ConstructorBinding
data class XquareAwsProperty(
data class XquareProperties(
val accessKey: String,
val secretKey: String
val secretKey: String,
val gatewayDns: String
)
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ class RequestPermitConfig : SecurityConfigurerAdapter<DefaultSecurityFilterChain
.antMatchers("/v1/deploy/**/approve").permitAll()
.antMatchers(("/v1/container/sync")).permitAll()
.antMatchers("/v1/logs").permitAll()
.antMatchers("/v2/container/**/**/sync-domain").permitAll()
anyRequest().authenticated()
}
}
Expand Down
9 changes: 8 additions & 1 deletion src/main/resources/application.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ url:
deploy: ${DEPLOY_URL}
log: ${LOG_URL}
gocd: ${GOCD_URL}
cloudflare: ${CLOUDFLARE_URL}

secret:
projectSecret: ${PROJECT_SECRET}
Expand All @@ -72,6 +73,12 @@ vault:
xquare:
accessKey: ${XQUARE_ACCESS}
secretKey: ${XQUARE_SECRET}
gatewayDns: ${GATEWAY_DNS}

kubernetes:
kubeConfig: ${KUBE_CONFIG}
kubeConfig: ${KUBE_CONFIG}

cloudflare:
zoneId: ${ZONE_ID}
xAuthKey: ${X_AUTH_KEY}
xAuthEmail: ${X_AUTH_EMAIL}

0 comments on commit c8acadc

Please sign in to comment.