From 28a391e605933feda6d790904019e9b6c53d6a1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Geir=20Andr=C3=A9=20Lund?= Date: Thu, 2 May 2024 15:54:34 +0200 Subject: [PATCH] =?UTF-8?q?Toggle=20p=C3=A5=20=C3=A5=20g=C3=A5=20mot=20Saf?= =?UTF-8?q?=20direkte=20enn=20via=20dp-proxy?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .nais/dev-vars.yaml | 4 ++ .nais/nais.yaml | 6 ++ .nais/prod-vars.yaml | 6 +- .../dagpenger/mottak/ApplicationBuilder.kt | 4 +- .../kotlin/no/nav/dagpenger/mottak/Config.kt | 8 +++ .../behov/journalpost/JournalPostQuery.kt | 39 +++++++++++ .../behov/journalpost/JournalpostArkiv.kt | 5 ++ .../mottak/behov/journalpost/SafClient.kt | 64 +++---------------- .../behov/journalpost/SafProxyClient.kt | 64 +++++++++++++++++++ .../behov/journalpost/S\303\270knadsArkiv.kt" | 8 +++ .../behov/journalpost/UnleashSafClient.kt | 28 ++++++++ .../S\303\270knadsDataVaktmester.kt" | 6 +- .../S\303\270knadsDataVaktmesterTest.kt" | 6 +- 13 files changed, 183 insertions(+), 65 deletions(-) create mode 100644 mediator/src/main/kotlin/no/nav/dagpenger/mottak/behov/journalpost/JournalPostQuery.kt create mode 100644 mediator/src/main/kotlin/no/nav/dagpenger/mottak/behov/journalpost/JournalpostArkiv.kt create mode 100644 mediator/src/main/kotlin/no/nav/dagpenger/mottak/behov/journalpost/SafProxyClient.kt create mode 100644 "mediator/src/main/kotlin/no/nav/dagpenger/mottak/behov/journalpost/S\303\270knadsArkiv.kt" create mode 100644 mediator/src/main/kotlin/no/nav/dagpenger/mottak/behov/journalpost/UnleashSafClient.kt diff --git a/.nais/dev-vars.yaml b/.nais/dev-vars.yaml index 133f470e..38cf1012 100644 --- a/.nais/dev-vars.yaml +++ b/.nais/dev-vars.yaml @@ -17,4 +17,8 @@ oppgave: app: oppgave-q1 ingress: oppgave-q1.dev-fss-pub.nais.io scope: api://dev-fss.oppgavehandtering.oppgave-q1/.default +saf: + app: saf-q1 + ingress: saf.dev-fss-pub.nais.io + scope: api://dev-fss.oppgavehandtering.saf/.default diff --git a/.nais/nais.yaml b/.nais/nais.yaml index ef3aefc2..d098bbc8 100644 --- a/.nais/nais.yaml +++ b/.nais/nais.yaml @@ -51,6 +51,10 @@ spec: value: {{oppgave.scope}} - name: OPPGAVE_URL value: {{oppgave.ingress}} + - name: SAF_URL + value: {{saf.ingress}} + - name: SAF_SCOPE + value: {{saf.scope}} envFrom: - secret: dp-mottak-unleash-api-token accessPolicy: @@ -60,6 +64,8 @@ spec: namespace: nom - application: {{ oppgave.app }} namespace: oppgavehandtering + - application: {{ saf.app }} + namespace: teamdokumenthandtering external: - host: {{dp_proxy.ingress}} - host: {{pdl.ingress}} diff --git a/.nais/prod-vars.yaml b/.nais/prod-vars.yaml index 60da48e0..6105ee5e 100644 --- a/.nais/prod-vars.yaml +++ b/.nais/prod-vars.yaml @@ -14,4 +14,8 @@ dokarkiv: oppgave: app: oppgave ingress: oppgave.prod-fss-pub.nais.io - scope: api://prod-fss.oppgavehandtering.oppgave/.default \ No newline at end of file + scope: api://prod-fss.oppgavehandtering.oppgave/.default +saf: + app: saf + ingress: saf.prod-fss-pub.nais.io + scope: api://prod-fss.oppgavehandtering.saf/.default \ No newline at end of file diff --git a/mediator/src/main/kotlin/no/nav/dagpenger/mottak/ApplicationBuilder.kt b/mediator/src/main/kotlin/no/nav/dagpenger/mottak/ApplicationBuilder.kt index a91ff26d..e3472e39 100644 --- a/mediator/src/main/kotlin/no/nav/dagpenger/mottak/ApplicationBuilder.kt +++ b/mediator/src/main/kotlin/no/nav/dagpenger/mottak/ApplicationBuilder.kt @@ -9,8 +9,8 @@ import no.nav.dagpenger.mottak.behov.journalpost.FerdigstillJournalpostBehovLøs import no.nav.dagpenger.mottak.behov.journalpost.JournalpostApiClient import no.nav.dagpenger.mottak.behov.journalpost.JournalpostBehovLøser import no.nav.dagpenger.mottak.behov.journalpost.OppdaterJournalpostBehovLøser -import no.nav.dagpenger.mottak.behov.journalpost.SafClient import no.nav.dagpenger.mottak.behov.journalpost.SøknadsdataBehovLøser +import no.nav.dagpenger.mottak.behov.journalpost.UnleashSafClient import no.nav.dagpenger.mottak.behov.person.PdlPersondataOppslag import no.nav.dagpenger.mottak.behov.person.PersondataBehovLøser import no.nav.dagpenger.mottak.behov.person.SkjermingOppslag @@ -32,7 +32,7 @@ private val logg = KotlinLogging.logger {} internal class ApplicationBuilder(env: Map) : RapidsConnection.StatusListener { private val innsendingRepository = InnsendingPostgresRepository(PostgresDataSourceBuilder.dataSource) - private val safClient = SafClient(Config.properties) + private val safClient = UnleashSafClient(Config.properties, unleash) private val arenaApiClient = ArenaApiClient(Config.properties) private val journalpostApiClient = JournalpostApiClient(tokenProvider = Config.properties.dokarkivTokenProvider) private val gosysOppslag = GosysClient(Config.properties) diff --git a/mediator/src/main/kotlin/no/nav/dagpenger/mottak/Config.kt b/mediator/src/main/kotlin/no/nav/dagpenger/mottak/Config.kt index bc35587d..0b1021cd 100644 --- a/mediator/src/main/kotlin/no/nav/dagpenger/mottak/Config.kt +++ b/mediator/src/main/kotlin/no/nav/dagpenger/mottak/Config.kt @@ -75,6 +75,12 @@ internal object Config { } } + val Configuration.safTokenProvider: () -> String by lazy { + { + cachedTokenProvider.clientCredentials(properties[Key("SAF_SCOPE", stringType)]).accessToken + } + } + val Configuration.pdlApiTokenProvider: () -> String by lazy { { cachedTokenProvider.clientCredentials(properties[Key("PDL_API_SCOPE", stringType)]).accessToken @@ -127,6 +133,8 @@ internal object Config { fun Configuration.gosysUrl(): String = this[Key("OPPGAVE_URL", stringType)].addHttpsrotocoll() + fun Configuration.safUrl(): String = this[Key("SAF_URL", stringType)].addHttpsrotocoll() + fun asMap(): Map = properties.list().reversed().fold(emptyMap()) { map, pair -> map + pair.second diff --git a/mediator/src/main/kotlin/no/nav/dagpenger/mottak/behov/journalpost/JournalPostQuery.kt b/mediator/src/main/kotlin/no/nav/dagpenger/mottak/behov/journalpost/JournalPostQuery.kt new file mode 100644 index 00000000..831eee95 --- /dev/null +++ b/mediator/src/main/kotlin/no/nav/dagpenger/mottak/behov/journalpost/JournalPostQuery.kt @@ -0,0 +1,39 @@ +package no.nav.dagpenger.mottak.behov.journalpost + +import com.fasterxml.jackson.annotation.JsonIgnore +import no.nav.dagpenger.mottak.behov.GraphqlQuery + +internal data class JournalPostQuery( + @JsonIgnore val journalpostId: String, +) : GraphqlQuery( + //language=Graphql + query = + """ + query(${'$'}journalpostId: String!) { + journalpost(journalpostId: ${'$'}journalpostId) { + journalstatus + journalpostId + journalfoerendeEnhet + datoOpprettet + behandlingstema + bruker { + type + id + } + relevanteDatoer { + dato + datotype + } + dokumenter { + tittel + dokumentInfoId + brevkode + } + } + } + """.trimIndent(), + variables = + mapOf( + "journalpostId" to journalpostId, + ), + ) diff --git a/mediator/src/main/kotlin/no/nav/dagpenger/mottak/behov/journalpost/JournalpostArkiv.kt b/mediator/src/main/kotlin/no/nav/dagpenger/mottak/behov/journalpost/JournalpostArkiv.kt new file mode 100644 index 00000000..d109c81d --- /dev/null +++ b/mediator/src/main/kotlin/no/nav/dagpenger/mottak/behov/journalpost/JournalpostArkiv.kt @@ -0,0 +1,5 @@ +package no.nav.dagpenger.mottak.behov.journalpost + +internal interface JournalpostArkiv { + suspend fun hentJournalpost(journalpostId: String): SafGraphQL.Journalpost +} diff --git a/mediator/src/main/kotlin/no/nav/dagpenger/mottak/behov/journalpost/SafClient.kt b/mediator/src/main/kotlin/no/nav/dagpenger/mottak/behov/journalpost/SafClient.kt index c683b1c3..e08bbbac 100644 --- a/mediator/src/main/kotlin/no/nav/dagpenger/mottak/behov/journalpost/SafClient.kt +++ b/mediator/src/main/kotlin/no/nav/dagpenger/mottak/behov/journalpost/SafClient.kt @@ -1,6 +1,5 @@ package no.nav.dagpenger.mottak.behov.journalpost -import com.fasterxml.jackson.annotation.JsonIgnore import com.natpryce.konfig.Configuration import io.ktor.client.HttpClient import io.ktor.client.plugins.ClientRequestException @@ -12,76 +11,29 @@ import io.ktor.http.HttpHeaders import io.ktor.http.HttpMethod import io.ktor.http.HttpStatusCode import mu.KotlinLogging -import no.nav.dagpenger.mottak.Config.dpProxyTokenProvider -import no.nav.dagpenger.mottak.Config.dpProxyUrl -import no.nav.dagpenger.mottak.behov.GraphqlQuery - -internal interface JournalpostArkiv { - suspend fun hentJournalpost(journalpostId: String): SafGraphQL.Journalpost -} - -internal interface SøknadsArkiv { - suspend fun hentSøknadsData( - journalpostId: String, - dokumentInfoId: String, - ): SafGraphQL.SøknadsData -} - -internal data class JournalPostQuery( - @JsonIgnore val journalpostId: String, -) : GraphqlQuery( - //language=Graphql - query = - """ - query(${'$'}journalpostId: String!) { - journalpost(journalpostId: ${'$'}journalpostId) { - journalstatus - journalpostId - journalfoerendeEnhet - datoOpprettet - behandlingstema - bruker { - type - id - } - relevanteDatoer { - dato - datotype - } - dokumenter { - tittel - dokumentInfoId - brevkode - } - } - } - """.trimIndent(), - variables = - mapOf( - "journalpostId" to journalpostId, - ), - ) +import no.nav.dagpenger.mottak.Config.safTokenProvider +import no.nav.dagpenger.mottak.Config.safUrl internal class SafClient(config: Configuration) : JournalpostArkiv, SøknadsArkiv { companion object { private val logger = KotlinLogging.logger {} } - private val tokenProvider = config.dpProxyTokenProvider - private val dpProxyUrl = config.dpProxyUrl() + private val tokenProvider = config.safTokenProvider + private val safUrl = config.safUrl() - private val proxyJoarkClient = + private val joarkClient = HttpClient { expectSuccess = true } - private val proxySøknadsDataClient = + private val søknadsDataClient = HttpClient { expectSuccess = true } override suspend fun hentJournalpost(journalpostId: String): SafGraphQL.Journalpost = - proxyJoarkClient.request("$dpProxyUrl//proxy/v1/saf/graphql") { + joarkClient.request("$safUrl/saf/graphql") { header("Content-Type", "application/json") header(HttpHeaders.Authorization, "Bearer ${tokenProvider.invoke()}") method = HttpMethod.Post @@ -95,7 +47,7 @@ internal class SafClient(config: Configuration) : JournalpostArkiv, SøknadsArki dokumentInfoId: String, ): SafGraphQL.SøknadsData = try { - proxySøknadsDataClient.request("$dpProxyUrl/proxy/v1/saf/rest/hentdokument/$journalpostId/$dokumentInfoId/ORIGINAL") { + søknadsDataClient.request("$safUrl/saf/rest/hentdokument/$journalpostId/$dokumentInfoId/ORIGINAL") { header(HttpHeaders.Authorization, "Bearer ${tokenProvider.invoke()}") method = HttpMethod.Get }.let { diff --git a/mediator/src/main/kotlin/no/nav/dagpenger/mottak/behov/journalpost/SafProxyClient.kt b/mediator/src/main/kotlin/no/nav/dagpenger/mottak/behov/journalpost/SafProxyClient.kt new file mode 100644 index 00000000..cce082f8 --- /dev/null +++ b/mediator/src/main/kotlin/no/nav/dagpenger/mottak/behov/journalpost/SafProxyClient.kt @@ -0,0 +1,64 @@ +package no.nav.dagpenger.mottak.behov.journalpost + +import com.natpryce.konfig.Configuration +import io.ktor.client.HttpClient +import io.ktor.client.plugins.ClientRequestException +import io.ktor.client.request.header +import io.ktor.client.request.request +import io.ktor.client.request.setBody +import io.ktor.client.statement.bodyAsText +import io.ktor.http.HttpHeaders +import io.ktor.http.HttpMethod +import io.ktor.http.HttpStatusCode +import mu.KotlinLogging +import no.nav.dagpenger.mottak.Config.dpProxyTokenProvider +import no.nav.dagpenger.mottak.Config.dpProxyUrl + +internal class SafProxyClient(config: Configuration) : JournalpostArkiv, SøknadsArkiv { + companion object { + private val logger = KotlinLogging.logger {} + } + + private val tokenProvider = config.dpProxyTokenProvider + private val dpProxyUrl = config.dpProxyUrl() + + private val proxyJoarkClient = + HttpClient { + expectSuccess = true + } + + private val proxySøknadsDataClient = + HttpClient { + expectSuccess = true + } + + override suspend fun hentJournalpost(journalpostId: String): SafGraphQL.Journalpost = + proxyJoarkClient.request("$dpProxyUrl//proxy/v1/saf/graphql") { + header("Content-Type", "application/json") + header(HttpHeaders.Authorization, "Bearer ${tokenProvider.invoke()}") + method = HttpMethod.Post + setBody(JournalPostQuery(journalpostId).toJson()) + }.let { + SafGraphQL.Journalpost.fromGraphQlJson(it.bodyAsText()) + } + + override suspend fun hentSøknadsData( + journalpostId: String, + dokumentInfoId: String, + ): SafGraphQL.SøknadsData = + try { + proxySøknadsDataClient.request("$dpProxyUrl/proxy/v1/saf/rest/hentdokument/$journalpostId/$dokumentInfoId/ORIGINAL") { + header(HttpHeaders.Authorization, "Bearer ${tokenProvider.invoke()}") + method = HttpMethod.Get + }.let { + SafGraphQL.SøknadsData.fromJson(it.bodyAsText()) + } + } catch (exception: ClientRequestException) { + if (exception.response.status == HttpStatusCode.NotFound) { + logger.warn(exception) { "Fant ikke dokumentInfo for journalpostId $journalpostId med dokumentinfoId $dokumentInfoId" } + SafGraphQL.SøknadsData.fromJson("{}") + } else { + throw exception + } + } +} diff --git "a/mediator/src/main/kotlin/no/nav/dagpenger/mottak/behov/journalpost/S\303\270knadsArkiv.kt" "b/mediator/src/main/kotlin/no/nav/dagpenger/mottak/behov/journalpost/S\303\270knadsArkiv.kt" new file mode 100644 index 00000000..4c41e7d6 --- /dev/null +++ "b/mediator/src/main/kotlin/no/nav/dagpenger/mottak/behov/journalpost/S\303\270knadsArkiv.kt" @@ -0,0 +1,8 @@ +package no.nav.dagpenger.mottak.behov.journalpost + +internal interface SøknadsArkiv { + suspend fun hentSøknadsData( + journalpostId: String, + dokumentInfoId: String, + ): SafGraphQL.SøknadsData +} diff --git a/mediator/src/main/kotlin/no/nav/dagpenger/mottak/behov/journalpost/UnleashSafClient.kt b/mediator/src/main/kotlin/no/nav/dagpenger/mottak/behov/journalpost/UnleashSafClient.kt new file mode 100644 index 00000000..1a6eded9 --- /dev/null +++ b/mediator/src/main/kotlin/no/nav/dagpenger/mottak/behov/journalpost/UnleashSafClient.kt @@ -0,0 +1,28 @@ +package no.nav.dagpenger.mottak.behov.journalpost + +import com.natpryce.konfig.Configuration +import io.getunleash.Unleash + +internal class UnleashSafClient(config: Configuration, private val unleash: Unleash) : JournalpostArkiv, SøknadsArkiv { + private val proxy = SafProxyClient(config) + private val safClient = SafClient(config) + + override suspend fun hentJournalpost(journalpostId: String): SafGraphQL.Journalpost { + return if (unleash.isEnabled("bruk-saf-client")) { + safClient.hentJournalpost(journalpostId) + } else { + proxy.hentJournalpost(journalpostId) + } + } + + override suspend fun hentSøknadsData( + journalpostId: String, + dokumentInfoId: String, + ): SafGraphQL.SøknadsData { + return if (unleash.isEnabled("bruk-saf-client")) { + safClient.hentSøknadsData(journalpostId, dokumentInfoId) + } else { + proxy.hentSøknadsData(journalpostId, dokumentInfoId) + } + } +} diff --git "a/mediator/src/main/kotlin/no/nav/dagpenger/mottak/tjenester/S\303\270knadsDataVaktmester.kt" "b/mediator/src/main/kotlin/no/nav/dagpenger/mottak/tjenester/S\303\270knadsDataVaktmester.kt" index e911964a..a058d8bb 100644 --- "a/mediator/src/main/kotlin/no/nav/dagpenger/mottak/tjenester/S\303\270knadsDataVaktmester.kt" +++ "b/mediator/src/main/kotlin/no/nav/dagpenger/mottak/tjenester/S\303\270knadsDataVaktmester.kt" @@ -6,7 +6,7 @@ import kotliquery.queryOf import kotliquery.sessionOf import kotliquery.using import mu.KotlinLogging -import no.nav.dagpenger.mottak.behov.journalpost.SafClient +import no.nav.dagpenger.mottak.behov.journalpost.SafProxyClient import no.nav.dagpenger.mottak.db.PostgresDataSourceBuilder import org.postgresql.util.PGobject import javax.sql.DataSource @@ -15,7 +15,7 @@ private val logger = KotlinLogging.logger {} private val sikkerlogg = KotlinLogging.logger("tjenestekall.SøknadsDataVaktmester") internal class SøknadsDataVaktmester( - private val safClient: SafClient, + private val safProxyClient: SafProxyClient, private val ds: DataSource = PostgresDataSourceBuilder.dataSource, ) { fun fixSoknadsData(jp: Int) { @@ -24,7 +24,7 @@ internal class SøknadsDataVaktmester( if (session.lås(jp)) { val (innsendingId, dokumentinfoId) = session.innsendingIdOgDokumentinfoId(jp) runBlocking { - val data = safClient.hentSøknadsData(jp.toString(), dokumentinfoId.toString()).data.toString() + val data = safProxyClient.hentSøknadsData(jp.toString(), dokumentinfoId.toString()).data.toString() session.insertSøknadsData(innsendingId, data) logger.info { "Oppdatert søknads data for journalpost id $jp" } sikkerlogg.info { "Oppdatert søknads data for journalpost id $jp. Søknadsdata: $data" } diff --git "a/mediator/src/test/kotlin/no/nav/dagpenger/mottak/tjenester/S\303\270knadsDataVaktmesterTest.kt" "b/mediator/src/test/kotlin/no/nav/dagpenger/mottak/tjenester/S\303\270knadsDataVaktmesterTest.kt" index 8fc2612e..526e0aad 100644 --- "a/mediator/src/test/kotlin/no/nav/dagpenger/mottak/tjenester/S\303\270knadsDataVaktmesterTest.kt" +++ "b/mediator/src/test/kotlin/no/nav/dagpenger/mottak/tjenester/S\303\270knadsDataVaktmesterTest.kt" @@ -7,8 +7,8 @@ import kotliquery.sessionOf import kotliquery.using import no.nav.dagpenger.innsendingData import no.nav.dagpenger.mottak.behov.JsonMapper -import no.nav.dagpenger.mottak.behov.journalpost.SafClient import no.nav.dagpenger.mottak.behov.journalpost.SafGraphQL +import no.nav.dagpenger.mottak.behov.journalpost.SafProxyClient import no.nav.dagpenger.mottak.db.InnsendingPostgresRepository import no.nav.dagpenger.mottak.db.PostgresDataSourceBuilder import no.nav.dagpenger.mottak.db.PostgresTestHelper @@ -24,8 +24,8 @@ class SøknadsDataVaktmesterTest { InnsendingPostgresRepository().lagre(innsending) SøknadsDataVaktmester( - safClient = - mockk().also { + safProxyClient = + mockk().also { coEvery { it.hentSøknadsData(innsending.journalpostId(), "12345678") } returns SafGraphQL.SøknadsData.fromJson("""{"hubba": "bubba"}""")