Skip to content

Commit

Permalink
Merge from master
Browse files Browse the repository at this point in the history
  • Loading branch information
htch committed Jan 14, 2019
2 parents 1e1153b + b653b11 commit 788f156
Show file tree
Hide file tree
Showing 36 changed files with 2,045 additions and 1,403 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ To get minikube follow the instructions [here](https://github.com/kubernetes/min
You can use the latest release (for Scala 2.11 or 2.12) by adding to your build:
```sbt
libraryDependencies += "io.skuber" %% "skuber" % "2.0.11"
libraryDependencies += "io.skuber" %% "skuber" % "2.0.12"
```
Meanwhile users of skuber v1 can continue to use the latest (and possibly final, with exception of important fixes) v1.x release, which is available only on Scala 2.11:
Expand Down
1 change: 1 addition & 0 deletions client/src/it/scala/skuber/DeploymentSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ class DeploymentSpec extends K8SFixture with Eventually with Matchers {

it should "upgrade the newly created deployment" in { k8s =>
k8s.get[Deployment](nginxDeploymentName).flatMap { d =>
println(s"DEPLOYMENT TO UPDATE ==> $d")
val updatedDeployment = d.updateContainer(getNginxContainer("1.9.1"))
k8s.update(updatedDeployment).flatMap { _ =>
eventually(timeout(200 seconds), interval(5 seconds)) {
Expand Down
3 changes: 2 additions & 1 deletion client/src/it/scala/skuber/K8SFixture.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@ import akka.stream.ActorMaterializer
import org.scalatest.{FutureOutcome, fixture}
import skuber.api.client._
import com.typesafe.config.ConfigFactory
import skuber.api.client.impl.KubernetesClientImpl

trait K8SFixture extends fixture.AsyncFlatSpec {

override type FixtureParam = RequestContext
override type FixtureParam = K8SRequestContext

implicit val system = ActorSystem()
implicit val materializer = ActorMaterializer()
Expand Down
4 changes: 2 additions & 2 deletions client/src/it/scala/skuber/PatchSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -88,12 +88,12 @@ class PatchSpec extends K8SFixture with Eventually with Matchers with BeforeAndA
it should "patch a pod with json patch" in { k8s =>
val randomString = java.util.UUID.randomUUID().toString
val annotations = Map("skuber" -> "wow")
val patchData = JsonPatchOperationList(List(
val patchData = JsonPatch(List(
JsonPatchOperation.Add("/metadata/labels/foo", randomString),
JsonPatchOperation.Add("/metadata/annotations", randomString),
JsonPatchOperation.Remove("/metadata/annotations"),
))
k8s.patch[JsonPatchOperationList, Pod](nginxPodName, patchData).map { _ =>
k8s.patch[JsonPatch, Pod](nginxPodName, patchData).map { _ =>
eventually(timeout(10 seconds), interval(1 seconds)) {
val retrievePod = k8s.get[Pod](nginxPodName)
val podRetrieved = Await.ready(retrievePod, 2 seconds).value.get
Expand Down
15 changes: 14 additions & 1 deletion client/src/it/scala/skuber/WatchContinuouslySpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import org.scalatest.time.{Seconds, Span}
import skuber.apps.v1.{Deployment, DeploymentList}

import scala.concurrent.duration._
import scala.concurrent.Await

import scala.language.postfixOps

class WatchContinuouslySpec extends K8SFixture with Eventually with Matchers with ScalaFutures {
Expand All @@ -32,6 +34,9 @@ class WatchContinuouslySpec extends K8SFixture with Eventually with Matchers wit
.run()
}

// Wait for watch to be confirmed before performing the actions that create new events to be watched
Await.result(stream, 5.seconds)

//Create first deployment and delete it.
k8s.create(deploymentOne).futureValue.name shouldBe deploymentOneName
eventually {
Expand Down Expand Up @@ -104,7 +109,15 @@ class WatchContinuouslySpec extends K8SFixture with Eventually with Matchers wit
killSwitch._1.shutdown()
}

stream.futureValue._2.futureValue.toList.map { d =>
val f1 = stream.futureValue

f1._2.onFailure {
case ex: Exception => ex.printStackTrace()
}

val f2 = f1._2.futureValue

f2.toList.map { d =>
(d._type, d._object.name)
} shouldBe List(
(EventType.ADDED, deploymentName),
Expand Down
2 changes: 1 addition & 1 deletion client/src/main/scala/skuber/Container.scala
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ case class Container(
terminationMessagePath: Option[String] = None,
terminationMessagePolicy: Option[Container.TerminationMessagePolicy.Value] = None,
imagePullPolicy: Container.PullPolicy.Value = Container.PullPolicy.IfNotPresent,
securityContext: Option[Security.Context] = None,
securityContext: Option[SecurityContext] = None,
envFrom: List[EnvFromSource] = Nil,
stdin: Option[Boolean] = None,
stdinOnce: Option[Boolean] = None,
Expand Down
16 changes: 8 additions & 8 deletions client/src/main/scala/skuber/Pod.scala
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ object Pod {
imagePullSecrets: List[LocalObjectReference] = List(),
affinity: Option[Affinity] = None,
tolerations: List[Toleration] = List(),
securityContext: Option[Security.Context] = None,
securityContext: Option[PodSecurityContext] = None,
hostname: Option[String] = None,
hostAliases: List[HostAlias] = Nil,
hostPID: Option[Boolean] = None,
Expand Down Expand Up @@ -90,11 +90,11 @@ object Pod {
val In, NotIn, Exists, DoesNotExist, Gt, Lt = Value
}

case class MatchExpression(key: String, operator: NodeSelectorOperator.Value, values: List[String])
type MatchExpressions = List[MatchExpression]
def MatchExpressions(xs: MatchExpression*) = List(xs: _*)
case class NodeSelectorRequirement(key: String, operator: NodeSelectorOperator.Value, values: List[String])
type NodeSelectorRequirements = List[NodeSelectorRequirement]
def NodeSelectorRequirements(xs: NodeSelectorRequirement*) = List(xs: _*)

case class NodeSelectorTerm(matchExpressions: MatchExpressions)
case class NodeSelectorTerm(matchExpressions: NodeSelectorRequirements = List.empty, matchFields: NodeSelectorRequirements = List.empty)
type NodeSelectorTerms = List[NodeSelectorTerm]
def NodeSelectorTerms(xs: NodeSelectorTerm*) = List(xs: _*)

Expand All @@ -111,8 +111,8 @@ object Pod {
RequiredDuringSchedulingIgnoredDuringExecution(
NodeSelectorTerms(
NodeSelectorTerm(
MatchExpressions(
MatchExpression(key, operator, values)
matchExpressions = NodeSelectorRequirements(
NodeSelectorRequirement(key, operator, values)
)
)
)
Expand All @@ -127,7 +127,7 @@ object Pod {
def preferredQuery(weight: Int, key: String, operator: NodeSelectorOperator.Value, values: List[String]): PreferredSchedulingTerm = {
PreferredSchedulingTerm(
preference = NodeSelectorTerm(
MatchExpressions(MatchExpression(key, operator, values))
matchExpressions = NodeSelectorRequirements(NodeSelectorRequirement(key, operator, values))
),
weight = weight
)
Expand Down
66 changes: 41 additions & 25 deletions client/src/main/scala/skuber/Security.scala
Original file line number Diff line number Diff line change
@@ -1,32 +1,48 @@
package skuber

/**
* @author David O'Riordan
*/
* @author David O'Riordan
*/

import Security._

case class SecurityContext(
allowPrivilegeEscalation: Option[Boolean] = None,
capabilities: Option[Capabilities] = None,
privileged: Option[Boolean] = None,
readOnlyRootFilesystem: Option[Boolean] = None,
runAsGroup: Option[Int] = None,
runAsNonRoot: Option[Boolean] = None,
runAsUser: Option[Int] = None,
seLinuxOptions: Option[SELinuxOptions] = None
)

case class PodSecurityContext(
fsGroup: Option[Int] = None,
runAsGroup: Option[Int] = None,
runAsNonRoot: Option[Boolean] = None,
runAsUser: Option[Int] = None,
seLinuxOptions: Option[SELinuxOptions] = None,
supplementalGroups: List[Int] = Nil,
sysctls: List[Sysctl] = Nil
)

object Security {
// Note: Context can be set at pod and/or container level but certain attributes are level-specific
case class Context(
capabilities: Option[Capabilities] = None,
privileged: Option[Boolean] = None,
seLinuxOptions: Option[SELinuxOptions] = None,
runAsUser: Option[Int] = None,
runAsGroup: Option[Int] = None,
runAsNonRoot: Option[Boolean] = None,
fsGroup: Option[Int] = None,
allowPrivilegeEscalation: Option[Boolean] = None
)

type Capability=String
type Capability = String

case class Capabilities(
add: List[Capability] = Nil,
drop: List[Capability] = Nil)
add: List[Capability] = Nil,
drop: List[Capability] = Nil)

case class SELinuxOptions(
user: String = "",
role: String = "",
_type: String = "",
level: String = "")


}
user: String = "",
role: String = "",
_type: String = "",
level: String = "")

case class Sysctl(
name: String,
value: String
)

}
38 changes: 38 additions & 0 deletions client/src/main/scala/skuber/api/Configuration.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package skuber.api

import java.io.File
import java.net.URL

import scala.collection.JavaConverters._
import scala.util.Try
Expand Down Expand Up @@ -276,4 +277,41 @@ object Configuration {
currentContext = ctx
)
}

/*
* Get the current default configuration
*/
def defaultK8sConfig = {
import java.nio.file.Paths

val skuberUrlOverride = sys.env.get("SKUBER_URL")
skuberUrlOverride match {
case Some(url) =>
Configuration.useProxyAt(url)
case None =>
val skuberConfigEnv = sys.env.get("SKUBER_CONFIG")
skuberConfigEnv match {
case Some(conf) if conf == "file" =>
Configuration.parseKubeconfigFile().get // default kubeconfig location
case Some(conf) if conf == "proxy" =>
Configuration.useLocalProxyDefault
case Some(fileUrl) =>
val path = Paths.get(new URL(fileUrl).toURI)
Configuration.parseKubeconfigFile(path).get
case None =>
// try KUBECONFIG
val kubeConfigEnv = sys.env.get("KUBECONFIG")
kubeConfigEnv.map { kc =>
Configuration.parseKubeconfigFile(Paths.get(kc))
}.getOrElse {
// Try to get config from a running pod
// if that is not set then use default kubeconfig location
Configuration.inClusterConfig.orElse(
Configuration.parseKubeconfigFile()
)
}.get
}
}
}

}
13 changes: 13 additions & 0 deletions client/src/main/scala/skuber/api/client/Cluster.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package skuber.api.client

/**
* @author David O'Riordan
*
* Defines the details needed to communicate with the API server for a Kubernetes cluster
*/
case class Cluster(
apiVersion: String = "v1",
server: String = defaultApiServerURL,
insecureSkipTLSVerify: Boolean = false,
certificateAuthority: Option[PathOrData] = None
)
13 changes: 13 additions & 0 deletions client/src/main/scala/skuber/api/client/Context.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package skuber.api.client

import skuber.Namespace

/**
* @author David O'Riordan
* Define the Kubernetes API context for requests
*/
case class Context(
cluster: Cluster = Cluster(),
authInfo: AuthInfo = NoAuth,
namespace: Namespace = Namespace.default
)
Loading

0 comments on commit 788f156

Please sign in to comment.