diff options
author | Brinda Santh <brindasanth@in.ibm.com> | 2019-05-15 13:50:20 -0400 |
---|---|---|
committer | Steve Siani <alphonse.steve.siani.djissitchi@ibm.com> | 2019-05-23 00:15:54 -0400 |
commit | 15680d3737f3eb623cfb0ca325907291d994b9c9 (patch) | |
tree | ce1856f88427899617ae105b96fdf16d30194594 /ms/blueprintsprocessor/modules/commons/ssh-lib/src | |
parent | 0042e9e09d4d43422459f9b1574e61d6c625099d (diff) |
Add ssh client configuration service
Change-Id: I88515b430311e7937ea45516cc0fb07b4dab3c2f
Issue-ID: CCSDK-1335
Signed-off-by: Brinda Santh <brindasanth@in.ibm.com>
Diffstat (limited to 'ms/blueprintsprocessor/modules/commons/ssh-lib/src')
8 files changed, 466 insertions, 0 deletions
diff --git a/ms/blueprintsprocessor/modules/commons/ssh-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/ssh/BluePrintSshLibConfiguration.kt b/ms/blueprintsprocessor/modules/commons/ssh-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/ssh/BluePrintSshLibConfiguration.kt new file mode 100644 index 000000000..48e451f03 --- /dev/null +++ b/ms/blueprintsprocessor/modules/commons/ssh-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/ssh/BluePrintSshLibConfiguration.kt @@ -0,0 +1,34 @@ +/* + * Copyright © 2019 IBM. + * + * 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 org.onap.ccsdk.cds.blueprintsprocessor.ssh + +import org.springframework.boot.context.properties.EnableConfigurationProperties +import org.springframework.context.annotation.ComponentScan +import org.springframework.context.annotation.Configuration + +@Configuration +@ComponentScan +@EnableConfigurationProperties +open class BluePrintSshLibConfiguration + +class SshLibConstants { + companion object { + const val SERVICE_BLUEPRINT_SSH_LIB_PROPERTY = "blueprint-ssh-lib-property-service" + const val PROPERTY_SSH_CLIENT_PREFIX = "blueprintsprocessor.sshclient." + const val TYPE_BASIC_AUTH = "basic-auth" + } +}
\ No newline at end of file diff --git a/ms/blueprintsprocessor/modules/commons/ssh-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/ssh/BluePrintSshLibData.kt b/ms/blueprintsprocessor/modules/commons/ssh-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/ssh/BluePrintSshLibData.kt new file mode 100644 index 000000000..a70ea5588 --- /dev/null +++ b/ms/blueprintsprocessor/modules/commons/ssh-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/ssh/BluePrintSshLibData.kt @@ -0,0 +1,29 @@ +/* + * Copyright © 2019 IBM. + * + * 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 org.onap.ccsdk.cds.blueprintsprocessor.ssh + +open class SshClientProperties { + lateinit var type: String + lateinit var host: String + var port: Int = 22 + var connectionTimeOut: Long = 3000 +} + +open class BasicAuthSshClientProperties : SshClientProperties() { + lateinit var password: String + lateinit var username: String +}
\ No newline at end of file diff --git a/ms/blueprintsprocessor/modules/commons/ssh-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/ssh/service/BasicAuthSshClientService.kt b/ms/blueprintsprocessor/modules/commons/ssh-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/ssh/service/BasicAuthSshClientService.kt new file mode 100644 index 000000000..67d5d5153 --- /dev/null +++ b/ms/blueprintsprocessor/modules/commons/ssh-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/ssh/service/BasicAuthSshClientService.kt @@ -0,0 +1,99 @@ +/* + * Copyright © 2019 IBM. + * + * 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 org.onap.ccsdk.cds.blueprintsprocessor.ssh.service + +import org.apache.sshd.client.SshClient +import org.apache.sshd.client.channel.ChannelExec +import org.apache.sshd.client.channel.ClientChannel +import org.apache.sshd.client.channel.ClientChannelEvent +import org.apache.sshd.client.keyverifier.AcceptAllServerKeyVerifier +import org.apache.sshd.client.session.ClientSession +import org.onap.ccsdk.cds.blueprintsprocessor.ssh.BasicAuthSshClientProperties +import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintProcessorException +import org.slf4j.LoggerFactory +import java.io.ByteArrayOutputStream +import java.util.* + + +open class BasicAuthSshClientService(private val basicAuthSshClientProperties: BasicAuthSshClientProperties) + : BlueprintSshClientService { + + private val log = LoggerFactory.getLogger(BasicAuthSshClientService::class.java)!! + + private lateinit var sshClient: SshClient + private lateinit var clientSession: ClientSession + + override suspend fun startSessionNB(): ClientSession { + sshClient = SshClient.setUpDefaultClient() + sshClient.serverKeyVerifier = AcceptAllServerKeyVerifier.INSTANCE + sshClient.start() + log.debug("SSH Client Service started successfully") + clientSession = sshClient.connect(basicAuthSshClientProperties.username, basicAuthSshClientProperties.host, + basicAuthSshClientProperties.port) + .verify(basicAuthSshClientProperties.connectionTimeOut) + .session + + clientSession.addPasswordIdentity(basicAuthSshClientProperties.password) + clientSession.auth().verify(basicAuthSshClientProperties.connectionTimeOut) + log.info("SSH client session($clientSession) created") + return clientSession + } + + override suspend fun executeCommandsNB(commands: List<String>, timeOut: Long): String { + val buffer = StringBuffer() + try { + commands.forEach { command -> + buffer.append("\nCommand : $command") + buffer.append("\n" + executeCommandNB(command, timeOut)) + } + } catch (e: Exception) { + throw BluePrintProcessorException("Failed to execute commands, below the output : $buffer") + } + return buffer.toString() + } + + override suspend fun executeCommandNB(command: String, timeOut: Long): String { + log.debug("Executing host($clientSession) command($command)") + + var channel: ChannelExec? = null + try { + channel = clientSession.createExecChannel(command) + //TODO("Convert to streaming ") + val outputStream = ByteArrayOutputStream() + channel.out = outputStream + channel.err = outputStream + channel.open().await() + val waitMask = channel.waitFor(Collections.unmodifiableSet(EnumSet.of(ClientChannelEvent.CLOSED)), timeOut) + if (waitMask.contains(ClientChannelEvent.TIMEOUT)) { + throw BluePrintProcessorException("Failed to retrieve command result in time: $command") + } + val exitStatus = channel.exitStatus + ClientChannel.validateCommandExitStatusCode(command, exitStatus!!) + return outputStream.toString() + } finally { + if (channel != null) + channel.close() + } + } + + override suspend fun closeSessionNB() { + if (sshClient.isStarted) { + sshClient.stop() + log.debug("SSH Client Service stopped successfully") + } + } +} diff --git a/ms/blueprintsprocessor/modules/commons/ssh-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/ssh/service/BluePrintSshLibPropertyService.kt b/ms/blueprintsprocessor/modules/commons/ssh-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/ssh/service/BluePrintSshLibPropertyService.kt new file mode 100644 index 000000000..9971c500f --- /dev/null +++ b/ms/blueprintsprocessor/modules/commons/ssh-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/ssh/service/BluePrintSshLibPropertyService.kt @@ -0,0 +1,64 @@ +/* + * Copyright © 2019 IBM. + * + * 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 org.onap.ccsdk.cds.blueprintsprocessor.ssh.service + +import org.onap.ccsdk.cds.blueprintsprocessor.core.BluePrintProperties +import org.onap.ccsdk.cds.blueprintsprocessor.ssh.BasicAuthSshClientProperties +import org.onap.ccsdk.cds.blueprintsprocessor.ssh.SshClientProperties +import org.onap.ccsdk.cds.blueprintsprocessor.ssh.SshLibConstants +import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintProcessorException +import org.springframework.stereotype.Service + +@Service(SshLibConstants.SERVICE_BLUEPRINT_SSH_LIB_PROPERTY) +open class BluePrintSshLibPropertyService(private var bluePrintProperties: BluePrintProperties) { + + fun blueprintSshClientService(selector: String): BlueprintSshClientService { + val prefix = "${SshLibConstants.PROPERTY_SSH_CLIENT_PREFIX}$selector" + val sshClientProperties = sshClientProperties(prefix) + return blueprintSshClientService(sshClientProperties) + } + + fun sshClientProperties(prefix: String): SshClientProperties { + val type = bluePrintProperties.propertyBeanType("$prefix.type", String::class.java) + return when (type) { + SshLibConstants.TYPE_BASIC_AUTH -> { + basicAuthSshClientProperties(prefix) + } + else -> { + throw BluePrintProcessorException("SSH adaptor($type) is not supported") + } + } + } + + private fun blueprintSshClientService(sshClientProperties: SshClientProperties): BlueprintSshClientService { + + when (sshClientProperties) { + is BasicAuthSshClientProperties -> { + return BasicAuthSshClientService(sshClientProperties) + } + else -> { + throw BluePrintProcessorException("couldn't get SSH client service for") + } + } + } + + private fun basicAuthSshClientProperties(prefix: String): BasicAuthSshClientProperties { + return bluePrintProperties.propertyBeanType( + prefix, BasicAuthSshClientProperties::class.java) + } + +} diff --git a/ms/blueprintsprocessor/modules/commons/ssh-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/ssh/service/BlueprintSshClientService.kt b/ms/blueprintsprocessor/modules/commons/ssh-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/ssh/service/BlueprintSshClientService.kt new file mode 100644 index 000000000..279e437cc --- /dev/null +++ b/ms/blueprintsprocessor/modules/commons/ssh-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/ssh/service/BlueprintSshClientService.kt @@ -0,0 +1,47 @@ +/* + * Copyright © 2019 IBM. + * + * 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 org.onap.ccsdk.cds.blueprintsprocessor.ssh.service + +import kotlinx.coroutines.runBlocking +import org.apache.sshd.client.session.ClientSession + +interface BlueprintSshClientService { + + fun startSession(): ClientSession = runBlocking { + startSessionNB() + } + + fun executeCommands(commands: List<String>, timeOut: Long): String = runBlocking { + executeCommandsNB(commands, timeOut) + } + + fun executeCommand(command: String, timeOut: Long): String = runBlocking { + executeCommandNB(command, timeOut) + } + + fun closeSession() = runBlocking { + closeSessionNB() + } + + suspend fun startSessionNB(): ClientSession + + suspend fun executeCommandsNB(commands: List<String>, timeOut: Long): String + + suspend fun executeCommandNB(command: String, timeOut: Long): String + + suspend fun closeSessionNB() +}
\ No newline at end of file diff --git a/ms/blueprintsprocessor/modules/commons/ssh-lib/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/ssh/service/BluePrintSshLibPropertyServiceTest.kt b/ms/blueprintsprocessor/modules/commons/ssh-lib/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/ssh/service/BluePrintSshLibPropertyServiceTest.kt new file mode 100644 index 000000000..d5c99935c --- /dev/null +++ b/ms/blueprintsprocessor/modules/commons/ssh-lib/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/ssh/service/BluePrintSshLibPropertyServiceTest.kt @@ -0,0 +1,58 @@ +/* + * Copyright © 2019 IBM. + * + * 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 org.onap.ccsdk.cds.blueprintsprocessor.ssh.service + +import org.junit.Test +import org.junit.runner.RunWith +import org.onap.ccsdk.cds.blueprintsprocessor.core.BluePrintProperties +import org.onap.ccsdk.cds.blueprintsprocessor.core.BlueprintPropertyConfiguration +import org.onap.ccsdk.cds.blueprintsprocessor.ssh.BasicAuthSshClientProperties +import org.onap.ccsdk.cds.blueprintsprocessor.ssh.BluePrintSshLibConfiguration +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.test.context.ContextConfiguration +import org.springframework.test.context.TestPropertySource +import org.springframework.test.context.junit4.SpringRunner +import kotlin.test.assertEquals +import kotlin.test.assertNotNull + + +@RunWith(SpringRunner::class) +@ContextConfiguration(classes = [BluePrintSshLibConfiguration::class, + BlueprintPropertyConfiguration::class, BluePrintProperties::class]) +@TestPropertySource(properties = +["blueprintsprocessor.sshclient.sample.type=basic-auth", + "blueprintsprocessor.sshclient.sample.host=127.0.0.1", + "blueprintsprocessor.sshclient.sample.port=22", + "blueprintsprocessor.sshclient.sample.password=1234", + "blueprintsprocessor.sshclient.sample.username=dummy" +]) +class BluePrintSshLibPropertyServiceTest { + + @Autowired + lateinit var bluePrintSshLibPropertyService: BluePrintSshLibPropertyService + + @Test + fun testRestClientProperties() { + val properties = bluePrintSshLibPropertyService + .sshClientProperties("blueprintsprocessor.sshclient.sample") as BasicAuthSshClientProperties + assertNotNull(properties, "failed to create property bean") + assertEquals(properties.host, "127.0.0.1", "failed to match host property") + assertEquals(properties.port, 22, "failed to match port property") + assertEquals(properties.password, "1234", "failed to match host property") + assertEquals(properties.username, "dummy", "failed to match host property") + } +}
\ No newline at end of file diff --git a/ms/blueprintsprocessor/modules/commons/ssh-lib/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/ssh/service/BlueprintSshClientServiceTest.kt b/ms/blueprintsprocessor/modules/commons/ssh-lib/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/ssh/service/BlueprintSshClientServiceTest.kt new file mode 100644 index 000000000..d61219215 --- /dev/null +++ b/ms/blueprintsprocessor/modules/commons/ssh-lib/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/ssh/service/BlueprintSshClientServiceTest.kt @@ -0,0 +1,100 @@ +/* + * Copyright © 2019 IBM. + * + * 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 org.onap.ccsdk.cds.blueprintsprocessor.ssh.service + +import kotlinx.coroutines.runBlocking +import org.apache.sshd.common.config.keys.KeyUtils.RSA_ALGORITHM +import org.apache.sshd.common.keyprovider.KeyPairProvider +import org.apache.sshd.server.SshServer +import org.apache.sshd.server.auth.password.PasswordAuthenticator +import org.apache.sshd.server.auth.pubkey.AcceptAllPublickeyAuthenticator +import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider +import org.apache.sshd.server.session.ServerSession +import org.apache.sshd.server.shell.ProcessShellCommandFactory +import org.junit.runner.RunWith +import org.onap.ccsdk.cds.blueprintsprocessor.core.BluePrintProperties +import org.onap.ccsdk.cds.blueprintsprocessor.core.BlueprintPropertyConfiguration +import org.onap.ccsdk.cds.blueprintsprocessor.ssh.BluePrintSshLibConfiguration +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.test.context.ContextConfiguration +import org.springframework.test.context.TestPropertySource +import org.springframework.test.context.junit4.SpringRunner +import java.nio.file.Paths +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertNotNull + + +@RunWith(SpringRunner::class) +@ContextConfiguration(classes = [BluePrintSshLibConfiguration::class, + BlueprintPropertyConfiguration::class, BluePrintProperties::class]) +@TestPropertySource(properties = +["blueprintsprocessor.sshclient.sample.type=basic-auth", + "blueprintsprocessor.sshclient.sample.host=localhost", + "blueprintsprocessor.sshclient.sample.port=52815", + "blueprintsprocessor.sshclient.sample.username=root", + "blueprintsprocessor.sshclient.sample.password=dummyps" +]) +class BlueprintSshClientServiceTest { + + @Autowired + lateinit var bluePrintSshLibPropertyService: BluePrintSshLibPropertyService + + @Test + fun testBasicAuthSshClientService() { + runBlocking { + val sshServer = setupTestServer("localhost", 52815, "root", "dummyps") + sshServer.start() + println(sshServer) + val bluePrintSshLibPropertyService = bluePrintSshLibPropertyService.blueprintSshClientService("sample") + val sshSession = bluePrintSshLibPropertyService.startSession() + val response = bluePrintSshLibPropertyService.executeCommandsNB(arrayListOf("echo '1'", "echo '2'"), 2000) + assertNotNull(response, "failed to get command response") + bluePrintSshLibPropertyService.closeSession() + sshServer.stop(true) + } + } + + private fun setupTestServer(host: String, port: Int, userName: String, password: String): SshServer { + val sshd = SshServer.setUpDefaultServer() + sshd.port = port + sshd.host = host + sshd.keyPairProvider = createTestHostKeyProvider() + sshd.passwordAuthenticator = BogusPasswordAuthenticator(userName, password) + sshd.publickeyAuthenticator = AcceptAllPublickeyAuthenticator.INSTANCE + //sshd.shellFactory = EchoShellFactory() + sshd.commandFactory = ProcessShellCommandFactory.INSTANCE + return sshd + } + + private fun createTestHostKeyProvider(): KeyPairProvider { + val keyProvider = SimpleGeneratorHostKeyProvider() + keyProvider.path = Paths.get("target").resolve("hostkey." + RSA_ALGORITHM.toLowerCase()) + keyProvider.algorithm = RSA_ALGORITHM + return keyProvider + } +} + +class BogusPasswordAuthenticator(userName: String, password: String) : PasswordAuthenticator { + override fun authenticate(username: String, password: String, serverSession: ServerSession): Boolean { + assertEquals(username, "root", "failed to match username") + assertEquals(password, "dummyps", "failed to match password") + return true + } +} + + diff --git a/ms/blueprintsprocessor/modules/commons/ssh-lib/src/test/resources/logback-test.xml b/ms/blueprintsprocessor/modules/commons/ssh-lib/src/test/resources/logback-test.xml new file mode 100644 index 000000000..365c41c9e --- /dev/null +++ b/ms/blueprintsprocessor/modules/commons/ssh-lib/src/test/resources/logback-test.xml @@ -0,0 +1,35 @@ +<!-- + ~ Copyright © 2017-2018 AT&T Intellectual Property. + ~ + ~ 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. + --> + +<configuration> + <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> + <!-- encoders are assigned the type + ch.qos.logback.classic.encoder.PatternLayoutEncoder by default --> + <encoder> + <pattern>%d{HH:mm:ss.SSS} %-5level %logger{100} - %msg%n</pattern> + </encoder> + </appender> + + <logger name="org.springframework.test" level="warn"/> + <logger name="org.springframework" level="warn"/> + <logger name="org.hibernate" level="info"/> + <logger name="org.onap.ccsdk.cds.blueprintsprocessor" level="info"/> + + <root level="warn"> + <appender-ref ref="STDOUT"/> + </root> + +</configuration> |