forked from LaconicNetwork/kompose
Upgrade OpenShift and its dependencies.
OpenShift version 1.4.0-alpha.0
This commit is contained in:
+693
@@ -0,0 +1,693 @@
|
||||
package graph
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/gonum/graph"
|
||||
"github.com/gonum/graph/concrete"
|
||||
"github.com/gonum/graph/encoding/dot"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api/meta"
|
||||
"k8s.io/kubernetes/pkg/util/sets"
|
||||
)
|
||||
|
||||
type Node struct {
|
||||
concrete.Node
|
||||
UniqueName
|
||||
}
|
||||
|
||||
// DOTAttributes implements an attribute getter for the DOT encoding
|
||||
func (n Node) DOTAttributes() []dot.Attribute {
|
||||
return []dot.Attribute{{Key: "label", Value: fmt.Sprintf("%q", n.UniqueName)}}
|
||||
}
|
||||
|
||||
// ExistenceChecker is an interface for those nodes that can be created without a backing object.
|
||||
// This can happen when a node wants an edge to a non-existent node. We know the node should exist,
|
||||
// The graph needs something in that location to track the information we have about the node, but the
|
||||
// backing object doesn't exist.
|
||||
type ExistenceChecker interface {
|
||||
// Found returns false if the node represents an object that we don't have the backing object for
|
||||
Found() bool
|
||||
}
|
||||
|
||||
type UniqueName string
|
||||
|
||||
type UniqueNameFunc func(obj interface{}) UniqueName
|
||||
|
||||
func (n UniqueName) UniqueName() string {
|
||||
return string(n)
|
||||
}
|
||||
|
||||
func (n UniqueName) String() string {
|
||||
return string(n)
|
||||
}
|
||||
|
||||
type uniqueNamer interface {
|
||||
UniqueName() UniqueName
|
||||
}
|
||||
|
||||
type NodeFinder interface {
|
||||
Find(name UniqueName) graph.Node
|
||||
}
|
||||
|
||||
// UniqueNodeInitializer is a graph that allows nodes with a unique name to be added without duplication.
|
||||
// If the node is newly added, true will be returned.
|
||||
type UniqueNodeInitializer interface {
|
||||
FindOrCreate(name UniqueName, fn NodeInitializerFunc) (graph.Node, bool)
|
||||
}
|
||||
|
||||
type NodeInitializerFunc func(Node) graph.Node
|
||||
|
||||
func EnsureUnique(g UniqueNodeInitializer, name UniqueName, fn NodeInitializerFunc) graph.Node {
|
||||
node, _ := g.FindOrCreate(name, fn)
|
||||
return node
|
||||
}
|
||||
|
||||
type MutableDirectedEdge interface {
|
||||
AddEdge(from, to graph.Node, edgeKind string)
|
||||
}
|
||||
|
||||
type MutableUniqueGraph interface {
|
||||
graph.Mutable
|
||||
MutableDirectedEdge
|
||||
UniqueNodeInitializer
|
||||
NodeFinder
|
||||
}
|
||||
|
||||
type Edge struct {
|
||||
concrete.Edge
|
||||
kinds sets.String
|
||||
}
|
||||
|
||||
func NewEdge(from, to graph.Node, kinds ...string) Edge {
|
||||
return Edge{concrete.Edge{F: from, T: to}, sets.NewString(kinds...)}
|
||||
}
|
||||
|
||||
func (e Edge) Kinds() sets.String {
|
||||
return e.kinds
|
||||
}
|
||||
|
||||
func (e Edge) IsKind(kind string) bool {
|
||||
return e.kinds.Has(kind)
|
||||
}
|
||||
|
||||
// DOTAttributes implements an attribute getter for the DOT encoding
|
||||
func (e Edge) DOTAttributes() []dot.Attribute {
|
||||
return []dot.Attribute{{Key: "label", Value: fmt.Sprintf("%q", strings.Join(e.Kinds().List(), ","))}}
|
||||
}
|
||||
|
||||
type GraphDescriber interface {
|
||||
Name(node graph.Node) string
|
||||
Kind(node graph.Node) string
|
||||
Object(node graph.Node) interface{}
|
||||
EdgeKinds(edge graph.Edge) sets.String
|
||||
}
|
||||
|
||||
type Interface interface {
|
||||
graph.Directed
|
||||
|
||||
GraphDescriber
|
||||
MutableUniqueGraph
|
||||
|
||||
Edges() []graph.Edge
|
||||
}
|
||||
|
||||
type Namer interface {
|
||||
ResourceName(obj interface{}) string
|
||||
}
|
||||
|
||||
type namer struct{}
|
||||
|
||||
var DefaultNamer Namer = namer{}
|
||||
|
||||
func (namer) ResourceName(obj interface{}) string {
|
||||
switch t := obj.(type) {
|
||||
case uniqueNamer:
|
||||
return t.UniqueName().String()
|
||||
default:
|
||||
return reflect.TypeOf(obj).String()
|
||||
}
|
||||
}
|
||||
|
||||
type Graph struct {
|
||||
// the standard graph
|
||||
graph.Directed
|
||||
// helper methods for switching on the kind and types of the node
|
||||
GraphDescriber
|
||||
|
||||
// exposes the public interface for adding nodes
|
||||
uniqueNamedGraph
|
||||
// the internal graph object, which allows edges and nodes to be directly added
|
||||
internal *concrete.DirectedGraph
|
||||
}
|
||||
|
||||
// Graph must implement MutableUniqueGraph
|
||||
var _ MutableUniqueGraph = Graph{}
|
||||
|
||||
// New initializes a graph from input to output.
|
||||
func New() Graph {
|
||||
g := concrete.NewDirectedGraph()
|
||||
return Graph{
|
||||
Directed: g,
|
||||
GraphDescriber: typedGraph{},
|
||||
|
||||
uniqueNamedGraph: newUniqueNamedGraph(g),
|
||||
|
||||
internal: g,
|
||||
}
|
||||
}
|
||||
|
||||
// Edges returns all the edges of the graph. Note that the returned set
|
||||
// will have no specific ordering.
|
||||
func (g Graph) Edges() []graph.Edge {
|
||||
return g.internal.Edges()
|
||||
}
|
||||
|
||||
func (g Graph) String() string {
|
||||
ret := ""
|
||||
|
||||
nodes := g.Nodes()
|
||||
sort.Sort(ByID(nodes))
|
||||
for _, node := range nodes {
|
||||
ret += fmt.Sprintf("%d: %v\n", node.ID(), g.GraphDescriber.Name(node))
|
||||
|
||||
// can't use SuccessorEdges, because I want stable ordering
|
||||
successors := g.From(node)
|
||||
sort.Sort(ByID(successors))
|
||||
for _, successor := range successors {
|
||||
edge := g.Edge(node, successor)
|
||||
kinds := g.EdgeKinds(edge)
|
||||
for _, kind := range kinds.List() {
|
||||
ret += fmt.Sprintf("\t%v to %d: %v\n", kind, successor.ID(), g.GraphDescriber.Name(successor))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
// ByID is a sorted group of nodes by ID
|
||||
type ByID []graph.Node
|
||||
|
||||
func (m ByID) Len() int { return len(m) }
|
||||
func (m ByID) Swap(i, j int) { m[i], m[j] = m[j], m[i] }
|
||||
func (m ByID) Less(i, j int) bool {
|
||||
return m[i].ID() < m[j].ID()
|
||||
}
|
||||
|
||||
// SyntheticNodes returns back the set of nodes that were created in response to edge requests, but did not exist
|
||||
func (g Graph) SyntheticNodes() []graph.Node {
|
||||
ret := []graph.Node{}
|
||||
|
||||
nodes := g.Nodes()
|
||||
sort.Sort(ByID(nodes))
|
||||
for _, node := range nodes {
|
||||
if potentiallySyntheticNode, ok := node.(ExistenceChecker); ok {
|
||||
if !potentiallySyntheticNode.Found() {
|
||||
ret = append(ret, node)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
// NodesByKind returns all the nodes of the graph with the provided kinds
|
||||
func (g Graph) NodesByKind(nodeKinds ...string) []graph.Node {
|
||||
ret := []graph.Node{}
|
||||
|
||||
kinds := sets.NewString(nodeKinds...)
|
||||
for _, node := range g.internal.Nodes() {
|
||||
if kinds.Has(g.Kind(node)) {
|
||||
ret = append(ret, node)
|
||||
}
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
// RootNodes returns all the roots of this graph.
|
||||
func (g Graph) RootNodes() []graph.Node {
|
||||
roots := []graph.Node{}
|
||||
for _, n := range g.Nodes() {
|
||||
if len(g.To(n)) != 0 {
|
||||
continue
|
||||
}
|
||||
roots = append(roots, n)
|
||||
}
|
||||
return roots
|
||||
}
|
||||
|
||||
// PredecessorEdges invokes fn with all of the predecessor edges of node that have the specified
|
||||
// edge kind.
|
||||
func (g Graph) PredecessorEdges(node graph.Node, fn EdgeFunc, edgeKinds ...string) {
|
||||
for _, n := range g.To(node) {
|
||||
edge := g.Edge(n, node)
|
||||
kinds := g.EdgeKinds(edge)
|
||||
|
||||
if kinds.HasAny(edgeKinds...) {
|
||||
fn(g, n, node, kinds)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// SuccessorEdges invokes fn with all of the successor edges of node that have the specified
|
||||
// edge kind.
|
||||
func (g Graph) SuccessorEdges(node graph.Node, fn EdgeFunc, edgeKinds ...string) {
|
||||
for _, n := range g.From(node) {
|
||||
edge := g.Edge(node, n)
|
||||
kinds := g.EdgeKinds(edge)
|
||||
|
||||
if kinds.HasAny(edgeKinds...) {
|
||||
fn(g, n, node, kinds)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// OutboundEdges returns all the outbound edges from node that are in the list of edgeKinds
|
||||
// if edgeKinds is empty, then all edges are returned
|
||||
func (g Graph) OutboundEdges(node graph.Node, edgeKinds ...string) []graph.Edge {
|
||||
ret := []graph.Edge{}
|
||||
|
||||
for _, n := range g.From(node) {
|
||||
edge := g.Edge(node, n)
|
||||
if edge == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if len(edgeKinds) == 0 || g.EdgeKinds(edge).HasAny(edgeKinds...) {
|
||||
ret = append(ret, edge)
|
||||
}
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
// InboundEdges returns all the inbound edges to node that are in the list of edgeKinds
|
||||
// if edgeKinds is empty, then all edges are returned
|
||||
func (g Graph) InboundEdges(node graph.Node, edgeKinds ...string) []graph.Edge {
|
||||
ret := []graph.Edge{}
|
||||
|
||||
for _, n := range g.To(node) {
|
||||
edge := g.Edge(n, node)
|
||||
if edge == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if len(edgeKinds) == 0 || g.EdgeKinds(edge).HasAny(edgeKinds...) {
|
||||
ret = append(ret, edge)
|
||||
}
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
// PredecessorNodesByEdgeKind returns all the predecessor nodes of the given node
|
||||
// that can be reached via edges of the provided kinds
|
||||
func (g Graph) PredecessorNodesByEdgeKind(node graph.Node, edgeKinds ...string) []graph.Node {
|
||||
ret := []graph.Node{}
|
||||
|
||||
for _, inboundEdges := range g.InboundEdges(node, edgeKinds...) {
|
||||
ret = append(ret, inboundEdges.From())
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
// SuccessorNodesByEdgeKind returns all the successor nodes of the given node
|
||||
// that can be reached via edges of the provided kinds
|
||||
func (g Graph) SuccessorNodesByEdgeKind(node graph.Node, edgeKinds ...string) []graph.Node {
|
||||
ret := []graph.Node{}
|
||||
|
||||
for _, outboundEdge := range g.OutboundEdges(node, edgeKinds...) {
|
||||
ret = append(ret, outboundEdge.To())
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
func (g Graph) SuccessorNodesByNodeAndEdgeKind(node graph.Node, nodeKind, edgeKind string) []graph.Node {
|
||||
ret := []graph.Node{}
|
||||
|
||||
for _, successor := range g.SuccessorNodesByEdgeKind(node, edgeKind) {
|
||||
if g.Kind(successor) != nodeKind {
|
||||
continue
|
||||
}
|
||||
|
||||
ret = append(ret, successor)
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
func (g Graph) AddNode(n graph.Node) {
|
||||
g.internal.AddNode(n)
|
||||
}
|
||||
|
||||
// AddEdge implements MutableUniqueGraph
|
||||
func (g Graph) AddEdge(from, to graph.Node, edgeKind string) {
|
||||
// a Contains edge has semantic meaning for osgraph.Graph objects. It never makes sense
|
||||
// to allow a single object to be "contained" by multiple nodes.
|
||||
if edgeKind == ContainsEdgeKind {
|
||||
// check incoming edges on the 'to' node to be certain that we aren't already contained
|
||||
containsEdges := g.InboundEdges(to, ContainsEdgeKind)
|
||||
if len(containsEdges) != 0 {
|
||||
// TODO consider changing the AddEdge API to make this cleaner. This is a pretty severe programming error
|
||||
panic(fmt.Sprintf("%v is already contained by %v", to, containsEdges))
|
||||
}
|
||||
}
|
||||
|
||||
kinds := sets.NewString(edgeKind)
|
||||
if existingEdge := g.Edge(from, to); existingEdge != nil {
|
||||
kinds.Insert(g.EdgeKinds(existingEdge).List()...)
|
||||
}
|
||||
|
||||
g.internal.SetEdge(NewEdge(from, to, kinds.List()...), 1.0)
|
||||
}
|
||||
|
||||
// addEdges adds the specified edges, filtered by the provided edge connection
|
||||
// function.
|
||||
func (g Graph) addEdges(edges []graph.Edge, fn EdgeFunc) {
|
||||
for _, e := range edges {
|
||||
switch t := e.(type) {
|
||||
case concrete.WeightedEdge:
|
||||
if fn(g, t.From(), t.To(), t.Edge.(Edge).Kinds()) {
|
||||
g.internal.SetEdge(t.Edge.(Edge), t.Cost)
|
||||
}
|
||||
case Edge:
|
||||
if fn(g, t.From(), t.To(), t.Kinds()) {
|
||||
g.internal.SetEdge(t, 1.0)
|
||||
}
|
||||
default:
|
||||
panic("bad edge")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NodeFunc is passed a new graph, a node in the graph, and should return true if the
|
||||
// node should be included.
|
||||
type NodeFunc func(g Interface, n graph.Node) bool
|
||||
|
||||
// NodesOfKind returns a new NodeFunc accepting the provided kinds of nodes
|
||||
// If no kinds are specified, the returned NodeFunc will accept all nodes
|
||||
func NodesOfKind(kinds ...string) NodeFunc {
|
||||
if len(kinds) == 0 {
|
||||
return func(g Interface, n graph.Node) bool {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
allowedKinds := sets.NewString(kinds...)
|
||||
return func(g Interface, n graph.Node) bool {
|
||||
return allowedKinds.Has(g.Kind(n))
|
||||
}
|
||||
}
|
||||
|
||||
// EdgeFunc is passed a new graph, an edge in the current graph, and should mutate
|
||||
// the new graph as needed. If true is returned, the existing edge will be added to the graph.
|
||||
type EdgeFunc func(g Interface, from, to graph.Node, edgeKinds sets.String) bool
|
||||
|
||||
// EdgesOfKind returns a new EdgeFunc accepting the provided kinds of edges
|
||||
// If no kinds are specified, the returned EdgeFunc will accept all edges
|
||||
func EdgesOfKind(kinds ...string) EdgeFunc {
|
||||
if len(kinds) == 0 {
|
||||
return func(g Interface, from, to graph.Node, edgeKinds sets.String) bool {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
allowedKinds := sets.NewString(kinds...)
|
||||
return func(g Interface, from, to graph.Node, edgeKinds sets.String) bool {
|
||||
return allowedKinds.HasAny(edgeKinds.List()...)
|
||||
}
|
||||
}
|
||||
|
||||
// RemoveInboundEdges returns a new EdgeFunc dismissing any inbound edges to
|
||||
// the provided set of nodes
|
||||
func RemoveInboundEdges(nodes []graph.Node) EdgeFunc {
|
||||
return func(g Interface, from, to graph.Node, edgeKinds sets.String) bool {
|
||||
for _, node := range nodes {
|
||||
if node == to {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
func RemoveOutboundEdges(nodes []graph.Node) EdgeFunc {
|
||||
return func(g Interface, from, to graph.Node, edgeKinds sets.String) bool {
|
||||
for _, node := range nodes {
|
||||
if node == from {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// EdgeSubgraph returns the directed subgraph with only the edges that match the
|
||||
// provided function.
|
||||
func (g Graph) EdgeSubgraph(edgeFn EdgeFunc) Graph {
|
||||
out := New()
|
||||
for _, node := range g.Nodes() {
|
||||
out.internal.AddNode(node)
|
||||
}
|
||||
out.addEdges(g.internal.Edges(), edgeFn)
|
||||
return out
|
||||
}
|
||||
|
||||
// Subgraph returns the directed subgraph with only the nodes and edges that match the
|
||||
// provided functions.
|
||||
func (g Graph) Subgraph(nodeFn NodeFunc, edgeFn EdgeFunc) Graph {
|
||||
out := New()
|
||||
for _, node := range g.Nodes() {
|
||||
if nodeFn(out, node) {
|
||||
out.internal.AddNode(node)
|
||||
}
|
||||
}
|
||||
out.addEdges(g.internal.Edges(), edgeFn)
|
||||
return out
|
||||
}
|
||||
|
||||
// SubgraphWithNodes returns the directed subgraph with only the listed nodes and edges that
|
||||
// match the provided function.
|
||||
func (g Graph) SubgraphWithNodes(nodes []graph.Node, fn EdgeFunc) Graph {
|
||||
out := New()
|
||||
for _, node := range nodes {
|
||||
out.internal.AddNode(node)
|
||||
}
|
||||
out.addEdges(g.internal.Edges(), fn)
|
||||
return out
|
||||
}
|
||||
|
||||
// ConnectedEdgeSubgraph creates a new graph that iterates through all edges in the graph
|
||||
// and includes all edges the provided function returns true for. Nodes not referenced by
|
||||
// an edge will be dropped unless the function adds them explicitly.
|
||||
func (g Graph) ConnectedEdgeSubgraph(fn EdgeFunc) Graph {
|
||||
out := New()
|
||||
out.addEdges(g.internal.Edges(), fn)
|
||||
return out
|
||||
}
|
||||
|
||||
// AllNodes includes all nodes in the graph
|
||||
func AllNodes(g Interface, node graph.Node) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// ExistingDirectEdge returns true if both from and to already exist in the graph and the edge kind is
|
||||
// not ReferencedByEdgeKind (the generic reverse edge kind). This will purge the graph of any
|
||||
// edges created by AddReversedEdge.
|
||||
func ExistingDirectEdge(g Interface, from, to graph.Node, edgeKinds sets.String) bool {
|
||||
return !edgeKinds.Has(ReferencedByEdgeKind) && g.Has(from) && g.Has(to)
|
||||
}
|
||||
|
||||
// ReverseExistingDirectEdge reverses the order of the edge and drops the existing edge only if
|
||||
// both from and to already exist in the graph and the edge kind is not ReferencedByEdgeKind
|
||||
// (the generic reverse edge kind).
|
||||
func ReverseExistingDirectEdge(g Interface, from, to graph.Node, edgeKinds sets.String) bool {
|
||||
return ExistingDirectEdge(g, from, to, edgeKinds) && ReverseGraphEdge(g, from, to, edgeKinds)
|
||||
}
|
||||
|
||||
// ReverseGraphEdge reverses the order of the edge and drops the existing edge.
|
||||
func ReverseGraphEdge(g Interface, from, to graph.Node, edgeKinds sets.String) bool {
|
||||
for edgeKind := range edgeKinds {
|
||||
g.AddEdge(to, from, edgeKind)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// AddReversedEdge adds a reversed edge for every passed edge and preserves the existing
|
||||
// edge. Used to convert a one directional edge into a bidirectional edge, but will
|
||||
// create duplicate edges if a bidirectional edge between two nodes already exists.
|
||||
func AddReversedEdge(g Interface, from, to graph.Node, edgeKinds sets.String) bool {
|
||||
g.AddEdge(to, from, ReferencedByEdgeKind)
|
||||
return true
|
||||
}
|
||||
|
||||
// AddGraphEdgesTo returns an EdgeFunc that will add the selected edges to the passed
|
||||
// graph.
|
||||
func AddGraphEdgesTo(g Interface) EdgeFunc {
|
||||
return func(_ Interface, from, to graph.Node, edgeKinds sets.String) bool {
|
||||
for edgeKind := range edgeKinds {
|
||||
g.AddEdge(from, to, edgeKind)
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
type uniqueNamedGraph struct {
|
||||
graph.Mutable
|
||||
names map[UniqueName]graph.Node
|
||||
}
|
||||
|
||||
func newUniqueNamedGraph(g graph.Mutable) uniqueNamedGraph {
|
||||
return uniqueNamedGraph{
|
||||
Mutable: g,
|
||||
names: make(map[UniqueName]graph.Node),
|
||||
}
|
||||
}
|
||||
|
||||
func (g uniqueNamedGraph) FindOrCreate(name UniqueName, fn NodeInitializerFunc) (graph.Node, bool) {
|
||||
if node, ok := g.names[name]; ok {
|
||||
return node, true
|
||||
}
|
||||
id := g.NewNodeID()
|
||||
node := fn(Node{concrete.Node(id), name})
|
||||
g.names[name] = node
|
||||
g.AddNode(node)
|
||||
return node, false
|
||||
}
|
||||
|
||||
func (g uniqueNamedGraph) Find(name UniqueName) graph.Node {
|
||||
if node, ok := g.names[name]; ok {
|
||||
return node
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type typedGraph struct{}
|
||||
|
||||
func (g typedGraph) Name(node graph.Node) string {
|
||||
switch t := node.(type) {
|
||||
case fmt.Stringer:
|
||||
return t.String()
|
||||
case uniqueNamer:
|
||||
return t.UniqueName().String()
|
||||
default:
|
||||
return fmt.Sprintf("<unknown:%d>", node.ID())
|
||||
}
|
||||
}
|
||||
|
||||
type objectifier interface {
|
||||
Object() interface{}
|
||||
}
|
||||
|
||||
func (g typedGraph) Object(node graph.Node) interface{} {
|
||||
switch t := node.(type) {
|
||||
case objectifier:
|
||||
return t.Object()
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
type kind interface {
|
||||
Kind() string
|
||||
}
|
||||
|
||||
func (g typedGraph) Kind(node graph.Node) string {
|
||||
if k, ok := node.(kind); ok {
|
||||
return k.Kind()
|
||||
}
|
||||
return UnknownNodeKind
|
||||
}
|
||||
|
||||
func (g typedGraph) EdgeKinds(edge graph.Edge) sets.String {
|
||||
var e Edge
|
||||
switch t := edge.(type) {
|
||||
case concrete.WeightedEdge:
|
||||
e = t.Edge.(Edge)
|
||||
case Edge:
|
||||
e = t
|
||||
default:
|
||||
return sets.NewString(UnknownEdgeKind)
|
||||
}
|
||||
return e.Kinds()
|
||||
}
|
||||
|
||||
type NodeSet map[int]struct{}
|
||||
|
||||
func (n NodeSet) Has(id int) bool {
|
||||
_, ok := n[id]
|
||||
return ok
|
||||
}
|
||||
|
||||
func (n NodeSet) Add(id int) {
|
||||
n[id] = struct{}{}
|
||||
}
|
||||
|
||||
func NodesByKind(g Interface, nodes []graph.Node, kinds ...string) [][]graph.Node {
|
||||
buckets := make(map[string]int)
|
||||
for i, kind := range kinds {
|
||||
buckets[kind] = i
|
||||
}
|
||||
if nodes == nil {
|
||||
nodes = g.Nodes()
|
||||
}
|
||||
|
||||
last := len(kinds)
|
||||
result := make([][]graph.Node, last+1)
|
||||
for _, node := range nodes {
|
||||
if bucket, ok := buckets[g.Kind(node)]; ok {
|
||||
result[bucket] = append(result[bucket], node)
|
||||
} else {
|
||||
result[last] = append(result[last], node)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// IsFromDifferentNamespace returns if a node is in a different namespace
|
||||
// than the one provided.
|
||||
func IsFromDifferentNamespace(namespace string, node graph.Node) bool {
|
||||
potentiallySyntheticNode, ok := node.(ExistenceChecker)
|
||||
if !ok || potentiallySyntheticNode.Found() {
|
||||
return false
|
||||
}
|
||||
objectified, ok := node.(objectifier)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
object, err := meta.Accessor(objectified)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return object.GetNamespace() != namespace
|
||||
}
|
||||
|
||||
func pathCovered(path []graph.Node, paths map[int][]graph.Node) bool {
|
||||
l := len(path)
|
||||
for _, existing := range paths {
|
||||
if l >= len(existing) {
|
||||
continue
|
||||
}
|
||||
if pathEqual(path, existing) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func pathEqual(a, b []graph.Node) bool {
|
||||
for i := range a {
|
||||
if a[i] != b[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
package graphview
|
||||
|
||||
import (
|
||||
"sort"
|
||||
|
||||
osgraph "github.com/openshift/origin/pkg/api/graph"
|
||||
kubegraph "github.com/openshift/origin/pkg/api/kubegraph/nodes"
|
||||
deployedges "github.com/openshift/origin/pkg/deploy/graph"
|
||||
deploygraph "github.com/openshift/origin/pkg/deploy/graph/nodes"
|
||||
)
|
||||
|
||||
type DeploymentConfigPipeline struct {
|
||||
Deployment *deploygraph.DeploymentConfigNode
|
||||
|
||||
ActiveDeployment *kubegraph.ReplicationControllerNode
|
||||
InactiveDeployments []*kubegraph.ReplicationControllerNode
|
||||
|
||||
Images []ImagePipeline
|
||||
}
|
||||
|
||||
// AllDeploymentConfigPipelines returns all the DCPipelines that aren't in the excludes set and the set of covered NodeIDs
|
||||
func AllDeploymentConfigPipelines(g osgraph.Graph, excludeNodeIDs IntSet) ([]DeploymentConfigPipeline, IntSet) {
|
||||
covered := IntSet{}
|
||||
dcPipelines := []DeploymentConfigPipeline{}
|
||||
|
||||
for _, uncastNode := range g.NodesByKind(deploygraph.DeploymentConfigNodeKind) {
|
||||
if excludeNodeIDs.Has(uncastNode.ID()) {
|
||||
continue
|
||||
}
|
||||
|
||||
pipeline, covers := NewDeploymentConfigPipeline(g, uncastNode.(*deploygraph.DeploymentConfigNode))
|
||||
covered.Insert(covers.List()...)
|
||||
dcPipelines = append(dcPipelines, pipeline)
|
||||
}
|
||||
|
||||
sort.Sort(SortedDeploymentConfigPipeline(dcPipelines))
|
||||
return dcPipelines, covered
|
||||
}
|
||||
|
||||
// NewDeploymentConfigPipeline returns the DeploymentConfigPipeline and a set of all the NodeIDs covered by the DeploymentConfigPipeline
|
||||
func NewDeploymentConfigPipeline(g osgraph.Graph, dcNode *deploygraph.DeploymentConfigNode) (DeploymentConfigPipeline, IntSet) {
|
||||
covered := IntSet{}
|
||||
covered.Insert(dcNode.ID())
|
||||
|
||||
dcPipeline := DeploymentConfigPipeline{}
|
||||
dcPipeline.Deployment = dcNode
|
||||
|
||||
// for everything that can trigger a deployment, create an image pipeline and add it to the list
|
||||
for _, istNode := range g.PredecessorNodesByEdgeKind(dcNode, deployedges.TriggersDeploymentEdgeKind) {
|
||||
imagePipeline, covers := NewImagePipelineFromImageTagLocation(g, istNode, istNode.(ImageTagLocation))
|
||||
|
||||
covered.Insert(covers.List()...)
|
||||
dcPipeline.Images = append(dcPipeline.Images, imagePipeline)
|
||||
}
|
||||
|
||||
// for image that we use, create an image pipeline and add it to the list
|
||||
for _, tagNode := range g.PredecessorNodesByEdgeKind(dcNode, deployedges.UsedInDeploymentEdgeKind) {
|
||||
imagePipeline, covers := NewImagePipelineFromImageTagLocation(g, tagNode, tagNode.(ImageTagLocation))
|
||||
|
||||
covered.Insert(covers.List()...)
|
||||
dcPipeline.Images = append(dcPipeline.Images, imagePipeline)
|
||||
}
|
||||
|
||||
dcPipeline.ActiveDeployment, dcPipeline.InactiveDeployments = deployedges.RelevantDeployments(g, dcNode)
|
||||
for _, rc := range dcPipeline.InactiveDeployments {
|
||||
_, covers := NewReplicationController(g, rc)
|
||||
covered.Insert(covers.List()...)
|
||||
}
|
||||
|
||||
if dcPipeline.ActiveDeployment != nil {
|
||||
_, covers := NewReplicationController(g, dcPipeline.ActiveDeployment)
|
||||
covered.Insert(covers.List()...)
|
||||
}
|
||||
|
||||
return dcPipeline, covered
|
||||
}
|
||||
|
||||
type SortedDeploymentConfigPipeline []DeploymentConfigPipeline
|
||||
|
||||
func (m SortedDeploymentConfigPipeline) Len() int { return len(m) }
|
||||
func (m SortedDeploymentConfigPipeline) Swap(i, j int) { m[i], m[j] = m[j], m[i] }
|
||||
func (m SortedDeploymentConfigPipeline) Less(i, j int) bool {
|
||||
return CompareObjectMeta(&m[i].Deployment.DeploymentConfig.ObjectMeta, &m[j].Deployment.DeploymentConfig.ObjectMeta)
|
||||
}
|
||||
+240
@@ -0,0 +1,240 @@
|
||||
package graphview
|
||||
|
||||
import (
|
||||
"sort"
|
||||
|
||||
"github.com/gonum/graph"
|
||||
|
||||
osgraph "github.com/openshift/origin/pkg/api/graph"
|
||||
buildedges "github.com/openshift/origin/pkg/build/graph"
|
||||
buildgraph "github.com/openshift/origin/pkg/build/graph/nodes"
|
||||
imageedges "github.com/openshift/origin/pkg/image/graph"
|
||||
imagegraph "github.com/openshift/origin/pkg/image/graph/nodes"
|
||||
)
|
||||
|
||||
// ImagePipeline represents a build, its output, and any inputs. The input
|
||||
// to a build may be another ImagePipeline.
|
||||
type ImagePipeline struct {
|
||||
Image ImageTagLocation
|
||||
DestinationResolved bool
|
||||
ScheduledImport bool
|
||||
|
||||
Build *buildgraph.BuildConfigNode
|
||||
|
||||
LastSuccessfulBuild *buildgraph.BuildNode
|
||||
LastUnsuccessfulBuild *buildgraph.BuildNode
|
||||
ActiveBuilds []*buildgraph.BuildNode
|
||||
|
||||
// If set, the base image used by the build
|
||||
BaseImage ImageTagLocation
|
||||
// if set, the build config names that produces the base image
|
||||
BaseBuilds []string
|
||||
// If set, the source repository that inputs to the build
|
||||
Source SourceLocation
|
||||
}
|
||||
|
||||
// ImageTagLocation identifies the source or destination of an image. Represents
|
||||
// both a tag in a Docker image repository, as well as a tag in an OpenShift image stream.
|
||||
type ImageTagLocation interface {
|
||||
ID() int
|
||||
ImageSpec() string
|
||||
ImageTag() string
|
||||
}
|
||||
|
||||
// SourceLocation identifies a repository that is an input to a build.
|
||||
type SourceLocation interface {
|
||||
ID() int
|
||||
}
|
||||
|
||||
func AllImagePipelinesFromBuildConfig(g osgraph.Graph, excludeNodeIDs IntSet) ([]ImagePipeline, IntSet) {
|
||||
covered := IntSet{}
|
||||
pipelines := []ImagePipeline{}
|
||||
|
||||
for _, uncastNode := range g.NodesByKind(buildgraph.BuildConfigNodeKind) {
|
||||
if excludeNodeIDs.Has(uncastNode.ID()) {
|
||||
continue
|
||||
}
|
||||
|
||||
pipeline, covers := NewImagePipelineFromBuildConfigNode(g, uncastNode.(*buildgraph.BuildConfigNode))
|
||||
covered.Insert(covers.List()...)
|
||||
pipelines = append(pipelines, pipeline)
|
||||
}
|
||||
|
||||
sort.Sort(SortedImagePipelines(pipelines))
|
||||
|
||||
outputImageToBCMap := make(map[string][]string)
|
||||
for _, pipeline := range pipelines {
|
||||
// note, bc does not have to have an output image
|
||||
if pipeline.Image != nil {
|
||||
bcs, ok := outputImageToBCMap[pipeline.Image.ImageSpec()]
|
||||
if !ok {
|
||||
bcs = []string{}
|
||||
}
|
||||
bcs = append(bcs, pipeline.Build.BuildConfig.Name)
|
||||
outputImageToBCMap[pipeline.Image.ImageSpec()] = bcs
|
||||
}
|
||||
}
|
||||
|
||||
if len(outputImageToBCMap) > 0 {
|
||||
for i, pipeline := range pipelines {
|
||||
// note, bc does not have to have an input strategy image
|
||||
if pipeline.BaseImage != nil {
|
||||
baseBCs, ok := outputImageToBCMap[pipeline.BaseImage.ImageSpec()]
|
||||
if ok && len(baseBCs) > 0 {
|
||||
pipelines[i].BaseBuilds = baseBCs
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return pipelines, covered
|
||||
}
|
||||
|
||||
// NewImagePipeline attempts to locate a build flow from the provided node. If no such
|
||||
// build flow can be located, false is returned.
|
||||
func NewImagePipelineFromBuildConfigNode(g osgraph.Graph, bcNode *buildgraph.BuildConfigNode) (ImagePipeline, IntSet) {
|
||||
covered := IntSet{}
|
||||
covered.Insert(bcNode.ID())
|
||||
|
||||
flow := ImagePipeline{}
|
||||
|
||||
base, src, coveredInputs, scheduled, _ := findBuildInputs(g, bcNode)
|
||||
covered.Insert(coveredInputs.List()...)
|
||||
flow.BaseImage = base
|
||||
flow.Source = src
|
||||
flow.Build = bcNode
|
||||
flow.ScheduledImport = scheduled
|
||||
flow.LastSuccessfulBuild, flow.LastUnsuccessfulBuild, flow.ActiveBuilds = buildedges.RelevantBuilds(g, flow.Build)
|
||||
flow.Image = findBuildOutput(g, bcNode)
|
||||
|
||||
// we should have at most one
|
||||
for _, buildOutputNode := range g.SuccessorNodesByEdgeKind(bcNode, buildedges.BuildOutputEdgeKind) {
|
||||
// this will handle the imagestream tag case
|
||||
for _, input := range g.SuccessorNodesByEdgeKind(buildOutputNode, imageedges.ReferencedImageStreamGraphEdgeKind) {
|
||||
imageStreamNode := input.(*imagegraph.ImageStreamNode)
|
||||
|
||||
flow.DestinationResolved = (len(imageStreamNode.Status.DockerImageRepository) != 0)
|
||||
}
|
||||
// this will handle the imagestream image case
|
||||
for _, input := range g.SuccessorNodesByEdgeKind(buildOutputNode, imageedges.ReferencedImageStreamImageGraphEdgeKind) {
|
||||
imageStreamNode := input.(*imagegraph.ImageStreamNode)
|
||||
|
||||
flow.DestinationResolved = (len(imageStreamNode.Status.DockerImageRepository) != 0)
|
||||
}
|
||||
|
||||
// TODO handle the DockerImage case
|
||||
}
|
||||
|
||||
return flow, covered
|
||||
}
|
||||
|
||||
// NewImagePipelineFromImageTagLocation returns the ImagePipeline and all the nodes contributing to it
|
||||
func NewImagePipelineFromImageTagLocation(g osgraph.Graph, node graph.Node, imageTagLocation ImageTagLocation) (ImagePipeline, IntSet) {
|
||||
covered := IntSet{}
|
||||
covered.Insert(node.ID())
|
||||
|
||||
flow := ImagePipeline{}
|
||||
flow.Image = imageTagLocation
|
||||
|
||||
for _, input := range g.PredecessorNodesByEdgeKind(node, buildedges.BuildOutputEdgeKind) {
|
||||
covered.Insert(input.ID())
|
||||
build := input.(*buildgraph.BuildConfigNode)
|
||||
if flow.Build != nil {
|
||||
// report this as an error (unexpected duplicate input build)
|
||||
}
|
||||
if build.BuildConfig == nil {
|
||||
// report this as as a missing build / broken link
|
||||
break
|
||||
}
|
||||
|
||||
base, src, coveredInputs, scheduled, _ := findBuildInputs(g, build)
|
||||
covered.Insert(coveredInputs.List()...)
|
||||
flow.BaseImage = base
|
||||
flow.Source = src
|
||||
flow.Build = build
|
||||
flow.ScheduledImport = scheduled
|
||||
flow.LastSuccessfulBuild, flow.LastUnsuccessfulBuild, flow.ActiveBuilds = buildedges.RelevantBuilds(g, flow.Build)
|
||||
}
|
||||
|
||||
for _, input := range g.SuccessorNodesByEdgeKind(node, imageedges.ReferencedImageStreamGraphEdgeKind) {
|
||||
covered.Insert(input.ID())
|
||||
imageStreamNode := input.(*imagegraph.ImageStreamNode)
|
||||
|
||||
flow.DestinationResolved = (len(imageStreamNode.Status.DockerImageRepository) != 0)
|
||||
}
|
||||
for _, input := range g.SuccessorNodesByEdgeKind(node, imageedges.ReferencedImageStreamImageGraphEdgeKind) {
|
||||
covered.Insert(input.ID())
|
||||
imageStreamNode := input.(*imagegraph.ImageStreamNode)
|
||||
|
||||
flow.DestinationResolved = (len(imageStreamNode.Status.DockerImageRepository) != 0)
|
||||
}
|
||||
|
||||
return flow, covered
|
||||
}
|
||||
|
||||
func findBuildInputs(g osgraph.Graph, bcNode *buildgraph.BuildConfigNode) (base ImageTagLocation, source SourceLocation, covered IntSet, scheduled bool, err error) {
|
||||
covered = IntSet{}
|
||||
|
||||
// find inputs to the build
|
||||
for _, input := range g.PredecessorNodesByEdgeKind(bcNode, buildedges.BuildInputEdgeKind) {
|
||||
if source != nil {
|
||||
// report this as an error (unexpected duplicate source)
|
||||
}
|
||||
covered.Insert(input.ID())
|
||||
source = input.(SourceLocation)
|
||||
}
|
||||
for _, input := range g.PredecessorNodesByEdgeKind(bcNode, buildedges.BuildInputImageEdgeKind) {
|
||||
if base != nil {
|
||||
// report this as an error (unexpected duplicate input build)
|
||||
}
|
||||
covered.Insert(input.ID())
|
||||
base = input.(ImageTagLocation)
|
||||
scheduled = imageStreamTagScheduled(g, input, base)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func findBuildOutput(g osgraph.Graph, bcNode *buildgraph.BuildConfigNode) (result ImageTagLocation) {
|
||||
for _, output := range g.SuccessorNodesByEdgeKind(bcNode, buildedges.BuildOutputEdgeKind) {
|
||||
result = output.(ImageTagLocation)
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func imageStreamTagScheduled(g osgraph.Graph, input graph.Node, base ImageTagLocation) (scheduled bool) {
|
||||
for _, uncastImageStreamNode := range g.SuccessorNodesByEdgeKind(input, imageedges.ReferencedImageStreamGraphEdgeKind) {
|
||||
imageStreamNode := uncastImageStreamNode.(*imagegraph.ImageStreamNode)
|
||||
if imageStreamNode.ImageStream != nil {
|
||||
if tag, ok := imageStreamNode.ImageStream.Spec.Tags[base.ImageTag()]; ok {
|
||||
scheduled = tag.ImportPolicy.Scheduled
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
type SortedImagePipelines []ImagePipeline
|
||||
|
||||
func (m SortedImagePipelines) Len() int { return len(m) }
|
||||
func (m SortedImagePipelines) Swap(i, j int) { m[i], m[j] = m[j], m[i] }
|
||||
func (m SortedImagePipelines) Less(i, j int) bool {
|
||||
return CompareImagePipeline(&m[i], &m[j])
|
||||
}
|
||||
|
||||
func CompareImagePipeline(a, b *ImagePipeline) bool {
|
||||
switch {
|
||||
case a.Build != nil && b.Build != nil && a.Build.BuildConfig != nil && b.Build.BuildConfig != nil:
|
||||
return CompareObjectMeta(&a.Build.BuildConfig.ObjectMeta, &b.Build.BuildConfig.ObjectMeta)
|
||||
case a.Build != nil && a.Build.BuildConfig != nil:
|
||||
return true
|
||||
case b.Build != nil && b.Build.BuildConfig != nil:
|
||||
return false
|
||||
}
|
||||
if a.Image == nil || b.Image == nil {
|
||||
return true
|
||||
}
|
||||
return a.Image.ImageSpec() < b.Image.ImageSpec()
|
||||
}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
package graphview
|
||||
|
||||
import (
|
||||
"sort"
|
||||
|
||||
"k8s.io/kubernetes/pkg/util/sets"
|
||||
)
|
||||
|
||||
type IntSet map[int]sets.Empty
|
||||
|
||||
// NewIntSet creates a IntSet from a list of values.
|
||||
func NewIntSet(items ...int) IntSet {
|
||||
ss := IntSet{}
|
||||
ss.Insert(items...)
|
||||
return ss
|
||||
}
|
||||
|
||||
// Insert adds items to the set.
|
||||
func (s IntSet) Insert(items ...int) {
|
||||
for _, item := range items {
|
||||
s[item] = sets.Empty{}
|
||||
}
|
||||
}
|
||||
|
||||
// Delete removes all items from the set.
|
||||
func (s IntSet) Delete(items ...int) {
|
||||
for _, item := range items {
|
||||
delete(s, item)
|
||||
}
|
||||
}
|
||||
|
||||
// Has returns true iff item is contained in the set.
|
||||
func (s IntSet) Has(item int) bool {
|
||||
_, contained := s[item]
|
||||
return contained
|
||||
}
|
||||
|
||||
// List returns the contents as a sorted string slice.
|
||||
func (s IntSet) List() []int {
|
||||
res := make([]int, 0, len(s))
|
||||
for key := range s {
|
||||
res = append(res, key)
|
||||
}
|
||||
sort.IntSlice(res).Sort()
|
||||
return res
|
||||
}
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
package graphview
|
||||
|
||||
import (
|
||||
osgraph "github.com/openshift/origin/pkg/api/graph"
|
||||
kubeedges "github.com/openshift/origin/pkg/api/kubegraph"
|
||||
kubegraph "github.com/openshift/origin/pkg/api/kubegraph/nodes"
|
||||
)
|
||||
|
||||
type PetSet struct {
|
||||
PetSet *kubegraph.PetSetNode
|
||||
|
||||
OwnedPods []*kubegraph.PodNode
|
||||
CreatedPods []*kubegraph.PodNode
|
||||
|
||||
// TODO: handle conflicting once controller refs are present, not worth it yet
|
||||
}
|
||||
|
||||
// AllPetSets returns all the PetSets that aren't in the excludes set and the set of covered NodeIDs
|
||||
func AllPetSets(g osgraph.Graph, excludeNodeIDs IntSet) ([]PetSet, IntSet) {
|
||||
covered := IntSet{}
|
||||
views := []PetSet{}
|
||||
|
||||
for _, uncastNode := range g.NodesByKind(kubegraph.PetSetNodeKind) {
|
||||
if excludeNodeIDs.Has(uncastNode.ID()) {
|
||||
continue
|
||||
}
|
||||
|
||||
view, covers := NewPetSet(g, uncastNode.(*kubegraph.PetSetNode))
|
||||
covered.Insert(covers.List()...)
|
||||
views = append(views, view)
|
||||
}
|
||||
|
||||
return views, covered
|
||||
}
|
||||
|
||||
// NewPetSet returns the PetSet and a set of all the NodeIDs covered by the PetSet
|
||||
func NewPetSet(g osgraph.Graph, node *kubegraph.PetSetNode) (PetSet, IntSet) {
|
||||
covered := IntSet{}
|
||||
covered.Insert(node.ID())
|
||||
|
||||
view := PetSet{}
|
||||
view.PetSet = node
|
||||
|
||||
for _, uncastPodNode := range g.PredecessorNodesByEdgeKind(node, kubeedges.ManagedByControllerEdgeKind) {
|
||||
podNode := uncastPodNode.(*kubegraph.PodNode)
|
||||
covered.Insert(podNode.ID())
|
||||
view.OwnedPods = append(view.OwnedPods, podNode)
|
||||
}
|
||||
|
||||
return view, covered
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
package graphview
|
||||
|
||||
import (
|
||||
osgraph "github.com/openshift/origin/pkg/api/graph"
|
||||
kubegraph "github.com/openshift/origin/pkg/api/kubegraph/nodes"
|
||||
)
|
||||
|
||||
type Pod struct {
|
||||
Pod *kubegraph.PodNode
|
||||
}
|
||||
|
||||
// AllPods returns all Pods and the set of covered NodeIDs
|
||||
func AllPods(g osgraph.Graph, excludeNodeIDs IntSet) ([]Pod, IntSet) {
|
||||
covered := IntSet{}
|
||||
pods := []Pod{}
|
||||
|
||||
for _, uncastNode := range g.NodesByKind(kubegraph.PodNodeKind) {
|
||||
if excludeNodeIDs.Has(uncastNode.ID()) {
|
||||
continue
|
||||
}
|
||||
|
||||
pod, covers := NewPod(g, uncastNode.(*kubegraph.PodNode))
|
||||
covered.Insert(covers.List()...)
|
||||
pods = append(pods, pod)
|
||||
}
|
||||
|
||||
return pods, covered
|
||||
}
|
||||
|
||||
// NewPod returns the Pod and a set of all the NodeIDs covered by the Pod
|
||||
func NewPod(g osgraph.Graph, podNode *kubegraph.PodNode) (Pod, IntSet) {
|
||||
covered := IntSet{}
|
||||
covered.Insert(podNode.ID())
|
||||
|
||||
podView := Pod{}
|
||||
podView.Pod = podNode
|
||||
|
||||
return podView, covered
|
||||
}
|
||||
+100
@@ -0,0 +1,100 @@
|
||||
package graphview
|
||||
|
||||
import (
|
||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||
|
||||
osgraph "github.com/openshift/origin/pkg/api/graph"
|
||||
kubeedges "github.com/openshift/origin/pkg/api/kubegraph"
|
||||
"github.com/openshift/origin/pkg/api/kubegraph/analysis"
|
||||
kubegraph "github.com/openshift/origin/pkg/api/kubegraph/nodes"
|
||||
)
|
||||
|
||||
type ReplicationController struct {
|
||||
RC *kubegraph.ReplicationControllerNode
|
||||
|
||||
OwnedPods []*kubegraph.PodNode
|
||||
CreatedPods []*kubegraph.PodNode
|
||||
|
||||
ConflictingRCs []*kubegraph.ReplicationControllerNode
|
||||
ConflictingRCIDToPods map[int][]*kubegraph.PodNode
|
||||
}
|
||||
|
||||
// AllReplicationControllers returns all the ReplicationControllers that aren't in the excludes set and the set of covered NodeIDs
|
||||
func AllReplicationControllers(g osgraph.Graph, excludeNodeIDs IntSet) ([]ReplicationController, IntSet) {
|
||||
covered := IntSet{}
|
||||
rcViews := []ReplicationController{}
|
||||
|
||||
for _, uncastNode := range g.NodesByKind(kubegraph.ReplicationControllerNodeKind) {
|
||||
if excludeNodeIDs.Has(uncastNode.ID()) {
|
||||
continue
|
||||
}
|
||||
|
||||
rcView, covers := NewReplicationController(g, uncastNode.(*kubegraph.ReplicationControllerNode))
|
||||
covered.Insert(covers.List()...)
|
||||
rcViews = append(rcViews, rcView)
|
||||
}
|
||||
|
||||
return rcViews, covered
|
||||
}
|
||||
|
||||
// MaxRecentContainerRestarts returns the maximum container restarts for all pods in
|
||||
// replication controller.
|
||||
func (rc *ReplicationController) MaxRecentContainerRestarts() int32 {
|
||||
var maxRestarts int32
|
||||
for _, pod := range rc.OwnedPods {
|
||||
for _, status := range pod.Status.ContainerStatuses {
|
||||
if status.RestartCount > maxRestarts && analysis.ContainerRestartedRecently(status, unversioned.Now()) {
|
||||
maxRestarts = status.RestartCount
|
||||
}
|
||||
}
|
||||
}
|
||||
return maxRestarts
|
||||
}
|
||||
|
||||
// NewReplicationController returns the ReplicationController and a set of all the NodeIDs covered by the ReplicationController
|
||||
func NewReplicationController(g osgraph.Graph, rcNode *kubegraph.ReplicationControllerNode) (ReplicationController, IntSet) {
|
||||
covered := IntSet{}
|
||||
covered.Insert(rcNode.ID())
|
||||
|
||||
rcView := ReplicationController{}
|
||||
rcView.RC = rcNode
|
||||
rcView.ConflictingRCIDToPods = map[int][]*kubegraph.PodNode{}
|
||||
|
||||
for _, uncastPodNode := range g.PredecessorNodesByEdgeKind(rcNode, kubeedges.ManagedByControllerEdgeKind) {
|
||||
podNode := uncastPodNode.(*kubegraph.PodNode)
|
||||
covered.Insert(podNode.ID())
|
||||
rcView.OwnedPods = append(rcView.OwnedPods, podNode)
|
||||
|
||||
// check to see if this pod is managed by more than one RC
|
||||
uncastOwningRCs := g.SuccessorNodesByEdgeKind(podNode, kubeedges.ManagedByControllerEdgeKind)
|
||||
if len(uncastOwningRCs) > 1 {
|
||||
for _, uncastOwningRC := range uncastOwningRCs {
|
||||
if uncastOwningRC.ID() == rcNode.ID() {
|
||||
continue
|
||||
}
|
||||
|
||||
conflictingRC := uncastOwningRC.(*kubegraph.ReplicationControllerNode)
|
||||
rcView.ConflictingRCs = append(rcView.ConflictingRCs, conflictingRC)
|
||||
|
||||
conflictingPods, ok := rcView.ConflictingRCIDToPods[conflictingRC.ID()]
|
||||
if !ok {
|
||||
conflictingPods = []*kubegraph.PodNode{}
|
||||
}
|
||||
conflictingPods = append(conflictingPods, podNode)
|
||||
rcView.ConflictingRCIDToPods[conflictingRC.ID()] = conflictingPods
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return rcView, covered
|
||||
}
|
||||
|
||||
// MaxRecentContainerRestartsForRC returns the maximum container restarts in pods
|
||||
// in the replication controller node for the last 10 minutes.
|
||||
func MaxRecentContainerRestartsForRC(g osgraph.Graph, rcNode *kubegraph.ReplicationControllerNode) int32 {
|
||||
if rcNode == nil {
|
||||
return 0
|
||||
}
|
||||
rc, _ := NewReplicationController(g, rcNode)
|
||||
return rc.MaxRecentContainerRestarts()
|
||||
}
|
||||
+134
@@ -0,0 +1,134 @@
|
||||
package graphview
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
|
||||
kapi "k8s.io/kubernetes/pkg/api"
|
||||
utilruntime "k8s.io/kubernetes/pkg/util/runtime"
|
||||
|
||||
osgraph "github.com/openshift/origin/pkg/api/graph"
|
||||
kubeedges "github.com/openshift/origin/pkg/api/kubegraph"
|
||||
kubegraph "github.com/openshift/origin/pkg/api/kubegraph/nodes"
|
||||
deploygraph "github.com/openshift/origin/pkg/deploy/graph/nodes"
|
||||
routeedges "github.com/openshift/origin/pkg/route/graph"
|
||||
routegraph "github.com/openshift/origin/pkg/route/graph/nodes"
|
||||
)
|
||||
|
||||
// ServiceGroup is a service, the DeploymentConfigPipelines it covers, and lists of the other nodes that fulfill it
|
||||
type ServiceGroup struct {
|
||||
Service *kubegraph.ServiceNode
|
||||
|
||||
DeploymentConfigPipelines []DeploymentConfigPipeline
|
||||
ReplicationControllers []ReplicationController
|
||||
PetSets []PetSet
|
||||
|
||||
// TODO: this has to stop
|
||||
FulfillingPetSets []*kubegraph.PetSetNode
|
||||
FulfillingDCs []*deploygraph.DeploymentConfigNode
|
||||
FulfillingRCs []*kubegraph.ReplicationControllerNode
|
||||
FulfillingPods []*kubegraph.PodNode
|
||||
|
||||
ExposingRoutes []*routegraph.RouteNode
|
||||
}
|
||||
|
||||
// AllServiceGroups returns all the ServiceGroups that aren't in the excludes set and the set of covered NodeIDs
|
||||
func AllServiceGroups(g osgraph.Graph, excludeNodeIDs IntSet) ([]ServiceGroup, IntSet) {
|
||||
covered := IntSet{}
|
||||
services := []ServiceGroup{}
|
||||
|
||||
for _, uncastNode := range g.NodesByKind(kubegraph.ServiceNodeKind) {
|
||||
if excludeNodeIDs.Has(uncastNode.ID()) {
|
||||
continue
|
||||
}
|
||||
|
||||
service, covers := NewServiceGroup(g, uncastNode.(*kubegraph.ServiceNode))
|
||||
covered.Insert(covers.List()...)
|
||||
services = append(services, service)
|
||||
}
|
||||
|
||||
sort.Sort(ServiceGroupByObjectMeta(services))
|
||||
return services, covered
|
||||
}
|
||||
|
||||
// NewServiceGroup returns the ServiceGroup and a set of all the NodeIDs covered by the service
|
||||
func NewServiceGroup(g osgraph.Graph, serviceNode *kubegraph.ServiceNode) (ServiceGroup, IntSet) {
|
||||
covered := IntSet{}
|
||||
covered.Insert(serviceNode.ID())
|
||||
|
||||
service := ServiceGroup{}
|
||||
service.Service = serviceNode
|
||||
|
||||
for _, uncastServiceFulfiller := range g.PredecessorNodesByEdgeKind(serviceNode, kubeedges.ExposedThroughServiceEdgeKind) {
|
||||
container := osgraph.GetTopLevelContainerNode(g, uncastServiceFulfiller)
|
||||
|
||||
switch castContainer := container.(type) {
|
||||
case *deploygraph.DeploymentConfigNode:
|
||||
service.FulfillingDCs = append(service.FulfillingDCs, castContainer)
|
||||
case *kubegraph.ReplicationControllerNode:
|
||||
service.FulfillingRCs = append(service.FulfillingRCs, castContainer)
|
||||
case *kubegraph.PodNode:
|
||||
service.FulfillingPods = append(service.FulfillingPods, castContainer)
|
||||
case *kubegraph.PetSetNode:
|
||||
service.FulfillingPetSets = append(service.FulfillingPetSets, castContainer)
|
||||
default:
|
||||
utilruntime.HandleError(fmt.Errorf("unrecognized container: %v", castContainer))
|
||||
}
|
||||
}
|
||||
|
||||
for _, uncastServiceFulfiller := range g.PredecessorNodesByEdgeKind(serviceNode, routeedges.ExposedThroughRouteEdgeKind) {
|
||||
container := osgraph.GetTopLevelContainerNode(g, uncastServiceFulfiller)
|
||||
|
||||
switch castContainer := container.(type) {
|
||||
case *routegraph.RouteNode:
|
||||
service.ExposingRoutes = append(service.ExposingRoutes, castContainer)
|
||||
default:
|
||||
utilruntime.HandleError(fmt.Errorf("unrecognized container: %v", castContainer))
|
||||
}
|
||||
}
|
||||
|
||||
// add the DCPipelines for all the DCs that fulfill the service
|
||||
for _, fulfillingDC := range service.FulfillingDCs {
|
||||
dcPipeline, dcCovers := NewDeploymentConfigPipeline(g, fulfillingDC)
|
||||
|
||||
covered.Insert(dcCovers.List()...)
|
||||
service.DeploymentConfigPipelines = append(service.DeploymentConfigPipelines, dcPipeline)
|
||||
}
|
||||
|
||||
for _, fulfillingRC := range service.FulfillingRCs {
|
||||
rcView, rcCovers := NewReplicationController(g, fulfillingRC)
|
||||
|
||||
covered.Insert(rcCovers.List()...)
|
||||
service.ReplicationControllers = append(service.ReplicationControllers, rcView)
|
||||
}
|
||||
|
||||
for _, fulfillingPetSet := range service.FulfillingPetSets {
|
||||
view, covers := NewPetSet(g, fulfillingPetSet)
|
||||
|
||||
covered.Insert(covers.List()...)
|
||||
service.PetSets = append(service.PetSets, view)
|
||||
}
|
||||
|
||||
for _, fulfillingPod := range service.FulfillingPods {
|
||||
_, podCovers := NewPod(g, fulfillingPod)
|
||||
covered.Insert(podCovers.List()...)
|
||||
}
|
||||
|
||||
return service, covered
|
||||
}
|
||||
|
||||
type ServiceGroupByObjectMeta []ServiceGroup
|
||||
|
||||
func (m ServiceGroupByObjectMeta) Len() int { return len(m) }
|
||||
func (m ServiceGroupByObjectMeta) Swap(i, j int) { m[i], m[j] = m[j], m[i] }
|
||||
func (m ServiceGroupByObjectMeta) Less(i, j int) bool {
|
||||
a, b := m[i], m[j]
|
||||
return CompareObjectMeta(&a.Service.Service.ObjectMeta, &b.Service.Service.ObjectMeta)
|
||||
}
|
||||
|
||||
func CompareObjectMeta(a, b *kapi.ObjectMeta) bool {
|
||||
if a.Namespace == b.Namespace {
|
||||
return a.Name < b.Name
|
||||
}
|
||||
return a.Namespace < b.Namespace
|
||||
}
|
||||
+134
@@ -0,0 +1,134 @@
|
||||
package graph
|
||||
|
||||
import (
|
||||
"github.com/gonum/graph"
|
||||
)
|
||||
|
||||
// Marker is a struct that describes something interesting on a Node
|
||||
type Marker struct {
|
||||
// Node is the optional node that this message is attached to
|
||||
Node graph.Node
|
||||
// RelatedNodes is an optional list of other nodes that are involved in this marker.
|
||||
RelatedNodes []graph.Node
|
||||
|
||||
// Severity indicates how important this problem is.
|
||||
Severity Severity
|
||||
// Key is a short string to identify this message
|
||||
Key string
|
||||
|
||||
// Message is a human-readable string that describes what is interesting
|
||||
Message string
|
||||
// Suggestion is a human-readable string that holds advice for resolving this
|
||||
// marker.
|
||||
Suggestion Suggestion
|
||||
}
|
||||
|
||||
// Severity indicates how important this problem is.
|
||||
type Severity string
|
||||
|
||||
const (
|
||||
// InfoSeverity is interesting
|
||||
// TODO: Consider what to do with this once we revisit the graph api - currently not used.
|
||||
InfoSeverity Severity = "info"
|
||||
// WarningSeverity is probably wrong, but we aren't certain
|
||||
WarningSeverity Severity = "warning"
|
||||
// ErrorSeverity is definitely wrong, this won't work
|
||||
ErrorSeverity Severity = "error"
|
||||
)
|
||||
|
||||
type Markers []Marker
|
||||
|
||||
// MarkerScanner is a function for analyzing a graph and finding interesting things in it
|
||||
type MarkerScanner func(g Graph, f Namer) []Marker
|
||||
|
||||
func (m Markers) BySeverity(severity Severity) []Marker {
|
||||
ret := []Marker{}
|
||||
for i := range m {
|
||||
if m[i].Severity == severity {
|
||||
ret = append(ret, m[i])
|
||||
}
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
// FilterByNamespace returns all the markers that are not associated with missing nodes
|
||||
// from other namespaces (other than the provided namespace).
|
||||
func (m Markers) FilterByNamespace(namespace string) Markers {
|
||||
filtered := Markers{}
|
||||
|
||||
for i := range m {
|
||||
markerNodes := []graph.Node{}
|
||||
markerNodes = append(markerNodes, m[i].Node)
|
||||
markerNodes = append(markerNodes, m[i].RelatedNodes...)
|
||||
hasCrossNamespaceLink := false
|
||||
for _, node := range markerNodes {
|
||||
if IsFromDifferentNamespace(namespace, node) {
|
||||
hasCrossNamespaceLink = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !hasCrossNamespaceLink {
|
||||
filtered = append(filtered, m[i])
|
||||
}
|
||||
}
|
||||
|
||||
return filtered
|
||||
}
|
||||
|
||||
type BySeverity []Marker
|
||||
|
||||
func (m BySeverity) Len() int { return len(m) }
|
||||
func (m BySeverity) Swap(i, j int) { m[i], m[j] = m[j], m[i] }
|
||||
func (m BySeverity) Less(i, j int) bool {
|
||||
lhs := m[i]
|
||||
rhs := m[j]
|
||||
|
||||
switch lhs.Severity {
|
||||
case ErrorSeverity:
|
||||
switch rhs.Severity {
|
||||
case ErrorSeverity:
|
||||
return false
|
||||
}
|
||||
case WarningSeverity:
|
||||
switch rhs.Severity {
|
||||
case ErrorSeverity, WarningSeverity:
|
||||
return false
|
||||
}
|
||||
case InfoSeverity:
|
||||
switch rhs.Severity {
|
||||
case ErrorSeverity, WarningSeverity, InfoSeverity:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
type ByNodeID []Marker
|
||||
|
||||
func (m ByNodeID) Len() int { return len(m) }
|
||||
func (m ByNodeID) Swap(i, j int) { m[i], m[j] = m[j], m[i] }
|
||||
func (m ByNodeID) Less(i, j int) bool {
|
||||
if m[i].Node == nil {
|
||||
return true
|
||||
}
|
||||
if m[j].Node == nil {
|
||||
return false
|
||||
}
|
||||
return m[i].Node.ID() < m[j].Node.ID()
|
||||
}
|
||||
|
||||
type ByKey []Marker
|
||||
|
||||
func (m ByKey) Len() int { return len(m) }
|
||||
func (m ByKey) Swap(i, j int) { m[i], m[j] = m[j], m[i] }
|
||||
func (m ByKey) Less(i, j int) bool {
|
||||
return m[i].Key < m[j].Key
|
||||
}
|
||||
|
||||
type Suggestion string
|
||||
|
||||
func (s Suggestion) String() string {
|
||||
return string(s)
|
||||
}
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
package graph
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/gonum/graph"
|
||||
|
||||
kapi "k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/runtime"
|
||||
)
|
||||
|
||||
const (
|
||||
UnknownNodeKind = "UnknownNode"
|
||||
)
|
||||
|
||||
const (
|
||||
UnknownEdgeKind = "UnknownEdge"
|
||||
// ReferencedByEdgeKind is the kind to use if you're building reverse links that don't have a specific edge in the other direction
|
||||
// other uses are discouraged. You should create a kind for your edge
|
||||
ReferencedByEdgeKind = "ReferencedBy"
|
||||
// ContainsEdgeKind is the kind to use if one node's contents logically contain another node's contents. A given node can only have
|
||||
// a single inbound Contais edge. The code does not prevent contains cycles, but that's insane, don't do that.
|
||||
ContainsEdgeKind = "Contains"
|
||||
)
|
||||
|
||||
func GetUniqueRuntimeObjectNodeName(nodeKind string, obj runtime.Object) UniqueName {
|
||||
meta, err := kapi.ObjectMetaFor(obj)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return UniqueName(fmt.Sprintf("%s|%s/%s", nodeKind, meta.Namespace, meta.Name))
|
||||
}
|
||||
|
||||
// GetTopLevelContainerNode traverses the reverse ContainsEdgeKind edges until it finds a node
|
||||
// that does not have an inbound ContainsEdgeKind edge. This could be the node itself
|
||||
func GetTopLevelContainerNode(g Graph, containedNode graph.Node) graph.Node {
|
||||
// my kingdom for a LinkedHashSet
|
||||
visited := map[int]bool{}
|
||||
prevContainingNode := containedNode
|
||||
|
||||
for {
|
||||
visited[prevContainingNode.ID()] = true
|
||||
currContainingNode := GetContainingNode(g, prevContainingNode)
|
||||
|
||||
if currContainingNode == nil {
|
||||
return prevContainingNode
|
||||
}
|
||||
if _, alreadyVisited := visited[currContainingNode.ID()]; alreadyVisited {
|
||||
panic(fmt.Sprintf("contains cycle in %v", visited))
|
||||
}
|
||||
|
||||
prevContainingNode = currContainingNode
|
||||
}
|
||||
}
|
||||
|
||||
// GetContainingNode returns the direct predecessor that is linked to the node by a ContainsEdgeKind. It returns
|
||||
// nil if no container is found.
|
||||
func GetContainingNode(g Graph, containedNode graph.Node) graph.Node {
|
||||
for _, node := range g.To(containedNode) {
|
||||
edge := g.Edge(node, containedNode)
|
||||
|
||||
if g.EdgeKinds(edge).Has(ContainsEdgeKind) {
|
||||
return node
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
+180
@@ -0,0 +1,180 @@
|
||||
package analysis
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"k8s.io/kubernetes/pkg/util/sets"
|
||||
|
||||
graphapi "github.com/gonum/graph"
|
||||
"github.com/gonum/graph/path"
|
||||
|
||||
osgraph "github.com/openshift/origin/pkg/api/graph"
|
||||
"github.com/openshift/origin/pkg/api/kubegraph"
|
||||
kubenodes "github.com/openshift/origin/pkg/api/kubegraph/nodes"
|
||||
deploygraph "github.com/openshift/origin/pkg/deploy/graph"
|
||||
deploynodes "github.com/openshift/origin/pkg/deploy/graph/nodes"
|
||||
)
|
||||
|
||||
const (
|
||||
// HPAMissingScaleRefError denotes an error where a Horizontal Pod Autoscaler does not have a reference to an object to scale
|
||||
HPAMissingScaleRefError = "HPAMissingScaleRef"
|
||||
// HPAMissingCPUTargetError denotes an error where a Horizontal Pod Autoscaler does not have a CPU target to scale by.
|
||||
// Currently, the only supported scale metric is CPU utilization, so without this metric an HPA is useless.
|
||||
HPAMissingCPUTargetError = "HPAMissingCPUTarget"
|
||||
// HPAOverlappingScaleRefWarning denotes a warning where a Horizontal Pod Autoscaler scales an object that is scaled by some other object as well
|
||||
HPAOverlappingScaleRefWarning = "HPAOverlappingScaleRef"
|
||||
)
|
||||
|
||||
// FindHPASpecsMissingCPUTargets scans the graph in search of HorizontalPodAutoscalers that are missing a CPU utilization target.
|
||||
// As of right now, the only metric that HPAs can use to scale pods is the CPU utilization, so if a HPA is missing this target it
|
||||
// is effectively useless.
|
||||
func FindHPASpecsMissingCPUTargets(graph osgraph.Graph, namer osgraph.Namer) []osgraph.Marker {
|
||||
markers := []osgraph.Marker{}
|
||||
|
||||
for _, uncastNode := range graph.NodesByKind(kubenodes.HorizontalPodAutoscalerNodeKind) {
|
||||
node := uncastNode.(*kubenodes.HorizontalPodAutoscalerNode)
|
||||
|
||||
if node.HorizontalPodAutoscaler.Spec.TargetCPUUtilizationPercentage == nil {
|
||||
markers = append(markers, osgraph.Marker{
|
||||
Node: node,
|
||||
Severity: osgraph.ErrorSeverity,
|
||||
Key: HPAMissingCPUTargetError,
|
||||
Message: fmt.Sprintf("%s is missing a CPU utilization target", namer.ResourceName(node)),
|
||||
Suggestion: osgraph.Suggestion(fmt.Sprintf(`oc patch %s -p '{"spec":{"targetCPUUtilizationPercentage": 80}}'`, namer.ResourceName(node))),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return markers
|
||||
}
|
||||
|
||||
// FindHPASpecsMissingScaleRefs finds all Horizontal Pod Autoscalers whose scale reference points to an object that doesn't exist
|
||||
// or that the client does not have the permission to see.
|
||||
func FindHPASpecsMissingScaleRefs(graph osgraph.Graph, namer osgraph.Namer) []osgraph.Marker {
|
||||
markers := []osgraph.Marker{}
|
||||
|
||||
for _, uncastNode := range graph.NodesByKind(kubenodes.HorizontalPodAutoscalerNodeKind) {
|
||||
node := uncastNode.(*kubenodes.HorizontalPodAutoscalerNode)
|
||||
|
||||
scaledObjects := graph.SuccessorNodesByEdgeKind(
|
||||
uncastNode,
|
||||
kubegraph.ScalingEdgeKind,
|
||||
)
|
||||
|
||||
if len(scaledObjects) < 1 {
|
||||
markers = append(markers, createMissingScaleRefMarker(node, nil, namer))
|
||||
continue
|
||||
}
|
||||
|
||||
for _, scaleRef := range scaledObjects {
|
||||
if existenceChecker, ok := scaleRef.(osgraph.ExistenceChecker); ok && !existenceChecker.Found() {
|
||||
// if this node is synthetic, we can't be sure that the HPA is scaling something that actually exists
|
||||
markers = append(markers, createMissingScaleRefMarker(node, scaleRef, namer))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return markers
|
||||
}
|
||||
|
||||
func createMissingScaleRefMarker(hpaNode *kubenodes.HorizontalPodAutoscalerNode, scaleRef graphapi.Node, namer osgraph.Namer) osgraph.Marker {
|
||||
return osgraph.Marker{
|
||||
Node: hpaNode,
|
||||
Severity: osgraph.ErrorSeverity,
|
||||
RelatedNodes: []graphapi.Node{scaleRef},
|
||||
Key: HPAMissingScaleRefError,
|
||||
Message: fmt.Sprintf("%s is attempting to scale %s/%s, which doesn't exist",
|
||||
namer.ResourceName(hpaNode),
|
||||
hpaNode.HorizontalPodAutoscaler.Spec.ScaleTargetRef.Kind,
|
||||
hpaNode.HorizontalPodAutoscaler.Spec.ScaleTargetRef.Name,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
// FindOverlappingHPAs scans the graph in search of HorizontalPodAutoscalers that are attempting to scale the same set of pods.
|
||||
// This can occur in two ways:
|
||||
// - 1. label selectors for two ReplicationControllers/DeploymentConfigs/etc overlap
|
||||
// - 2. multiple HorizontalPodAutoscalers are attempting to scale the same ReplicationController/DeploymentConfig/etc
|
||||
// Case 1 is handled by deconflicting the area of influence of ReplicationControllers/DeploymentConfigs/etc, and therefore we
|
||||
// can assume that it will be handled before this step. Therefore, we are only concerned with finding HPAs that are trying to
|
||||
// scale the same resources.
|
||||
//
|
||||
// The algorithm that is used to implement this check is described as follows:
|
||||
// - create a sub-graph containing only HPA nodes and other nodes that can be scaled, as well as any scaling edges or other
|
||||
// edges used to connect between objects that can be scaled
|
||||
// - for every resulting edge in the new sub-graph, create an edge in the reverse direction
|
||||
// - find the shortest paths between all HPA nodes in the graph
|
||||
// - shortest paths connecting two horizontal pod autoscalers are used to create markers for the graph
|
||||
func FindOverlappingHPAs(graph osgraph.Graph, namer osgraph.Namer) []osgraph.Marker {
|
||||
markers := []osgraph.Marker{}
|
||||
|
||||
nodeFilter := osgraph.NodesOfKind(
|
||||
kubenodes.HorizontalPodAutoscalerNodeKind,
|
||||
kubenodes.ReplicationControllerNodeKind,
|
||||
deploynodes.DeploymentConfigNodeKind,
|
||||
)
|
||||
edgeFilter := osgraph.EdgesOfKind(
|
||||
kubegraph.ScalingEdgeKind,
|
||||
deploygraph.DeploymentEdgeKind,
|
||||
)
|
||||
|
||||
hpaSubGraph := graph.Subgraph(nodeFilter, edgeFilter)
|
||||
for _, edge := range hpaSubGraph.Edges() {
|
||||
osgraph.AddReversedEdge(hpaSubGraph, edge.From(), edge.To(), sets.NewString())
|
||||
}
|
||||
|
||||
hpaNodes := hpaSubGraph.NodesByKind(kubenodes.HorizontalPodAutoscalerNodeKind)
|
||||
|
||||
for _, firstHPA := range hpaNodes {
|
||||
// we can use Dijkstra's algorithm as we know we do not have any negative edge weights
|
||||
shortestPaths := path.DijkstraFrom(firstHPA, hpaSubGraph)
|
||||
|
||||
for _, secondHPA := range hpaNodes {
|
||||
if firstHPA == secondHPA {
|
||||
continue
|
||||
}
|
||||
|
||||
shortestPath, _ := shortestPaths.To(secondHPA)
|
||||
|
||||
if shortestPath == nil {
|
||||
// if two HPAs have no path between them, no error exists
|
||||
continue
|
||||
}
|
||||
|
||||
markers = append(markers, osgraph.Marker{
|
||||
Node: firstHPA,
|
||||
Severity: osgraph.WarningSeverity,
|
||||
RelatedNodes: shortestPath[1:],
|
||||
Key: HPAOverlappingScaleRefWarning,
|
||||
Message: fmt.Sprintf("%s and %s overlap because they both attempt to scale %s",
|
||||
namer.ResourceName(firstHPA), namer.ResourceName(secondHPA), nameList(shortestPath[1:len(shortestPath)-1], namer)),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return markers
|
||||
}
|
||||
|
||||
// nameList outputs a nicely-formatted list of names:
|
||||
// - given nodes ['a', 'b', 'c'], this will return "one of a, b, or c"
|
||||
// - given nodes ['a', 'b'], this will return "a or b"
|
||||
// - given nodes ['a'], this will return "a"
|
||||
func nameList(nodes []graphapi.Node, namer osgraph.Namer) string {
|
||||
names := []string{}
|
||||
|
||||
for _, node := range nodes {
|
||||
names = append(names, namer.ResourceName(node))
|
||||
}
|
||||
|
||||
switch len(names) {
|
||||
case 0:
|
||||
return ""
|
||||
case 1:
|
||||
return names[0]
|
||||
case 2:
|
||||
return names[0] + " or " + names[1]
|
||||
default:
|
||||
return "one of " + strings.Join(names[:len(names)-1], ", ") + ", or " + names[len(names)-1]
|
||||
}
|
||||
}
|
||||
+135
@@ -0,0 +1,135 @@
|
||||
package analysis
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/MakeNowJust/heredoc"
|
||||
|
||||
kapi "k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||
|
||||
osgraph "github.com/openshift/origin/pkg/api/graph"
|
||||
kubegraph "github.com/openshift/origin/pkg/api/kubegraph/nodes"
|
||||
)
|
||||
|
||||
const (
|
||||
CrashLoopingPodError = "CrashLoopingPod"
|
||||
RestartingPodWarning = "RestartingPod"
|
||||
|
||||
RestartThreshold = 5
|
||||
// TODO: if you change this, you must change the messages below.
|
||||
RestartRecentDuration = 10 * time.Minute
|
||||
)
|
||||
|
||||
// exposed for testing
|
||||
var nowFn = unversioned.Now
|
||||
|
||||
// FindRestartingPods inspects all Pods to see if they've restarted more than the threshold. logsCommandName is the name of
|
||||
// the command that should be invoked to see pod logs. securityPolicyCommandPattern is a format string accepting two replacement
|
||||
// variables for fmt.Sprintf - 1, the namespace of the current pod, 2 the service account of the pod.
|
||||
func FindRestartingPods(g osgraph.Graph, f osgraph.Namer, logsCommandName, securityPolicyCommandPattern string) []osgraph.Marker {
|
||||
markers := []osgraph.Marker{}
|
||||
|
||||
for _, uncastPodNode := range g.NodesByKind(kubegraph.PodNodeKind) {
|
||||
podNode := uncastPodNode.(*kubegraph.PodNode)
|
||||
pod, ok := podNode.Object().(*kapi.Pod)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
for _, containerStatus := range pod.Status.ContainerStatuses {
|
||||
containerString := ""
|
||||
if len(pod.Spec.Containers) > 1 {
|
||||
containerString = fmt.Sprintf("container %q in ", containerStatus.Name)
|
||||
}
|
||||
switch {
|
||||
case containerCrashLoopBackOff(containerStatus):
|
||||
var suggestion string
|
||||
switch {
|
||||
case containerIsNonRoot(pod, containerStatus.Name):
|
||||
suggestion = heredoc.Docf(`
|
||||
The container is starting and exiting repeatedly. This usually means the container is unable
|
||||
to start, misconfigured, or limited by security restrictions. Check the container logs with
|
||||
|
||||
%s %s -c %s
|
||||
|
||||
Current security policy prevents your containers from being run as the root user. Some images
|
||||
may fail expecting to be able to change ownership or permissions on directories. Your admin
|
||||
can grant you access to run containers that need to run as the root user with this command:
|
||||
|
||||
%s
|
||||
`, logsCommandName, pod.Name, containerStatus.Name, fmt.Sprintf(securityPolicyCommandPattern, pod.Namespace, pod.Spec.ServiceAccountName))
|
||||
default:
|
||||
suggestion = heredoc.Docf(`
|
||||
The container is starting and exiting repeatedly. This usually means the container is unable
|
||||
to start, misconfigured, or limited by security restrictions. Check the container logs with
|
||||
|
||||
%s %s -c %s
|
||||
`, logsCommandName, pod.Name, containerStatus.Name)
|
||||
}
|
||||
markers = append(markers, osgraph.Marker{
|
||||
Node: podNode,
|
||||
|
||||
Severity: osgraph.ErrorSeverity,
|
||||
Key: CrashLoopingPodError,
|
||||
Message: fmt.Sprintf("%s%s is crash-looping", containerString,
|
||||
f.ResourceName(podNode)),
|
||||
Suggestion: osgraph.Suggestion(suggestion),
|
||||
})
|
||||
case ContainerRestartedRecently(containerStatus, nowFn()):
|
||||
markers = append(markers, osgraph.Marker{
|
||||
Node: podNode,
|
||||
|
||||
Severity: osgraph.WarningSeverity,
|
||||
Key: RestartingPodWarning,
|
||||
Message: fmt.Sprintf("%s%s has restarted within the last 10 minutes", containerString,
|
||||
f.ResourceName(podNode)),
|
||||
})
|
||||
case containerRestartedFrequently(containerStatus):
|
||||
markers = append(markers, osgraph.Marker{
|
||||
Node: podNode,
|
||||
|
||||
Severity: osgraph.WarningSeverity,
|
||||
Key: RestartingPodWarning,
|
||||
Message: fmt.Sprintf("%s%s has restarted %d times", containerString,
|
||||
f.ResourceName(podNode), containerStatus.RestartCount),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return markers
|
||||
}
|
||||
|
||||
func containerIsNonRoot(pod *kapi.Pod, container string) bool {
|
||||
for _, c := range pod.Spec.Containers {
|
||||
if c.Name != container || c.SecurityContext == nil {
|
||||
continue
|
||||
}
|
||||
switch {
|
||||
case c.SecurityContext.RunAsUser != nil && *c.SecurityContext.RunAsUser != 0:
|
||||
//c.SecurityContext.RunAsNonRoot != nil && *c.SecurityContext.RunAsNonRoot,
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func containerCrashLoopBackOff(status kapi.ContainerStatus) bool {
|
||||
return status.State.Waiting != nil && status.State.Waiting.Reason == "CrashLoopBackOff"
|
||||
}
|
||||
|
||||
func ContainerRestartedRecently(status kapi.ContainerStatus, now unversioned.Time) bool {
|
||||
if status.RestartCount == 0 {
|
||||
return false
|
||||
}
|
||||
if status.LastTerminationState.Terminated != nil && now.Sub(status.LastTerminationState.Terminated.FinishedAt.Time) < RestartRecentDuration {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func containerRestartedFrequently(status kapi.ContainerStatus) bool {
|
||||
return status.RestartCount > RestartThreshold
|
||||
}
|
||||
+124
@@ -0,0 +1,124 @@
|
||||
package analysis
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/gonum/graph"
|
||||
|
||||
osgraph "github.com/openshift/origin/pkg/api/graph"
|
||||
kubeedges "github.com/openshift/origin/pkg/api/kubegraph"
|
||||
kubegraph "github.com/openshift/origin/pkg/api/kubegraph/nodes"
|
||||
)
|
||||
|
||||
const (
|
||||
UnmountableSecretWarning = "UnmountableSecret"
|
||||
MissingSecretWarning = "MissingSecret"
|
||||
)
|
||||
|
||||
// FindUnmountableSecrets inspects all PodSpecs for any Secret reference that isn't listed as mountable by the referenced ServiceAccount
|
||||
func FindUnmountableSecrets(g osgraph.Graph, f osgraph.Namer) []osgraph.Marker {
|
||||
markers := []osgraph.Marker{}
|
||||
|
||||
for _, uncastPodSpecNode := range g.NodesByKind(kubegraph.PodSpecNodeKind) {
|
||||
podSpecNode := uncastPodSpecNode.(*kubegraph.PodSpecNode)
|
||||
unmountableSecrets := CheckForUnmountableSecrets(g, podSpecNode)
|
||||
|
||||
topLevelNode := osgraph.GetTopLevelContainerNode(g, podSpecNode)
|
||||
topLevelString := f.ResourceName(topLevelNode)
|
||||
|
||||
saString := "MISSING_SA"
|
||||
saNodes := g.SuccessorNodesByEdgeKind(podSpecNode, kubeedges.ReferencedServiceAccountEdgeKind)
|
||||
if len(saNodes) > 0 {
|
||||
saString = f.ResourceName(saNodes[0])
|
||||
}
|
||||
|
||||
for _, unmountableSecret := range unmountableSecrets {
|
||||
markers = append(markers, osgraph.Marker{
|
||||
Node: podSpecNode,
|
||||
RelatedNodes: []graph.Node{unmountableSecret},
|
||||
|
||||
Severity: osgraph.WarningSeverity,
|
||||
Key: UnmountableSecretWarning,
|
||||
Message: fmt.Sprintf("%s is attempting to mount a secret %s disallowed by %s",
|
||||
topLevelString, f.ResourceName(unmountableSecret), saString),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return markers
|
||||
}
|
||||
|
||||
// FindMissingSecrets inspects all PodSpecs for any Secret reference that is a synthetic node (not a pre-existing node in the graph)
|
||||
func FindMissingSecrets(g osgraph.Graph, f osgraph.Namer) []osgraph.Marker {
|
||||
markers := []osgraph.Marker{}
|
||||
|
||||
for _, uncastPodSpecNode := range g.NodesByKind(kubegraph.PodSpecNodeKind) {
|
||||
podSpecNode := uncastPodSpecNode.(*kubegraph.PodSpecNode)
|
||||
missingSecrets := CheckMissingMountedSecrets(g, podSpecNode)
|
||||
|
||||
topLevelNode := osgraph.GetTopLevelContainerNode(g, podSpecNode)
|
||||
topLevelString := f.ResourceName(topLevelNode)
|
||||
|
||||
for _, missingSecret := range missingSecrets {
|
||||
markers = append(markers, osgraph.Marker{
|
||||
Node: podSpecNode,
|
||||
RelatedNodes: []graph.Node{missingSecret},
|
||||
|
||||
Severity: osgraph.WarningSeverity,
|
||||
Key: UnmountableSecretWarning,
|
||||
Message: fmt.Sprintf("%s is attempting to mount a missing secret %s",
|
||||
topLevelString, f.ResourceName(missingSecret)),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return markers
|
||||
}
|
||||
|
||||
// CheckForUnmountableSecrets checks to be sure that all the referenced secrets are mountable (by service account)
|
||||
func CheckForUnmountableSecrets(g osgraph.Graph, podSpecNode *kubegraph.PodSpecNode) []*kubegraph.SecretNode {
|
||||
saNodes := g.SuccessorNodesByNodeAndEdgeKind(podSpecNode, kubegraph.ServiceAccountNodeKind, kubeedges.ReferencedServiceAccountEdgeKind)
|
||||
saMountableSecrets := []*kubegraph.SecretNode{}
|
||||
|
||||
if len(saNodes) > 0 {
|
||||
saNode := saNodes[0].(*kubegraph.ServiceAccountNode)
|
||||
for _, secretNode := range g.SuccessorNodesByNodeAndEdgeKind(saNode, kubegraph.SecretNodeKind, kubeedges.MountableSecretEdgeKind) {
|
||||
saMountableSecrets = append(saMountableSecrets, secretNode.(*kubegraph.SecretNode))
|
||||
}
|
||||
}
|
||||
|
||||
unmountableSecrets := []*kubegraph.SecretNode{}
|
||||
|
||||
for _, uncastMountedSecretNode := range g.SuccessorNodesByNodeAndEdgeKind(podSpecNode, kubegraph.SecretNodeKind, kubeedges.MountedSecretEdgeKind) {
|
||||
mountedSecretNode := uncastMountedSecretNode.(*kubegraph.SecretNode)
|
||||
|
||||
mountable := false
|
||||
for _, mountableSecretNode := range saMountableSecrets {
|
||||
if mountableSecretNode == mountedSecretNode {
|
||||
mountable = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !mountable {
|
||||
unmountableSecrets = append(unmountableSecrets, mountedSecretNode)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
return unmountableSecrets
|
||||
}
|
||||
|
||||
// CheckMissingMountedSecrets checks to be sure that all the referenced secrets are present (not synthetic)
|
||||
func CheckMissingMountedSecrets(g osgraph.Graph, podSpecNode *kubegraph.PodSpecNode) []*kubegraph.SecretNode {
|
||||
missingSecrets := []*kubegraph.SecretNode{}
|
||||
|
||||
for _, uncastMountedSecretNode := range g.SuccessorNodesByNodeAndEdgeKind(podSpecNode, kubegraph.SecretNodeKind, kubeedges.MountedSecretEdgeKind) {
|
||||
mountedSecretNode := uncastMountedSecretNode.(*kubegraph.SecretNode)
|
||||
if !mountedSecretNode.Found() {
|
||||
missingSecrets = append(missingSecrets, mountedSecretNode)
|
||||
}
|
||||
}
|
||||
|
||||
return missingSecrets
|
||||
}
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
package analysis
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/gonum/graph"
|
||||
|
||||
osgraph "github.com/openshift/origin/pkg/api/graph"
|
||||
kubeedges "github.com/openshift/origin/pkg/api/kubegraph"
|
||||
kubegraph "github.com/openshift/origin/pkg/api/kubegraph/nodes"
|
||||
)
|
||||
|
||||
const (
|
||||
DuelingReplicationControllerWarning = "DuelingReplicationControllers"
|
||||
)
|
||||
|
||||
func FindDuelingReplicationControllers(g osgraph.Graph, f osgraph.Namer) []osgraph.Marker {
|
||||
markers := []osgraph.Marker{}
|
||||
|
||||
for _, uncastRCNode := range g.NodesByKind(kubegraph.ReplicationControllerNodeKind) {
|
||||
rcNode := uncastRCNode.(*kubegraph.ReplicationControllerNode)
|
||||
|
||||
for _, uncastPodNode := range g.PredecessorNodesByEdgeKind(rcNode, kubeedges.ManagedByControllerEdgeKind) {
|
||||
podNode := uncastPodNode.(*kubegraph.PodNode)
|
||||
|
||||
// check to see if this pod is managed by more than one RC
|
||||
uncastOwningRCs := g.SuccessorNodesByEdgeKind(podNode, kubeedges.ManagedByControllerEdgeKind)
|
||||
if len(uncastOwningRCs) > 1 {
|
||||
involvedRCNames := []string{}
|
||||
relatedNodes := []graph.Node{uncastPodNode}
|
||||
|
||||
for _, uncastOwningRC := range uncastOwningRCs {
|
||||
if uncastOwningRC.ID() == rcNode.ID() {
|
||||
continue
|
||||
}
|
||||
owningRC := uncastOwningRC.(*kubegraph.ReplicationControllerNode)
|
||||
involvedRCNames = append(involvedRCNames, f.ResourceName(owningRC))
|
||||
|
||||
relatedNodes = append(relatedNodes, uncastOwningRC)
|
||||
}
|
||||
|
||||
markers = append(markers, osgraph.Marker{
|
||||
Node: rcNode,
|
||||
RelatedNodes: relatedNodes,
|
||||
|
||||
Severity: osgraph.WarningSeverity,
|
||||
Key: DuelingReplicationControllerWarning,
|
||||
Message: fmt.Sprintf("%s is competing for %s with %s", f.ResourceName(rcNode), f.ResourceName(podNode), strings.Join(involvedRCNames, ", ")),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return markers
|
||||
}
|
||||
+248
@@ -0,0 +1,248 @@
|
||||
package kubegraph
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/gonum/graph"
|
||||
|
||||
kapi "k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||
"k8s.io/kubernetes/pkg/apimachinery/registered"
|
||||
"k8s.io/kubernetes/pkg/labels"
|
||||
"k8s.io/kubernetes/pkg/runtime"
|
||||
|
||||
osgraph "github.com/openshift/origin/pkg/api/graph"
|
||||
kubegraph "github.com/openshift/origin/pkg/api/kubegraph/nodes"
|
||||
deployapi "github.com/openshift/origin/pkg/deploy/api"
|
||||
deploygraph "github.com/openshift/origin/pkg/deploy/graph/nodes"
|
||||
)
|
||||
|
||||
const (
|
||||
// ExposedThroughServiceEdgeKind goes from a PodTemplateSpec or a Pod to Service. The head should make the service's selector.
|
||||
ExposedThroughServiceEdgeKind = "ExposedThroughService"
|
||||
// ManagedByControllerEdgeKind goes from Pod to controller when the Pod satisfies a controller's label selector
|
||||
ManagedByControllerEdgeKind = "ManagedByController"
|
||||
// MountedSecretEdgeKind goes from PodSpec to Secret indicating that is or will be a request to mount a volume with the Secret.
|
||||
MountedSecretEdgeKind = "MountedSecret"
|
||||
// MountableSecretEdgeKind goes from ServiceAccount to Secret indicating that the SA allows the Secret to be mounted
|
||||
MountableSecretEdgeKind = "MountableSecret"
|
||||
// ReferencedServiceAccountEdgeKind goes from PodSpec to ServiceAccount indicating that Pod is or will be running as the SA.
|
||||
ReferencedServiceAccountEdgeKind = "ReferencedServiceAccount"
|
||||
// ScalingEdgeKind goes from HorizontalPodAutoscaler to scaled objects indicating that the HPA scales the object
|
||||
ScalingEdgeKind = "Scaling"
|
||||
)
|
||||
|
||||
// AddExposedPodTemplateSpecEdges ensures that a directed edge exists between a service and all the PodTemplateSpecs
|
||||
// in the graph that match the service selector
|
||||
func AddExposedPodTemplateSpecEdges(g osgraph.MutableUniqueGraph, node *kubegraph.ServiceNode) {
|
||||
if node.Service.Spec.Selector == nil {
|
||||
return
|
||||
}
|
||||
query := labels.SelectorFromSet(node.Service.Spec.Selector)
|
||||
for _, n := range g.(graph.Graph).Nodes() {
|
||||
switch target := n.(type) {
|
||||
case *kubegraph.PodTemplateSpecNode:
|
||||
if target.Namespace != node.Namespace {
|
||||
continue
|
||||
}
|
||||
|
||||
if query.Matches(labels.Set(target.PodTemplateSpec.Labels)) {
|
||||
g.AddEdge(target, node, ExposedThroughServiceEdgeKind)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// AddAllExposedPodTemplateSpecEdges calls AddExposedPodTemplateSpecEdges for every ServiceNode in the graph
|
||||
func AddAllExposedPodTemplateSpecEdges(g osgraph.MutableUniqueGraph) {
|
||||
for _, node := range g.(graph.Graph).Nodes() {
|
||||
if serviceNode, ok := node.(*kubegraph.ServiceNode); ok {
|
||||
AddExposedPodTemplateSpecEdges(g, serviceNode)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// AddExposedPodEdges ensures that a directed edge exists between a service and all the pods
|
||||
// in the graph that match the service selector
|
||||
func AddExposedPodEdges(g osgraph.MutableUniqueGraph, node *kubegraph.ServiceNode) {
|
||||
if node.Service.Spec.Selector == nil {
|
||||
return
|
||||
}
|
||||
query := labels.SelectorFromSet(node.Service.Spec.Selector)
|
||||
for _, n := range g.(graph.Graph).Nodes() {
|
||||
switch target := n.(type) {
|
||||
case *kubegraph.PodNode:
|
||||
if target.Namespace != node.Namespace {
|
||||
continue
|
||||
}
|
||||
if query.Matches(labels.Set(target.Labels)) {
|
||||
g.AddEdge(target, node, ExposedThroughServiceEdgeKind)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// AddAllExposedPodEdges calls AddExposedPodEdges for every ServiceNode in the graph
|
||||
func AddAllExposedPodEdges(g osgraph.MutableUniqueGraph) {
|
||||
for _, node := range g.(graph.Graph).Nodes() {
|
||||
if serviceNode, ok := node.(*kubegraph.ServiceNode); ok {
|
||||
AddExposedPodEdges(g, serviceNode)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// AddManagedByControllerPodEdges ensures that a directed edge exists between a controller and all the pods
|
||||
// in the graph that match the label selector
|
||||
func AddManagedByControllerPodEdges(g osgraph.MutableUniqueGraph, to graph.Node, namespace string, selector map[string]string) {
|
||||
if selector == nil {
|
||||
return
|
||||
}
|
||||
query := labels.SelectorFromSet(selector)
|
||||
for _, n := range g.(graph.Graph).Nodes() {
|
||||
switch target := n.(type) {
|
||||
case *kubegraph.PodNode:
|
||||
if target.Namespace != namespace {
|
||||
continue
|
||||
}
|
||||
if query.Matches(labels.Set(target.Labels)) {
|
||||
g.AddEdge(target, to, ManagedByControllerEdgeKind)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// AddAllManagedByControllerPodEdges calls AddManagedByControllerPodEdges for every node in the graph
|
||||
// TODO: should do this through an interface (selects pods)
|
||||
func AddAllManagedByControllerPodEdges(g osgraph.MutableUniqueGraph) {
|
||||
for _, node := range g.(graph.Graph).Nodes() {
|
||||
switch cast := node.(type) {
|
||||
case *kubegraph.ReplicationControllerNode:
|
||||
AddManagedByControllerPodEdges(g, cast, cast.ReplicationController.Namespace, cast.ReplicationController.Spec.Selector)
|
||||
case *kubegraph.PetSetNode:
|
||||
// TODO: refactor to handle expanded selectors (along with ReplicaSets and Deployments)
|
||||
AddManagedByControllerPodEdges(g, cast, cast.PetSet.Namespace, cast.PetSet.Spec.Selector.MatchLabels)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func AddMountedSecretEdges(g osgraph.Graph, podSpec *kubegraph.PodSpecNode) {
|
||||
//pod specs are always contained. We'll get the toplevel container so that we can pull a namespace from it
|
||||
containerNode := osgraph.GetTopLevelContainerNode(g, podSpec)
|
||||
containerObj := g.GraphDescriber.Object(containerNode)
|
||||
|
||||
meta, err := kapi.ObjectMetaFor(containerObj.(runtime.Object))
|
||||
if err != nil {
|
||||
// this should never happen. it means that a podSpec is owned by a top level container that is not a runtime.Object
|
||||
panic(err)
|
||||
}
|
||||
|
||||
for _, volume := range podSpec.Volumes {
|
||||
source := volume.VolumeSource
|
||||
if source.Secret == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
// pod secrets must be in the same namespace
|
||||
syntheticSecret := &kapi.Secret{}
|
||||
syntheticSecret.Namespace = meta.Namespace
|
||||
syntheticSecret.Name = source.Secret.SecretName
|
||||
|
||||
secretNode := kubegraph.FindOrCreateSyntheticSecretNode(g, syntheticSecret)
|
||||
g.AddEdge(podSpec, secretNode, MountedSecretEdgeKind)
|
||||
}
|
||||
}
|
||||
|
||||
func AddAllMountedSecretEdges(g osgraph.Graph) {
|
||||
for _, node := range g.Nodes() {
|
||||
if podSpecNode, ok := node.(*kubegraph.PodSpecNode); ok {
|
||||
AddMountedSecretEdges(g, podSpecNode)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func AddMountableSecretEdges(g osgraph.Graph, saNode *kubegraph.ServiceAccountNode) {
|
||||
for _, mountableSecret := range saNode.ServiceAccount.Secrets {
|
||||
syntheticSecret := &kapi.Secret{}
|
||||
syntheticSecret.Namespace = saNode.ServiceAccount.Namespace
|
||||
syntheticSecret.Name = mountableSecret.Name
|
||||
|
||||
secretNode := kubegraph.FindOrCreateSyntheticSecretNode(g, syntheticSecret)
|
||||
g.AddEdge(saNode, secretNode, MountableSecretEdgeKind)
|
||||
}
|
||||
}
|
||||
|
||||
func AddAllMountableSecretEdges(g osgraph.Graph) {
|
||||
for _, node := range g.Nodes() {
|
||||
if saNode, ok := node.(*kubegraph.ServiceAccountNode); ok {
|
||||
AddMountableSecretEdges(g, saNode)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func AddRequestedServiceAccountEdges(g osgraph.Graph, podSpecNode *kubegraph.PodSpecNode) {
|
||||
//pod specs are always contained. We'll get the toplevel container so that we can pull a namespace from it
|
||||
containerNode := osgraph.GetTopLevelContainerNode(g, podSpecNode)
|
||||
containerObj := g.GraphDescriber.Object(containerNode)
|
||||
|
||||
meta, err := kapi.ObjectMetaFor(containerObj.(runtime.Object))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// if no SA name is present, admission will set 'default'
|
||||
name := "default"
|
||||
if len(podSpecNode.ServiceAccountName) > 0 {
|
||||
name = podSpecNode.ServiceAccountName
|
||||
}
|
||||
|
||||
syntheticSA := &kapi.ServiceAccount{}
|
||||
syntheticSA.Namespace = meta.Namespace
|
||||
syntheticSA.Name = name
|
||||
|
||||
saNode := kubegraph.FindOrCreateSyntheticServiceAccountNode(g, syntheticSA)
|
||||
g.AddEdge(podSpecNode, saNode, ReferencedServiceAccountEdgeKind)
|
||||
}
|
||||
|
||||
func AddAllRequestedServiceAccountEdges(g osgraph.Graph) {
|
||||
for _, node := range g.Nodes() {
|
||||
if podSpecNode, ok := node.(*kubegraph.PodSpecNode); ok {
|
||||
AddRequestedServiceAccountEdges(g, podSpecNode)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func AddHPAScaleRefEdges(g osgraph.Graph) {
|
||||
for _, node := range g.NodesByKind(kubegraph.HorizontalPodAutoscalerNodeKind) {
|
||||
hpaNode := node.(*kubegraph.HorizontalPodAutoscalerNode)
|
||||
|
||||
syntheticMeta := kapi.ObjectMeta{
|
||||
Name: hpaNode.HorizontalPodAutoscaler.Spec.ScaleTargetRef.Name,
|
||||
Namespace: hpaNode.HorizontalPodAutoscaler.Namespace,
|
||||
}
|
||||
|
||||
var groupVersionResource unversioned.GroupVersionResource
|
||||
resource := strings.ToLower(hpaNode.HorizontalPodAutoscaler.Spec.ScaleTargetRef.Kind)
|
||||
if groupVersion, err := unversioned.ParseGroupVersion(hpaNode.HorizontalPodAutoscaler.Spec.ScaleTargetRef.APIVersion); err == nil {
|
||||
groupVersionResource = groupVersion.WithResource(resource)
|
||||
} else {
|
||||
groupVersionResource = unversioned.GroupVersionResource{Resource: resource}
|
||||
}
|
||||
|
||||
groupVersionResource, err := registered.RESTMapper().ResourceFor(groupVersionResource)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
var syntheticNode graph.Node
|
||||
switch groupVersionResource.GroupResource() {
|
||||
case kapi.Resource("replicationcontrollers"):
|
||||
syntheticNode = kubegraph.FindOrCreateSyntheticReplicationControllerNode(g, &kapi.ReplicationController{ObjectMeta: syntheticMeta})
|
||||
case deployapi.Resource("deploymentconfigs"):
|
||||
syntheticNode = deploygraph.FindOrCreateSyntheticDeploymentConfigNode(g, &deployapi.DeploymentConfig{ObjectMeta: syntheticMeta})
|
||||
default:
|
||||
continue
|
||||
}
|
||||
|
||||
g.AddEdge(hpaNode, syntheticNode, ScalingEdgeKind)
|
||||
}
|
||||
}
|
||||
+187
@@ -0,0 +1,187 @@
|
||||
package nodes
|
||||
|
||||
import (
|
||||
"github.com/gonum/graph"
|
||||
|
||||
kapi "k8s.io/kubernetes/pkg/api"
|
||||
kapps "k8s.io/kubernetes/pkg/apis/apps"
|
||||
"k8s.io/kubernetes/pkg/apis/autoscaling"
|
||||
|
||||
osgraph "github.com/openshift/origin/pkg/api/graph"
|
||||
)
|
||||
|
||||
func EnsurePodNode(g osgraph.MutableUniqueGraph, pod *kapi.Pod) *PodNode {
|
||||
podNodeName := PodNodeName(pod)
|
||||
podNode := osgraph.EnsureUnique(g,
|
||||
podNodeName,
|
||||
func(node osgraph.Node) graph.Node {
|
||||
return &PodNode{node, pod}
|
||||
},
|
||||
).(*PodNode)
|
||||
|
||||
podSpecNode := EnsurePodSpecNode(g, &pod.Spec, pod.Namespace, podNodeName)
|
||||
g.AddEdge(podNode, podSpecNode, osgraph.ContainsEdgeKind)
|
||||
|
||||
return podNode
|
||||
}
|
||||
|
||||
func EnsurePodSpecNode(g osgraph.MutableUniqueGraph, podSpec *kapi.PodSpec, namespace string, ownerName osgraph.UniqueName) *PodSpecNode {
|
||||
return osgraph.EnsureUnique(g,
|
||||
PodSpecNodeName(podSpec, ownerName),
|
||||
func(node osgraph.Node) graph.Node {
|
||||
return &PodSpecNode{node, podSpec, namespace, ownerName}
|
||||
},
|
||||
).(*PodSpecNode)
|
||||
}
|
||||
|
||||
// EnsureServiceNode adds the provided service to the graph if it does not already exist.
|
||||
func EnsureServiceNode(g osgraph.MutableUniqueGraph, svc *kapi.Service) *ServiceNode {
|
||||
return osgraph.EnsureUnique(g,
|
||||
ServiceNodeName(svc),
|
||||
func(node osgraph.Node) graph.Node {
|
||||
return &ServiceNode{node, svc, true}
|
||||
},
|
||||
).(*ServiceNode)
|
||||
}
|
||||
|
||||
// FindOrCreateSyntheticServiceNode returns the existing service node or creates a synthetic node in its place
|
||||
func FindOrCreateSyntheticServiceNode(g osgraph.MutableUniqueGraph, svc *kapi.Service) *ServiceNode {
|
||||
return osgraph.EnsureUnique(g,
|
||||
ServiceNodeName(svc),
|
||||
func(node osgraph.Node) graph.Node {
|
||||
return &ServiceNode{node, svc, false}
|
||||
},
|
||||
).(*ServiceNode)
|
||||
}
|
||||
|
||||
func EnsureServiceAccountNode(g osgraph.MutableUniqueGraph, o *kapi.ServiceAccount) *ServiceAccountNode {
|
||||
return osgraph.EnsureUnique(g,
|
||||
ServiceAccountNodeName(o),
|
||||
func(node osgraph.Node) graph.Node {
|
||||
return &ServiceAccountNode{node, o, true}
|
||||
},
|
||||
).(*ServiceAccountNode)
|
||||
}
|
||||
|
||||
func FindOrCreateSyntheticServiceAccountNode(g osgraph.MutableUniqueGraph, o *kapi.ServiceAccount) *ServiceAccountNode {
|
||||
return osgraph.EnsureUnique(g,
|
||||
ServiceAccountNodeName(o),
|
||||
func(node osgraph.Node) graph.Node {
|
||||
return &ServiceAccountNode{node, o, false}
|
||||
},
|
||||
).(*ServiceAccountNode)
|
||||
}
|
||||
|
||||
func EnsureSecretNode(g osgraph.MutableUniqueGraph, o *kapi.Secret) *SecretNode {
|
||||
return osgraph.EnsureUnique(g,
|
||||
SecretNodeName(o),
|
||||
func(node osgraph.Node) graph.Node {
|
||||
return &SecretNode{node, o, true}
|
||||
},
|
||||
).(*SecretNode)
|
||||
}
|
||||
|
||||
func FindOrCreateSyntheticSecretNode(g osgraph.MutableUniqueGraph, o *kapi.Secret) *SecretNode {
|
||||
return osgraph.EnsureUnique(g,
|
||||
SecretNodeName(o),
|
||||
func(node osgraph.Node) graph.Node {
|
||||
return &SecretNode{node, o, false}
|
||||
},
|
||||
).(*SecretNode)
|
||||
}
|
||||
|
||||
// EnsureReplicationControllerNode adds a graph node for the ReplicationController if it does not already exist.
|
||||
func EnsureReplicationControllerNode(g osgraph.MutableUniqueGraph, rc *kapi.ReplicationController) *ReplicationControllerNode {
|
||||
rcNodeName := ReplicationControllerNodeName(rc)
|
||||
rcNode := osgraph.EnsureUnique(g,
|
||||
rcNodeName,
|
||||
func(node osgraph.Node) graph.Node {
|
||||
return &ReplicationControllerNode{node, rc, true}
|
||||
},
|
||||
).(*ReplicationControllerNode)
|
||||
|
||||
rcSpecNode := EnsureReplicationControllerSpecNode(g, &rc.Spec, rc.Namespace, rcNodeName)
|
||||
g.AddEdge(rcNode, rcSpecNode, osgraph.ContainsEdgeKind)
|
||||
|
||||
return rcNode
|
||||
}
|
||||
|
||||
func FindOrCreateSyntheticReplicationControllerNode(g osgraph.MutableUniqueGraph, rc *kapi.ReplicationController) *ReplicationControllerNode {
|
||||
return osgraph.EnsureUnique(g,
|
||||
ReplicationControllerNodeName(rc),
|
||||
func(node osgraph.Node) graph.Node {
|
||||
return &ReplicationControllerNode{node, rc, false}
|
||||
},
|
||||
).(*ReplicationControllerNode)
|
||||
}
|
||||
|
||||
func EnsureReplicationControllerSpecNode(g osgraph.MutableUniqueGraph, rcSpec *kapi.ReplicationControllerSpec, namespace string, ownerName osgraph.UniqueName) *ReplicationControllerSpecNode {
|
||||
rcSpecName := ReplicationControllerSpecNodeName(rcSpec, ownerName)
|
||||
rcSpecNode := osgraph.EnsureUnique(g,
|
||||
rcSpecName,
|
||||
func(node osgraph.Node) graph.Node {
|
||||
return &ReplicationControllerSpecNode{node, rcSpec, namespace, ownerName}
|
||||
},
|
||||
).(*ReplicationControllerSpecNode)
|
||||
|
||||
if rcSpec.Template != nil {
|
||||
ptSpecNode := EnsurePodTemplateSpecNode(g, rcSpec.Template, namespace, rcSpecName)
|
||||
g.AddEdge(rcSpecNode, ptSpecNode, osgraph.ContainsEdgeKind)
|
||||
}
|
||||
|
||||
return rcSpecNode
|
||||
}
|
||||
|
||||
func EnsurePodTemplateSpecNode(g osgraph.MutableUniqueGraph, ptSpec *kapi.PodTemplateSpec, namespace string, ownerName osgraph.UniqueName) *PodTemplateSpecNode {
|
||||
ptSpecName := PodTemplateSpecNodeName(ptSpec, ownerName)
|
||||
ptSpecNode := osgraph.EnsureUnique(g,
|
||||
ptSpecName,
|
||||
func(node osgraph.Node) graph.Node {
|
||||
return &PodTemplateSpecNode{node, ptSpec, namespace, ownerName}
|
||||
},
|
||||
).(*PodTemplateSpecNode)
|
||||
|
||||
podSpecNode := EnsurePodSpecNode(g, &ptSpec.Spec, namespace, ptSpecName)
|
||||
g.AddEdge(ptSpecNode, podSpecNode, osgraph.ContainsEdgeKind)
|
||||
|
||||
return ptSpecNode
|
||||
}
|
||||
|
||||
func EnsureHorizontalPodAutoscalerNode(g osgraph.MutableUniqueGraph, hpa *autoscaling.HorizontalPodAutoscaler) *HorizontalPodAutoscalerNode {
|
||||
return osgraph.EnsureUnique(g,
|
||||
HorizontalPodAutoscalerNodeName(hpa),
|
||||
func(node osgraph.Node) graph.Node {
|
||||
return &HorizontalPodAutoscalerNode{Node: node, HorizontalPodAutoscaler: hpa}
|
||||
},
|
||||
).(*HorizontalPodAutoscalerNode)
|
||||
}
|
||||
|
||||
func EnsurePetSetNode(g osgraph.MutableUniqueGraph, petset *kapps.PetSet) *PetSetNode {
|
||||
nodeName := PetSetNodeName(petset)
|
||||
node := osgraph.EnsureUnique(g,
|
||||
nodeName,
|
||||
func(node osgraph.Node) graph.Node {
|
||||
return &PetSetNode{node, petset}
|
||||
},
|
||||
).(*PetSetNode)
|
||||
|
||||
specNode := EnsurePetSetSpecNode(g, &petset.Spec, petset.Namespace, nodeName)
|
||||
g.AddEdge(node, specNode, osgraph.ContainsEdgeKind)
|
||||
|
||||
return node
|
||||
}
|
||||
|
||||
func EnsurePetSetSpecNode(g osgraph.MutableUniqueGraph, spec *kapps.PetSetSpec, namespace string, ownerName osgraph.UniqueName) *PetSetSpecNode {
|
||||
specName := PetSetSpecNodeName(spec, ownerName)
|
||||
specNode := osgraph.EnsureUnique(g,
|
||||
specName,
|
||||
func(node osgraph.Node) graph.Node {
|
||||
return &PetSetSpecNode{node, spec, namespace, ownerName}
|
||||
},
|
||||
).(*PetSetSpecNode)
|
||||
|
||||
ptSpecNode := EnsurePodTemplateSpecNode(g, &spec.Template, namespace, specName)
|
||||
g.AddEdge(specNode, ptSpecNode, osgraph.ContainsEdgeKind)
|
||||
|
||||
return specNode
|
||||
}
|
||||
+325
@@ -0,0 +1,325 @@
|
||||
package nodes
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
kapi "k8s.io/kubernetes/pkg/api"
|
||||
kapps "k8s.io/kubernetes/pkg/apis/apps"
|
||||
"k8s.io/kubernetes/pkg/apis/autoscaling"
|
||||
|
||||
osgraph "github.com/openshift/origin/pkg/api/graph"
|
||||
)
|
||||
|
||||
var (
|
||||
ServiceNodeKind = reflect.TypeOf(kapi.Service{}).Name()
|
||||
PodNodeKind = reflect.TypeOf(kapi.Pod{}).Name()
|
||||
PodSpecNodeKind = reflect.TypeOf(kapi.PodSpec{}).Name()
|
||||
PodTemplateSpecNodeKind = reflect.TypeOf(kapi.PodTemplateSpec{}).Name()
|
||||
ReplicationControllerNodeKind = reflect.TypeOf(kapi.ReplicationController{}).Name()
|
||||
ReplicationControllerSpecNodeKind = reflect.TypeOf(kapi.ReplicationControllerSpec{}).Name()
|
||||
ServiceAccountNodeKind = reflect.TypeOf(kapi.ServiceAccount{}).Name()
|
||||
SecretNodeKind = reflect.TypeOf(kapi.Secret{}).Name()
|
||||
HorizontalPodAutoscalerNodeKind = reflect.TypeOf(autoscaling.HorizontalPodAutoscaler{}).Name()
|
||||
PetSetNodeKind = reflect.TypeOf(kapps.PetSet{}).Name()
|
||||
PetSetSpecNodeKind = reflect.TypeOf(kapps.PetSetSpec{}).Name()
|
||||
)
|
||||
|
||||
func ServiceNodeName(o *kapi.Service) osgraph.UniqueName {
|
||||
return osgraph.GetUniqueRuntimeObjectNodeName(ServiceNodeKind, o)
|
||||
}
|
||||
|
||||
type ServiceNode struct {
|
||||
osgraph.Node
|
||||
*kapi.Service
|
||||
|
||||
IsFound bool
|
||||
}
|
||||
|
||||
func (n ServiceNode) Object() interface{} {
|
||||
return n.Service
|
||||
}
|
||||
|
||||
func (n ServiceNode) String() string {
|
||||
return string(ServiceNodeName(n.Service))
|
||||
}
|
||||
|
||||
func (*ServiceNode) Kind() string {
|
||||
return ServiceNodeKind
|
||||
}
|
||||
|
||||
func (n ServiceNode) Found() bool {
|
||||
return n.IsFound
|
||||
}
|
||||
|
||||
func PodNodeName(o *kapi.Pod) osgraph.UniqueName {
|
||||
return osgraph.GetUniqueRuntimeObjectNodeName(PodNodeKind, o)
|
||||
}
|
||||
|
||||
type PodNode struct {
|
||||
osgraph.Node
|
||||
*kapi.Pod
|
||||
}
|
||||
|
||||
func (n PodNode) Object() interface{} {
|
||||
return n.Pod
|
||||
}
|
||||
|
||||
func (n PodNode) String() string {
|
||||
return string(PodNodeName(n.Pod))
|
||||
}
|
||||
|
||||
func (n PodNode) UniqueName() osgraph.UniqueName {
|
||||
return PodNodeName(n.Pod)
|
||||
}
|
||||
|
||||
func (*PodNode) Kind() string {
|
||||
return PodNodeKind
|
||||
}
|
||||
|
||||
func PodSpecNodeName(o *kapi.PodSpec, ownerName osgraph.UniqueName) osgraph.UniqueName {
|
||||
return osgraph.UniqueName(fmt.Sprintf("%s|%v", PodSpecNodeKind, ownerName))
|
||||
}
|
||||
|
||||
type PodSpecNode struct {
|
||||
osgraph.Node
|
||||
*kapi.PodSpec
|
||||
Namespace string
|
||||
|
||||
OwnerName osgraph.UniqueName
|
||||
}
|
||||
|
||||
func (n PodSpecNode) Object() interface{} {
|
||||
return n.PodSpec
|
||||
}
|
||||
|
||||
func (n PodSpecNode) String() string {
|
||||
return string(n.UniqueName())
|
||||
}
|
||||
|
||||
func (n PodSpecNode) UniqueName() osgraph.UniqueName {
|
||||
return PodSpecNodeName(n.PodSpec, n.OwnerName)
|
||||
}
|
||||
|
||||
func (*PodSpecNode) Kind() string {
|
||||
return PodSpecNodeKind
|
||||
}
|
||||
|
||||
func ReplicationControllerNodeName(o *kapi.ReplicationController) osgraph.UniqueName {
|
||||
return osgraph.GetUniqueRuntimeObjectNodeName(ReplicationControllerNodeKind, o)
|
||||
}
|
||||
|
||||
type ReplicationControllerNode struct {
|
||||
osgraph.Node
|
||||
ReplicationController *kapi.ReplicationController
|
||||
|
||||
IsFound bool
|
||||
}
|
||||
|
||||
func (n ReplicationControllerNode) Found() bool {
|
||||
return n.IsFound
|
||||
}
|
||||
|
||||
func (n ReplicationControllerNode) Object() interface{} {
|
||||
return n.ReplicationController
|
||||
}
|
||||
|
||||
func (n ReplicationControllerNode) String() string {
|
||||
return string(ReplicationControllerNodeName(n.ReplicationController))
|
||||
}
|
||||
|
||||
func (n ReplicationControllerNode) UniqueName() osgraph.UniqueName {
|
||||
return ReplicationControllerNodeName(n.ReplicationController)
|
||||
}
|
||||
|
||||
func (*ReplicationControllerNode) Kind() string {
|
||||
return ReplicationControllerNodeKind
|
||||
}
|
||||
|
||||
func ReplicationControllerSpecNodeName(o *kapi.ReplicationControllerSpec, ownerName osgraph.UniqueName) osgraph.UniqueName {
|
||||
return osgraph.UniqueName(fmt.Sprintf("%s|%v", ReplicationControllerSpecNodeKind, ownerName))
|
||||
}
|
||||
|
||||
type ReplicationControllerSpecNode struct {
|
||||
osgraph.Node
|
||||
ReplicationControllerSpec *kapi.ReplicationControllerSpec
|
||||
Namespace string
|
||||
|
||||
OwnerName osgraph.UniqueName
|
||||
}
|
||||
|
||||
func (n ReplicationControllerSpecNode) Object() interface{} {
|
||||
return n.ReplicationControllerSpec
|
||||
}
|
||||
|
||||
func (n ReplicationControllerSpecNode) String() string {
|
||||
return string(n.UniqueName())
|
||||
}
|
||||
|
||||
func (n ReplicationControllerSpecNode) UniqueName() osgraph.UniqueName {
|
||||
return ReplicationControllerSpecNodeName(n.ReplicationControllerSpec, n.OwnerName)
|
||||
}
|
||||
|
||||
func (*ReplicationControllerSpecNode) Kind() string {
|
||||
return ReplicationControllerSpecNodeKind
|
||||
}
|
||||
|
||||
func PodTemplateSpecNodeName(o *kapi.PodTemplateSpec, ownerName osgraph.UniqueName) osgraph.UniqueName {
|
||||
return osgraph.UniqueName(fmt.Sprintf("%s|%v", PodTemplateSpecNodeKind, ownerName))
|
||||
}
|
||||
|
||||
type PodTemplateSpecNode struct {
|
||||
osgraph.Node
|
||||
*kapi.PodTemplateSpec
|
||||
Namespace string
|
||||
|
||||
OwnerName osgraph.UniqueName
|
||||
}
|
||||
|
||||
func (n PodTemplateSpecNode) Object() interface{} {
|
||||
return n.PodTemplateSpec
|
||||
}
|
||||
|
||||
func (n PodTemplateSpecNode) String() string {
|
||||
return string(n.UniqueName())
|
||||
}
|
||||
|
||||
func (n PodTemplateSpecNode) UniqueName() osgraph.UniqueName {
|
||||
return PodTemplateSpecNodeName(n.PodTemplateSpec, n.OwnerName)
|
||||
}
|
||||
|
||||
func (*PodTemplateSpecNode) Kind() string {
|
||||
return PodTemplateSpecNodeKind
|
||||
}
|
||||
|
||||
func ServiceAccountNodeName(o *kapi.ServiceAccount) osgraph.UniqueName {
|
||||
return osgraph.GetUniqueRuntimeObjectNodeName(ServiceAccountNodeKind, o)
|
||||
}
|
||||
|
||||
type ServiceAccountNode struct {
|
||||
osgraph.Node
|
||||
*kapi.ServiceAccount
|
||||
|
||||
IsFound bool
|
||||
}
|
||||
|
||||
func (n ServiceAccountNode) Found() bool {
|
||||
return n.IsFound
|
||||
}
|
||||
|
||||
func (n ServiceAccountNode) Object() interface{} {
|
||||
return n.ServiceAccount
|
||||
}
|
||||
|
||||
func (n ServiceAccountNode) String() string {
|
||||
return string(ServiceAccountNodeName(n.ServiceAccount))
|
||||
}
|
||||
|
||||
func (*ServiceAccountNode) Kind() string {
|
||||
return ServiceAccountNodeKind
|
||||
}
|
||||
|
||||
func SecretNodeName(o *kapi.Secret) osgraph.UniqueName {
|
||||
return osgraph.GetUniqueRuntimeObjectNodeName(SecretNodeKind, o)
|
||||
}
|
||||
|
||||
type SecretNode struct {
|
||||
osgraph.Node
|
||||
*kapi.Secret
|
||||
|
||||
IsFound bool
|
||||
}
|
||||
|
||||
func (n SecretNode) Found() bool {
|
||||
return n.IsFound
|
||||
}
|
||||
|
||||
func (n SecretNode) Object() interface{} {
|
||||
return n.Secret
|
||||
}
|
||||
|
||||
func (n SecretNode) String() string {
|
||||
return string(SecretNodeName(n.Secret))
|
||||
}
|
||||
|
||||
func (*SecretNode) Kind() string {
|
||||
return SecretNodeKind
|
||||
}
|
||||
|
||||
func HorizontalPodAutoscalerNodeName(o *autoscaling.HorizontalPodAutoscaler) osgraph.UniqueName {
|
||||
return osgraph.GetUniqueRuntimeObjectNodeName(HorizontalPodAutoscalerNodeKind, o)
|
||||
}
|
||||
|
||||
type HorizontalPodAutoscalerNode struct {
|
||||
osgraph.Node
|
||||
HorizontalPodAutoscaler *autoscaling.HorizontalPodAutoscaler
|
||||
}
|
||||
|
||||
func (n HorizontalPodAutoscalerNode) Object() interface{} {
|
||||
return n.HorizontalPodAutoscaler
|
||||
}
|
||||
|
||||
func (n HorizontalPodAutoscalerNode) String() string {
|
||||
return string(n.UniqueName())
|
||||
}
|
||||
|
||||
func (*HorizontalPodAutoscalerNode) Kind() string {
|
||||
return HorizontalPodAutoscalerNodeKind
|
||||
}
|
||||
|
||||
func (n HorizontalPodAutoscalerNode) UniqueName() osgraph.UniqueName {
|
||||
return HorizontalPodAutoscalerNodeName(n.HorizontalPodAutoscaler)
|
||||
}
|
||||
|
||||
func PetSetNodeName(o *kapps.PetSet) osgraph.UniqueName {
|
||||
return osgraph.GetUniqueRuntimeObjectNodeName(PetSetNodeKind, o)
|
||||
}
|
||||
|
||||
type PetSetNode struct {
|
||||
osgraph.Node
|
||||
PetSet *kapps.PetSet
|
||||
}
|
||||
|
||||
func (n PetSetNode) Object() interface{} {
|
||||
return n.PetSet
|
||||
}
|
||||
|
||||
func (n PetSetNode) String() string {
|
||||
return string(n.UniqueName())
|
||||
}
|
||||
|
||||
func (n PetSetNode) UniqueName() osgraph.UniqueName {
|
||||
return PetSetNodeName(n.PetSet)
|
||||
}
|
||||
|
||||
func (*PetSetNode) Kind() string {
|
||||
return PetSetNodeKind
|
||||
}
|
||||
|
||||
func PetSetSpecNodeName(o *kapps.PetSetSpec, ownerName osgraph.UniqueName) osgraph.UniqueName {
|
||||
return osgraph.UniqueName(fmt.Sprintf("%s|%v", PetSetSpecNodeKind, ownerName))
|
||||
}
|
||||
|
||||
type PetSetSpecNode struct {
|
||||
osgraph.Node
|
||||
PetSetSpec *kapps.PetSetSpec
|
||||
Namespace string
|
||||
|
||||
OwnerName osgraph.UniqueName
|
||||
}
|
||||
|
||||
func (n PetSetSpecNode) Object() interface{} {
|
||||
return n.PetSetSpec
|
||||
}
|
||||
|
||||
func (n PetSetSpecNode) String() string {
|
||||
return string(n.UniqueName())
|
||||
}
|
||||
|
||||
func (n PetSetSpecNode) UniqueName() osgraph.UniqueName {
|
||||
return PetSetSpecNodeName(n.PetSetSpec, n.OwnerName)
|
||||
}
|
||||
|
||||
func (*PetSetSpecNode) Kind() string {
|
||||
return PetSetSpecNodeKind
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
// Package latest defines the default output serializations that code should
|
||||
// use and imports the required schemas. It also ensures all previously known
|
||||
// and supported API versions are available for conversion. Consumers may
|
||||
// import this package in lieu of importing individual versions.
|
||||
package latest
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
package latest
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||
)
|
||||
|
||||
// HACK TO ELIMINATE CYCLES UNTIL WE KILL THIS PACKAGE
|
||||
|
||||
// Version is the string that represents the current external default version.
|
||||
var Version = unversioned.GroupVersion{Group: "", Version: "v1"}
|
||||
|
||||
// OldestVersion is the string that represents the oldest server version supported,
|
||||
// for client code that wants to hardcode the lowest common denominator.
|
||||
var OldestVersion = unversioned.GroupVersion{Group: "", Version: "v1"}
|
||||
|
||||
// Versions is the list of versions that are recognized in code. The order provided
|
||||
// may be assumed to be most preferred to least preferred, and clients may
|
||||
// choose to prefer the earlier items in the list over the latter items when presented
|
||||
// with a set of versions to choose.
|
||||
var Versions = []unversioned.GroupVersion{{Group: "", Version: "v1"}}
|
||||
|
||||
// originTypes are the hardcoded types defined by the OpenShift API.
|
||||
var originTypes map[unversioned.GroupVersionKind]bool
|
||||
|
||||
// originTypesLock allows lazying initialization of originTypes to allow initializers to run before
|
||||
// loading the map. It means that initializers have to know ahead of time where their type is from,
|
||||
// but that is not onerous
|
||||
var originTypesLock sync.Once
|
||||
|
||||
// OriginKind returns true if OpenShift owns the GroupVersionKind.
|
||||
func OriginKind(gvk unversioned.GroupVersionKind) bool {
|
||||
return getOrCreateOriginKinds()[gvk]
|
||||
}
|
||||
|
||||
// IsKindInAnyOriginGroup returns true if OpenShift owns the kind described in any apiVersion.
|
||||
// TODO: this may not work once we divide builds/deployments/images into their own API groups
|
||||
func IsKindInAnyOriginGroup(kind string) bool {
|
||||
for _, version := range Versions {
|
||||
if OriginKind(version.WithKind(kind)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func getOrCreateOriginKinds() map[unversioned.GroupVersionKind]bool {
|
||||
if originTypes == nil {
|
||||
originTypesLock.Do(func() {
|
||||
newOriginTypes := map[unversioned.GroupVersionKind]bool{}
|
||||
|
||||
// enumerate all supported versions, get the kinds, and register with the mapper how to address our resources
|
||||
for _, version := range Versions {
|
||||
for kind, t := range api.Scheme.KnownTypes(version) {
|
||||
if !strings.Contains(t.PkgPath(), "github.com/openshift/origin") || strings.Contains(t.PkgPath(), "github.com/openshift/origin/vendor/") {
|
||||
continue
|
||||
}
|
||||
gvk := version.WithKind(kind)
|
||||
newOriginTypes[gvk] = true
|
||||
}
|
||||
}
|
||||
originTypes = newOriginTypes
|
||||
})
|
||||
|
||||
return originTypes
|
||||
}
|
||||
|
||||
return originTypes
|
||||
}
|
||||
+176
@@ -0,0 +1,176 @@
|
||||
package restmapper
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
kapi "k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/meta"
|
||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||
"k8s.io/kubernetes/pkg/apimachinery/registered"
|
||||
"k8s.io/kubernetes/pkg/client/typed/discovery"
|
||||
)
|
||||
|
||||
type discoveryRESTMapper struct {
|
||||
discoveryClient discovery.DiscoveryInterface
|
||||
|
||||
delegate meta.RESTMapper
|
||||
|
||||
initLock sync.Mutex
|
||||
}
|
||||
|
||||
// NewDiscoveryRESTMapper that initializes using the discovery APIs, relying on group ordering and preferred versions
|
||||
// to build its appropriate priorities. Only versions are registered with API machinery are added now.
|
||||
// TODO make this work with generic resources at some point. For now, this handles enabled and disabled resources cleanly.
|
||||
func NewDiscoveryRESTMapper(discoveryClient discovery.DiscoveryInterface) meta.RESTMapper {
|
||||
return &discoveryRESTMapper{discoveryClient: discoveryClient}
|
||||
}
|
||||
|
||||
func (d *discoveryRESTMapper) getDelegate() (meta.RESTMapper, error) {
|
||||
d.initLock.Lock()
|
||||
defer d.initLock.Unlock()
|
||||
|
||||
if d.delegate != nil {
|
||||
return d.delegate, nil
|
||||
}
|
||||
|
||||
serverGroups, err := d.discoveryClient.ServerGroups()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// always prefer our default group for now. The version should be discovered from discovery, but this will hold us
|
||||
// for quite some time.
|
||||
resourcePriority := []unversioned.GroupVersionResource{
|
||||
{Group: kapi.GroupName, Version: meta.AnyVersion, Resource: meta.AnyResource},
|
||||
}
|
||||
kindPriority := []unversioned.GroupVersionKind{
|
||||
{Group: kapi.GroupName, Version: meta.AnyVersion, Kind: meta.AnyKind},
|
||||
}
|
||||
groupPriority := []string{}
|
||||
|
||||
unionMapper := meta.MultiRESTMapper{}
|
||||
|
||||
for _, group := range serverGroups.Groups {
|
||||
if len(group.Versions) == 0 {
|
||||
continue
|
||||
}
|
||||
groupPriority = append(groupPriority, group.Name)
|
||||
|
||||
if len(group.PreferredVersion.Version) != 0 {
|
||||
preferredVersion := unversioned.GroupVersion{Group: group.Name, Version: group.PreferredVersion.Version}
|
||||
if registered.IsEnabledVersion(preferredVersion) {
|
||||
resourcePriority = append(resourcePriority, preferredVersion.WithResource(meta.AnyResource))
|
||||
kindPriority = append(kindPriority, preferredVersion.WithKind(meta.AnyKind))
|
||||
}
|
||||
}
|
||||
|
||||
for _, discoveryVersion := range group.Versions {
|
||||
version := unversioned.GroupVersion{Group: group.Name, Version: discoveryVersion.Version}
|
||||
if !registered.IsEnabledVersion(version) {
|
||||
continue
|
||||
}
|
||||
groupMeta, err := registered.Group(group.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resources, err := d.discoveryClient.ServerResourcesForGroupVersion(version.String())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
versionMapper := meta.NewDefaultRESTMapper([]unversioned.GroupVersion{version}, groupMeta.InterfacesFor)
|
||||
for _, resource := range resources.APIResources {
|
||||
// TODO properly handle resource versus kind
|
||||
gvk := version.WithKind(resource.Kind)
|
||||
|
||||
scope := meta.RESTScopeNamespace
|
||||
if !resource.Namespaced {
|
||||
scope = meta.RESTScopeRoot
|
||||
}
|
||||
versionMapper.Add(gvk, scope)
|
||||
|
||||
// TODO formalize this by checking to see if they support listing
|
||||
versionMapper.Add(version.WithKind(resource.Kind+"List"), scope)
|
||||
}
|
||||
|
||||
// we need to add List. Its a special case of something we need that isn't in the discovery doc
|
||||
if group.Name == kapi.GroupName {
|
||||
versionMapper.Add(version.WithKind("List"), meta.RESTScopeNamespace)
|
||||
}
|
||||
|
||||
unionMapper = append(unionMapper, versionMapper)
|
||||
}
|
||||
}
|
||||
|
||||
for _, group := range groupPriority {
|
||||
resourcePriority = append(resourcePriority, unversioned.GroupVersionResource{Group: group, Version: meta.AnyVersion, Resource: meta.AnyResource})
|
||||
kindPriority = append(kindPriority, unversioned.GroupVersionKind{Group: group, Version: meta.AnyVersion, Kind: meta.AnyKind})
|
||||
}
|
||||
|
||||
d.delegate = meta.PriorityRESTMapper{Delegate: unionMapper, ResourcePriority: resourcePriority, KindPriority: kindPriority}
|
||||
return d.delegate, nil
|
||||
}
|
||||
|
||||
func (d *discoveryRESTMapper) KindFor(resource unversioned.GroupVersionResource) (unversioned.GroupVersionKind, error) {
|
||||
delegate, err := d.getDelegate()
|
||||
if err != nil {
|
||||
return unversioned.GroupVersionKind{}, err
|
||||
}
|
||||
return delegate.KindFor(resource)
|
||||
}
|
||||
|
||||
func (d *discoveryRESTMapper) KindsFor(resource unversioned.GroupVersionResource) ([]unversioned.GroupVersionKind, error) {
|
||||
delegate, err := d.getDelegate()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return delegate.KindsFor(resource)
|
||||
}
|
||||
|
||||
func (d *discoveryRESTMapper) ResourceFor(input unversioned.GroupVersionResource) (unversioned.GroupVersionResource, error) {
|
||||
delegate, err := d.getDelegate()
|
||||
if err != nil {
|
||||
return unversioned.GroupVersionResource{}, err
|
||||
}
|
||||
return delegate.ResourceFor(input)
|
||||
}
|
||||
|
||||
func (d *discoveryRESTMapper) ResourcesFor(input unversioned.GroupVersionResource) ([]unversioned.GroupVersionResource, error) {
|
||||
delegate, err := d.getDelegate()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return delegate.ResourcesFor(input)
|
||||
}
|
||||
|
||||
func (d *discoveryRESTMapper) RESTMapping(gk unversioned.GroupKind, versions ...string) (*meta.RESTMapping, error) {
|
||||
delegate, err := d.getDelegate()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return delegate.RESTMapping(gk, versions...)
|
||||
}
|
||||
|
||||
func (d *discoveryRESTMapper) RESTMappings(gk unversioned.GroupKind) ([]*meta.RESTMapping, error) {
|
||||
delegate, err := d.getDelegate()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return delegate.RESTMappings(gk)
|
||||
}
|
||||
|
||||
func (d *discoveryRESTMapper) AliasesForResource(resource string) ([]string, bool) {
|
||||
delegate, err := d.getDelegate()
|
||||
if err != nil {
|
||||
return nil, false
|
||||
}
|
||||
return delegate.AliasesForResource(resource)
|
||||
}
|
||||
|
||||
func (d *discoveryRESTMapper) ResourceSingularizer(resource string) (singular string, err error) {
|
||||
delegate, err := d.getDelegate()
|
||||
if err != nil {
|
||||
return resource, err
|
||||
}
|
||||
return delegate.ResourceSingularizer(resource)
|
||||
}
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"k8s.io/kubernetes/pkg/auth/user"
|
||||
)
|
||||
|
||||
const (
|
||||
// IdentityDisplayNameKey is the key for an optional display name in an identity's Extra map
|
||||
IdentityDisplayNameKey = "name"
|
||||
// IdentityEmailKey is the key for an optional email address in an identity's Extra map
|
||||
IdentityEmailKey = "email"
|
||||
// IdentityPreferredUsernameKey is the key for an optional preferred username in an identity's Extra map.
|
||||
// This is useful when the immutable providerUserName is different than the login used to authenticate
|
||||
// If present, this extra value is used as the preferred username
|
||||
IdentityPreferredUsernameKey = "preferred_username"
|
||||
|
||||
ImpersonateUserHeader = "Impersonate-User"
|
||||
ImpersonateGroupHeader = "Impersonate-Group"
|
||||
ImpersonateUserScopeHeader = "Impersonate-User-Scope"
|
||||
)
|
||||
|
||||
// UserIdentityInfo contains information about an identity. Identities are distinct from users. An authentication server of
|
||||
// some kind (like oauth for example) describes an identity. Our system controls the users mapped to this identity.
|
||||
type UserIdentityInfo interface {
|
||||
// GetIdentityName returns the name of this identity. It must be equal to GetProviderName() + ":" + GetProviderUserName()
|
||||
GetIdentityName() string
|
||||
// GetProviderName returns the name of the provider of this identity.
|
||||
GetProviderName() string
|
||||
// GetProviderUserName uniquely identifies this particular identity for this provider. It is NOT guaranteed to be unique across providers
|
||||
GetProviderUserName() string
|
||||
// GetExtra is a map to allow providers to add additional fields that they understand
|
||||
GetExtra() map[string]string
|
||||
}
|
||||
|
||||
// UserIdentityMapper maps UserIdentities into user.Info objects to allow different user abstractions within auth code.
|
||||
type UserIdentityMapper interface {
|
||||
// UserFor takes an identity, ignores the passed identity.Provider, forces the provider value to some other value and then creates the mapping.
|
||||
// It returns the corresponding user.Info
|
||||
UserFor(identityInfo UserIdentityInfo) (user.Info, error)
|
||||
}
|
||||
|
||||
type Client interface {
|
||||
GetId() string
|
||||
ValidateSecret(secret string) bool
|
||||
GetRedirectUri() string
|
||||
GetUserData() interface{}
|
||||
}
|
||||
|
||||
type Grant struct {
|
||||
Client Client
|
||||
Scope string
|
||||
Expiration int64
|
||||
RedirectURI string
|
||||
}
|
||||
|
||||
type DefaultUserIdentityInfo struct {
|
||||
ProviderName string
|
||||
ProviderUserName string
|
||||
Extra map[string]string
|
||||
}
|
||||
|
||||
// NewDefaultUserIdentityInfo returns a DefaultUserIdentityInfo with a non-nil Extra component
|
||||
func NewDefaultUserIdentityInfo(providerName, providerUserName string) *DefaultUserIdentityInfo {
|
||||
return &DefaultUserIdentityInfo{
|
||||
ProviderName: providerName,
|
||||
ProviderUserName: providerUserName,
|
||||
Extra: map[string]string{},
|
||||
}
|
||||
}
|
||||
|
||||
func (i *DefaultUserIdentityInfo) GetIdentityName() string {
|
||||
return i.ProviderName + ":" + i.ProviderUserName
|
||||
}
|
||||
|
||||
func (i *DefaultUserIdentityInfo) GetProviderName() string {
|
||||
return i.ProviderName
|
||||
}
|
||||
|
||||
func (i *DefaultUserIdentityInfo) GetProviderUserName() string {
|
||||
return i.ProviderUserName
|
||||
}
|
||||
|
||||
func (i *DefaultUserIdentityInfo) GetExtra() map[string]string {
|
||||
return i.Extra
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
package authenticator
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/openshift/origin/pkg/auth/api"
|
||||
"k8s.io/kubernetes/pkg/auth/user"
|
||||
)
|
||||
|
||||
type Token interface {
|
||||
AuthenticateToken(token string) (user.Info, bool, error)
|
||||
}
|
||||
|
||||
type Request interface {
|
||||
AuthenticateRequest(req *http.Request) (user.Info, bool, error)
|
||||
}
|
||||
|
||||
type Password interface {
|
||||
AuthenticatePassword(user, password string) (user.Info, bool, error)
|
||||
}
|
||||
|
||||
type Assertion interface {
|
||||
AuthenticateAssertion(assertionType, data string) (user.Info, bool, error)
|
||||
}
|
||||
|
||||
type Client interface {
|
||||
AuthenticateClient(client api.Client) (user.Info, bool, error)
|
||||
}
|
||||
|
||||
type RequestFunc func(req *http.Request) (user.Info, bool, error)
|
||||
|
||||
func (f RequestFunc) AuthenticateRequest(req *http.Request) (user.Info, bool, error) {
|
||||
return f(req)
|
||||
}
|
||||
Generated
Vendored
+3
@@ -0,0 +1,3 @@
|
||||
// Package x509request provides a request authenticator that validates and
|
||||
// extracts user information from client certificates
|
||||
package x509request
|
||||
Generated
Vendored
+173
@@ -0,0 +1,173 @@
|
||||
package x509request
|
||||
|
||||
import (
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/openshift/origin/pkg/auth/authenticator"
|
||||
"k8s.io/kubernetes/pkg/auth/user"
|
||||
kerrors "k8s.io/kubernetes/pkg/util/errors"
|
||||
"k8s.io/kubernetes/pkg/util/sets"
|
||||
)
|
||||
|
||||
// UserConversion defines an interface for extracting user info from a client certificate chain
|
||||
type UserConversion interface {
|
||||
User(chain []*x509.Certificate) (user.Info, bool, error)
|
||||
}
|
||||
|
||||
// UserConversionFunc is a function that implements the UserConversion interface.
|
||||
type UserConversionFunc func(chain []*x509.Certificate) (user.Info, bool, error)
|
||||
|
||||
// User implements x509.UserConversion
|
||||
func (f UserConversionFunc) User(chain []*x509.Certificate) (user.Info, bool, error) {
|
||||
return f(chain)
|
||||
}
|
||||
|
||||
// Authenticator implements request.Authenticator by extracting user info from verified client certificates
|
||||
type Authenticator struct {
|
||||
opts x509.VerifyOptions
|
||||
user UserConversion
|
||||
}
|
||||
|
||||
// New returns a request.Authenticator that verifies client certificates using the provided
|
||||
// VerifyOptions, and converts valid certificate chains into user.Info using the provided UserConversion
|
||||
func New(opts x509.VerifyOptions, user UserConversion) *Authenticator {
|
||||
return &Authenticator{opts, user}
|
||||
}
|
||||
|
||||
// AuthenticateRequest authenticates the request using presented client certificates
|
||||
func (a *Authenticator) AuthenticateRequest(req *http.Request) (user.Info, bool, error) {
|
||||
if req.TLS == nil {
|
||||
return nil, false, nil
|
||||
}
|
||||
|
||||
var errlist []error
|
||||
for _, cert := range req.TLS.PeerCertificates {
|
||||
chains, err := cert.Verify(a.opts)
|
||||
if err != nil {
|
||||
errlist = append(errlist, err)
|
||||
continue
|
||||
}
|
||||
|
||||
for _, chain := range chains {
|
||||
user, ok, err := a.user.User(chain)
|
||||
if err != nil {
|
||||
errlist = append(errlist, err)
|
||||
continue
|
||||
}
|
||||
|
||||
if ok {
|
||||
return user, ok, err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil, false, kerrors.NewAggregate(errlist)
|
||||
}
|
||||
|
||||
// Verifier implements request.Authenticator by verifying a client cert on the request, then delegating to the wrapped auth
|
||||
type Verifier struct {
|
||||
opts x509.VerifyOptions
|
||||
auth authenticator.Request
|
||||
|
||||
// allowedCommonNames contains the common names which a verified certificate is allowed to have.
|
||||
// If empty, all verified certificates are allowed.
|
||||
allowedCommonNames sets.String
|
||||
}
|
||||
|
||||
func NewVerifier(opts x509.VerifyOptions, auth authenticator.Request, allowedCommonNames sets.String) authenticator.Request {
|
||||
return &Verifier{opts, auth, allowedCommonNames}
|
||||
}
|
||||
|
||||
// AuthenticateRequest verifies the presented client certificates, then delegates to the wrapped auth
|
||||
func (a *Verifier) AuthenticateRequest(req *http.Request) (user.Info, bool, error) {
|
||||
if req.TLS == nil {
|
||||
return nil, false, nil
|
||||
}
|
||||
|
||||
var errlist []error
|
||||
for _, cert := range req.TLS.PeerCertificates {
|
||||
if _, err := cert.Verify(a.opts); err != nil {
|
||||
errlist = append(errlist, err)
|
||||
continue
|
||||
}
|
||||
if err := a.verifySubject(cert.Subject); err != nil {
|
||||
errlist = append(errlist, err)
|
||||
continue
|
||||
}
|
||||
return a.auth.AuthenticateRequest(req)
|
||||
}
|
||||
return nil, false, kerrors.NewAggregate(errlist)
|
||||
}
|
||||
|
||||
func (a *Verifier) verifySubject(subject pkix.Name) error {
|
||||
// No CN restrictions
|
||||
if len(a.allowedCommonNames) == 0 {
|
||||
return nil
|
||||
}
|
||||
// Enforce CN restrictions
|
||||
if a.allowedCommonNames.Has(subject.CommonName) {
|
||||
return nil
|
||||
}
|
||||
glog.Warningf("x509: subject with cn=%s is not in the allowed list: %v", subject.CommonName, a.allowedCommonNames.List())
|
||||
return fmt.Errorf("x509: subject with cn=%s is not allowed", subject.CommonName)
|
||||
}
|
||||
|
||||
// DefaultVerifyOptions returns VerifyOptions that use the system root certificates, current time,
|
||||
// and requires certificates to be valid for client auth (x509.ExtKeyUsageClientAuth)
|
||||
func DefaultVerifyOptions() x509.VerifyOptions {
|
||||
return x509.VerifyOptions{
|
||||
KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
|
||||
}
|
||||
}
|
||||
|
||||
// SubjectToUserConversion calls SubjectToUser on the subject of the first certificate in the chain.
|
||||
// If the resulting user has no name, it returns nil, false, nil
|
||||
var SubjectToUserConversion = UserConversionFunc(func(chain []*x509.Certificate) (user.Info, bool, error) {
|
||||
user := SubjectToUser(chain[0].Subject)
|
||||
if len(user.GetName()) == 0 {
|
||||
return nil, false, nil
|
||||
}
|
||||
return user, true, nil
|
||||
})
|
||||
|
||||
// CommonNameUserConversion builds user info from a certificate chain using the subject's CommonName
|
||||
var CommonNameUserConversion = UserConversionFunc(func(chain []*x509.Certificate) (user.Info, bool, error) {
|
||||
if len(chain[0].Subject.CommonName) == 0 {
|
||||
return nil, false, nil
|
||||
}
|
||||
return &user.DefaultInfo{Name: chain[0].Subject.CommonName}, true, nil
|
||||
})
|
||||
|
||||
// DNSNameUserConversion builds user info from a certificate chain using the first DNSName on the certificate
|
||||
var DNSNameUserConversion = UserConversionFunc(func(chain []*x509.Certificate) (user.Info, bool, error) {
|
||||
if len(chain[0].DNSNames) == 0 {
|
||||
return nil, false, nil
|
||||
}
|
||||
return &user.DefaultInfo{Name: chain[0].DNSNames[0]}, true, nil
|
||||
})
|
||||
|
||||
// EmailAddressUserConversion builds user info from a certificate chain using the first EmailAddress on the certificate
|
||||
var EmailAddressUserConversion = UserConversionFunc(func(chain []*x509.Certificate) (user.Info, bool, error) {
|
||||
if len(chain[0].EmailAddresses) == 0 {
|
||||
return nil, false, nil
|
||||
}
|
||||
return &user.DefaultInfo{Name: chain[0].EmailAddresses[0]}, true, nil
|
||||
})
|
||||
|
||||
func UserToSubject(u user.Info) pkix.Name {
|
||||
return pkix.Name{
|
||||
CommonName: u.GetName(),
|
||||
SerialNumber: u.GetUID(),
|
||||
Organization: u.GetGroups(),
|
||||
}
|
||||
}
|
||||
func SubjectToUser(subject pkix.Name) user.Info {
|
||||
return &user.DefaultInfo{
|
||||
Name: subject.CommonName,
|
||||
UID: subject.SerialNumber,
|
||||
Groups: subject.Organization,
|
||||
}
|
||||
}
|
||||
-678
@@ -1,678 +0,0 @@
|
||||
// +build !ignore_autogenerated_openshift
|
||||
|
||||
// This file was autogenerated by deepcopy-gen. Do not edit it manually!
|
||||
|
||||
package api
|
||||
|
||||
import (
|
||||
api "k8s.io/kubernetes/pkg/api"
|
||||
unversioned "k8s.io/kubernetes/pkg/api/unversioned"
|
||||
conversion "k8s.io/kubernetes/pkg/conversion"
|
||||
runtime "k8s.io/kubernetes/pkg/runtime"
|
||||
sets "k8s.io/kubernetes/pkg/util/sets"
|
||||
)
|
||||
|
||||
func init() {
|
||||
if err := api.Scheme.AddGeneratedDeepCopyFuncs(
|
||||
DeepCopy_api_AuthorizationAttributes,
|
||||
DeepCopy_api_ClusterPolicy,
|
||||
DeepCopy_api_ClusterPolicyBinding,
|
||||
DeepCopy_api_ClusterPolicyBindingList,
|
||||
DeepCopy_api_ClusterPolicyList,
|
||||
DeepCopy_api_ClusterRole,
|
||||
DeepCopy_api_ClusterRoleBinding,
|
||||
DeepCopy_api_ClusterRoleBindingList,
|
||||
DeepCopy_api_ClusterRoleList,
|
||||
DeepCopy_api_IsPersonalSubjectAccessReview,
|
||||
DeepCopy_api_LocalResourceAccessReview,
|
||||
DeepCopy_api_LocalSubjectAccessReview,
|
||||
DeepCopy_api_Policy,
|
||||
DeepCopy_api_PolicyBinding,
|
||||
DeepCopy_api_PolicyBindingList,
|
||||
DeepCopy_api_PolicyList,
|
||||
DeepCopy_api_PolicyRule,
|
||||
DeepCopy_api_ResourceAccessReview,
|
||||
DeepCopy_api_ResourceAccessReviewResponse,
|
||||
DeepCopy_api_Role,
|
||||
DeepCopy_api_RoleBinding,
|
||||
DeepCopy_api_RoleBindingList,
|
||||
DeepCopy_api_RoleList,
|
||||
DeepCopy_api_SelfSubjectRulesReview,
|
||||
DeepCopy_api_SelfSubjectRulesReviewSpec,
|
||||
DeepCopy_api_SubjectAccessReview,
|
||||
DeepCopy_api_SubjectAccessReviewResponse,
|
||||
DeepCopy_api_SubjectRulesReviewStatus,
|
||||
); err != nil {
|
||||
// if one of the deep copy functions is malformed, detect it immediately.
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func DeepCopy_api_AuthorizationAttributes(in AuthorizationAttributes, out *AuthorizationAttributes, c *conversion.Cloner) error {
|
||||
out.Namespace = in.Namespace
|
||||
out.Verb = in.Verb
|
||||
out.Group = in.Group
|
||||
out.Version = in.Version
|
||||
out.Resource = in.Resource
|
||||
out.ResourceName = in.ResourceName
|
||||
if in.Content == nil {
|
||||
out.Content = nil
|
||||
} else if newVal, err := c.DeepCopy(in.Content); err != nil {
|
||||
return err
|
||||
} else {
|
||||
out.Content = newVal.(runtime.Object)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeepCopy_api_ClusterPolicy(in ClusterPolicy, out *ClusterPolicy, c *conversion.Cloner) error {
|
||||
if err := unversioned.DeepCopy_unversioned_TypeMeta(in.TypeMeta, &out.TypeMeta, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := api.DeepCopy_api_ObjectMeta(in.ObjectMeta, &out.ObjectMeta, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := unversioned.DeepCopy_unversioned_Time(in.LastModified, &out.LastModified, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if in.Roles != nil {
|
||||
in, out := in.Roles, &out.Roles
|
||||
*out = make(map[string]*ClusterRole)
|
||||
for key, val := range in {
|
||||
if newVal, err := c.DeepCopy(val); err != nil {
|
||||
return err
|
||||
} else {
|
||||
(*out)[key] = newVal.(*ClusterRole)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.Roles = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeepCopy_api_ClusterPolicyBinding(in ClusterPolicyBinding, out *ClusterPolicyBinding, c *conversion.Cloner) error {
|
||||
if err := unversioned.DeepCopy_unversioned_TypeMeta(in.TypeMeta, &out.TypeMeta, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := api.DeepCopy_api_ObjectMeta(in.ObjectMeta, &out.ObjectMeta, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := unversioned.DeepCopy_unversioned_Time(in.LastModified, &out.LastModified, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := api.DeepCopy_api_ObjectReference(in.PolicyRef, &out.PolicyRef, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if in.RoleBindings != nil {
|
||||
in, out := in.RoleBindings, &out.RoleBindings
|
||||
*out = make(map[string]*ClusterRoleBinding)
|
||||
for key, val := range in {
|
||||
if newVal, err := c.DeepCopy(val); err != nil {
|
||||
return err
|
||||
} else {
|
||||
(*out)[key] = newVal.(*ClusterRoleBinding)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.RoleBindings = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeepCopy_api_ClusterPolicyBindingList(in ClusterPolicyBindingList, out *ClusterPolicyBindingList, c *conversion.Cloner) error {
|
||||
if err := unversioned.DeepCopy_unversioned_TypeMeta(in.TypeMeta, &out.TypeMeta, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := unversioned.DeepCopy_unversioned_ListMeta(in.ListMeta, &out.ListMeta, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if in.Items != nil {
|
||||
in, out := in.Items, &out.Items
|
||||
*out = make([]ClusterPolicyBinding, len(in))
|
||||
for i := range in {
|
||||
if err := DeepCopy_api_ClusterPolicyBinding(in[i], &(*out)[i], c); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.Items = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeepCopy_api_ClusterPolicyList(in ClusterPolicyList, out *ClusterPolicyList, c *conversion.Cloner) error {
|
||||
if err := unversioned.DeepCopy_unversioned_TypeMeta(in.TypeMeta, &out.TypeMeta, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := unversioned.DeepCopy_unversioned_ListMeta(in.ListMeta, &out.ListMeta, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if in.Items != nil {
|
||||
in, out := in.Items, &out.Items
|
||||
*out = make([]ClusterPolicy, len(in))
|
||||
for i := range in {
|
||||
if err := DeepCopy_api_ClusterPolicy(in[i], &(*out)[i], c); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.Items = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeepCopy_api_ClusterRole(in ClusterRole, out *ClusterRole, c *conversion.Cloner) error {
|
||||
if err := unversioned.DeepCopy_unversioned_TypeMeta(in.TypeMeta, &out.TypeMeta, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := api.DeepCopy_api_ObjectMeta(in.ObjectMeta, &out.ObjectMeta, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if in.Rules != nil {
|
||||
in, out := in.Rules, &out.Rules
|
||||
*out = make([]PolicyRule, len(in))
|
||||
for i := range in {
|
||||
if err := DeepCopy_api_PolicyRule(in[i], &(*out)[i], c); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.Rules = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeepCopy_api_ClusterRoleBinding(in ClusterRoleBinding, out *ClusterRoleBinding, c *conversion.Cloner) error {
|
||||
if err := unversioned.DeepCopy_unversioned_TypeMeta(in.TypeMeta, &out.TypeMeta, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := api.DeepCopy_api_ObjectMeta(in.ObjectMeta, &out.ObjectMeta, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if in.Subjects != nil {
|
||||
in, out := in.Subjects, &out.Subjects
|
||||
*out = make([]api.ObjectReference, len(in))
|
||||
for i := range in {
|
||||
if err := api.DeepCopy_api_ObjectReference(in[i], &(*out)[i], c); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.Subjects = nil
|
||||
}
|
||||
if err := api.DeepCopy_api_ObjectReference(in.RoleRef, &out.RoleRef, c); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeepCopy_api_ClusterRoleBindingList(in ClusterRoleBindingList, out *ClusterRoleBindingList, c *conversion.Cloner) error {
|
||||
if err := unversioned.DeepCopy_unversioned_TypeMeta(in.TypeMeta, &out.TypeMeta, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := unversioned.DeepCopy_unversioned_ListMeta(in.ListMeta, &out.ListMeta, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if in.Items != nil {
|
||||
in, out := in.Items, &out.Items
|
||||
*out = make([]ClusterRoleBinding, len(in))
|
||||
for i := range in {
|
||||
if err := DeepCopy_api_ClusterRoleBinding(in[i], &(*out)[i], c); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.Items = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeepCopy_api_ClusterRoleList(in ClusterRoleList, out *ClusterRoleList, c *conversion.Cloner) error {
|
||||
if err := unversioned.DeepCopy_unversioned_TypeMeta(in.TypeMeta, &out.TypeMeta, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := unversioned.DeepCopy_unversioned_ListMeta(in.ListMeta, &out.ListMeta, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if in.Items != nil {
|
||||
in, out := in.Items, &out.Items
|
||||
*out = make([]ClusterRole, len(in))
|
||||
for i := range in {
|
||||
if err := DeepCopy_api_ClusterRole(in[i], &(*out)[i], c); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.Items = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeepCopy_api_IsPersonalSubjectAccessReview(in IsPersonalSubjectAccessReview, out *IsPersonalSubjectAccessReview, c *conversion.Cloner) error {
|
||||
if err := unversioned.DeepCopy_unversioned_TypeMeta(in.TypeMeta, &out.TypeMeta, c); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeepCopy_api_LocalResourceAccessReview(in LocalResourceAccessReview, out *LocalResourceAccessReview, c *conversion.Cloner) error {
|
||||
if err := unversioned.DeepCopy_unversioned_TypeMeta(in.TypeMeta, &out.TypeMeta, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := DeepCopy_api_AuthorizationAttributes(in.Action, &out.Action, c); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeepCopy_api_LocalSubjectAccessReview(in LocalSubjectAccessReview, out *LocalSubjectAccessReview, c *conversion.Cloner) error {
|
||||
if err := unversioned.DeepCopy_unversioned_TypeMeta(in.TypeMeta, &out.TypeMeta, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := DeepCopy_api_AuthorizationAttributes(in.Action, &out.Action, c); err != nil {
|
||||
return err
|
||||
}
|
||||
out.User = in.User
|
||||
if in.Groups != nil {
|
||||
in, out := in.Groups, &out.Groups
|
||||
*out = make(sets.String)
|
||||
for key, val := range in {
|
||||
if newVal, err := c.DeepCopy(val); err != nil {
|
||||
return err
|
||||
} else {
|
||||
(*out)[key] = newVal.(sets.Empty)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.Groups = nil
|
||||
}
|
||||
if in.Scopes != nil {
|
||||
in, out := in.Scopes, &out.Scopes
|
||||
*out = make([]string, len(in))
|
||||
copy(*out, in)
|
||||
} else {
|
||||
out.Scopes = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeepCopy_api_Policy(in Policy, out *Policy, c *conversion.Cloner) error {
|
||||
if err := unversioned.DeepCopy_unversioned_TypeMeta(in.TypeMeta, &out.TypeMeta, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := api.DeepCopy_api_ObjectMeta(in.ObjectMeta, &out.ObjectMeta, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := unversioned.DeepCopy_unversioned_Time(in.LastModified, &out.LastModified, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if in.Roles != nil {
|
||||
in, out := in.Roles, &out.Roles
|
||||
*out = make(map[string]*Role)
|
||||
for key, val := range in {
|
||||
if newVal, err := c.DeepCopy(val); err != nil {
|
||||
return err
|
||||
} else {
|
||||
(*out)[key] = newVal.(*Role)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.Roles = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeepCopy_api_PolicyBinding(in PolicyBinding, out *PolicyBinding, c *conversion.Cloner) error {
|
||||
if err := unversioned.DeepCopy_unversioned_TypeMeta(in.TypeMeta, &out.TypeMeta, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := api.DeepCopy_api_ObjectMeta(in.ObjectMeta, &out.ObjectMeta, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := unversioned.DeepCopy_unversioned_Time(in.LastModified, &out.LastModified, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := api.DeepCopy_api_ObjectReference(in.PolicyRef, &out.PolicyRef, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if in.RoleBindings != nil {
|
||||
in, out := in.RoleBindings, &out.RoleBindings
|
||||
*out = make(map[string]*RoleBinding)
|
||||
for key, val := range in {
|
||||
if newVal, err := c.DeepCopy(val); err != nil {
|
||||
return err
|
||||
} else {
|
||||
(*out)[key] = newVal.(*RoleBinding)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.RoleBindings = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeepCopy_api_PolicyBindingList(in PolicyBindingList, out *PolicyBindingList, c *conversion.Cloner) error {
|
||||
if err := unversioned.DeepCopy_unversioned_TypeMeta(in.TypeMeta, &out.TypeMeta, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := unversioned.DeepCopy_unversioned_ListMeta(in.ListMeta, &out.ListMeta, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if in.Items != nil {
|
||||
in, out := in.Items, &out.Items
|
||||
*out = make([]PolicyBinding, len(in))
|
||||
for i := range in {
|
||||
if err := DeepCopy_api_PolicyBinding(in[i], &(*out)[i], c); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.Items = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeepCopy_api_PolicyList(in PolicyList, out *PolicyList, c *conversion.Cloner) error {
|
||||
if err := unversioned.DeepCopy_unversioned_TypeMeta(in.TypeMeta, &out.TypeMeta, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := unversioned.DeepCopy_unversioned_ListMeta(in.ListMeta, &out.ListMeta, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if in.Items != nil {
|
||||
in, out := in.Items, &out.Items
|
||||
*out = make([]Policy, len(in))
|
||||
for i := range in {
|
||||
if err := DeepCopy_api_Policy(in[i], &(*out)[i], c); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.Items = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeepCopy_api_PolicyRule(in PolicyRule, out *PolicyRule, c *conversion.Cloner) error {
|
||||
if in.Verbs != nil {
|
||||
in, out := in.Verbs, &out.Verbs
|
||||
*out = make(sets.String)
|
||||
for key, val := range in {
|
||||
if newVal, err := c.DeepCopy(val); err != nil {
|
||||
return err
|
||||
} else {
|
||||
(*out)[key] = newVal.(sets.Empty)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.Verbs = nil
|
||||
}
|
||||
if in.AttributeRestrictions == nil {
|
||||
out.AttributeRestrictions = nil
|
||||
} else if newVal, err := c.DeepCopy(in.AttributeRestrictions); err != nil {
|
||||
return err
|
||||
} else {
|
||||
out.AttributeRestrictions = newVal.(runtime.Object)
|
||||
}
|
||||
if in.APIGroups != nil {
|
||||
in, out := in.APIGroups, &out.APIGroups
|
||||
*out = make([]string, len(in))
|
||||
copy(*out, in)
|
||||
} else {
|
||||
out.APIGroups = nil
|
||||
}
|
||||
if in.Resources != nil {
|
||||
in, out := in.Resources, &out.Resources
|
||||
*out = make(sets.String)
|
||||
for key, val := range in {
|
||||
if newVal, err := c.DeepCopy(val); err != nil {
|
||||
return err
|
||||
} else {
|
||||
(*out)[key] = newVal.(sets.Empty)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.Resources = nil
|
||||
}
|
||||
if in.ResourceNames != nil {
|
||||
in, out := in.ResourceNames, &out.ResourceNames
|
||||
*out = make(sets.String)
|
||||
for key, val := range in {
|
||||
if newVal, err := c.DeepCopy(val); err != nil {
|
||||
return err
|
||||
} else {
|
||||
(*out)[key] = newVal.(sets.Empty)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.ResourceNames = nil
|
||||
}
|
||||
if in.NonResourceURLs != nil {
|
||||
in, out := in.NonResourceURLs, &out.NonResourceURLs
|
||||
*out = make(sets.String)
|
||||
for key, val := range in {
|
||||
if newVal, err := c.DeepCopy(val); err != nil {
|
||||
return err
|
||||
} else {
|
||||
(*out)[key] = newVal.(sets.Empty)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.NonResourceURLs = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeepCopy_api_ResourceAccessReview(in ResourceAccessReview, out *ResourceAccessReview, c *conversion.Cloner) error {
|
||||
if err := unversioned.DeepCopy_unversioned_TypeMeta(in.TypeMeta, &out.TypeMeta, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := DeepCopy_api_AuthorizationAttributes(in.Action, &out.Action, c); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeepCopy_api_ResourceAccessReviewResponse(in ResourceAccessReviewResponse, out *ResourceAccessReviewResponse, c *conversion.Cloner) error {
|
||||
if err := unversioned.DeepCopy_unversioned_TypeMeta(in.TypeMeta, &out.TypeMeta, c); err != nil {
|
||||
return err
|
||||
}
|
||||
out.Namespace = in.Namespace
|
||||
if in.Users != nil {
|
||||
in, out := in.Users, &out.Users
|
||||
*out = make(sets.String)
|
||||
for key, val := range in {
|
||||
if newVal, err := c.DeepCopy(val); err != nil {
|
||||
return err
|
||||
} else {
|
||||
(*out)[key] = newVal.(sets.Empty)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.Users = nil
|
||||
}
|
||||
if in.Groups != nil {
|
||||
in, out := in.Groups, &out.Groups
|
||||
*out = make(sets.String)
|
||||
for key, val := range in {
|
||||
if newVal, err := c.DeepCopy(val); err != nil {
|
||||
return err
|
||||
} else {
|
||||
(*out)[key] = newVal.(sets.Empty)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.Groups = nil
|
||||
}
|
||||
out.EvaluationError = in.EvaluationError
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeepCopy_api_Role(in Role, out *Role, c *conversion.Cloner) error {
|
||||
if err := unversioned.DeepCopy_unversioned_TypeMeta(in.TypeMeta, &out.TypeMeta, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := api.DeepCopy_api_ObjectMeta(in.ObjectMeta, &out.ObjectMeta, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if in.Rules != nil {
|
||||
in, out := in.Rules, &out.Rules
|
||||
*out = make([]PolicyRule, len(in))
|
||||
for i := range in {
|
||||
if err := DeepCopy_api_PolicyRule(in[i], &(*out)[i], c); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.Rules = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeepCopy_api_RoleBinding(in RoleBinding, out *RoleBinding, c *conversion.Cloner) error {
|
||||
if err := unversioned.DeepCopy_unversioned_TypeMeta(in.TypeMeta, &out.TypeMeta, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := api.DeepCopy_api_ObjectMeta(in.ObjectMeta, &out.ObjectMeta, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if in.Subjects != nil {
|
||||
in, out := in.Subjects, &out.Subjects
|
||||
*out = make([]api.ObjectReference, len(in))
|
||||
for i := range in {
|
||||
if err := api.DeepCopy_api_ObjectReference(in[i], &(*out)[i], c); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.Subjects = nil
|
||||
}
|
||||
if err := api.DeepCopy_api_ObjectReference(in.RoleRef, &out.RoleRef, c); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeepCopy_api_RoleBindingList(in RoleBindingList, out *RoleBindingList, c *conversion.Cloner) error {
|
||||
if err := unversioned.DeepCopy_unversioned_TypeMeta(in.TypeMeta, &out.TypeMeta, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := unversioned.DeepCopy_unversioned_ListMeta(in.ListMeta, &out.ListMeta, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if in.Items != nil {
|
||||
in, out := in.Items, &out.Items
|
||||
*out = make([]RoleBinding, len(in))
|
||||
for i := range in {
|
||||
if err := DeepCopy_api_RoleBinding(in[i], &(*out)[i], c); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.Items = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeepCopy_api_RoleList(in RoleList, out *RoleList, c *conversion.Cloner) error {
|
||||
if err := unversioned.DeepCopy_unversioned_TypeMeta(in.TypeMeta, &out.TypeMeta, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := unversioned.DeepCopy_unversioned_ListMeta(in.ListMeta, &out.ListMeta, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if in.Items != nil {
|
||||
in, out := in.Items, &out.Items
|
||||
*out = make([]Role, len(in))
|
||||
for i := range in {
|
||||
if err := DeepCopy_api_Role(in[i], &(*out)[i], c); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.Items = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeepCopy_api_SelfSubjectRulesReview(in SelfSubjectRulesReview, out *SelfSubjectRulesReview, c *conversion.Cloner) error {
|
||||
if err := unversioned.DeepCopy_unversioned_TypeMeta(in.TypeMeta, &out.TypeMeta, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := DeepCopy_api_SelfSubjectRulesReviewSpec(in.Spec, &out.Spec, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := DeepCopy_api_SubjectRulesReviewStatus(in.Status, &out.Status, c); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeepCopy_api_SelfSubjectRulesReviewSpec(in SelfSubjectRulesReviewSpec, out *SelfSubjectRulesReviewSpec, c *conversion.Cloner) error {
|
||||
if in.Scopes != nil {
|
||||
in, out := in.Scopes, &out.Scopes
|
||||
*out = make([]string, len(in))
|
||||
copy(*out, in)
|
||||
} else {
|
||||
out.Scopes = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeepCopy_api_SubjectAccessReview(in SubjectAccessReview, out *SubjectAccessReview, c *conversion.Cloner) error {
|
||||
if err := unversioned.DeepCopy_unversioned_TypeMeta(in.TypeMeta, &out.TypeMeta, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := DeepCopy_api_AuthorizationAttributes(in.Action, &out.Action, c); err != nil {
|
||||
return err
|
||||
}
|
||||
out.User = in.User
|
||||
if in.Groups != nil {
|
||||
in, out := in.Groups, &out.Groups
|
||||
*out = make(sets.String)
|
||||
for key, val := range in {
|
||||
if newVal, err := c.DeepCopy(val); err != nil {
|
||||
return err
|
||||
} else {
|
||||
(*out)[key] = newVal.(sets.Empty)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.Groups = nil
|
||||
}
|
||||
if in.Scopes != nil {
|
||||
in, out := in.Scopes, &out.Scopes
|
||||
*out = make([]string, len(in))
|
||||
copy(*out, in)
|
||||
} else {
|
||||
out.Scopes = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeepCopy_api_SubjectAccessReviewResponse(in SubjectAccessReviewResponse, out *SubjectAccessReviewResponse, c *conversion.Cloner) error {
|
||||
if err := unversioned.DeepCopy_unversioned_TypeMeta(in.TypeMeta, &out.TypeMeta, c); err != nil {
|
||||
return err
|
||||
}
|
||||
out.Namespace = in.Namespace
|
||||
out.Allowed = in.Allowed
|
||||
out.Reason = in.Reason
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeepCopy_api_SubjectRulesReviewStatus(in SubjectRulesReviewStatus, out *SubjectRulesReviewStatus, c *conversion.Cloner) error {
|
||||
if in.Rules != nil {
|
||||
in, out := in.Rules, &out.Rules
|
||||
*out = make([]PolicyRule, len(in))
|
||||
for i := range in {
|
||||
if err := DeepCopy_api_PolicyRule(in[i], &(*out)[i], c); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.Rules = nil
|
||||
}
|
||||
out.EvaluationError = in.EvaluationError
|
||||
return nil
|
||||
}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
// +k8s:deepcopy-gen=package,register
|
||||
|
||||
// Package api is the internal version of the API.
|
||||
package api
|
||||
+53
@@ -244,6 +244,59 @@ func SubjectsStrings(currentNamespace string, subjects []kapi.ObjectReference) (
|
||||
return users, groups, sas, others
|
||||
}
|
||||
|
||||
// SubjectsContainUser returns true if the provided subjects contain the named user. currentNamespace
|
||||
// is used to identify service accounts that are defined in a relative fashion.
|
||||
func SubjectsContainUser(subjects []kapi.ObjectReference, currentNamespace string, user string) bool {
|
||||
if !strings.HasPrefix(user, serviceaccount.ServiceAccountUsernamePrefix) {
|
||||
for _, subject := range subjects {
|
||||
switch subject.Kind {
|
||||
case UserKind, SystemUserKind:
|
||||
if user == subject.Name {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
for _, subject := range subjects {
|
||||
switch subject.Kind {
|
||||
case ServiceAccountKind:
|
||||
namespace := currentNamespace
|
||||
if len(subject.Namespace) > 0 {
|
||||
namespace = subject.Namespace
|
||||
}
|
||||
if len(namespace) == 0 {
|
||||
continue
|
||||
}
|
||||
if user == serviceaccount.MakeUsername(namespace, subject.Name) {
|
||||
return true
|
||||
}
|
||||
|
||||
case UserKind, SystemUserKind:
|
||||
if user == subject.Name {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// SubjectsContainAnyGroup returns true if the provided subjects any of the named groups.
|
||||
func SubjectsContainAnyGroup(subjects []kapi.ObjectReference, groups []string) bool {
|
||||
for _, subject := range subjects {
|
||||
switch subject.Kind {
|
||||
case GroupKind, SystemGroupKind:
|
||||
for _, group := range groups {
|
||||
if group == subject.Name {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func AddUserToSAR(user user.Info, sar *SubjectAccessReview) *SubjectAccessReview {
|
||||
origScopes := user.GetExtra()[ScopesKey]
|
||||
scopes := make([]string, len(origScopes), len(origScopes))
|
||||
|
||||
+7
-5
@@ -6,6 +6,7 @@ import (
|
||||
)
|
||||
|
||||
const GroupName = ""
|
||||
const FutureGroupName = "authorization.openshift.io"
|
||||
|
||||
// SchemeGroupVersion is group version used to register these objects
|
||||
var SchemeGroupVersion = unversioned.GroupVersion{Group: GroupName, Version: runtime.APIVersionInternal}
|
||||
@@ -20,13 +21,13 @@ func Resource(resource string) unversioned.GroupResource {
|
||||
return SchemeGroupVersion.WithResource(resource).GroupResource()
|
||||
}
|
||||
|
||||
func AddToScheme(scheme *runtime.Scheme) {
|
||||
// Add the API to Scheme.
|
||||
addKnownTypes(scheme)
|
||||
}
|
||||
var (
|
||||
SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes)
|
||||
AddToScheme = SchemeBuilder.AddToScheme
|
||||
)
|
||||
|
||||
// Adds the list of known types to api.Scheme.
|
||||
func addKnownTypes(scheme *runtime.Scheme) {
|
||||
func addKnownTypes(scheme *runtime.Scheme) error {
|
||||
scheme.AddKnownTypes(SchemeGroupVersion,
|
||||
&Role{},
|
||||
&RoleBinding{},
|
||||
@@ -55,4 +56,5 @@ func addKnownTypes(scheme *runtime.Scheme) {
|
||||
&ClusterRoleBindingList{},
|
||||
&ClusterRoleList{},
|
||||
)
|
||||
return nil
|
||||
}
|
||||
|
||||
+26
-10
@@ -105,6 +105,8 @@ type RoleBinding struct {
|
||||
RoleRef kapi.ObjectReference
|
||||
}
|
||||
|
||||
type RolesByName map[string]*Role
|
||||
|
||||
// +genclient=true
|
||||
|
||||
// Policy is a object that holds all the Roles for a particular namespace. There is at most
|
||||
@@ -117,9 +119,11 @@ type Policy struct {
|
||||
LastModified unversioned.Time
|
||||
|
||||
// Roles holds all the Roles held by this Policy, mapped by Role.Name
|
||||
Roles map[string]*Role
|
||||
Roles RolesByName
|
||||
}
|
||||
|
||||
type RoleBindingsByName map[string]*RoleBinding
|
||||
|
||||
// PolicyBinding is a object that holds all the RoleBindings for a particular namespace. There is
|
||||
// one PolicyBinding document per referenced Policy namespace
|
||||
type PolicyBinding struct {
|
||||
@@ -133,7 +137,7 @@ type PolicyBinding struct {
|
||||
// PolicyRef is a reference to the Policy that contains all the Roles that this PolicyBinding's RoleBindings may reference
|
||||
PolicyRef kapi.ObjectReference
|
||||
// RoleBindings holds all the RoleBindings held by this PolicyBinding, mapped by RoleBinding.Name
|
||||
RoleBindings map[string]*RoleBinding
|
||||
RoleBindings RoleBindingsByName
|
||||
}
|
||||
|
||||
// SelfSubjectRulesReview is a resource you can create to determine which actions you can perform in a namespace
|
||||
@@ -171,8 +175,10 @@ type ResourceAccessReviewResponse struct {
|
||||
// Namespace is the namespace used for the access review
|
||||
Namespace string
|
||||
// Users is the list of users who can perform the action
|
||||
// +k8s:conversion-gen=false
|
||||
Users sets.String
|
||||
// Groups is the list of groups who can perform the action
|
||||
// +k8s:conversion-gen=false
|
||||
Groups sets.String
|
||||
|
||||
// EvaluationError is an indication that some error occurred during resolution, but partial results can still be returned.
|
||||
@@ -187,7 +193,7 @@ type ResourceAccessReview struct {
|
||||
unversioned.TypeMeta
|
||||
|
||||
// Action describes the action being tested
|
||||
Action AuthorizationAttributes
|
||||
Action
|
||||
}
|
||||
|
||||
// SubjectAccessReviewResponse describes whether or not a user or group can perform an action
|
||||
@@ -200,6 +206,10 @@ type SubjectAccessReviewResponse struct {
|
||||
Allowed bool
|
||||
// Reason is optional. It indicates why a request was allowed or denied.
|
||||
Reason string
|
||||
// EvaluationError is an indication that some error occurred during the authorization check.
|
||||
// It is entirely possible to get an error and be able to continue determine authorization status in spite of it. This is
|
||||
// most common when a bound role is missing, but enough roles are still present and bound to reason about the request.
|
||||
EvaluationError string
|
||||
}
|
||||
|
||||
// SubjectAccessReview is an object for requesting information about whether a user or group can perform an action
|
||||
@@ -207,10 +217,11 @@ type SubjectAccessReview struct {
|
||||
unversioned.TypeMeta
|
||||
|
||||
// Action describes the action being tested
|
||||
Action AuthorizationAttributes
|
||||
Action
|
||||
// User is optional. If both User and Groups are empty, the current authenticated user is used.
|
||||
User string
|
||||
// Groups is optional. Groups is the list of groups to which the User belongs.
|
||||
// +k8s:conversion-gen=false
|
||||
Groups sets.String
|
||||
// Scopes to use for the evaluation. Empty means "use the unscoped (full) permissions of the user/groups".
|
||||
// Nil for a self-SAR, means "use the scopes on this request".
|
||||
@@ -223,7 +234,7 @@ type LocalResourceAccessReview struct {
|
||||
unversioned.TypeMeta
|
||||
|
||||
// Action describes the action being tested
|
||||
Action AuthorizationAttributes
|
||||
Action
|
||||
}
|
||||
|
||||
// LocalSubjectAccessReview is an object for requesting information about whether a user or group can perform an action in a particular namespace
|
||||
@@ -231,10 +242,11 @@ type LocalSubjectAccessReview struct {
|
||||
unversioned.TypeMeta
|
||||
|
||||
// Action describes the action being tested. The Namespace element is FORCED to the current namespace.
|
||||
Action AuthorizationAttributes
|
||||
Action
|
||||
// User is optional. If both User and Groups are empty, the current authenticated user is used.
|
||||
User string
|
||||
// Groups is optional. Groups is the list of groups to which the User belongs.
|
||||
// +k8s:conversion-gen=false
|
||||
Groups sets.String
|
||||
// Scopes to use for the evaluation. Empty means "use the unscoped (full) permissions of the user/groups".
|
||||
// Nil for a self-SAR, means "use the scopes on this request".
|
||||
@@ -242,8 +254,8 @@ type LocalSubjectAccessReview struct {
|
||||
Scopes []string
|
||||
}
|
||||
|
||||
// AuthorizationAttributes describes a request to be authorized
|
||||
type AuthorizationAttributes struct {
|
||||
// Action describes a request to be authorized
|
||||
type Action struct {
|
||||
// Namespace is the namespace of the action being requested. Currently, there is no distinction between no namespace and all namespaces
|
||||
Namespace string
|
||||
// Verb is one of: get, list, watch, create, update, delete
|
||||
@@ -327,6 +339,8 @@ type ClusterRoleBinding struct {
|
||||
RoleRef kapi.ObjectReference
|
||||
}
|
||||
|
||||
type ClusterRolesByName map[string]*ClusterRole
|
||||
|
||||
// ClusterPolicy is a object that holds all the ClusterRoles for a particular namespace. There is at most
|
||||
// one ClusterPolicy document per namespace.
|
||||
type ClusterPolicy struct {
|
||||
@@ -338,9 +352,11 @@ type ClusterPolicy struct {
|
||||
LastModified unversioned.Time
|
||||
|
||||
// Roles holds all the ClusterRoles held by this ClusterPolicy, mapped by Role.Name
|
||||
Roles map[string]*ClusterRole
|
||||
Roles ClusterRolesByName
|
||||
}
|
||||
|
||||
type ClusterRoleBindingsByName map[string]*ClusterRoleBinding
|
||||
|
||||
// ClusterPolicyBinding is a object that holds all the ClusterRoleBindings for a particular namespace. There is
|
||||
// one ClusterPolicyBinding document per referenced ClusterPolicy namespace
|
||||
type ClusterPolicyBinding struct {
|
||||
@@ -354,7 +370,7 @@ type ClusterPolicyBinding struct {
|
||||
// ClusterPolicyRef is a reference to the ClusterPolicy that contains all the ClusterRoles that this ClusterPolicyBinding's RoleBindings may reference
|
||||
PolicyRef kapi.ObjectReference
|
||||
// RoleBindings holds all the RoleBindings held by this ClusterPolicyBinding, mapped by RoleBinding.Name
|
||||
RoleBindings map[string]*ClusterRoleBinding
|
||||
RoleBindings ClusterRoleBindingsByName
|
||||
}
|
||||
|
||||
// ClusterPolicyList is a collection of ClusterPolicies
|
||||
|
||||
Generated
Vendored
+690
@@ -0,0 +1,690 @@
|
||||
// +build !ignore_autogenerated_openshift
|
||||
|
||||
// This file was autogenerated by deepcopy-gen. Do not edit it manually!
|
||||
|
||||
package api
|
||||
|
||||
import (
|
||||
pkg_api "k8s.io/kubernetes/pkg/api"
|
||||
conversion "k8s.io/kubernetes/pkg/conversion"
|
||||
runtime "k8s.io/kubernetes/pkg/runtime"
|
||||
sets "k8s.io/kubernetes/pkg/util/sets"
|
||||
reflect "reflect"
|
||||
)
|
||||
|
||||
func init() {
|
||||
SchemeBuilder.Register(RegisterDeepCopies)
|
||||
}
|
||||
|
||||
// RegisterDeepCopies adds deep-copy functions to the given scheme. Public
|
||||
// to allow building arbitrary schemes.
|
||||
func RegisterDeepCopies(scheme *runtime.Scheme) error {
|
||||
return scheme.AddGeneratedDeepCopyFuncs(
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_Action, InType: reflect.TypeOf(&Action{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_ClusterPolicy, InType: reflect.TypeOf(&ClusterPolicy{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_ClusterPolicyBinding, InType: reflect.TypeOf(&ClusterPolicyBinding{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_ClusterPolicyBindingList, InType: reflect.TypeOf(&ClusterPolicyBindingList{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_ClusterPolicyList, InType: reflect.TypeOf(&ClusterPolicyList{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_ClusterRole, InType: reflect.TypeOf(&ClusterRole{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_ClusterRoleBinding, InType: reflect.TypeOf(&ClusterRoleBinding{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_ClusterRoleBindingList, InType: reflect.TypeOf(&ClusterRoleBindingList{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_ClusterRoleList, InType: reflect.TypeOf(&ClusterRoleList{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_IsPersonalSubjectAccessReview, InType: reflect.TypeOf(&IsPersonalSubjectAccessReview{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_LocalResourceAccessReview, InType: reflect.TypeOf(&LocalResourceAccessReview{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_LocalSubjectAccessReview, InType: reflect.TypeOf(&LocalSubjectAccessReview{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_Policy, InType: reflect.TypeOf(&Policy{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_PolicyBinding, InType: reflect.TypeOf(&PolicyBinding{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_PolicyBindingList, InType: reflect.TypeOf(&PolicyBindingList{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_PolicyList, InType: reflect.TypeOf(&PolicyList{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_PolicyRule, InType: reflect.TypeOf(&PolicyRule{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_PolicyRuleBuilder, InType: reflect.TypeOf(&PolicyRuleBuilder{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_ResourceAccessReview, InType: reflect.TypeOf(&ResourceAccessReview{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_ResourceAccessReviewResponse, InType: reflect.TypeOf(&ResourceAccessReviewResponse{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_Role, InType: reflect.TypeOf(&Role{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_RoleBinding, InType: reflect.TypeOf(&RoleBinding{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_RoleBindingList, InType: reflect.TypeOf(&RoleBindingList{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_RoleList, InType: reflect.TypeOf(&RoleList{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_SelfSubjectRulesReview, InType: reflect.TypeOf(&SelfSubjectRulesReview{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_SelfSubjectRulesReviewSpec, InType: reflect.TypeOf(&SelfSubjectRulesReviewSpec{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_SubjectAccessReview, InType: reflect.TypeOf(&SubjectAccessReview{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_SubjectAccessReviewResponse, InType: reflect.TypeOf(&SubjectAccessReviewResponse{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_SubjectRulesReviewStatus, InType: reflect.TypeOf(&SubjectRulesReviewStatus{})},
|
||||
)
|
||||
}
|
||||
|
||||
func DeepCopy_api_Action(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
{
|
||||
in := in.(*Action)
|
||||
out := out.(*Action)
|
||||
out.Namespace = in.Namespace
|
||||
out.Verb = in.Verb
|
||||
out.Group = in.Group
|
||||
out.Version = in.Version
|
||||
out.Resource = in.Resource
|
||||
out.ResourceName = in.ResourceName
|
||||
if in.Content == nil {
|
||||
out.Content = nil
|
||||
} else if newVal, err := c.DeepCopy(&in.Content); err != nil {
|
||||
return err
|
||||
} else {
|
||||
out.Content = *newVal.(*runtime.Object)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func DeepCopy_api_ClusterPolicy(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
{
|
||||
in := in.(*ClusterPolicy)
|
||||
out := out.(*ClusterPolicy)
|
||||
out.TypeMeta = in.TypeMeta
|
||||
if err := pkg_api.DeepCopy_api_ObjectMeta(&in.ObjectMeta, &out.ObjectMeta, c); err != nil {
|
||||
return err
|
||||
}
|
||||
out.LastModified = in.LastModified.DeepCopy()
|
||||
if in.Roles != nil {
|
||||
in, out := &in.Roles, &out.Roles
|
||||
*out = make(ClusterRolesByName)
|
||||
for key, val := range *in {
|
||||
if newVal, err := c.DeepCopy(&val); err != nil {
|
||||
return err
|
||||
} else {
|
||||
(*out)[key] = *newVal.(**ClusterRole)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.Roles = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func DeepCopy_api_ClusterPolicyBinding(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
{
|
||||
in := in.(*ClusterPolicyBinding)
|
||||
out := out.(*ClusterPolicyBinding)
|
||||
out.TypeMeta = in.TypeMeta
|
||||
if err := pkg_api.DeepCopy_api_ObjectMeta(&in.ObjectMeta, &out.ObjectMeta, c); err != nil {
|
||||
return err
|
||||
}
|
||||
out.LastModified = in.LastModified.DeepCopy()
|
||||
out.PolicyRef = in.PolicyRef
|
||||
if in.RoleBindings != nil {
|
||||
in, out := &in.RoleBindings, &out.RoleBindings
|
||||
*out = make(ClusterRoleBindingsByName)
|
||||
for key, val := range *in {
|
||||
if newVal, err := c.DeepCopy(&val); err != nil {
|
||||
return err
|
||||
} else {
|
||||
(*out)[key] = *newVal.(**ClusterRoleBinding)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.RoleBindings = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func DeepCopy_api_ClusterPolicyBindingList(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
{
|
||||
in := in.(*ClusterPolicyBindingList)
|
||||
out := out.(*ClusterPolicyBindingList)
|
||||
out.TypeMeta = in.TypeMeta
|
||||
out.ListMeta = in.ListMeta
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = make([]ClusterPolicyBinding, len(*in))
|
||||
for i := range *in {
|
||||
if err := DeepCopy_api_ClusterPolicyBinding(&(*in)[i], &(*out)[i], c); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.Items = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func DeepCopy_api_ClusterPolicyList(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
{
|
||||
in := in.(*ClusterPolicyList)
|
||||
out := out.(*ClusterPolicyList)
|
||||
out.TypeMeta = in.TypeMeta
|
||||
out.ListMeta = in.ListMeta
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = make([]ClusterPolicy, len(*in))
|
||||
for i := range *in {
|
||||
if err := DeepCopy_api_ClusterPolicy(&(*in)[i], &(*out)[i], c); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.Items = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func DeepCopy_api_ClusterRole(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
{
|
||||
in := in.(*ClusterRole)
|
||||
out := out.(*ClusterRole)
|
||||
out.TypeMeta = in.TypeMeta
|
||||
if err := pkg_api.DeepCopy_api_ObjectMeta(&in.ObjectMeta, &out.ObjectMeta, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if in.Rules != nil {
|
||||
in, out := &in.Rules, &out.Rules
|
||||
*out = make([]PolicyRule, len(*in))
|
||||
for i := range *in {
|
||||
if err := DeepCopy_api_PolicyRule(&(*in)[i], &(*out)[i], c); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.Rules = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func DeepCopy_api_ClusterRoleBinding(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
{
|
||||
in := in.(*ClusterRoleBinding)
|
||||
out := out.(*ClusterRoleBinding)
|
||||
out.TypeMeta = in.TypeMeta
|
||||
if err := pkg_api.DeepCopy_api_ObjectMeta(&in.ObjectMeta, &out.ObjectMeta, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if in.Subjects != nil {
|
||||
in, out := &in.Subjects, &out.Subjects
|
||||
*out = make([]pkg_api.ObjectReference, len(*in))
|
||||
for i := range *in {
|
||||
(*out)[i] = (*in)[i]
|
||||
}
|
||||
} else {
|
||||
out.Subjects = nil
|
||||
}
|
||||
out.RoleRef = in.RoleRef
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func DeepCopy_api_ClusterRoleBindingList(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
{
|
||||
in := in.(*ClusterRoleBindingList)
|
||||
out := out.(*ClusterRoleBindingList)
|
||||
out.TypeMeta = in.TypeMeta
|
||||
out.ListMeta = in.ListMeta
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = make([]ClusterRoleBinding, len(*in))
|
||||
for i := range *in {
|
||||
if err := DeepCopy_api_ClusterRoleBinding(&(*in)[i], &(*out)[i], c); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.Items = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func DeepCopy_api_ClusterRoleList(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
{
|
||||
in := in.(*ClusterRoleList)
|
||||
out := out.(*ClusterRoleList)
|
||||
out.TypeMeta = in.TypeMeta
|
||||
out.ListMeta = in.ListMeta
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = make([]ClusterRole, len(*in))
|
||||
for i := range *in {
|
||||
if err := DeepCopy_api_ClusterRole(&(*in)[i], &(*out)[i], c); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.Items = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func DeepCopy_api_IsPersonalSubjectAccessReview(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
{
|
||||
in := in.(*IsPersonalSubjectAccessReview)
|
||||
out := out.(*IsPersonalSubjectAccessReview)
|
||||
out.TypeMeta = in.TypeMeta
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func DeepCopy_api_LocalResourceAccessReview(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
{
|
||||
in := in.(*LocalResourceAccessReview)
|
||||
out := out.(*LocalResourceAccessReview)
|
||||
out.TypeMeta = in.TypeMeta
|
||||
if err := DeepCopy_api_Action(&in.Action, &out.Action, c); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func DeepCopy_api_LocalSubjectAccessReview(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
{
|
||||
in := in.(*LocalSubjectAccessReview)
|
||||
out := out.(*LocalSubjectAccessReview)
|
||||
out.TypeMeta = in.TypeMeta
|
||||
if err := DeepCopy_api_Action(&in.Action, &out.Action, c); err != nil {
|
||||
return err
|
||||
}
|
||||
out.User = in.User
|
||||
if in.Groups != nil {
|
||||
in, out := &in.Groups, &out.Groups
|
||||
*out = make(sets.String)
|
||||
for key, val := range *in {
|
||||
(*out)[key] = val
|
||||
}
|
||||
} else {
|
||||
out.Groups = nil
|
||||
}
|
||||
if in.Scopes != nil {
|
||||
in, out := &in.Scopes, &out.Scopes
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
} else {
|
||||
out.Scopes = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func DeepCopy_api_Policy(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
{
|
||||
in := in.(*Policy)
|
||||
out := out.(*Policy)
|
||||
out.TypeMeta = in.TypeMeta
|
||||
if err := pkg_api.DeepCopy_api_ObjectMeta(&in.ObjectMeta, &out.ObjectMeta, c); err != nil {
|
||||
return err
|
||||
}
|
||||
out.LastModified = in.LastModified.DeepCopy()
|
||||
if in.Roles != nil {
|
||||
in, out := &in.Roles, &out.Roles
|
||||
*out = make(RolesByName)
|
||||
for key, val := range *in {
|
||||
if newVal, err := c.DeepCopy(&val); err != nil {
|
||||
return err
|
||||
} else {
|
||||
(*out)[key] = *newVal.(**Role)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.Roles = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func DeepCopy_api_PolicyBinding(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
{
|
||||
in := in.(*PolicyBinding)
|
||||
out := out.(*PolicyBinding)
|
||||
out.TypeMeta = in.TypeMeta
|
||||
if err := pkg_api.DeepCopy_api_ObjectMeta(&in.ObjectMeta, &out.ObjectMeta, c); err != nil {
|
||||
return err
|
||||
}
|
||||
out.LastModified = in.LastModified.DeepCopy()
|
||||
out.PolicyRef = in.PolicyRef
|
||||
if in.RoleBindings != nil {
|
||||
in, out := &in.RoleBindings, &out.RoleBindings
|
||||
*out = make(RoleBindingsByName)
|
||||
for key, val := range *in {
|
||||
if newVal, err := c.DeepCopy(&val); err != nil {
|
||||
return err
|
||||
} else {
|
||||
(*out)[key] = *newVal.(**RoleBinding)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.RoleBindings = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func DeepCopy_api_PolicyBindingList(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
{
|
||||
in := in.(*PolicyBindingList)
|
||||
out := out.(*PolicyBindingList)
|
||||
out.TypeMeta = in.TypeMeta
|
||||
out.ListMeta = in.ListMeta
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = make([]PolicyBinding, len(*in))
|
||||
for i := range *in {
|
||||
if err := DeepCopy_api_PolicyBinding(&(*in)[i], &(*out)[i], c); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.Items = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func DeepCopy_api_PolicyList(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
{
|
||||
in := in.(*PolicyList)
|
||||
out := out.(*PolicyList)
|
||||
out.TypeMeta = in.TypeMeta
|
||||
out.ListMeta = in.ListMeta
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = make([]Policy, len(*in))
|
||||
for i := range *in {
|
||||
if err := DeepCopy_api_Policy(&(*in)[i], &(*out)[i], c); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.Items = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func DeepCopy_api_PolicyRule(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
{
|
||||
in := in.(*PolicyRule)
|
||||
out := out.(*PolicyRule)
|
||||
if in.Verbs != nil {
|
||||
in, out := &in.Verbs, &out.Verbs
|
||||
*out = make(sets.String)
|
||||
for key, val := range *in {
|
||||
(*out)[key] = val
|
||||
}
|
||||
} else {
|
||||
out.Verbs = nil
|
||||
}
|
||||
if in.AttributeRestrictions == nil {
|
||||
out.AttributeRestrictions = nil
|
||||
} else if newVal, err := c.DeepCopy(&in.AttributeRestrictions); err != nil {
|
||||
return err
|
||||
} else {
|
||||
out.AttributeRestrictions = *newVal.(*runtime.Object)
|
||||
}
|
||||
if in.APIGroups != nil {
|
||||
in, out := &in.APIGroups, &out.APIGroups
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
} else {
|
||||
out.APIGroups = nil
|
||||
}
|
||||
if in.Resources != nil {
|
||||
in, out := &in.Resources, &out.Resources
|
||||
*out = make(sets.String)
|
||||
for key, val := range *in {
|
||||
(*out)[key] = val
|
||||
}
|
||||
} else {
|
||||
out.Resources = nil
|
||||
}
|
||||
if in.ResourceNames != nil {
|
||||
in, out := &in.ResourceNames, &out.ResourceNames
|
||||
*out = make(sets.String)
|
||||
for key, val := range *in {
|
||||
(*out)[key] = val
|
||||
}
|
||||
} else {
|
||||
out.ResourceNames = nil
|
||||
}
|
||||
if in.NonResourceURLs != nil {
|
||||
in, out := &in.NonResourceURLs, &out.NonResourceURLs
|
||||
*out = make(sets.String)
|
||||
for key, val := range *in {
|
||||
(*out)[key] = val
|
||||
}
|
||||
} else {
|
||||
out.NonResourceURLs = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func DeepCopy_api_PolicyRuleBuilder(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
{
|
||||
in := in.(*PolicyRuleBuilder)
|
||||
out := out.(*PolicyRuleBuilder)
|
||||
if err := DeepCopy_api_PolicyRule(&in.PolicyRule, &out.PolicyRule, c); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func DeepCopy_api_ResourceAccessReview(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
{
|
||||
in := in.(*ResourceAccessReview)
|
||||
out := out.(*ResourceAccessReview)
|
||||
out.TypeMeta = in.TypeMeta
|
||||
if err := DeepCopy_api_Action(&in.Action, &out.Action, c); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func DeepCopy_api_ResourceAccessReviewResponse(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
{
|
||||
in := in.(*ResourceAccessReviewResponse)
|
||||
out := out.(*ResourceAccessReviewResponse)
|
||||
out.TypeMeta = in.TypeMeta
|
||||
out.Namespace = in.Namespace
|
||||
if in.Users != nil {
|
||||
in, out := &in.Users, &out.Users
|
||||
*out = make(sets.String)
|
||||
for key, val := range *in {
|
||||
(*out)[key] = val
|
||||
}
|
||||
} else {
|
||||
out.Users = nil
|
||||
}
|
||||
if in.Groups != nil {
|
||||
in, out := &in.Groups, &out.Groups
|
||||
*out = make(sets.String)
|
||||
for key, val := range *in {
|
||||
(*out)[key] = val
|
||||
}
|
||||
} else {
|
||||
out.Groups = nil
|
||||
}
|
||||
out.EvaluationError = in.EvaluationError
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func DeepCopy_api_Role(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
{
|
||||
in := in.(*Role)
|
||||
out := out.(*Role)
|
||||
out.TypeMeta = in.TypeMeta
|
||||
if err := pkg_api.DeepCopy_api_ObjectMeta(&in.ObjectMeta, &out.ObjectMeta, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if in.Rules != nil {
|
||||
in, out := &in.Rules, &out.Rules
|
||||
*out = make([]PolicyRule, len(*in))
|
||||
for i := range *in {
|
||||
if err := DeepCopy_api_PolicyRule(&(*in)[i], &(*out)[i], c); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.Rules = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func DeepCopy_api_RoleBinding(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
{
|
||||
in := in.(*RoleBinding)
|
||||
out := out.(*RoleBinding)
|
||||
out.TypeMeta = in.TypeMeta
|
||||
if err := pkg_api.DeepCopy_api_ObjectMeta(&in.ObjectMeta, &out.ObjectMeta, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if in.Subjects != nil {
|
||||
in, out := &in.Subjects, &out.Subjects
|
||||
*out = make([]pkg_api.ObjectReference, len(*in))
|
||||
for i := range *in {
|
||||
(*out)[i] = (*in)[i]
|
||||
}
|
||||
} else {
|
||||
out.Subjects = nil
|
||||
}
|
||||
out.RoleRef = in.RoleRef
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func DeepCopy_api_RoleBindingList(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
{
|
||||
in := in.(*RoleBindingList)
|
||||
out := out.(*RoleBindingList)
|
||||
out.TypeMeta = in.TypeMeta
|
||||
out.ListMeta = in.ListMeta
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = make([]RoleBinding, len(*in))
|
||||
for i := range *in {
|
||||
if err := DeepCopy_api_RoleBinding(&(*in)[i], &(*out)[i], c); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.Items = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func DeepCopy_api_RoleList(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
{
|
||||
in := in.(*RoleList)
|
||||
out := out.(*RoleList)
|
||||
out.TypeMeta = in.TypeMeta
|
||||
out.ListMeta = in.ListMeta
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = make([]Role, len(*in))
|
||||
for i := range *in {
|
||||
if err := DeepCopy_api_Role(&(*in)[i], &(*out)[i], c); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.Items = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func DeepCopy_api_SelfSubjectRulesReview(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
{
|
||||
in := in.(*SelfSubjectRulesReview)
|
||||
out := out.(*SelfSubjectRulesReview)
|
||||
out.TypeMeta = in.TypeMeta
|
||||
if err := DeepCopy_api_SelfSubjectRulesReviewSpec(&in.Spec, &out.Spec, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := DeepCopy_api_SubjectRulesReviewStatus(&in.Status, &out.Status, c); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func DeepCopy_api_SelfSubjectRulesReviewSpec(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
{
|
||||
in := in.(*SelfSubjectRulesReviewSpec)
|
||||
out := out.(*SelfSubjectRulesReviewSpec)
|
||||
if in.Scopes != nil {
|
||||
in, out := &in.Scopes, &out.Scopes
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
} else {
|
||||
out.Scopes = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func DeepCopy_api_SubjectAccessReview(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
{
|
||||
in := in.(*SubjectAccessReview)
|
||||
out := out.(*SubjectAccessReview)
|
||||
out.TypeMeta = in.TypeMeta
|
||||
if err := DeepCopy_api_Action(&in.Action, &out.Action, c); err != nil {
|
||||
return err
|
||||
}
|
||||
out.User = in.User
|
||||
if in.Groups != nil {
|
||||
in, out := &in.Groups, &out.Groups
|
||||
*out = make(sets.String)
|
||||
for key, val := range *in {
|
||||
(*out)[key] = val
|
||||
}
|
||||
} else {
|
||||
out.Groups = nil
|
||||
}
|
||||
if in.Scopes != nil {
|
||||
in, out := &in.Scopes, &out.Scopes
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
} else {
|
||||
out.Scopes = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func DeepCopy_api_SubjectAccessReviewResponse(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
{
|
||||
in := in.(*SubjectAccessReviewResponse)
|
||||
out := out.(*SubjectAccessReviewResponse)
|
||||
out.TypeMeta = in.TypeMeta
|
||||
out.Namespace = in.Namespace
|
||||
out.Allowed = in.Allowed
|
||||
out.Reason = in.Reason
|
||||
out.EvaluationError = in.EvaluationError
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func DeepCopy_api_SubjectRulesReviewStatus(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
{
|
||||
in := in.(*SubjectRulesReviewStatus)
|
||||
out := out.(*SubjectRulesReviewStatus)
|
||||
if in.Rules != nil {
|
||||
in, out := &in.Rules, &out.Rules
|
||||
*out = make([]PolicyRule, len(*in))
|
||||
for i := range *in {
|
||||
if err := DeepCopy_api_PolicyRule(&(*in)[i], &(*out)[i], c); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.Rules = nil
|
||||
}
|
||||
out.EvaluationError = in.EvaluationError
|
||||
return nil
|
||||
}
|
||||
}
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
package reaper
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/golang/glog"
|
||||
kapi "k8s.io/kubernetes/pkg/api"
|
||||
kerrors "k8s.io/kubernetes/pkg/api/errors"
|
||||
"k8s.io/kubernetes/pkg/kubectl"
|
||||
|
||||
"github.com/openshift/origin/pkg/client"
|
||||
)
|
||||
|
||||
func NewClusterRoleReaper(roleClient client.ClusterRolesInterface, clusterBindingClient client.ClusterRoleBindingsInterface, bindingClient client.RoleBindingsNamespacer) kubectl.Reaper {
|
||||
return &ClusterRoleReaper{
|
||||
roleClient: roleClient,
|
||||
clusterBindingClient: clusterBindingClient,
|
||||
bindingClient: bindingClient,
|
||||
}
|
||||
}
|
||||
|
||||
type ClusterRoleReaper struct {
|
||||
roleClient client.ClusterRolesInterface
|
||||
clusterBindingClient client.ClusterRoleBindingsInterface
|
||||
bindingClient client.RoleBindingsNamespacer
|
||||
}
|
||||
|
||||
// Stop on a reaper is actually used for deletion. In this case, we'll delete referencing clusterroleclusterBindings
|
||||
// then delete the clusterrole.
|
||||
func (r *ClusterRoleReaper) Stop(namespace, name string, timeout time.Duration, gracePeriod *kapi.DeleteOptions) error {
|
||||
clusterBindings, err := r.clusterBindingClient.ClusterRoleBindings().List(kapi.ListOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, clusterBinding := range clusterBindings.Items {
|
||||
if clusterBinding.RoleRef.Name == name {
|
||||
if err := r.clusterBindingClient.ClusterRoleBindings().Delete(clusterBinding.Name); err != nil && !kerrors.IsNotFound(err) {
|
||||
glog.Infof("Cannot delete clusterrolebinding/%s: %v", clusterBinding.Name, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespacedBindings, err := r.bindingClient.RoleBindings(kapi.NamespaceNone).List(kapi.ListOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, namespacedBinding := range namespacedBindings.Items {
|
||||
if namespacedBinding.RoleRef.Namespace == kapi.NamespaceNone && namespacedBinding.RoleRef.Name == name {
|
||||
if err := r.bindingClient.RoleBindings(namespacedBinding.Namespace).Delete(namespacedBinding.Name); err != nil && !kerrors.IsNotFound(err) {
|
||||
glog.Infof("Cannot delete rolebinding/%s in %s: %v", namespacedBinding.Name, namespacedBinding.Namespace, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err := r.roleClient.ClusterRoles().Delete(name); err != nil && !kerrors.IsNotFound(err) {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
package reaper
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/golang/glog"
|
||||
kapi "k8s.io/kubernetes/pkg/api"
|
||||
kerrors "k8s.io/kubernetes/pkg/api/errors"
|
||||
"k8s.io/kubernetes/pkg/kubectl"
|
||||
|
||||
"github.com/openshift/origin/pkg/client"
|
||||
)
|
||||
|
||||
func NewRoleReaper(roleClient client.RolesNamespacer, bindingClient client.RoleBindingsNamespacer) kubectl.Reaper {
|
||||
return &RoleReaper{
|
||||
roleClient: roleClient,
|
||||
bindingClient: bindingClient,
|
||||
}
|
||||
}
|
||||
|
||||
type RoleReaper struct {
|
||||
roleClient client.RolesNamespacer
|
||||
bindingClient client.RoleBindingsNamespacer
|
||||
}
|
||||
|
||||
// Stop on a reaper is actually used for deletion. In this case, we'll delete referencing rolebindings
|
||||
// then delete the role.
|
||||
func (r *RoleReaper) Stop(namespace, name string, timeout time.Duration, gracePeriod *kapi.DeleteOptions) error {
|
||||
bindings, err := r.bindingClient.RoleBindings(namespace).List(kapi.ListOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, binding := range bindings.Items {
|
||||
if binding.RoleRef.Namespace == namespace && binding.RoleRef.Name == name {
|
||||
if err := r.bindingClient.RoleBindings(namespace).Delete(binding.Name); err != nil && !kerrors.IsNotFound(err) {
|
||||
glog.Infof("Cannot delete rolebinding/%s: %v", binding.Name, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err := r.roleClient.Roles(namespace).Delete(name); err != nil && !kerrors.IsNotFound(err) {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
-937
@@ -1,937 +0,0 @@
|
||||
// +build !ignore_autogenerated_openshift
|
||||
|
||||
// This file was autogenerated by deepcopy-gen. Do not edit it manually!
|
||||
|
||||
package api
|
||||
|
||||
import (
|
||||
api "k8s.io/kubernetes/pkg/api"
|
||||
unversioned "k8s.io/kubernetes/pkg/api/unversioned"
|
||||
conversion "k8s.io/kubernetes/pkg/conversion"
|
||||
)
|
||||
|
||||
func init() {
|
||||
if err := api.Scheme.AddGeneratedDeepCopyFuncs(
|
||||
DeepCopy_api_BinaryBuildRequestOptions,
|
||||
DeepCopy_api_BinaryBuildSource,
|
||||
DeepCopy_api_Build,
|
||||
DeepCopy_api_BuildConfig,
|
||||
DeepCopy_api_BuildConfigList,
|
||||
DeepCopy_api_BuildConfigSpec,
|
||||
DeepCopy_api_BuildConfigStatus,
|
||||
DeepCopy_api_BuildList,
|
||||
DeepCopy_api_BuildLog,
|
||||
DeepCopy_api_BuildLogOptions,
|
||||
DeepCopy_api_BuildOutput,
|
||||
DeepCopy_api_BuildPostCommitSpec,
|
||||
DeepCopy_api_BuildRequest,
|
||||
DeepCopy_api_BuildSource,
|
||||
DeepCopy_api_BuildSpec,
|
||||
DeepCopy_api_BuildStatus,
|
||||
DeepCopy_api_BuildStrategy,
|
||||
DeepCopy_api_BuildTriggerCause,
|
||||
DeepCopy_api_BuildTriggerPolicy,
|
||||
DeepCopy_api_CommonSpec,
|
||||
DeepCopy_api_CustomBuildStrategy,
|
||||
DeepCopy_api_DockerBuildStrategy,
|
||||
DeepCopy_api_GenericWebHookCause,
|
||||
DeepCopy_api_GenericWebHookEvent,
|
||||
DeepCopy_api_GitBuildSource,
|
||||
DeepCopy_api_GitHubWebHookCause,
|
||||
DeepCopy_api_GitInfo,
|
||||
DeepCopy_api_GitRefInfo,
|
||||
DeepCopy_api_GitSourceRevision,
|
||||
DeepCopy_api_ImageChangeCause,
|
||||
DeepCopy_api_ImageChangeTrigger,
|
||||
DeepCopy_api_ImageSource,
|
||||
DeepCopy_api_ImageSourcePath,
|
||||
DeepCopy_api_JenkinsPipelineBuildStrategy,
|
||||
DeepCopy_api_SecretBuildSource,
|
||||
DeepCopy_api_SecretSpec,
|
||||
DeepCopy_api_SourceBuildStrategy,
|
||||
DeepCopy_api_SourceControlUser,
|
||||
DeepCopy_api_SourceRevision,
|
||||
DeepCopy_api_WebHookTrigger,
|
||||
); err != nil {
|
||||
// if one of the deep copy functions is malformed, detect it immediately.
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func DeepCopy_api_BinaryBuildRequestOptions(in BinaryBuildRequestOptions, out *BinaryBuildRequestOptions, c *conversion.Cloner) error {
|
||||
if err := unversioned.DeepCopy_unversioned_TypeMeta(in.TypeMeta, &out.TypeMeta, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := api.DeepCopy_api_ObjectMeta(in.ObjectMeta, &out.ObjectMeta, c); err != nil {
|
||||
return err
|
||||
}
|
||||
out.AsFile = in.AsFile
|
||||
out.Commit = in.Commit
|
||||
out.Message = in.Message
|
||||
out.AuthorName = in.AuthorName
|
||||
out.AuthorEmail = in.AuthorEmail
|
||||
out.CommitterName = in.CommitterName
|
||||
out.CommitterEmail = in.CommitterEmail
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeepCopy_api_BinaryBuildSource(in BinaryBuildSource, out *BinaryBuildSource, c *conversion.Cloner) error {
|
||||
out.AsFile = in.AsFile
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeepCopy_api_Build(in Build, out *Build, c *conversion.Cloner) error {
|
||||
if err := unversioned.DeepCopy_unversioned_TypeMeta(in.TypeMeta, &out.TypeMeta, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := api.DeepCopy_api_ObjectMeta(in.ObjectMeta, &out.ObjectMeta, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := DeepCopy_api_BuildSpec(in.Spec, &out.Spec, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := DeepCopy_api_BuildStatus(in.Status, &out.Status, c); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeepCopy_api_BuildConfig(in BuildConfig, out *BuildConfig, c *conversion.Cloner) error {
|
||||
if err := unversioned.DeepCopy_unversioned_TypeMeta(in.TypeMeta, &out.TypeMeta, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := api.DeepCopy_api_ObjectMeta(in.ObjectMeta, &out.ObjectMeta, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := DeepCopy_api_BuildConfigSpec(in.Spec, &out.Spec, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := DeepCopy_api_BuildConfigStatus(in.Status, &out.Status, c); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeepCopy_api_BuildConfigList(in BuildConfigList, out *BuildConfigList, c *conversion.Cloner) error {
|
||||
if err := unversioned.DeepCopy_unversioned_TypeMeta(in.TypeMeta, &out.TypeMeta, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := unversioned.DeepCopy_unversioned_ListMeta(in.ListMeta, &out.ListMeta, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if in.Items != nil {
|
||||
in, out := in.Items, &out.Items
|
||||
*out = make([]BuildConfig, len(in))
|
||||
for i := range in {
|
||||
if err := DeepCopy_api_BuildConfig(in[i], &(*out)[i], c); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.Items = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeepCopy_api_BuildConfigSpec(in BuildConfigSpec, out *BuildConfigSpec, c *conversion.Cloner) error {
|
||||
if in.Triggers != nil {
|
||||
in, out := in.Triggers, &out.Triggers
|
||||
*out = make([]BuildTriggerPolicy, len(in))
|
||||
for i := range in {
|
||||
if err := DeepCopy_api_BuildTriggerPolicy(in[i], &(*out)[i], c); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.Triggers = nil
|
||||
}
|
||||
out.RunPolicy = in.RunPolicy
|
||||
if err := DeepCopy_api_CommonSpec(in.CommonSpec, &out.CommonSpec, c); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeepCopy_api_BuildConfigStatus(in BuildConfigStatus, out *BuildConfigStatus, c *conversion.Cloner) error {
|
||||
out.LastVersion = in.LastVersion
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeepCopy_api_BuildList(in BuildList, out *BuildList, c *conversion.Cloner) error {
|
||||
if err := unversioned.DeepCopy_unversioned_TypeMeta(in.TypeMeta, &out.TypeMeta, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := unversioned.DeepCopy_unversioned_ListMeta(in.ListMeta, &out.ListMeta, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if in.Items != nil {
|
||||
in, out := in.Items, &out.Items
|
||||
*out = make([]Build, len(in))
|
||||
for i := range in {
|
||||
if err := DeepCopy_api_Build(in[i], &(*out)[i], c); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.Items = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeepCopy_api_BuildLog(in BuildLog, out *BuildLog, c *conversion.Cloner) error {
|
||||
if err := unversioned.DeepCopy_unversioned_TypeMeta(in.TypeMeta, &out.TypeMeta, c); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeepCopy_api_BuildLogOptions(in BuildLogOptions, out *BuildLogOptions, c *conversion.Cloner) error {
|
||||
if err := unversioned.DeepCopy_unversioned_TypeMeta(in.TypeMeta, &out.TypeMeta, c); err != nil {
|
||||
return err
|
||||
}
|
||||
out.Container = in.Container
|
||||
out.Follow = in.Follow
|
||||
out.Previous = in.Previous
|
||||
if in.SinceSeconds != nil {
|
||||
in, out := in.SinceSeconds, &out.SinceSeconds
|
||||
*out = new(int64)
|
||||
**out = *in
|
||||
} else {
|
||||
out.SinceSeconds = nil
|
||||
}
|
||||
if in.SinceTime != nil {
|
||||
in, out := in.SinceTime, &out.SinceTime
|
||||
*out = new(unversioned.Time)
|
||||
if err := unversioned.DeepCopy_unversioned_Time(*in, *out, c); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
out.SinceTime = nil
|
||||
}
|
||||
out.Timestamps = in.Timestamps
|
||||
if in.TailLines != nil {
|
||||
in, out := in.TailLines, &out.TailLines
|
||||
*out = new(int64)
|
||||
**out = *in
|
||||
} else {
|
||||
out.TailLines = nil
|
||||
}
|
||||
if in.LimitBytes != nil {
|
||||
in, out := in.LimitBytes, &out.LimitBytes
|
||||
*out = new(int64)
|
||||
**out = *in
|
||||
} else {
|
||||
out.LimitBytes = nil
|
||||
}
|
||||
out.NoWait = in.NoWait
|
||||
if in.Version != nil {
|
||||
in, out := in.Version, &out.Version
|
||||
*out = new(int64)
|
||||
**out = *in
|
||||
} else {
|
||||
out.Version = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeepCopy_api_BuildOutput(in BuildOutput, out *BuildOutput, c *conversion.Cloner) error {
|
||||
if in.To != nil {
|
||||
in, out := in.To, &out.To
|
||||
*out = new(api.ObjectReference)
|
||||
if err := api.DeepCopy_api_ObjectReference(*in, *out, c); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
out.To = nil
|
||||
}
|
||||
if in.PushSecret != nil {
|
||||
in, out := in.PushSecret, &out.PushSecret
|
||||
*out = new(api.LocalObjectReference)
|
||||
if err := api.DeepCopy_api_LocalObjectReference(*in, *out, c); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
out.PushSecret = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeepCopy_api_BuildPostCommitSpec(in BuildPostCommitSpec, out *BuildPostCommitSpec, c *conversion.Cloner) error {
|
||||
if in.Command != nil {
|
||||
in, out := in.Command, &out.Command
|
||||
*out = make([]string, len(in))
|
||||
copy(*out, in)
|
||||
} else {
|
||||
out.Command = nil
|
||||
}
|
||||
if in.Args != nil {
|
||||
in, out := in.Args, &out.Args
|
||||
*out = make([]string, len(in))
|
||||
copy(*out, in)
|
||||
} else {
|
||||
out.Args = nil
|
||||
}
|
||||
out.Script = in.Script
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeepCopy_api_BuildRequest(in BuildRequest, out *BuildRequest, c *conversion.Cloner) error {
|
||||
if err := unversioned.DeepCopy_unversioned_TypeMeta(in.TypeMeta, &out.TypeMeta, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := api.DeepCopy_api_ObjectMeta(in.ObjectMeta, &out.ObjectMeta, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if in.Revision != nil {
|
||||
in, out := in.Revision, &out.Revision
|
||||
*out = new(SourceRevision)
|
||||
if err := DeepCopy_api_SourceRevision(*in, *out, c); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
out.Revision = nil
|
||||
}
|
||||
if in.TriggeredByImage != nil {
|
||||
in, out := in.TriggeredByImage, &out.TriggeredByImage
|
||||
*out = new(api.ObjectReference)
|
||||
if err := api.DeepCopy_api_ObjectReference(*in, *out, c); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
out.TriggeredByImage = nil
|
||||
}
|
||||
if in.From != nil {
|
||||
in, out := in.From, &out.From
|
||||
*out = new(api.ObjectReference)
|
||||
if err := api.DeepCopy_api_ObjectReference(*in, *out, c); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
out.From = nil
|
||||
}
|
||||
if in.Binary != nil {
|
||||
in, out := in.Binary, &out.Binary
|
||||
*out = new(BinaryBuildSource)
|
||||
if err := DeepCopy_api_BinaryBuildSource(*in, *out, c); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
out.Binary = nil
|
||||
}
|
||||
if in.LastVersion != nil {
|
||||
in, out := in.LastVersion, &out.LastVersion
|
||||
*out = new(int64)
|
||||
**out = *in
|
||||
} else {
|
||||
out.LastVersion = nil
|
||||
}
|
||||
if in.Env != nil {
|
||||
in, out := in.Env, &out.Env
|
||||
*out = make([]api.EnvVar, len(in))
|
||||
for i := range in {
|
||||
if err := api.DeepCopy_api_EnvVar(in[i], &(*out)[i], c); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.Env = nil
|
||||
}
|
||||
if in.TriggeredBy != nil {
|
||||
in, out := in.TriggeredBy, &out.TriggeredBy
|
||||
*out = make([]BuildTriggerCause, len(in))
|
||||
for i := range in {
|
||||
if err := DeepCopy_api_BuildTriggerCause(in[i], &(*out)[i], c); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.TriggeredBy = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeepCopy_api_BuildSource(in BuildSource, out *BuildSource, c *conversion.Cloner) error {
|
||||
if in.Binary != nil {
|
||||
in, out := in.Binary, &out.Binary
|
||||
*out = new(BinaryBuildSource)
|
||||
if err := DeepCopy_api_BinaryBuildSource(*in, *out, c); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
out.Binary = nil
|
||||
}
|
||||
if in.Dockerfile != nil {
|
||||
in, out := in.Dockerfile, &out.Dockerfile
|
||||
*out = new(string)
|
||||
**out = *in
|
||||
} else {
|
||||
out.Dockerfile = nil
|
||||
}
|
||||
if in.Git != nil {
|
||||
in, out := in.Git, &out.Git
|
||||
*out = new(GitBuildSource)
|
||||
if err := DeepCopy_api_GitBuildSource(*in, *out, c); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
out.Git = nil
|
||||
}
|
||||
if in.Images != nil {
|
||||
in, out := in.Images, &out.Images
|
||||
*out = make([]ImageSource, len(in))
|
||||
for i := range in {
|
||||
if err := DeepCopy_api_ImageSource(in[i], &(*out)[i], c); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.Images = nil
|
||||
}
|
||||
out.ContextDir = in.ContextDir
|
||||
if in.SourceSecret != nil {
|
||||
in, out := in.SourceSecret, &out.SourceSecret
|
||||
*out = new(api.LocalObjectReference)
|
||||
if err := api.DeepCopy_api_LocalObjectReference(*in, *out, c); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
out.SourceSecret = nil
|
||||
}
|
||||
if in.Secrets != nil {
|
||||
in, out := in.Secrets, &out.Secrets
|
||||
*out = make([]SecretBuildSource, len(in))
|
||||
for i := range in {
|
||||
if err := DeepCopy_api_SecretBuildSource(in[i], &(*out)[i], c); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.Secrets = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeepCopy_api_BuildSpec(in BuildSpec, out *BuildSpec, c *conversion.Cloner) error {
|
||||
if err := DeepCopy_api_CommonSpec(in.CommonSpec, &out.CommonSpec, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if in.TriggeredBy != nil {
|
||||
in, out := in.TriggeredBy, &out.TriggeredBy
|
||||
*out = make([]BuildTriggerCause, len(in))
|
||||
for i := range in {
|
||||
if err := DeepCopy_api_BuildTriggerCause(in[i], &(*out)[i], c); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.TriggeredBy = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeepCopy_api_BuildStatus(in BuildStatus, out *BuildStatus, c *conversion.Cloner) error {
|
||||
out.Phase = in.Phase
|
||||
out.Cancelled = in.Cancelled
|
||||
out.Reason = in.Reason
|
||||
out.Message = in.Message
|
||||
if in.StartTimestamp != nil {
|
||||
in, out := in.StartTimestamp, &out.StartTimestamp
|
||||
*out = new(unversioned.Time)
|
||||
if err := unversioned.DeepCopy_unversioned_Time(*in, *out, c); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
out.StartTimestamp = nil
|
||||
}
|
||||
if in.CompletionTimestamp != nil {
|
||||
in, out := in.CompletionTimestamp, &out.CompletionTimestamp
|
||||
*out = new(unversioned.Time)
|
||||
if err := unversioned.DeepCopy_unversioned_Time(*in, *out, c); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
out.CompletionTimestamp = nil
|
||||
}
|
||||
out.Duration = in.Duration
|
||||
out.OutputDockerImageReference = in.OutputDockerImageReference
|
||||
if in.Config != nil {
|
||||
in, out := in.Config, &out.Config
|
||||
*out = new(api.ObjectReference)
|
||||
if err := api.DeepCopy_api_ObjectReference(*in, *out, c); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
out.Config = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeepCopy_api_BuildStrategy(in BuildStrategy, out *BuildStrategy, c *conversion.Cloner) error {
|
||||
if in.DockerStrategy != nil {
|
||||
in, out := in.DockerStrategy, &out.DockerStrategy
|
||||
*out = new(DockerBuildStrategy)
|
||||
if err := DeepCopy_api_DockerBuildStrategy(*in, *out, c); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
out.DockerStrategy = nil
|
||||
}
|
||||
if in.SourceStrategy != nil {
|
||||
in, out := in.SourceStrategy, &out.SourceStrategy
|
||||
*out = new(SourceBuildStrategy)
|
||||
if err := DeepCopy_api_SourceBuildStrategy(*in, *out, c); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
out.SourceStrategy = nil
|
||||
}
|
||||
if in.CustomStrategy != nil {
|
||||
in, out := in.CustomStrategy, &out.CustomStrategy
|
||||
*out = new(CustomBuildStrategy)
|
||||
if err := DeepCopy_api_CustomBuildStrategy(*in, *out, c); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
out.CustomStrategy = nil
|
||||
}
|
||||
if in.JenkinsPipelineStrategy != nil {
|
||||
in, out := in.JenkinsPipelineStrategy, &out.JenkinsPipelineStrategy
|
||||
*out = new(JenkinsPipelineBuildStrategy)
|
||||
if err := DeepCopy_api_JenkinsPipelineBuildStrategy(*in, *out, c); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
out.JenkinsPipelineStrategy = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeepCopy_api_BuildTriggerCause(in BuildTriggerCause, out *BuildTriggerCause, c *conversion.Cloner) error {
|
||||
out.Message = in.Message
|
||||
if in.GenericWebHook != nil {
|
||||
in, out := in.GenericWebHook, &out.GenericWebHook
|
||||
*out = new(GenericWebHookCause)
|
||||
if err := DeepCopy_api_GenericWebHookCause(*in, *out, c); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
out.GenericWebHook = nil
|
||||
}
|
||||
if in.GitHubWebHook != nil {
|
||||
in, out := in.GitHubWebHook, &out.GitHubWebHook
|
||||
*out = new(GitHubWebHookCause)
|
||||
if err := DeepCopy_api_GitHubWebHookCause(*in, *out, c); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
out.GitHubWebHook = nil
|
||||
}
|
||||
if in.ImageChangeBuild != nil {
|
||||
in, out := in.ImageChangeBuild, &out.ImageChangeBuild
|
||||
*out = new(ImageChangeCause)
|
||||
if err := DeepCopy_api_ImageChangeCause(*in, *out, c); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
out.ImageChangeBuild = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeepCopy_api_BuildTriggerPolicy(in BuildTriggerPolicy, out *BuildTriggerPolicy, c *conversion.Cloner) error {
|
||||
out.Type = in.Type
|
||||
if in.GitHubWebHook != nil {
|
||||
in, out := in.GitHubWebHook, &out.GitHubWebHook
|
||||
*out = new(WebHookTrigger)
|
||||
if err := DeepCopy_api_WebHookTrigger(*in, *out, c); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
out.GitHubWebHook = nil
|
||||
}
|
||||
if in.GenericWebHook != nil {
|
||||
in, out := in.GenericWebHook, &out.GenericWebHook
|
||||
*out = new(WebHookTrigger)
|
||||
if err := DeepCopy_api_WebHookTrigger(*in, *out, c); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
out.GenericWebHook = nil
|
||||
}
|
||||
if in.ImageChange != nil {
|
||||
in, out := in.ImageChange, &out.ImageChange
|
||||
*out = new(ImageChangeTrigger)
|
||||
if err := DeepCopy_api_ImageChangeTrigger(*in, *out, c); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
out.ImageChange = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeepCopy_api_CommonSpec(in CommonSpec, out *CommonSpec, c *conversion.Cloner) error {
|
||||
out.ServiceAccount = in.ServiceAccount
|
||||
if err := DeepCopy_api_BuildSource(in.Source, &out.Source, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if in.Revision != nil {
|
||||
in, out := in.Revision, &out.Revision
|
||||
*out = new(SourceRevision)
|
||||
if err := DeepCopy_api_SourceRevision(*in, *out, c); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
out.Revision = nil
|
||||
}
|
||||
if err := DeepCopy_api_BuildStrategy(in.Strategy, &out.Strategy, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := DeepCopy_api_BuildOutput(in.Output, &out.Output, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := api.DeepCopy_api_ResourceRequirements(in.Resources, &out.Resources, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := DeepCopy_api_BuildPostCommitSpec(in.PostCommit, &out.PostCommit, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if in.CompletionDeadlineSeconds != nil {
|
||||
in, out := in.CompletionDeadlineSeconds, &out.CompletionDeadlineSeconds
|
||||
*out = new(int64)
|
||||
**out = *in
|
||||
} else {
|
||||
out.CompletionDeadlineSeconds = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeepCopy_api_CustomBuildStrategy(in CustomBuildStrategy, out *CustomBuildStrategy, c *conversion.Cloner) error {
|
||||
if err := api.DeepCopy_api_ObjectReference(in.From, &out.From, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if in.PullSecret != nil {
|
||||
in, out := in.PullSecret, &out.PullSecret
|
||||
*out = new(api.LocalObjectReference)
|
||||
if err := api.DeepCopy_api_LocalObjectReference(*in, *out, c); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
out.PullSecret = nil
|
||||
}
|
||||
if in.Env != nil {
|
||||
in, out := in.Env, &out.Env
|
||||
*out = make([]api.EnvVar, len(in))
|
||||
for i := range in {
|
||||
if err := api.DeepCopy_api_EnvVar(in[i], &(*out)[i], c); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.Env = nil
|
||||
}
|
||||
out.ExposeDockerSocket = in.ExposeDockerSocket
|
||||
out.ForcePull = in.ForcePull
|
||||
if in.Secrets != nil {
|
||||
in, out := in.Secrets, &out.Secrets
|
||||
*out = make([]SecretSpec, len(in))
|
||||
for i := range in {
|
||||
if err := DeepCopy_api_SecretSpec(in[i], &(*out)[i], c); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.Secrets = nil
|
||||
}
|
||||
out.BuildAPIVersion = in.BuildAPIVersion
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeepCopy_api_DockerBuildStrategy(in DockerBuildStrategy, out *DockerBuildStrategy, c *conversion.Cloner) error {
|
||||
if in.From != nil {
|
||||
in, out := in.From, &out.From
|
||||
*out = new(api.ObjectReference)
|
||||
if err := api.DeepCopy_api_ObjectReference(*in, *out, c); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
out.From = nil
|
||||
}
|
||||
if in.PullSecret != nil {
|
||||
in, out := in.PullSecret, &out.PullSecret
|
||||
*out = new(api.LocalObjectReference)
|
||||
if err := api.DeepCopy_api_LocalObjectReference(*in, *out, c); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
out.PullSecret = nil
|
||||
}
|
||||
out.NoCache = in.NoCache
|
||||
if in.Env != nil {
|
||||
in, out := in.Env, &out.Env
|
||||
*out = make([]api.EnvVar, len(in))
|
||||
for i := range in {
|
||||
if err := api.DeepCopy_api_EnvVar(in[i], &(*out)[i], c); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.Env = nil
|
||||
}
|
||||
out.ForcePull = in.ForcePull
|
||||
out.DockerfilePath = in.DockerfilePath
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeepCopy_api_GenericWebHookCause(in GenericWebHookCause, out *GenericWebHookCause, c *conversion.Cloner) error {
|
||||
if in.Revision != nil {
|
||||
in, out := in.Revision, &out.Revision
|
||||
*out = new(SourceRevision)
|
||||
if err := DeepCopy_api_SourceRevision(*in, *out, c); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
out.Revision = nil
|
||||
}
|
||||
out.Secret = in.Secret
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeepCopy_api_GenericWebHookEvent(in GenericWebHookEvent, out *GenericWebHookEvent, c *conversion.Cloner) error {
|
||||
if in.Git != nil {
|
||||
in, out := in.Git, &out.Git
|
||||
*out = new(GitInfo)
|
||||
if err := DeepCopy_api_GitInfo(*in, *out, c); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
out.Git = nil
|
||||
}
|
||||
if in.Env != nil {
|
||||
in, out := in.Env, &out.Env
|
||||
*out = make([]api.EnvVar, len(in))
|
||||
for i := range in {
|
||||
if err := api.DeepCopy_api_EnvVar(in[i], &(*out)[i], c); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.Env = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeepCopy_api_GitBuildSource(in GitBuildSource, out *GitBuildSource, c *conversion.Cloner) error {
|
||||
out.URI = in.URI
|
||||
out.Ref = in.Ref
|
||||
if in.HTTPProxy != nil {
|
||||
in, out := in.HTTPProxy, &out.HTTPProxy
|
||||
*out = new(string)
|
||||
**out = *in
|
||||
} else {
|
||||
out.HTTPProxy = nil
|
||||
}
|
||||
if in.HTTPSProxy != nil {
|
||||
in, out := in.HTTPSProxy, &out.HTTPSProxy
|
||||
*out = new(string)
|
||||
**out = *in
|
||||
} else {
|
||||
out.HTTPSProxy = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeepCopy_api_GitHubWebHookCause(in GitHubWebHookCause, out *GitHubWebHookCause, c *conversion.Cloner) error {
|
||||
if in.Revision != nil {
|
||||
in, out := in.Revision, &out.Revision
|
||||
*out = new(SourceRevision)
|
||||
if err := DeepCopy_api_SourceRevision(*in, *out, c); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
out.Revision = nil
|
||||
}
|
||||
out.Secret = in.Secret
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeepCopy_api_GitInfo(in GitInfo, out *GitInfo, c *conversion.Cloner) error {
|
||||
if err := DeepCopy_api_GitBuildSource(in.GitBuildSource, &out.GitBuildSource, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := DeepCopy_api_GitSourceRevision(in.GitSourceRevision, &out.GitSourceRevision, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if in.Refs != nil {
|
||||
in, out := in.Refs, &out.Refs
|
||||
*out = make([]GitRefInfo, len(in))
|
||||
for i := range in {
|
||||
if err := DeepCopy_api_GitRefInfo(in[i], &(*out)[i], c); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.Refs = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeepCopy_api_GitRefInfo(in GitRefInfo, out *GitRefInfo, c *conversion.Cloner) error {
|
||||
if err := DeepCopy_api_GitBuildSource(in.GitBuildSource, &out.GitBuildSource, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := DeepCopy_api_GitSourceRevision(in.GitSourceRevision, &out.GitSourceRevision, c); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeepCopy_api_GitSourceRevision(in GitSourceRevision, out *GitSourceRevision, c *conversion.Cloner) error {
|
||||
out.Commit = in.Commit
|
||||
if err := DeepCopy_api_SourceControlUser(in.Author, &out.Author, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := DeepCopy_api_SourceControlUser(in.Committer, &out.Committer, c); err != nil {
|
||||
return err
|
||||
}
|
||||
out.Message = in.Message
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeepCopy_api_ImageChangeCause(in ImageChangeCause, out *ImageChangeCause, c *conversion.Cloner) error {
|
||||
out.ImageID = in.ImageID
|
||||
if in.FromRef != nil {
|
||||
in, out := in.FromRef, &out.FromRef
|
||||
*out = new(api.ObjectReference)
|
||||
if err := api.DeepCopy_api_ObjectReference(*in, *out, c); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
out.FromRef = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeepCopy_api_ImageChangeTrigger(in ImageChangeTrigger, out *ImageChangeTrigger, c *conversion.Cloner) error {
|
||||
out.LastTriggeredImageID = in.LastTriggeredImageID
|
||||
if in.From != nil {
|
||||
in, out := in.From, &out.From
|
||||
*out = new(api.ObjectReference)
|
||||
if err := api.DeepCopy_api_ObjectReference(*in, *out, c); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
out.From = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeepCopy_api_ImageSource(in ImageSource, out *ImageSource, c *conversion.Cloner) error {
|
||||
if err := api.DeepCopy_api_ObjectReference(in.From, &out.From, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if in.Paths != nil {
|
||||
in, out := in.Paths, &out.Paths
|
||||
*out = make([]ImageSourcePath, len(in))
|
||||
for i := range in {
|
||||
if err := DeepCopy_api_ImageSourcePath(in[i], &(*out)[i], c); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.Paths = nil
|
||||
}
|
||||
if in.PullSecret != nil {
|
||||
in, out := in.PullSecret, &out.PullSecret
|
||||
*out = new(api.LocalObjectReference)
|
||||
if err := api.DeepCopy_api_LocalObjectReference(*in, *out, c); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
out.PullSecret = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeepCopy_api_ImageSourcePath(in ImageSourcePath, out *ImageSourcePath, c *conversion.Cloner) error {
|
||||
out.SourcePath = in.SourcePath
|
||||
out.DestinationDir = in.DestinationDir
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeepCopy_api_JenkinsPipelineBuildStrategy(in JenkinsPipelineBuildStrategy, out *JenkinsPipelineBuildStrategy, c *conversion.Cloner) error {
|
||||
out.JenkinsfilePath = in.JenkinsfilePath
|
||||
out.Jenkinsfile = in.Jenkinsfile
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeepCopy_api_SecretBuildSource(in SecretBuildSource, out *SecretBuildSource, c *conversion.Cloner) error {
|
||||
if err := api.DeepCopy_api_LocalObjectReference(in.Secret, &out.Secret, c); err != nil {
|
||||
return err
|
||||
}
|
||||
out.DestinationDir = in.DestinationDir
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeepCopy_api_SecretSpec(in SecretSpec, out *SecretSpec, c *conversion.Cloner) error {
|
||||
if err := api.DeepCopy_api_LocalObjectReference(in.SecretSource, &out.SecretSource, c); err != nil {
|
||||
return err
|
||||
}
|
||||
out.MountPath = in.MountPath
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeepCopy_api_SourceBuildStrategy(in SourceBuildStrategy, out *SourceBuildStrategy, c *conversion.Cloner) error {
|
||||
if err := api.DeepCopy_api_ObjectReference(in.From, &out.From, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if in.PullSecret != nil {
|
||||
in, out := in.PullSecret, &out.PullSecret
|
||||
*out = new(api.LocalObjectReference)
|
||||
if err := api.DeepCopy_api_LocalObjectReference(*in, *out, c); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
out.PullSecret = nil
|
||||
}
|
||||
if in.Env != nil {
|
||||
in, out := in.Env, &out.Env
|
||||
*out = make([]api.EnvVar, len(in))
|
||||
for i := range in {
|
||||
if err := api.DeepCopy_api_EnvVar(in[i], &(*out)[i], c); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.Env = nil
|
||||
}
|
||||
out.Scripts = in.Scripts
|
||||
out.Incremental = in.Incremental
|
||||
out.ForcePull = in.ForcePull
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeepCopy_api_SourceControlUser(in SourceControlUser, out *SourceControlUser, c *conversion.Cloner) error {
|
||||
out.Name = in.Name
|
||||
out.Email = in.Email
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeepCopy_api_SourceRevision(in SourceRevision, out *SourceRevision, c *conversion.Cloner) error {
|
||||
if in.Git != nil {
|
||||
in, out := in.Git, &out.Git
|
||||
*out = new(GitSourceRevision)
|
||||
if err := DeepCopy_api_GitSourceRevision(*in, *out, c); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
out.Git = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeepCopy_api_WebHookTrigger(in WebHookTrigger, out *WebHookTrigger, c *conversion.Cloner) error {
|
||||
out.Secret = in.Secret
|
||||
out.AllowEnv = in.AllowEnv
|
||||
return nil
|
||||
}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
// +k8s:deepcopy-gen=package,register
|
||||
|
||||
// Package api is the internal version of the API.
|
||||
package api
|
||||
+7
-5
@@ -6,6 +6,7 @@ import (
|
||||
)
|
||||
|
||||
const GroupName = ""
|
||||
const FutureGroupName = "build.openshift.io"
|
||||
|
||||
// SchemeGroupVersion is group version used to register these objects
|
||||
var SchemeGroupVersion = unversioned.GroupVersion{Group: GroupName, Version: runtime.APIVersionInternal}
|
||||
@@ -20,13 +21,13 @@ func Resource(resource string) unversioned.GroupResource {
|
||||
return SchemeGroupVersion.WithResource(resource).GroupResource()
|
||||
}
|
||||
|
||||
func AddToScheme(scheme *runtime.Scheme) {
|
||||
// Add the API to Scheme.
|
||||
addKnownTypes(scheme)
|
||||
}
|
||||
var (
|
||||
SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes)
|
||||
AddToScheme = SchemeBuilder.AddToScheme
|
||||
)
|
||||
|
||||
// Adds the list of known types to api.Scheme.
|
||||
func addKnownTypes(scheme *runtime.Scheme) {
|
||||
func addKnownTypes(scheme *runtime.Scheme) error {
|
||||
scheme.AddKnownTypes(SchemeGroupVersion,
|
||||
&Build{},
|
||||
&BuildList{},
|
||||
@@ -37,6 +38,7 @@ func addKnownTypes(scheme *runtime.Scheme) {
|
||||
&BuildLogOptions{},
|
||||
&BinaryBuildRequestOptions{},
|
||||
)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (obj *Build) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta }
|
||||
|
||||
+18
-3
@@ -424,7 +424,7 @@ type BuildStrategy struct {
|
||||
CustomStrategy *CustomBuildStrategy
|
||||
|
||||
// JenkinsPipelineStrategy holds the parameters to the Jenkins Pipeline build strategy.
|
||||
// This strategy is experimental.
|
||||
// This strategy is in tech preview.
|
||||
JenkinsPipelineStrategy *JenkinsPipelineBuildStrategy
|
||||
}
|
||||
|
||||
@@ -512,14 +512,28 @@ type SourceBuildStrategy struct {
|
||||
Scripts string
|
||||
|
||||
// Incremental flag forces the Source build to do incremental builds if true.
|
||||
Incremental bool
|
||||
Incremental *bool
|
||||
|
||||
// ForcePull describes if the builder should pull the images from registry prior to building.
|
||||
ForcePull bool
|
||||
|
||||
// RuntimeImage is an optional image that is used to run an application
|
||||
// without unneeded dependencies installed. The building of the application
|
||||
// is still done in the builder image but, post build, you can copy the
|
||||
// needed artifacts in the runtime image for use.
|
||||
// This field and the feature it enables are in tech preview.
|
||||
RuntimeImage *kapi.ObjectReference
|
||||
|
||||
// RuntimeArtifacts specifies a list of source/destination pairs that will be
|
||||
// copied from the builder to a runtime image. sourcePath can be a file or
|
||||
// directory. destinationDir must be a directory. destinationDir can also be
|
||||
// empty or equal to ".", in this case it just refers to the root of WORKDIR.
|
||||
// This field and the feature it enables are in tech preview.
|
||||
RuntimeArtifacts []ImageSourcePath
|
||||
}
|
||||
|
||||
// JenkinsPipelineStrategy holds parameters specific to a Jenkins Pipeline build.
|
||||
// This strategy is experimental.
|
||||
// This strategy is in tech preview.
|
||||
type JenkinsPipelineBuildStrategy struct {
|
||||
// JenkinsfilePath is the optional path of the Jenkinsfile that will be used to configure the pipeline
|
||||
// relative to the root of the context (contextDir). If both JenkinsfilePath & Jenkinsfile are
|
||||
@@ -792,6 +806,7 @@ type GitInfo struct {
|
||||
// Refs is a list of GitRefs for the provided repo - generally sent
|
||||
// when used from a post-receive hook. This field is optional and is
|
||||
// used when sending multiple refs
|
||||
// +k8s:conversion-gen=false
|
||||
Refs []GitRefInfo
|
||||
}
|
||||
|
||||
|
||||
+1034
File diff suppressed because it is too large
Load Diff
+109
@@ -0,0 +1,109 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
buildapi "github.com/openshift/origin/pkg/build/api"
|
||||
osclient "github.com/openshift/origin/pkg/client"
|
||||
kapi "k8s.io/kubernetes/pkg/api"
|
||||
)
|
||||
|
||||
// BuildConfigGetter provides methods for getting BuildConfigs
|
||||
type BuildConfigGetter interface {
|
||||
Get(namespace, name string) (*buildapi.BuildConfig, error)
|
||||
}
|
||||
|
||||
// BuildConfigUpdater provides methods for updating BuildConfigs
|
||||
type BuildConfigUpdater interface {
|
||||
Update(buildConfig *buildapi.BuildConfig) error
|
||||
}
|
||||
|
||||
// OSClientBuildConfigClient delegates get and update operations to the OpenShift client interface
|
||||
type OSClientBuildConfigClient struct {
|
||||
Client osclient.Interface
|
||||
}
|
||||
|
||||
// NewOSClientBuildConfigClient creates a new build config client that uses an openshift client to create and get BuildConfigs
|
||||
func NewOSClientBuildConfigClient(client osclient.Interface) *OSClientBuildConfigClient {
|
||||
return &OSClientBuildConfigClient{Client: client}
|
||||
}
|
||||
|
||||
// Get returns a BuildConfig using the OpenShift client.
|
||||
func (c OSClientBuildConfigClient) Get(namespace, name string) (*buildapi.BuildConfig, error) {
|
||||
return c.Client.BuildConfigs(namespace).Get(name)
|
||||
}
|
||||
|
||||
// Update updates a BuildConfig using the OpenShift client.
|
||||
func (c OSClientBuildConfigClient) Update(buildConfig *buildapi.BuildConfig) error {
|
||||
_, err := c.Client.BuildConfigs(buildConfig.Namespace).Update(buildConfig)
|
||||
return err
|
||||
}
|
||||
|
||||
// BuildUpdater provides methods for updating existing Builds.
|
||||
type BuildUpdater interface {
|
||||
Update(namespace string, build *buildapi.Build) error
|
||||
}
|
||||
|
||||
// BuildLister provides methods for listing the Builds.
|
||||
type BuildLister interface {
|
||||
List(namespace string, opts kapi.ListOptions) (*buildapi.BuildList, error)
|
||||
}
|
||||
|
||||
// OSClientBuildClient deletes build create and update operations to the OpenShift client interface
|
||||
type OSClientBuildClient struct {
|
||||
Client osclient.Interface
|
||||
}
|
||||
|
||||
// NewOSClientBuildClient creates a new build client that uses an openshift client to update builds
|
||||
func NewOSClientBuildClient(client osclient.Interface) *OSClientBuildClient {
|
||||
return &OSClientBuildClient{Client: client}
|
||||
}
|
||||
|
||||
// Update updates builds using the OpenShift client.
|
||||
func (c OSClientBuildClient) Update(namespace string, build *buildapi.Build) error {
|
||||
_, e := c.Client.Builds(namespace).Update(build)
|
||||
return e
|
||||
}
|
||||
|
||||
// List lists the builds using the OpenShift client.
|
||||
func (c OSClientBuildClient) List(namespace string, opts kapi.ListOptions) (*buildapi.BuildList, error) {
|
||||
return c.Client.Builds(namespace).List(opts)
|
||||
}
|
||||
|
||||
// BuildCloner provides methods for cloning builds
|
||||
type BuildCloner interface {
|
||||
Clone(namespace string, request *buildapi.BuildRequest) (*buildapi.Build, error)
|
||||
}
|
||||
|
||||
// OSClientBuildClonerClient creates a new build client that uses an openshift client to clone builds
|
||||
type OSClientBuildClonerClient struct {
|
||||
Client osclient.Interface
|
||||
}
|
||||
|
||||
// NewOSClientBuildClonerClient creates a new build client that uses an openshift client to clone builds
|
||||
func NewOSClientBuildClonerClient(client osclient.Interface) *OSClientBuildClonerClient {
|
||||
return &OSClientBuildClonerClient{Client: client}
|
||||
}
|
||||
|
||||
// Clone generates new build for given build name
|
||||
func (c OSClientBuildClonerClient) Clone(namespace string, request *buildapi.BuildRequest) (*buildapi.Build, error) {
|
||||
return c.Client.Builds(namespace).Clone(request)
|
||||
}
|
||||
|
||||
// BuildConfigInstantiator provides methods for instantiating builds from build configs
|
||||
type BuildConfigInstantiator interface {
|
||||
Instantiate(namespace string, request *buildapi.BuildRequest) (*buildapi.Build, error)
|
||||
}
|
||||
|
||||
// OSClientBuildConfigInstantiatorClient creates a new build client that uses an openshift client to create builds
|
||||
type OSClientBuildConfigInstantiatorClient struct {
|
||||
Client osclient.Interface
|
||||
}
|
||||
|
||||
// NewOSClientBuildConfigInstantiatorClient creates a new build client that uses an openshift client to create builds
|
||||
func NewOSClientBuildConfigInstantiatorClient(client osclient.Interface) *OSClientBuildConfigInstantiatorClient {
|
||||
return &OSClientBuildConfigInstantiatorClient{Client: client}
|
||||
}
|
||||
|
||||
// Instantiate generates new build for given buildConfig
|
||||
func (c OSClientBuildConfigInstantiatorClient) Instantiate(namespace string, request *buildapi.BuildRequest) (*buildapi.Build, error) {
|
||||
return c.Client.BuildConfigs(namespace).Instantiate(request)
|
||||
}
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
// Package cmd provides command helpers for builds
|
||||
package cmd
|
||||
+150
@@ -0,0 +1,150 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/golang/glog"
|
||||
kapi "k8s.io/kubernetes/pkg/api"
|
||||
kerrors "k8s.io/kubernetes/pkg/api/errors"
|
||||
"k8s.io/kubernetes/pkg/client/unversioned"
|
||||
"k8s.io/kubernetes/pkg/kubectl"
|
||||
ktypes "k8s.io/kubernetes/pkg/types"
|
||||
kutilerrors "k8s.io/kubernetes/pkg/util/errors"
|
||||
|
||||
buildapi "github.com/openshift/origin/pkg/build/api"
|
||||
buildutil "github.com/openshift/origin/pkg/build/util"
|
||||
"github.com/openshift/origin/pkg/client"
|
||||
"github.com/openshift/origin/pkg/util"
|
||||
)
|
||||
|
||||
// NewBuildConfigReaper returns a new reaper for buildConfigs
|
||||
func NewBuildConfigReaper(oc *client.Client) kubectl.Reaper {
|
||||
return &BuildConfigReaper{oc: oc, pollInterval: kubectl.Interval, timeout: kubectl.Timeout}
|
||||
}
|
||||
|
||||
// BuildConfigReaper implements the Reaper interface for buildConfigs
|
||||
type BuildConfigReaper struct {
|
||||
oc client.Interface
|
||||
pollInterval, timeout time.Duration
|
||||
}
|
||||
|
||||
// Stop deletes the build configuration and all of the associated builds.
|
||||
func (reaper *BuildConfigReaper) Stop(namespace, name string, timeout time.Duration, gracePeriod *kapi.DeleteOptions) error {
|
||||
_, err := reaper.oc.BuildConfigs(namespace).Get(name)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var bcPotentialBuilds []buildapi.Build
|
||||
|
||||
// Collect builds related to the config.
|
||||
builds, err := reaper.oc.Builds(namespace).List(kapi.ListOptions{LabelSelector: buildutil.BuildConfigSelector(name)})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
bcPotentialBuilds = append(bcPotentialBuilds, builds.Items...)
|
||||
|
||||
// Collect deprecated builds related to the config.
|
||||
// TODO: Delete this block after BuildConfigLabelDeprecated is removed.
|
||||
builds, err = reaper.oc.Builds(namespace).List(kapi.ListOptions{LabelSelector: buildutil.BuildConfigSelectorDeprecated(name)})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
bcPotentialBuilds = append(bcPotentialBuilds, builds.Items...)
|
||||
|
||||
// A map of builds associated with this build configuration
|
||||
bcBuilds := make(map[ktypes.UID]buildapi.Build)
|
||||
|
||||
// Because of name length limits in the BuildConfigSelector, annotations are used to ensure
|
||||
// reliable selection of associated builds.
|
||||
for _, build := range bcPotentialBuilds {
|
||||
if build.Annotations != nil {
|
||||
if bcName, ok := build.Annotations[buildapi.BuildConfigAnnotation]; ok {
|
||||
// The annotation, if present, has the full build config name.
|
||||
if bcName != name {
|
||||
// If the name does not match exactly, the build is not truly associated with the build configuration
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
// Note that if there is no annotation, this is a deprecated build spec
|
||||
// and we choose to include it in the deletion having matched only the BuildConfigSelectorDeprecated
|
||||
|
||||
// Use a map to union the lists returned by the contemporary & deprecated build queries
|
||||
// (there will be overlap between the lists, and we only want to try to delete each build once)
|
||||
bcBuilds[build.UID] = build
|
||||
}
|
||||
|
||||
// If there are builds associated with this build configuration, pause it before attempting the deletion
|
||||
if len(bcBuilds) > 0 {
|
||||
|
||||
// Add paused annotation to the build config pending the deletion
|
||||
err = unversioned.RetryOnConflict(unversioned.DefaultRetry, func() error {
|
||||
|
||||
bc, err := reaper.oc.BuildConfigs(namespace).Get(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Ignore if the annotation already exists
|
||||
if strings.ToLower(bc.Annotations[buildapi.BuildConfigPausedAnnotation]) == "true" {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Set the annotation and update
|
||||
if err := util.AddObjectAnnotations(bc, map[string]string{buildapi.BuildConfigPausedAnnotation: "true"}); err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = reaper.oc.BuildConfigs(namespace).Update(bc)
|
||||
return err
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Warn the user if the BuildConfig won't get deleted after this point.
|
||||
bcDeleted := false
|
||||
defer func() {
|
||||
if !bcDeleted {
|
||||
glog.Warningf("BuildConfig %s/%s will not be deleted because not all associated builds could be deleted. You can try re-running the command or removing them manually", namespace, name)
|
||||
}
|
||||
}()
|
||||
|
||||
// For the benefit of test cases, sort the UIDs so that the deletion order is deterministic
|
||||
buildUIDs := make([]string, 0, len(bcBuilds))
|
||||
for buildUID := range bcBuilds {
|
||||
buildUIDs = append(buildUIDs, string(buildUID))
|
||||
}
|
||||
sort.Strings(buildUIDs)
|
||||
|
||||
errList := []error{}
|
||||
for _, buildUID := range buildUIDs {
|
||||
build := bcBuilds[ktypes.UID(buildUID)]
|
||||
if err := reaper.oc.Builds(namespace).Delete(build.Name); err != nil {
|
||||
glog.Warningf("Cannot delete Build %s/%s: %v", build.Namespace, build.Name, err)
|
||||
if !kerrors.IsNotFound(err) {
|
||||
errList = append(errList, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Aggregate all errors
|
||||
if len(errList) > 0 {
|
||||
return kutilerrors.NewAggregate(errList)
|
||||
}
|
||||
|
||||
if err := reaper.oc.BuildConfigs(namespace).Delete(name); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
bcDeleted = true
|
||||
return nil
|
||||
}
|
||||
+351
@@ -0,0 +1,351 @@
|
||||
package analysis
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gonum/graph"
|
||||
"github.com/gonum/graph/topo"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||
|
||||
osgraph "github.com/openshift/origin/pkg/api/graph"
|
||||
buildapi "github.com/openshift/origin/pkg/build/api"
|
||||
buildedges "github.com/openshift/origin/pkg/build/graph"
|
||||
buildgraph "github.com/openshift/origin/pkg/build/graph/nodes"
|
||||
imageapi "github.com/openshift/origin/pkg/image/api"
|
||||
imageedges "github.com/openshift/origin/pkg/image/graph"
|
||||
imagegraph "github.com/openshift/origin/pkg/image/graph/nodes"
|
||||
)
|
||||
|
||||
const (
|
||||
TagNotAvailableWarning = "ImageStreamTagNotAvailable"
|
||||
LatestBuildFailedErr = "LatestBuildFailed"
|
||||
MissingRequiredRegistryErr = "MissingRequiredRegistry"
|
||||
MissingOutputImageStreamErr = "MissingOutputImageStream"
|
||||
CyclicBuildConfigWarning = "CyclicBuildConfig"
|
||||
MissingImageStreamTagWarning = "MissingImageStreamTag"
|
||||
MissingImageStreamImageWarning = "MissingImageStreamImage"
|
||||
)
|
||||
|
||||
// FindUnpushableBuildConfigs checks all build configs that will output to an IST backed by an ImageStream and checks to make sure their builds can push.
|
||||
func FindUnpushableBuildConfigs(g osgraph.Graph, f osgraph.Namer) []osgraph.Marker {
|
||||
markers := []osgraph.Marker{}
|
||||
|
||||
// note, unlike with Inputs, ImageStreamImage is not a valid type for build output
|
||||
|
||||
bc:
|
||||
for _, bcNode := range g.NodesByKind(buildgraph.BuildConfigNodeKind) {
|
||||
for _, istNode := range g.SuccessorNodesByEdgeKind(bcNode, buildedges.BuildOutputEdgeKind) {
|
||||
for _, uncastImageStreamNode := range g.SuccessorNodesByEdgeKind(istNode, imageedges.ReferencedImageStreamGraphEdgeKind) {
|
||||
imageStreamNode := uncastImageStreamNode.(*imagegraph.ImageStreamNode)
|
||||
|
||||
if !imageStreamNode.IsFound {
|
||||
markers = append(markers, osgraph.Marker{
|
||||
Node: bcNode,
|
||||
RelatedNodes: []graph.Node{istNode},
|
||||
|
||||
Severity: osgraph.ErrorSeverity,
|
||||
Key: MissingOutputImageStreamErr,
|
||||
Message: fmt.Sprintf("%s is pushing to %s, but the image stream for that tag does not exist.",
|
||||
f.ResourceName(bcNode), f.ResourceName(istNode)),
|
||||
})
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
if len(imageStreamNode.Status.DockerImageRepository) == 0 {
|
||||
markers = append(markers, osgraph.Marker{
|
||||
Node: bcNode,
|
||||
RelatedNodes: []graph.Node{istNode},
|
||||
|
||||
Severity: osgraph.ErrorSeverity,
|
||||
Key: MissingRequiredRegistryErr,
|
||||
Message: fmt.Sprintf("%s is pushing to %s, but the administrator has not configured the integrated Docker registry.",
|
||||
f.ResourceName(bcNode), f.ResourceName(istNode)),
|
||||
Suggestion: osgraph.Suggestion("oc adm registry -h"),
|
||||
})
|
||||
|
||||
continue bc
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return markers
|
||||
}
|
||||
|
||||
// FindMissingInputImageStreams checks all build configs and confirms that their From element exists
|
||||
//
|
||||
// Precedence of failures:
|
||||
// 1. A build config's input points to an image stream that does not exist
|
||||
// 2. A build config's input uses an image stream tag reference in an existing image stream, but no images within the image stream have that tag assigned
|
||||
// 3. A build config's input uses an image stream image reference in an exisiting image stream, but no images within the image stream have the supplied image hexadecimal ID
|
||||
func FindMissingInputImageStreams(g osgraph.Graph, f osgraph.Namer) []osgraph.Marker {
|
||||
markers := []osgraph.Marker{}
|
||||
|
||||
for _, bcNode := range g.NodesByKind(buildgraph.BuildConfigNodeKind) {
|
||||
for _, bcInputNode := range g.PredecessorNodesByEdgeKind(bcNode, buildedges.BuildInputImageEdgeKind) {
|
||||
switch bcInputNode.(type) {
|
||||
case *imagegraph.ImageStreamTagNode:
|
||||
|
||||
for _, uncastImageStreamNode := range g.SuccessorNodesByEdgeKind(bcInputNode, imageedges.ReferencedImageStreamGraphEdgeKind) {
|
||||
imageStreamNode := uncastImageStreamNode.(*imagegraph.ImageStreamNode)
|
||||
|
||||
// note, BuildConfig.Spec.BuildSpec.Strategy.[Docker|Source|Custom]Stragegy.From Input of ImageStream has been converted to ImageStreamTag on the vX to api conversion
|
||||
// prior to our reaching this point in the code; so there is not need to check for that type vs. ImageStreamTag or ImageStreamImage;
|
||||
|
||||
tagNode, _ := bcInputNode.(*imagegraph.ImageStreamTagNode)
|
||||
imageStream := imageStreamNode.Object().(*imageapi.ImageStream)
|
||||
if _, ok := imageStream.Status.Tags[tagNode.ImageTag()]; !ok {
|
||||
|
||||
markers = append(markers, getImageStreamTagMarker(g, f, bcInputNode, imageStreamNode, tagNode, bcNode))
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
case *imagegraph.ImageStreamImageNode:
|
||||
|
||||
for _, uncastImageStreamNode := range g.SuccessorNodesByEdgeKind(bcInputNode, imageedges.ReferencedImageStreamImageGraphEdgeKind) {
|
||||
imageStreamNode := uncastImageStreamNode.(*imagegraph.ImageStreamNode)
|
||||
|
||||
imageNode, _ := bcInputNode.(*imagegraph.ImageStreamImageNode)
|
||||
imageStream := imageStreamNode.Object().(*imageapi.ImageStream)
|
||||
found, imageID := validImageStreamImage(imageNode, imageStream)
|
||||
if !found {
|
||||
|
||||
markers = append(markers, getImageStreamImageMarker(g, f, bcNode, bcInputNode, imageStreamNode, imageNode, imageStream, imageID))
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return markers
|
||||
}
|
||||
|
||||
// FindCircularBuilds checks all build configs for cycles
|
||||
func FindCircularBuilds(g osgraph.Graph, f osgraph.Namer) []osgraph.Marker {
|
||||
// Filter out all but ImageStreamTag and BuildConfig nodes
|
||||
nodeFn := osgraph.NodesOfKind(imagegraph.ImageStreamTagNodeKind, buildgraph.BuildConfigNodeKind)
|
||||
// Filter out all but BuildInputImage and BuildOutput edges
|
||||
edgeFn := osgraph.EdgesOfKind(buildedges.BuildInputImageEdgeKind, buildedges.BuildOutputEdgeKind)
|
||||
|
||||
// Create desired subgraph
|
||||
sub := g.Subgraph(nodeFn, edgeFn)
|
||||
|
||||
markers := []osgraph.Marker{}
|
||||
|
||||
// Check for cycles
|
||||
for _, cycle := range topo.CyclesIn(sub) {
|
||||
nodeNames := []string{}
|
||||
for _, node := range cycle {
|
||||
nodeNames = append(nodeNames, f.ResourceName(node))
|
||||
}
|
||||
|
||||
markers = append(markers, osgraph.Marker{
|
||||
Node: cycle[0],
|
||||
RelatedNodes: cycle,
|
||||
|
||||
Severity: osgraph.WarningSeverity,
|
||||
Key: CyclicBuildConfigWarning,
|
||||
Message: fmt.Sprintf("Cycle detected in build configurations: %s", strings.Join(nodeNames, " -> ")),
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
return markers
|
||||
}
|
||||
|
||||
// multiBCStartBuildSuggestion builds the `oc start-build` suggestion string with multiple build configs
|
||||
func multiBCStartBuildSuggestion(bcNodes []*buildgraph.BuildConfigNode) string {
|
||||
var ret string
|
||||
if len(bcNodes) > 1 {
|
||||
ret = "Run one of the following commands: "
|
||||
}
|
||||
for i, bcNode := range bcNodes {
|
||||
// use of f.ResourceName(bcNode) will produce a string like oc start-build BuildConfig|example/ruby-hello-world
|
||||
ret = ret + fmt.Sprintf("oc start-build %s", bcNode.BuildConfig.GetName())
|
||||
if i < (len(bcNodes) - 1) {
|
||||
ret = ret + ", "
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// bcNodesToRelatedNodes takes an array of BuildConfigNode's and returns an array of graph.Node's for the Marker.RelatedNodes field
|
||||
func bcNodesToRelatedNodes(bcNodes []*buildgraph.BuildConfigNode) []graph.Node {
|
||||
relatedNodes := []graph.Node{}
|
||||
for _, bcNode := range bcNodes {
|
||||
relatedNodes = append(relatedNodes, graph.Node(bcNode))
|
||||
}
|
||||
return relatedNodes
|
||||
}
|
||||
|
||||
// findPendingTagMarkers is the guts behind FindPendingTags .... break out some of the content and reduce some indentation
|
||||
func findPendingTagMarkers(istNode *imagegraph.ImageStreamTagNode, g osgraph.Graph, f osgraph.Namer) []osgraph.Marker {
|
||||
markers := []osgraph.Marker{}
|
||||
|
||||
buildFound := false
|
||||
bcNodes := buildedges.BuildConfigsForTag(g, graph.Node(istNode))
|
||||
for _, bcNode := range bcNodes {
|
||||
latestBuild := buildedges.GetLatestBuild(g, bcNode)
|
||||
|
||||
// A build config points to the non existent tag but no current build exists.
|
||||
if latestBuild == nil {
|
||||
continue
|
||||
}
|
||||
buildFound = true
|
||||
|
||||
// A build config points to the non existent tag but something is going on with
|
||||
// the latest build.
|
||||
// TODO: Handle other build phases.
|
||||
switch latestBuild.Build.Status.Phase {
|
||||
case buildapi.BuildPhaseCancelled:
|
||||
// TODO: Add a warning here.
|
||||
case buildapi.BuildPhaseError:
|
||||
// TODO: Add a warning here.
|
||||
case buildapi.BuildPhaseComplete:
|
||||
// We should never hit this. The output of our build is missing but the build is complete.
|
||||
// Most probably the user has messed up?
|
||||
case buildapi.BuildPhaseFailed:
|
||||
// Since the tag hasn't been populated yet, we assume there hasn't been a successful
|
||||
// build so far.
|
||||
markers = append(markers, osgraph.Marker{
|
||||
Node: graph.Node(latestBuild),
|
||||
RelatedNodes: []graph.Node{graph.Node(istNode), graph.Node(bcNode)},
|
||||
|
||||
Severity: osgraph.ErrorSeverity,
|
||||
Key: LatestBuildFailedErr,
|
||||
Message: fmt.Sprintf("%s has failed.", f.ResourceName(latestBuild)),
|
||||
Suggestion: osgraph.Suggestion(fmt.Sprintf("Inspect the build failure with 'oc logs -f bc/%s'", bcNode.BuildConfig.GetName())),
|
||||
})
|
||||
default:
|
||||
// Do nothing when latest build is new, pending, or running.
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// if no current builds exist for any of the build configs, append marker for that
|
||||
// but ignore ISTs which have no build configs
|
||||
if !buildFound && len(bcNodes) > 0 {
|
||||
markers = append(markers, osgraph.Marker{
|
||||
Node: graph.Node(istNode),
|
||||
RelatedNodes: bcNodesToRelatedNodes(bcNodes),
|
||||
|
||||
Severity: osgraph.WarningSeverity,
|
||||
Key: TagNotAvailableWarning,
|
||||
Message: fmt.Sprintf("%s needs to be imported or created by a build.", f.ResourceName(istNode)),
|
||||
Suggestion: osgraph.Suggestion(multiBCStartBuildSuggestion(bcNodes)),
|
||||
})
|
||||
}
|
||||
return markers
|
||||
}
|
||||
|
||||
// FindPendingTags inspects all imageStreamTags that serve as outputs to builds.
|
||||
//
|
||||
// Precedence of failures:
|
||||
// 1. A build config points to the non existent tag but no current build exists.
|
||||
// 2. A build config points to the non existent tag but the latest build has failed.
|
||||
func FindPendingTags(g osgraph.Graph, f osgraph.Namer) []osgraph.Marker {
|
||||
markers := []osgraph.Marker{}
|
||||
|
||||
for _, uncastIstNode := range g.NodesByKind(imagegraph.ImageStreamTagNodeKind) {
|
||||
istNode := uncastIstNode.(*imagegraph.ImageStreamTagNode)
|
||||
if !istNode.Found() {
|
||||
markers = append(markers, findPendingTagMarkers(istNode, g, f)...)
|
||||
}
|
||||
}
|
||||
|
||||
return markers
|
||||
}
|
||||
|
||||
// getImageStreamTagMarker will return the appropriate marker for when a BuildConfig is missing its input ImageStreamTag
|
||||
func getImageStreamTagMarker(g osgraph.Graph, f osgraph.Namer, bcInputNode graph.Node, imageStreamNode graph.Node, tagNode *imagegraph.ImageStreamTagNode, bcNode graph.Node) osgraph.Marker {
|
||||
return osgraph.Marker{
|
||||
Node: bcNode,
|
||||
RelatedNodes: []graph.Node{bcInputNode,
|
||||
imageStreamNode},
|
||||
Severity: osgraph.WarningSeverity,
|
||||
Key: MissingImageStreamImageWarning,
|
||||
Message: fmt.Sprintf("%s builds from %s, but the image stream tag does not exist.", f.ResourceName(bcNode), f.ResourceName(bcInputNode)),
|
||||
Suggestion: getImageStreamTagSuggestion(g, f, tagNode),
|
||||
}
|
||||
}
|
||||
|
||||
// getImageStreamTagSuggestion will return the appropriate marker Suggestion for when a BuildConfig is missing its input ImageStreamTag; in particular,
|
||||
// it will determine whether or not another BuildConfig can produce the aforementioned ImageStreamTag
|
||||
func getImageStreamTagSuggestion(g osgraph.Graph, f osgraph.Namer, tagNode *imagegraph.ImageStreamTagNode) osgraph.Suggestion {
|
||||
bcs := []string{}
|
||||
for _, bcNode := range g.PredecessorNodesByEdgeKind(tagNode, buildedges.BuildOutputEdgeKind) {
|
||||
bcs = append(bcs, f.ResourceName(bcNode))
|
||||
}
|
||||
if len(bcs) == 1 {
|
||||
return osgraph.Suggestion(fmt.Sprintf("oc start-build %s", bcs[0]))
|
||||
}
|
||||
if len(bcs) > 0 {
|
||||
return osgraph.Suggestion(fmt.Sprintf("`oc start-build` with one of these: %s.", strings.Join(bcs[:], ",")))
|
||||
}
|
||||
return osgraph.Suggestion(fmt.Sprintf("%s needs to be imported.", f.ResourceName(tagNode)))
|
||||
}
|
||||
|
||||
// getImageStreamImageMarker will return the appropriate marker for when a BuildConfig is missing its input ImageStreamImage
|
||||
func getImageStreamImageMarker(g osgraph.Graph, f osgraph.Namer, bcNode graph.Node, bcInputNode graph.Node, imageStreamNode graph.Node, imageNode *imagegraph.ImageStreamImageNode, imageStream *imageapi.ImageStream, imageID string) osgraph.Marker {
|
||||
return osgraph.Marker{
|
||||
Node: bcNode,
|
||||
RelatedNodes: []graph.Node{bcInputNode,
|
||||
imageStreamNode},
|
||||
Severity: osgraph.WarningSeverity,
|
||||
Key: MissingImageStreamImageWarning,
|
||||
Message: fmt.Sprintf("%s builds from %s, but the image stream image does not exist.", f.ResourceName(bcNode), f.ResourceName(bcInputNode)),
|
||||
Suggestion: getImageStreamImageSuggestion(imageID, imageStream),
|
||||
}
|
||||
}
|
||||
|
||||
// getImageStreamImageSuggestion will return the appropriate marker Suggestion for when a BuildConfig is missing its input ImageStreamImage
|
||||
func getImageStreamImageSuggestion(imageID string, imageStream *imageapi.ImageStream) osgraph.Suggestion {
|
||||
// check the images stream to see if any import images are in flight or have failed
|
||||
annotation, ok := imageStream.Annotations[imageapi.DockerImageRepositoryCheckAnnotation]
|
||||
if !ok {
|
||||
return osgraph.Suggestion(fmt.Sprintf("`oc import-image %s --from=` where `--from` specifies an image with hexadecimal ID %s", imageStream.GetName(), imageID))
|
||||
}
|
||||
|
||||
if checkTime, err := time.Parse(time.RFC3339, annotation); err == nil {
|
||||
// this time based annotation is set by pkg/image/controller/controller.go whenever import/tag operations are performed; unless
|
||||
// in the midst of an import/tag operation, it stays set and serves as a timestamp for when the last operation occurred;
|
||||
// so we will check if the image stream has been updated "recently";
|
||||
// in case it is a slow link to the remote repo, see if if the check annotation occurred within the last 5 minutes; if so, consider that as potentially "in progress"
|
||||
compareTime := checkTime.Add(5 * time.Minute)
|
||||
currentTime, _ := time.Parse(time.RFC3339, unversioned.Now().UTC().Format(time.RFC3339))
|
||||
if compareTime.Before(currentTime) {
|
||||
return osgraph.Suggestion(fmt.Sprintf("`oc import-image %s --from=` where `--from` specifies an image with hexadecimal ID %s", imageStream.GetName(), imageID))
|
||||
}
|
||||
|
||||
return osgraph.Suggestion(fmt.Sprintf("`oc import-image %s --from=` with hexadecimal ID %s possibly in progress", imageStream.GetName(), imageID))
|
||||
|
||||
}
|
||||
return osgraph.Suggestion(fmt.Sprintf("Possible error occurred with `oc import-image %s --from=` with hexadecimal ID %s; inspect images stream annotations", imageStream.GetName(), imageID))
|
||||
}
|
||||
|
||||
// validImageStreamImage will cycle through the imageStream.Status.Tags.[]TagEvent.DockerImageReference and determine whether an image with the hexadecimal image id
|
||||
// associated with an ImageStreamImage reference in fact exists in a given ImageStream; on return, this method returns a true if does exist, and as well as the hexadecimal image
|
||||
// id from the ImageStreamImage
|
||||
func validImageStreamImage(imageNode *imagegraph.ImageStreamImageNode, imageStream *imageapi.ImageStream) (bool, string) {
|
||||
dockerImageReference, err := imageapi.ParseDockerImageReference(imageNode.Name)
|
||||
if err == nil {
|
||||
for _, tagEventList := range imageStream.Status.Tags {
|
||||
for _, tagEvent := range tagEventList.Items {
|
||||
if strings.Contains(tagEvent.DockerImageReference, dockerImageReference.ID) {
|
||||
return true, dockerImageReference.ID
|
||||
}
|
||||
}
|
||||
}
|
||||
return false, dockerImageReference.ID
|
||||
}
|
||||
return false, ""
|
||||
}
|
||||
+133
@@ -0,0 +1,133 @@
|
||||
package graph
|
||||
|
||||
import (
|
||||
"github.com/gonum/graph"
|
||||
kapi "k8s.io/kubernetes/pkg/api"
|
||||
|
||||
osgraph "github.com/openshift/origin/pkg/api/graph"
|
||||
buildapi "github.com/openshift/origin/pkg/build/api"
|
||||
buildgraph "github.com/openshift/origin/pkg/build/graph/nodes"
|
||||
buildutil "github.com/openshift/origin/pkg/build/util"
|
||||
imageapi "github.com/openshift/origin/pkg/image/api"
|
||||
imagegraph "github.com/openshift/origin/pkg/image/graph/nodes"
|
||||
)
|
||||
|
||||
const (
|
||||
// BuildTriggerImageEdgeKind is an edge from an ImageStream to a BuildConfig that
|
||||
// represents a trigger connection. Changes to the ImageStream will trigger a new build
|
||||
// from the BuildConfig.
|
||||
BuildTriggerImageEdgeKind = "BuildTriggerImage"
|
||||
|
||||
// BuildInputImageEdgeKind is an edge from an ImageStream to a BuildConfig, where the
|
||||
// ImageStream is the source image for the build (builder in S2I builds, FROM in Docker builds,
|
||||
// custom builder in Custom builds). The same ImageStream can also have a trigger
|
||||
// relationship with the BuildConfig, but not necessarily.
|
||||
BuildInputImageEdgeKind = "BuildInputImage"
|
||||
|
||||
// BuildOutputEdgeKind is an edge from a BuildConfig to an ImageStream. The ImageStream will hold
|
||||
// the ouptut of the Builds created with that BuildConfig.
|
||||
BuildOutputEdgeKind = "BuildOutput"
|
||||
|
||||
// BuildInputEdgeKind is an edge from a source repository to a BuildConfig. The source repository is the
|
||||
// input source for the build.
|
||||
BuildInputEdgeKind = "BuildInput"
|
||||
|
||||
// BuildEdgeKind goes from a BuildConfigNode to a BuildNode and indicates that the buildConfig owns the build
|
||||
BuildEdgeKind = "Build"
|
||||
)
|
||||
|
||||
// AddBuildEdges adds edges that connect a BuildConfig to Builds to the given graph
|
||||
func AddBuildEdges(g osgraph.MutableUniqueGraph, node *buildgraph.BuildConfigNode) {
|
||||
for _, n := range g.(graph.Graph).Nodes() {
|
||||
if buildNode, ok := n.(*buildgraph.BuildNode); ok {
|
||||
if buildNode.Build.Namespace != node.BuildConfig.Namespace {
|
||||
continue
|
||||
}
|
||||
if belongsToBuildConfig(node.BuildConfig, buildNode.Build) {
|
||||
g.AddEdge(node, buildNode, BuildEdgeKind)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// AddAllBuildEdges adds build edges to all BuildConfig nodes in the given graph
|
||||
func AddAllBuildEdges(g osgraph.MutableUniqueGraph) {
|
||||
for _, node := range g.(graph.Graph).Nodes() {
|
||||
if bcNode, ok := node.(*buildgraph.BuildConfigNode); ok {
|
||||
AddBuildEdges(g, bcNode)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func imageRefNode(g osgraph.MutableUniqueGraph, ref *kapi.ObjectReference, bc *buildapi.BuildConfig) graph.Node {
|
||||
if ref == nil {
|
||||
return nil
|
||||
}
|
||||
switch ref.Kind {
|
||||
case "DockerImage":
|
||||
if ref, err := imageapi.ParseDockerImageReference(ref.Name); err == nil {
|
||||
tag := ref.Tag
|
||||
ref.Tag = ""
|
||||
return imagegraph.EnsureDockerRepositoryNode(g, ref.String(), tag)
|
||||
}
|
||||
case "ImageStream":
|
||||
return imagegraph.FindOrCreateSyntheticImageStreamTagNode(g, imagegraph.MakeImageStreamTagObjectMeta(defaultNamespace(ref.Namespace, bc.Namespace), ref.Name, imageapi.DefaultImageTag))
|
||||
case "ImageStreamTag":
|
||||
return imagegraph.FindOrCreateSyntheticImageStreamTagNode(g, imagegraph.MakeImageStreamTagObjectMeta2(defaultNamespace(ref.Namespace, bc.Namespace), ref.Name))
|
||||
case "ImageStreamImage":
|
||||
return imagegraph.FindOrCreateSyntheticImageStreamImageNode(g, imagegraph.MakeImageStreamImageObjectMeta(defaultNamespace(ref.Namespace, bc.Namespace), ref.Name))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddOutputEdges links the build config to its output image node.
|
||||
func AddOutputEdges(g osgraph.MutableUniqueGraph, node *buildgraph.BuildConfigNode) {
|
||||
if node.BuildConfig.Spec.Output.To == nil {
|
||||
return
|
||||
}
|
||||
out := imageRefNode(g, node.BuildConfig.Spec.Output.To, node.BuildConfig)
|
||||
g.AddEdge(node, out, BuildOutputEdgeKind)
|
||||
}
|
||||
|
||||
// AddInputEdges links the build config to its input image and source nodes.
|
||||
func AddInputEdges(g osgraph.MutableUniqueGraph, node *buildgraph.BuildConfigNode) {
|
||||
if in := buildgraph.EnsureSourceRepositoryNode(g, node.BuildConfig.Spec.Source); in != nil {
|
||||
g.AddEdge(in, node, BuildInputEdgeKind)
|
||||
}
|
||||
inputImage := buildutil.GetInputReference(node.BuildConfig.Spec.Strategy)
|
||||
if input := imageRefNode(g, inputImage, node.BuildConfig); input != nil {
|
||||
g.AddEdge(input, node, BuildInputImageEdgeKind)
|
||||
}
|
||||
}
|
||||
|
||||
// AddTriggerEdges links the build config to its trigger input image nodes.
|
||||
func AddTriggerEdges(g osgraph.MutableUniqueGraph, node *buildgraph.BuildConfigNode) {
|
||||
for _, trigger := range node.BuildConfig.Spec.Triggers {
|
||||
if trigger.Type != buildapi.ImageChangeBuildTriggerType {
|
||||
continue
|
||||
}
|
||||
from := trigger.ImageChange.From
|
||||
if trigger.ImageChange.From == nil {
|
||||
from = buildutil.GetInputReference(node.BuildConfig.Spec.Strategy)
|
||||
}
|
||||
triggerNode := imageRefNode(g, from, node.BuildConfig)
|
||||
g.AddEdge(triggerNode, node, BuildTriggerImageEdgeKind)
|
||||
}
|
||||
}
|
||||
|
||||
// AddInputOutputEdges links the build config to other nodes for the images and source repositories it depends on.
|
||||
func AddInputOutputEdges(g osgraph.MutableUniqueGraph, node *buildgraph.BuildConfigNode) *buildgraph.BuildConfigNode {
|
||||
AddInputEdges(g, node)
|
||||
AddTriggerEdges(g, node)
|
||||
AddOutputEdges(g, node)
|
||||
return node
|
||||
}
|
||||
|
||||
// AddAllInputOutputEdges adds input and output edges for all BuildConfigs in the given graph
|
||||
func AddAllInputOutputEdges(g osgraph.MutableUniqueGraph) {
|
||||
for _, node := range g.(graph.Graph).Nodes() {
|
||||
if bcNode, ok := node.(*buildgraph.BuildConfigNode); ok {
|
||||
AddInputOutputEdges(g, bcNode)
|
||||
}
|
||||
}
|
||||
}
|
||||
+111
@@ -0,0 +1,111 @@
|
||||
package graph
|
||||
|
||||
import (
|
||||
"sort"
|
||||
|
||||
"github.com/gonum/graph"
|
||||
|
||||
osgraph "github.com/openshift/origin/pkg/api/graph"
|
||||
buildapi "github.com/openshift/origin/pkg/build/api"
|
||||
buildgraph "github.com/openshift/origin/pkg/build/graph/nodes"
|
||||
)
|
||||
|
||||
// RelevantBuilds returns the lastSuccessful build, lastUnsuccessful build, and a list of active builds
|
||||
func RelevantBuilds(g osgraph.Graph, bcNode *buildgraph.BuildConfigNode) (*buildgraph.BuildNode, *buildgraph.BuildNode, []*buildgraph.BuildNode) {
|
||||
var (
|
||||
lastSuccessfulBuild *buildgraph.BuildNode
|
||||
lastUnsuccessfulBuild *buildgraph.BuildNode
|
||||
)
|
||||
activeBuilds := []*buildgraph.BuildNode{}
|
||||
allBuilds := []*buildgraph.BuildNode{}
|
||||
uncastBuilds := g.SuccessorNodesByEdgeKind(bcNode, BuildEdgeKind)
|
||||
|
||||
for i := range uncastBuilds {
|
||||
buildNode := uncastBuilds[i].(*buildgraph.BuildNode)
|
||||
if belongsToBuildConfig(bcNode.BuildConfig, buildNode.Build) {
|
||||
allBuilds = append(allBuilds, buildNode)
|
||||
}
|
||||
}
|
||||
|
||||
if len(allBuilds) == 0 {
|
||||
return nil, nil, []*buildgraph.BuildNode{}
|
||||
}
|
||||
|
||||
sort.Sort(RecentBuildReferences(allBuilds))
|
||||
|
||||
for i := range allBuilds {
|
||||
switch allBuilds[i].Build.Status.Phase {
|
||||
case buildapi.BuildPhaseComplete:
|
||||
if lastSuccessfulBuild == nil {
|
||||
lastSuccessfulBuild = allBuilds[i]
|
||||
}
|
||||
case buildapi.BuildPhaseFailed, buildapi.BuildPhaseCancelled, buildapi.BuildPhaseError:
|
||||
if lastUnsuccessfulBuild == nil {
|
||||
lastUnsuccessfulBuild = allBuilds[i]
|
||||
}
|
||||
default:
|
||||
activeBuilds = append(activeBuilds, allBuilds[i])
|
||||
}
|
||||
}
|
||||
|
||||
return lastSuccessfulBuild, lastUnsuccessfulBuild, activeBuilds
|
||||
}
|
||||
|
||||
func belongsToBuildConfig(config *buildapi.BuildConfig, b *buildapi.Build) bool {
|
||||
if b.Labels == nil {
|
||||
return false
|
||||
}
|
||||
if b.Annotations != nil && b.Annotations[buildapi.BuildConfigAnnotation] == config.Name {
|
||||
return true
|
||||
}
|
||||
if b.Labels[buildapi.BuildConfigLabel] == config.Name {
|
||||
return true
|
||||
}
|
||||
if b.Labels[buildapi.BuildConfigLabelDeprecated] == config.Name {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type RecentBuildReferences []*buildgraph.BuildNode
|
||||
|
||||
func (m RecentBuildReferences) Len() int { return len(m) }
|
||||
func (m RecentBuildReferences) Swap(i, j int) { m[i], m[j] = m[j], m[i] }
|
||||
func (m RecentBuildReferences) Less(i, j int) bool {
|
||||
return m[i].Build.CreationTimestamp.After(m[j].Build.CreationTimestamp.Time)
|
||||
}
|
||||
|
||||
func defaultNamespace(value, defaultValue string) string {
|
||||
if len(value) == 0 {
|
||||
return defaultValue
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
// BuildConfigsForTag returns the buildConfig that points to the provided imageStreamTag.
|
||||
func BuildConfigsForTag(g osgraph.Graph, istag graph.Node) []*buildgraph.BuildConfigNode {
|
||||
bcs := []*buildgraph.BuildConfigNode{}
|
||||
for _, bcNode := range g.PredecessorNodesByEdgeKind(istag, BuildOutputEdgeKind) {
|
||||
bcs = append(bcs, bcNode.(*buildgraph.BuildConfigNode))
|
||||
}
|
||||
return bcs
|
||||
}
|
||||
|
||||
// GetLatestBuild returns the latest build for the provided buildConfig.
|
||||
func GetLatestBuild(g osgraph.Graph, bc graph.Node) *buildgraph.BuildNode {
|
||||
builds := g.SuccessorNodesByEdgeKind(bc, BuildEdgeKind)
|
||||
if len(builds) == 0 {
|
||||
return nil
|
||||
}
|
||||
latestBuild := builds[0].(*buildgraph.BuildNode)
|
||||
|
||||
for _, buildNode := range builds[1:] {
|
||||
if build, ok := buildNode.(*buildgraph.BuildNode); ok {
|
||||
if latestBuild.Build.CreationTimestamp.Before(build.Build.CreationTimestamp) {
|
||||
latestBuild = build
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return latestBuild
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
package nodes
|
||||
|
||||
import (
|
||||
"github.com/gonum/graph"
|
||||
|
||||
osgraph "github.com/openshift/origin/pkg/api/graph"
|
||||
buildapi "github.com/openshift/origin/pkg/build/api"
|
||||
)
|
||||
|
||||
// EnsureBuildConfigNode adds a graph node for the specific build config if it does not exist
|
||||
func EnsureBuildConfigNode(g osgraph.MutableUniqueGraph, config *buildapi.BuildConfig) *BuildConfigNode {
|
||||
return osgraph.EnsureUnique(
|
||||
g,
|
||||
BuildConfigNodeName(config),
|
||||
func(node osgraph.Node) graph.Node {
|
||||
return &BuildConfigNode{
|
||||
Node: node,
|
||||
BuildConfig: config,
|
||||
}
|
||||
},
|
||||
).(*BuildConfigNode)
|
||||
}
|
||||
|
||||
// EnsureSourceRepositoryNode adds the specific BuildSource to the graph if it does not already exist.
|
||||
func EnsureSourceRepositoryNode(g osgraph.MutableUniqueGraph, source buildapi.BuildSource) *SourceRepositoryNode {
|
||||
switch {
|
||||
case source.Git != nil:
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
return osgraph.EnsureUnique(g,
|
||||
SourceRepositoryNodeName(source),
|
||||
func(node osgraph.Node) graph.Node {
|
||||
return &SourceRepositoryNode{node, source}
|
||||
},
|
||||
).(*SourceRepositoryNode)
|
||||
}
|
||||
|
||||
// EnsureBuildNode adds a graph node for the build if it does not already exist.
|
||||
func EnsureBuildNode(g osgraph.MutableUniqueGraph, build *buildapi.Build) *BuildNode {
|
||||
return osgraph.EnsureUnique(g,
|
||||
BuildNodeName(build),
|
||||
func(node osgraph.Node) graph.Node {
|
||||
return &BuildNode{node, build}
|
||||
},
|
||||
).(*BuildNode)
|
||||
}
|
||||
+90
@@ -0,0 +1,90 @@
|
||||
package nodes
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
osgraph "github.com/openshift/origin/pkg/api/graph"
|
||||
buildapi "github.com/openshift/origin/pkg/build/api"
|
||||
)
|
||||
|
||||
var (
|
||||
BuildConfigNodeKind = reflect.TypeOf(buildapi.BuildConfig{}).Name()
|
||||
BuildNodeKind = reflect.TypeOf(buildapi.Build{}).Name()
|
||||
|
||||
// non-api types
|
||||
SourceRepositoryNodeKind = reflect.TypeOf(buildapi.BuildSource{}).Name()
|
||||
)
|
||||
|
||||
func BuildConfigNodeName(o *buildapi.BuildConfig) osgraph.UniqueName {
|
||||
return osgraph.GetUniqueRuntimeObjectNodeName(BuildConfigNodeKind, o)
|
||||
}
|
||||
|
||||
type BuildConfigNode struct {
|
||||
osgraph.Node
|
||||
BuildConfig *buildapi.BuildConfig
|
||||
}
|
||||
|
||||
func (n BuildConfigNode) Object() interface{} {
|
||||
return n.BuildConfig
|
||||
}
|
||||
|
||||
func (n BuildConfigNode) String() string {
|
||||
return string(BuildConfigNodeName(n.BuildConfig))
|
||||
}
|
||||
|
||||
func (n BuildConfigNode) UniqueName() osgraph.UniqueName {
|
||||
return BuildConfigNodeName(n.BuildConfig)
|
||||
}
|
||||
|
||||
func (*BuildConfigNode) Kind() string {
|
||||
return BuildConfigNodeKind
|
||||
}
|
||||
|
||||
func SourceRepositoryNodeName(source buildapi.BuildSource) osgraph.UniqueName {
|
||||
switch {
|
||||
case source.Git != nil:
|
||||
sourceType, uri, ref := "git", source.Git.URI, source.Git.Ref
|
||||
return osgraph.UniqueName(fmt.Sprintf("%s|%s|%s#%s", SourceRepositoryNodeKind, sourceType, uri, ref))
|
||||
default:
|
||||
panic(fmt.Sprintf("invalid build source: %v", source))
|
||||
}
|
||||
}
|
||||
|
||||
type SourceRepositoryNode struct {
|
||||
osgraph.Node
|
||||
Source buildapi.BuildSource
|
||||
}
|
||||
|
||||
func (n SourceRepositoryNode) String() string {
|
||||
return string(SourceRepositoryNodeName(n.Source))
|
||||
}
|
||||
|
||||
func (SourceRepositoryNode) Kind() string {
|
||||
return SourceRepositoryNodeKind
|
||||
}
|
||||
|
||||
func BuildNodeName(o *buildapi.Build) osgraph.UniqueName {
|
||||
return osgraph.GetUniqueRuntimeObjectNodeName(BuildNodeKind, o)
|
||||
}
|
||||
|
||||
type BuildNode struct {
|
||||
osgraph.Node
|
||||
Build *buildapi.Build
|
||||
}
|
||||
|
||||
func (n BuildNode) Object() interface{} {
|
||||
return n.Build
|
||||
}
|
||||
|
||||
func (n BuildNode) String() string {
|
||||
return string(BuildNodeName(n.Build))
|
||||
}
|
||||
|
||||
func (n BuildNode) UniqueName() osgraph.UniqueName {
|
||||
return BuildNodeName(n.Build)
|
||||
}
|
||||
|
||||
func (*BuildNode) Kind() string {
|
||||
return BuildNodeKind
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
// Package util contains common functions that are used
|
||||
// by the rest of the OpenShift build system.
|
||||
package util
|
||||
+169
@@ -0,0 +1,169 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
kapi "k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/labels"
|
||||
|
||||
"github.com/golang/glog"
|
||||
buildapi "github.com/openshift/origin/pkg/build/api"
|
||||
buildclient "github.com/openshift/origin/pkg/build/client"
|
||||
)
|
||||
|
||||
const (
|
||||
// NoBuildLogsMessage reports that no build logs are available
|
||||
NoBuildLogsMessage = "No logs are available."
|
||||
)
|
||||
|
||||
// GetBuildName returns name of the build pod.
|
||||
func GetBuildName(pod *kapi.Pod) string {
|
||||
if pod == nil {
|
||||
return ""
|
||||
}
|
||||
return pod.Annotations[buildapi.BuildAnnotation]
|
||||
}
|
||||
|
||||
// GetInputReference returns the From ObjectReference associated with the
|
||||
// BuildStrategy.
|
||||
func GetInputReference(strategy buildapi.BuildStrategy) *kapi.ObjectReference {
|
||||
switch {
|
||||
case strategy.SourceStrategy != nil:
|
||||
return &strategy.SourceStrategy.From
|
||||
case strategy.DockerStrategy != nil:
|
||||
return strategy.DockerStrategy.From
|
||||
case strategy.CustomStrategy != nil:
|
||||
return &strategy.CustomStrategy.From
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// NameFromImageStream returns a concatenated name representing an ImageStream[Tag/Image]
|
||||
// reference. If the reference does not contain a Namespace, the namespace parameter
|
||||
// is used instead.
|
||||
func NameFromImageStream(namespace string, ref *kapi.ObjectReference, tag string) string {
|
||||
var ret string
|
||||
if ref.Namespace == "" {
|
||||
ret = namespace
|
||||
} else {
|
||||
ret = ref.Namespace
|
||||
}
|
||||
ret = ret + "/" + ref.Name
|
||||
if tag != "" && strings.Index(ref.Name, ":") == -1 && strings.Index(ref.Name, "@") == -1 {
|
||||
ret = ret + ":" + tag
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// IsBuildComplete returns whether the provided build is complete or not
|
||||
func IsBuildComplete(build *buildapi.Build) bool {
|
||||
return build.Status.Phase != buildapi.BuildPhaseRunning && build.Status.Phase != buildapi.BuildPhasePending && build.Status.Phase != buildapi.BuildPhaseNew
|
||||
}
|
||||
|
||||
// IsPaused returns true if the provided BuildConfig is paused and cannot be used to create a new Build
|
||||
func IsPaused(bc *buildapi.BuildConfig) bool {
|
||||
return strings.ToLower(bc.Annotations[buildapi.BuildConfigPausedAnnotation]) == "true"
|
||||
}
|
||||
|
||||
// BuildNumber returns the given build number.
|
||||
func BuildNumber(build *buildapi.Build) (int64, error) {
|
||||
annotations := build.GetAnnotations()
|
||||
if stringNumber, ok := annotations[buildapi.BuildNumberAnnotation]; ok {
|
||||
return strconv.ParseInt(stringNumber, 10, 64)
|
||||
}
|
||||
return 0, fmt.Errorf("build %s/%s does not have %s annotation", build.Namespace, build.Name, buildapi.BuildNumberAnnotation)
|
||||
}
|
||||
|
||||
// BuildRunPolicy returns the scheduling policy for the build based on the
|
||||
// "queued" label.
|
||||
func BuildRunPolicy(build *buildapi.Build) buildapi.BuildRunPolicy {
|
||||
labels := build.GetLabels()
|
||||
if value, found := labels[buildapi.BuildRunPolicyLabel]; found {
|
||||
switch value {
|
||||
case "Parallel":
|
||||
return buildapi.BuildRunPolicyParallel
|
||||
case "Serial":
|
||||
return buildapi.BuildRunPolicySerial
|
||||
case "SerialLatestOnly":
|
||||
return buildapi.BuildRunPolicySerialLatestOnly
|
||||
}
|
||||
}
|
||||
glog.V(5).Infof("Build %s/%s does not have start policy label set, using default (Serial)")
|
||||
return buildapi.BuildRunPolicySerial
|
||||
}
|
||||
|
||||
// BuildNameForConfigVersion returns the name of the version-th build
|
||||
// for the config that has the provided name.
|
||||
func BuildNameForConfigVersion(name string, version int) string {
|
||||
return fmt.Sprintf("%s-%d", name, version)
|
||||
}
|
||||
|
||||
// BuildConfigSelector returns a label Selector which can be used to find all
|
||||
// builds for a BuildConfig.
|
||||
func BuildConfigSelector(name string) labels.Selector {
|
||||
return labels.Set{buildapi.BuildConfigLabel: buildapi.LabelValue(name)}.AsSelector()
|
||||
}
|
||||
|
||||
// BuildConfigSelectorDeprecated returns a label Selector which can be used to find
|
||||
// all builds for a BuildConfig that use the deprecated labels.
|
||||
func BuildConfigSelectorDeprecated(name string) labels.Selector {
|
||||
return labels.Set{buildapi.BuildConfigLabelDeprecated: name}.AsSelector()
|
||||
}
|
||||
|
||||
type buildFilter func(buildapi.Build) bool
|
||||
|
||||
// BuildConfigBuilds return a list of builds for the given build config.
|
||||
// Optionally you can specify a filter function to select only builds that
|
||||
// matches your criteria.
|
||||
func BuildConfigBuilds(c buildclient.BuildLister, namespace, name string, filterFunc buildFilter) (*buildapi.BuildList, error) {
|
||||
result, err := c.List(namespace, kapi.ListOptions{
|
||||
LabelSelector: BuildConfigSelector(name),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if filterFunc == nil {
|
||||
return result, nil
|
||||
}
|
||||
filteredList := &buildapi.BuildList{TypeMeta: result.TypeMeta, ListMeta: result.ListMeta}
|
||||
for _, b := range result.Items {
|
||||
if filterFunc(b) {
|
||||
filteredList.Items = append(filteredList.Items, b)
|
||||
}
|
||||
}
|
||||
return filteredList, nil
|
||||
}
|
||||
|
||||
// ConfigNameForBuild returns the name of the build config from a
|
||||
// build name.
|
||||
func ConfigNameForBuild(build *buildapi.Build) string {
|
||||
if build == nil {
|
||||
return ""
|
||||
}
|
||||
if build.Annotations != nil {
|
||||
if _, exists := build.Annotations[buildapi.BuildConfigAnnotation]; exists {
|
||||
return build.Annotations[buildapi.BuildConfigAnnotation]
|
||||
}
|
||||
}
|
||||
if _, exists := build.Labels[buildapi.BuildConfigLabel]; exists {
|
||||
return build.Labels[buildapi.BuildConfigLabel]
|
||||
}
|
||||
return build.Labels[buildapi.BuildConfigLabelDeprecated]
|
||||
}
|
||||
|
||||
// VersionForBuild returns the version from the provided build name.
|
||||
// If no version can be found, 0 is returned to indicate no version.
|
||||
func VersionForBuild(build *buildapi.Build) int {
|
||||
if build == nil {
|
||||
return 0
|
||||
}
|
||||
versionString := build.Annotations[buildapi.BuildNumberAnnotation]
|
||||
version, err := strconv.Atoi(versionString)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
return version
|
||||
}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
kapi "k8s.io/kubernetes/pkg/api"
|
||||
|
||||
quotaapi "github.com/openshift/origin/pkg/quota/api"
|
||||
)
|
||||
|
||||
// AppliedClusterResourceQuotasNamespacer has methods to work with AppliedClusterResourceQuota resources in a namespace
|
||||
type AppliedClusterResourceQuotasNamespacer interface {
|
||||
AppliedClusterResourceQuotas(namespace string) AppliedClusterResourceQuotaInterface
|
||||
}
|
||||
|
||||
// AppliedClusterResourceQuotaInterface exposes methods on AppliedClusterResourceQuota resources.
|
||||
type AppliedClusterResourceQuotaInterface interface {
|
||||
List(opts kapi.ListOptions) (*quotaapi.AppliedClusterResourceQuotaList, error)
|
||||
Get(name string) (*quotaapi.AppliedClusterResourceQuota, error)
|
||||
}
|
||||
|
||||
// appliedClusterResourceQuotas implements AppliedClusterResourceQuotasNamespacer interface
|
||||
type appliedClusterResourceQuotas struct {
|
||||
r *Client
|
||||
ns string
|
||||
}
|
||||
|
||||
// newAppliedClusterResourceQuotas returns a appliedClusterResourceQuotas
|
||||
func newAppliedClusterResourceQuotas(c *Client, namespace string) *appliedClusterResourceQuotas {
|
||||
return &appliedClusterResourceQuotas{
|
||||
r: c,
|
||||
ns: namespace,
|
||||
}
|
||||
}
|
||||
|
||||
// List returns a list of appliedClusterResourceQuotas that match the label and field selectors.
|
||||
func (c *appliedClusterResourceQuotas) List(opts kapi.ListOptions) (result *quotaapi.AppliedClusterResourceQuotaList, err error) {
|
||||
result = "aapi.AppliedClusterResourceQuotaList{}
|
||||
err = c.r.Get().Namespace(c.ns).Resource("appliedclusterresourcequotas").VersionedParams(&opts, kapi.ParameterCodec).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Get returns information about a particular appliedClusterResourceQuota and error if one occurs.
|
||||
func (c *appliedClusterResourceQuotas) Get(name string) (result *quotaapi.AppliedClusterResourceQuota, err error) {
|
||||
result = "aapi.AppliedClusterResourceQuota{}
|
||||
err = c.r.Get().Namespace(c.ns).Resource("appliedclusterresourcequotas").Name(name).Do().Into(result)
|
||||
return
|
||||
}
|
||||
+132
@@ -0,0 +1,132 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/url"
|
||||
|
||||
kapi "k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/watch"
|
||||
|
||||
buildapi "github.com/openshift/origin/pkg/build/api"
|
||||
)
|
||||
|
||||
// ErrTriggerIsNotAWebHook is returned when a webhook URL is requested for a trigger
|
||||
// that is not a webhook type.
|
||||
var ErrTriggerIsNotAWebHook = fmt.Errorf("the specified trigger is not a webhook")
|
||||
|
||||
// BuildConfigsNamespacer has methods to work with BuildConfig resources in a namespace
|
||||
type BuildConfigsNamespacer interface {
|
||||
BuildConfigs(namespace string) BuildConfigInterface
|
||||
}
|
||||
|
||||
// BuildConfigInterface exposes methods on BuildConfig resources
|
||||
type BuildConfigInterface interface {
|
||||
List(opts kapi.ListOptions) (*buildapi.BuildConfigList, error)
|
||||
Get(name string) (*buildapi.BuildConfig, error)
|
||||
Create(config *buildapi.BuildConfig) (*buildapi.BuildConfig, error)
|
||||
Update(config *buildapi.BuildConfig) (*buildapi.BuildConfig, error)
|
||||
Delete(name string) error
|
||||
Watch(opts kapi.ListOptions) (watch.Interface, error)
|
||||
|
||||
Instantiate(request *buildapi.BuildRequest) (result *buildapi.Build, err error)
|
||||
InstantiateBinary(request *buildapi.BinaryBuildRequestOptions, r io.Reader) (result *buildapi.Build, err error)
|
||||
|
||||
WebHookURL(name string, trigger *buildapi.BuildTriggerPolicy) (*url.URL, error)
|
||||
}
|
||||
|
||||
// buildConfigs implements BuildConfigsNamespacer interface
|
||||
type buildConfigs struct {
|
||||
r *Client
|
||||
ns string
|
||||
}
|
||||
|
||||
// newBuildConfigs returns a buildConfigs
|
||||
func newBuildConfigs(c *Client, namespace string) *buildConfigs {
|
||||
return &buildConfigs{
|
||||
r: c,
|
||||
ns: namespace,
|
||||
}
|
||||
}
|
||||
|
||||
// List returns a list of buildconfigs that match the label and field selectors.
|
||||
func (c *buildConfigs) List(opts kapi.ListOptions) (result *buildapi.BuildConfigList, err error) {
|
||||
result = &buildapi.BuildConfigList{}
|
||||
err = c.r.Get().
|
||||
Namespace(c.ns).
|
||||
Resource("buildConfigs").
|
||||
VersionedParams(&opts, kapi.ParameterCodec).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Get returns information about a particular buildconfig and error if one occurs.
|
||||
func (c *buildConfigs) Get(name string) (result *buildapi.BuildConfig, err error) {
|
||||
result = &buildapi.BuildConfig{}
|
||||
err = c.r.Get().Namespace(c.ns).Resource("buildConfigs").Name(name).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// WebHookURL returns the URL for the provided build config name and trigger policy, or ErrTriggerIsNotAWebHook
|
||||
// if the trigger is not a webhook type.
|
||||
func (c *buildConfigs) WebHookURL(name string, trigger *buildapi.BuildTriggerPolicy) (*url.URL, error) {
|
||||
switch {
|
||||
case trigger.GenericWebHook != nil:
|
||||
return c.r.Get().Namespace(c.ns).Resource("buildConfigs").Name(name).SubResource("webhooks").Suffix(trigger.GenericWebHook.Secret, "generic").URL(), nil
|
||||
case trigger.GitHubWebHook != nil:
|
||||
return c.r.Get().Namespace(c.ns).Resource("buildConfigs").Name(name).SubResource("webhooks").Suffix(trigger.GitHubWebHook.Secret, "github").URL(), nil
|
||||
default:
|
||||
return nil, ErrTriggerIsNotAWebHook
|
||||
}
|
||||
}
|
||||
|
||||
// Create creates a new buildconfig. Returns the server's representation of the buildconfig and error if one occurs.
|
||||
func (c *buildConfigs) Create(build *buildapi.BuildConfig) (result *buildapi.BuildConfig, err error) {
|
||||
result = &buildapi.BuildConfig{}
|
||||
err = c.r.Post().Namespace(c.ns).Resource("buildConfigs").Body(build).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Update updates the buildconfig on server. Returns the server's representation of the buildconfig and error if one occurs.
|
||||
func (c *buildConfigs) Update(build *buildapi.BuildConfig) (result *buildapi.BuildConfig, err error) {
|
||||
result = &buildapi.BuildConfig{}
|
||||
err = c.r.Put().Namespace(c.ns).Resource("buildConfigs").Name(build.Name).Body(build).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Delete deletes a BuildConfig, returns error if one occurs.
|
||||
func (c *buildConfigs) Delete(name string) error {
|
||||
return c.r.Delete().Namespace(c.ns).Resource("buildConfigs").Name(name).Do().Error()
|
||||
}
|
||||
|
||||
// Watch returns a watch.Interface that watches the requested buildConfigs.
|
||||
func (c *buildConfigs) Watch(opts kapi.ListOptions) (watch.Interface, error) {
|
||||
return c.r.Get().
|
||||
Prefix("watch").
|
||||
Namespace(c.ns).
|
||||
Resource("buildConfigs").
|
||||
VersionedParams(&opts, kapi.ParameterCodec).
|
||||
Watch()
|
||||
}
|
||||
|
||||
// Instantiate instantiates a new build from build config returning new object or an error
|
||||
func (c *buildConfigs) Instantiate(request *buildapi.BuildRequest) (result *buildapi.Build, err error) {
|
||||
result = &buildapi.Build{}
|
||||
err = c.r.Post().Namespace(c.ns).Resource("buildConfigs").Name(request.Name).SubResource("instantiate").Body(request).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// InstantiateBinary instantiates a new build from a build config, given a structured request and an input stream,
|
||||
// and returns the created build or an error.
|
||||
func (c *buildConfigs) InstantiateBinary(request *buildapi.BinaryBuildRequestOptions, r io.Reader) (result *buildapi.Build, err error) {
|
||||
result = &buildapi.Build{}
|
||||
err = c.r.Post().
|
||||
Namespace(c.ns).
|
||||
Resource("buildConfigs").
|
||||
Name(request.Name).
|
||||
SubResource("instantiatebinary").
|
||||
VersionedParams(request, kapi.ParameterCodec).
|
||||
Body(r).Do().Into(result)
|
||||
return
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
kapi "k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/client/restclient"
|
||||
|
||||
api "github.com/openshift/origin/pkg/build/api"
|
||||
)
|
||||
|
||||
// BuildLogsNamespacer has methods to work with BuildLogs resources in a namespace
|
||||
type BuildLogsNamespacer interface {
|
||||
BuildLogs(namespace string) BuildLogsInterface
|
||||
}
|
||||
|
||||
// BuildLogsInterface exposes methods on BuildLogs resources.
|
||||
type BuildLogsInterface interface {
|
||||
Get(name string, opts api.BuildLogOptions) *restclient.Request
|
||||
}
|
||||
|
||||
// buildLogs implements BuildLogsNamespacer interface
|
||||
type buildLogs struct {
|
||||
r *Client
|
||||
ns string
|
||||
}
|
||||
|
||||
// newBuildLogs returns a buildLogs
|
||||
func newBuildLogs(c *Client, namespace string) *buildLogs {
|
||||
return &buildLogs{
|
||||
r: c,
|
||||
ns: namespace,
|
||||
}
|
||||
}
|
||||
|
||||
// Get builds and returns a buildLog request
|
||||
func (c *buildLogs) Get(name string, opts api.BuildLogOptions) *restclient.Request {
|
||||
return c.r.Get().Namespace(c.ns).Resource("builds").Name(name).SubResource("log").VersionedParams(&opts, kapi.ParameterCodec)
|
||||
}
|
||||
+104
@@ -0,0 +1,104 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
kapi "k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/watch"
|
||||
|
||||
buildapi "github.com/openshift/origin/pkg/build/api"
|
||||
)
|
||||
|
||||
// BuildsNamespacer has methods to work with Build resources in a namespace
|
||||
type BuildsNamespacer interface {
|
||||
Builds(namespace string) BuildInterface
|
||||
}
|
||||
|
||||
// BuildInterface exposes methods on Build resources.
|
||||
type BuildInterface interface {
|
||||
List(opts kapi.ListOptions) (*buildapi.BuildList, error)
|
||||
Get(name string) (*buildapi.Build, error)
|
||||
Create(build *buildapi.Build) (*buildapi.Build, error)
|
||||
Update(build *buildapi.Build) (*buildapi.Build, error)
|
||||
Delete(name string) error
|
||||
Watch(opts kapi.ListOptions) (watch.Interface, error)
|
||||
Clone(request *buildapi.BuildRequest) (*buildapi.Build, error)
|
||||
UpdateDetails(build *buildapi.Build) (*buildapi.Build, error)
|
||||
}
|
||||
|
||||
// builds implements BuildsNamespacer interface
|
||||
type builds struct {
|
||||
r *Client
|
||||
ns string
|
||||
}
|
||||
|
||||
// newBuilds returns a builds
|
||||
func newBuilds(c *Client, namespace string) *builds {
|
||||
return &builds{
|
||||
r: c,
|
||||
ns: namespace,
|
||||
}
|
||||
}
|
||||
|
||||
// List returns a list of builds that match the label and field selectors.
|
||||
func (c *builds) List(opts kapi.ListOptions) (result *buildapi.BuildList, err error) {
|
||||
result = &buildapi.BuildList{}
|
||||
err = c.r.Get().
|
||||
Namespace(c.ns).
|
||||
Resource("builds").
|
||||
VersionedParams(&opts, kapi.ParameterCodec).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Get returns information about a particular build and error if one occurs.
|
||||
func (c *builds) Get(name string) (result *buildapi.Build, err error) {
|
||||
result = &buildapi.Build{}
|
||||
err = c.r.Get().Namespace(c.ns).Resource("builds").Name(name).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Create creates new build. Returns the server's representation of the build and error if one occurs.
|
||||
func (c *builds) Create(build *buildapi.Build) (result *buildapi.Build, err error) {
|
||||
result = &buildapi.Build{}
|
||||
err = c.r.Post().Namespace(c.ns).Resource("builds").Body(build).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Update updates the build on server. Returns the server's representation of the build and error if one occurs.
|
||||
func (c *builds) Update(build *buildapi.Build) (result *buildapi.Build, err error) {
|
||||
result = &buildapi.Build{}
|
||||
err = c.r.Put().Namespace(c.ns).Resource("builds").Name(build.Name).Body(build).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Delete deletes a build, returns error if one occurs.
|
||||
func (c *builds) Delete(name string) (err error) {
|
||||
err = c.r.Delete().Namespace(c.ns).Resource("builds").Name(name).Do().Error()
|
||||
return
|
||||
}
|
||||
|
||||
// Watch returns a watch.Interface that watches the requested builds
|
||||
func (c *builds) Watch(opts kapi.ListOptions) (watch.Interface, error) {
|
||||
return c.r.Get().
|
||||
Prefix("watch").
|
||||
Namespace(c.ns).
|
||||
Resource("builds").
|
||||
VersionedParams(&opts, kapi.ParameterCodec).
|
||||
Watch()
|
||||
}
|
||||
|
||||
// Clone creates a clone of a build returning new object or an error
|
||||
func (c *builds) Clone(request *buildapi.BuildRequest) (result *buildapi.Build, err error) {
|
||||
result = &buildapi.Build{}
|
||||
err = c.r.Post().Namespace(c.ns).Resource("builds").Name(request.Name).SubResource("clone").Body(request).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// UpdateDetails updates the build details for a given build.
|
||||
// Currently only the Spec.Revision is allowed to be updated.
|
||||
// Returns the server's representation of the build and error if one occurs.
|
||||
func (c *builds) UpdateDetails(build *buildapi.Build) (result *buildapi.Build, err error) {
|
||||
result = &buildapi.Build{}
|
||||
err = c.r.Put().Namespace(c.ns).Resource("builds").Name(build.Name).SubResource("details").Body(build).Do().Into(result)
|
||||
return
|
||||
}
|
||||
+367
@@ -0,0 +1,367 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
kapi "k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/errors"
|
||||
"k8s.io/kubernetes/pkg/client/restclient"
|
||||
"k8s.io/kubernetes/pkg/client/typed/discovery"
|
||||
|
||||
"github.com/openshift/origin/pkg/api/latest"
|
||||
"github.com/openshift/origin/pkg/version"
|
||||
)
|
||||
|
||||
// Interface exposes methods on OpenShift resources.
|
||||
type Interface interface {
|
||||
BuildsNamespacer
|
||||
BuildConfigsNamespacer
|
||||
BuildLogsNamespacer
|
||||
ImagesInterfacer
|
||||
ImageSignaturesInterfacer
|
||||
ImageStreamsNamespacer
|
||||
ImageStreamMappingsNamespacer
|
||||
ImageStreamTagsNamespacer
|
||||
ImageStreamImagesNamespacer
|
||||
ImageStreamSecretsNamespacer
|
||||
DeploymentConfigsNamespacer
|
||||
DeploymentLogsNamespacer
|
||||
RoutesNamespacer
|
||||
HostSubnetsInterface
|
||||
NetNamespacesInterface
|
||||
ClusterNetworkingInterface
|
||||
EgressNetworkPoliciesNamespacer
|
||||
IdentitiesInterface
|
||||
UsersInterface
|
||||
GroupsInterface
|
||||
UserIdentityMappingsInterface
|
||||
ProjectsInterface
|
||||
ProjectRequestsInterface
|
||||
LocalSubjectAccessReviewsImpersonator
|
||||
SubjectAccessReviewsImpersonator
|
||||
LocalResourceAccessReviewsNamespacer
|
||||
ResourceAccessReviews
|
||||
SubjectAccessReviews
|
||||
LocalSubjectAccessReviewsNamespacer
|
||||
SelfSubjectRulesReviewsNamespacer
|
||||
TemplatesNamespacer
|
||||
TemplateConfigsNamespacer
|
||||
OAuthClientsInterface
|
||||
OAuthClientAuthorizationsInterface
|
||||
OAuthAccessTokensInterface
|
||||
OAuthAuthorizeTokensInterface
|
||||
PoliciesNamespacer
|
||||
PolicyBindingsNamespacer
|
||||
RolesNamespacer
|
||||
RoleBindingsNamespacer
|
||||
ClusterPoliciesInterface
|
||||
ClusterPolicyBindingsInterface
|
||||
ClusterRolesInterface
|
||||
ClusterRoleBindingsInterface
|
||||
ClusterResourceQuotasInterface
|
||||
AppliedClusterResourceQuotasNamespacer
|
||||
}
|
||||
|
||||
// Builds provides a REST client for Builds
|
||||
func (c *Client) Builds(namespace string) BuildInterface {
|
||||
return newBuilds(c, namespace)
|
||||
}
|
||||
|
||||
// BuildConfigs provides a REST client for BuildConfigs
|
||||
func (c *Client) BuildConfigs(namespace string) BuildConfigInterface {
|
||||
return newBuildConfigs(c, namespace)
|
||||
}
|
||||
|
||||
// BuildLogs provides a REST client for BuildLogs
|
||||
func (c *Client) BuildLogs(namespace string) BuildLogsInterface {
|
||||
return newBuildLogs(c, namespace)
|
||||
}
|
||||
|
||||
// Images provides a REST client for Images
|
||||
func (c *Client) Images() ImageInterface {
|
||||
return newImages(c)
|
||||
}
|
||||
|
||||
// ImageSignatures provides a REST client for ImageSignatures
|
||||
func (c *Client) ImageSignatures() ImageSignatureInterface {
|
||||
return newImageSignatures(c)
|
||||
}
|
||||
|
||||
// ImageStreamImages provides a REST client for retrieving image secrets in a namespace
|
||||
func (c *Client) ImageStreamSecrets(namespace string) ImageStreamSecretInterface {
|
||||
return newImageStreamSecrets(c, namespace)
|
||||
}
|
||||
|
||||
// ImageStreams provides a REST client for ImageStream
|
||||
func (c *Client) ImageStreams(namespace string) ImageStreamInterface {
|
||||
return newImageStreams(c, namespace)
|
||||
}
|
||||
|
||||
// ImageStreamMappings provides a REST client for ImageStreamMapping
|
||||
func (c *Client) ImageStreamMappings(namespace string) ImageStreamMappingInterface {
|
||||
return newImageStreamMappings(c, namespace)
|
||||
}
|
||||
|
||||
// ImageStreamTags provides a REST client for ImageStreamTag
|
||||
func (c *Client) ImageStreamTags(namespace string) ImageStreamTagInterface {
|
||||
return newImageStreamTags(c, namespace)
|
||||
}
|
||||
|
||||
// ImageStreamImages provides a REST client for ImageStreamImage
|
||||
func (c *Client) ImageStreamImages(namespace string) ImageStreamImageInterface {
|
||||
return newImageStreamImages(c, namespace)
|
||||
}
|
||||
|
||||
// DeploymentConfigs provides a REST client for DeploymentConfig
|
||||
func (c *Client) DeploymentConfigs(namespace string) DeploymentConfigInterface {
|
||||
return newDeploymentConfigs(c, namespace)
|
||||
}
|
||||
|
||||
// DeploymentLogs provides a REST client for DeploymentLog
|
||||
func (c *Client) DeploymentLogs(namespace string) DeploymentLogInterface {
|
||||
return newDeploymentLogs(c, namespace)
|
||||
}
|
||||
|
||||
// Routes provides a REST client for Route
|
||||
func (c *Client) Routes(namespace string) RouteInterface {
|
||||
return newRoutes(c, namespace)
|
||||
}
|
||||
|
||||
// HostSubnets provides a REST client for HostSubnet
|
||||
func (c *Client) HostSubnets() HostSubnetInterface {
|
||||
return newHostSubnet(c)
|
||||
}
|
||||
|
||||
// NetNamespaces provides a REST client for NetNamespace
|
||||
func (c *Client) NetNamespaces() NetNamespaceInterface {
|
||||
return newNetNamespace(c)
|
||||
}
|
||||
|
||||
// ClusterNetwork provides a REST client for ClusterNetworking
|
||||
func (c *Client) ClusterNetwork() ClusterNetworkInterface {
|
||||
return newClusterNetwork(c)
|
||||
}
|
||||
|
||||
// EgressNetworkPolicies provides a REST client for EgressNetworkPolicy
|
||||
func (c *Client) EgressNetworkPolicies(namespace string) EgressNetworkPolicyInterface {
|
||||
return newEgressNetworkPolicy(c, namespace)
|
||||
}
|
||||
|
||||
// Users provides a REST client for User
|
||||
func (c *Client) Users() UserInterface {
|
||||
return newUsers(c)
|
||||
}
|
||||
|
||||
// Identities provides a REST client for Identity
|
||||
func (c *Client) Identities() IdentityInterface {
|
||||
return newIdentities(c)
|
||||
}
|
||||
|
||||
// UserIdentityMappings provides a REST client for UserIdentityMapping
|
||||
func (c *Client) UserIdentityMappings() UserIdentityMappingInterface {
|
||||
return newUserIdentityMappings(c)
|
||||
}
|
||||
|
||||
// Groups provides a REST client for Groups
|
||||
func (c *Client) Groups() GroupInterface {
|
||||
return newGroups(c)
|
||||
}
|
||||
|
||||
// Projects provides a REST client for Projects
|
||||
func (c *Client) Projects() ProjectInterface {
|
||||
return newProjects(c)
|
||||
}
|
||||
|
||||
// ProjectRequests provides a REST client for Projects
|
||||
func (c *Client) ProjectRequests() ProjectRequestInterface {
|
||||
return newProjectRequests(c)
|
||||
}
|
||||
|
||||
// TemplateConfigs provides a REST client for TemplateConfig
|
||||
func (c *Client) TemplateConfigs(namespace string) TemplateConfigInterface {
|
||||
return newTemplateConfigs(c, namespace)
|
||||
}
|
||||
|
||||
// Templates provides a REST client for Templates
|
||||
func (c *Client) Templates(namespace string) TemplateInterface {
|
||||
return newTemplates(c, namespace)
|
||||
}
|
||||
|
||||
// Policies provides a REST client for Policies
|
||||
func (c *Client) Policies(namespace string) PolicyInterface {
|
||||
return newPolicies(c, namespace)
|
||||
}
|
||||
|
||||
// PolicyBindings provides a REST client for PolicyBindings
|
||||
func (c *Client) PolicyBindings(namespace string) PolicyBindingInterface {
|
||||
return newPolicyBindings(c, namespace)
|
||||
}
|
||||
|
||||
// Roles provides a REST client for Roles
|
||||
func (c *Client) Roles(namespace string) RoleInterface {
|
||||
return newRoles(c, namespace)
|
||||
}
|
||||
|
||||
// RoleBindings provides a REST client for RoleBindings
|
||||
func (c *Client) RoleBindings(namespace string) RoleBindingInterface {
|
||||
return newRoleBindings(c, namespace)
|
||||
}
|
||||
|
||||
// LocalResourceAccessReviews provides a REST client for LocalResourceAccessReviews
|
||||
func (c *Client) LocalResourceAccessReviews(namespace string) LocalResourceAccessReviewInterface {
|
||||
return newLocalResourceAccessReviews(c, namespace)
|
||||
}
|
||||
|
||||
// ClusterResourceAccessReviews provides a REST client for ClusterResourceAccessReviews
|
||||
func (c *Client) ResourceAccessReviews() ResourceAccessReviewInterface {
|
||||
return newResourceAccessReviews(c)
|
||||
}
|
||||
|
||||
// ImpersonateSubjectAccessReviews provides a REST client for SubjectAccessReviews
|
||||
func (c *Client) ImpersonateSubjectAccessReviews(token string) SubjectAccessReviewInterface {
|
||||
return newImpersonatingSubjectAccessReviews(c, token)
|
||||
}
|
||||
|
||||
// ImpersonateLocalSubjectAccessReviews provides a REST client for SubjectAccessReviews
|
||||
func (c *Client) ImpersonateLocalSubjectAccessReviews(namespace, token string) LocalSubjectAccessReviewInterface {
|
||||
return newImpersonatingLocalSubjectAccessReviews(c, namespace, token)
|
||||
}
|
||||
|
||||
// LocalSubjectAccessReviews provides a REST client for LocalSubjectAccessReviews
|
||||
func (c *Client) LocalSubjectAccessReviews(namespace string) LocalSubjectAccessReviewInterface {
|
||||
return newLocalSubjectAccessReviews(c, namespace)
|
||||
}
|
||||
|
||||
// SubjectAccessReviews provides a REST client for SubjectAccessReviews
|
||||
func (c *Client) SubjectAccessReviews() SubjectAccessReviewInterface {
|
||||
return newSubjectAccessReviews(c)
|
||||
}
|
||||
|
||||
func (c *Client) SelfSubjectRulesReviews(namespace string) SelfSubjectRulesReviewInterface {
|
||||
return newSelfSubjectRulesReviews(c, namespace)
|
||||
}
|
||||
|
||||
func (c *Client) OAuthClients() OAuthClientInterface {
|
||||
return newOAuthClients(c)
|
||||
}
|
||||
|
||||
func (c *Client) OAuthClientAuthorizations() OAuthClientAuthorizationInterface {
|
||||
return newOAuthClientAuthorizations(c)
|
||||
}
|
||||
|
||||
func (c *Client) OAuthAccessTokens() OAuthAccessTokenInterface {
|
||||
return newOAuthAccessTokens(c)
|
||||
}
|
||||
|
||||
func (c *Client) OAuthAuthorizeTokens() OAuthAuthorizeTokenInterface {
|
||||
return newOAuthAuthorizeTokens(c)
|
||||
}
|
||||
|
||||
func (c *Client) ClusterPolicies() ClusterPolicyInterface {
|
||||
return newClusterPolicies(c)
|
||||
}
|
||||
|
||||
func (c *Client) ClusterPolicyBindings() ClusterPolicyBindingInterface {
|
||||
return newClusterPolicyBindings(c)
|
||||
}
|
||||
|
||||
func (c *Client) ClusterRoles() ClusterRoleInterface {
|
||||
return newClusterRoles(c)
|
||||
}
|
||||
|
||||
func (c *Client) ClusterRoleBindings() ClusterRoleBindingInterface {
|
||||
return newClusterRoleBindings(c)
|
||||
}
|
||||
|
||||
func (c *Client) ClusterResourceQuotas() ClusterResourceQuotaInterface {
|
||||
return newClusterResourceQuotas(c)
|
||||
}
|
||||
|
||||
func (c *Client) AppliedClusterResourceQuotas(namespace string) AppliedClusterResourceQuotaInterface {
|
||||
return newAppliedClusterResourceQuotas(c, namespace)
|
||||
}
|
||||
|
||||
// Client is an OpenShift client object
|
||||
type Client struct {
|
||||
*restclient.RESTClient
|
||||
}
|
||||
|
||||
// New creates an OpenShift client for the given config. This client works with builds, deployments,
|
||||
// templates, routes, and images. It allows operations such as list, get, update and delete on these
|
||||
// objects. An error is returned if the provided configuration is not valid.
|
||||
func New(c *restclient.Config) (*Client, error) {
|
||||
config := *c
|
||||
if err := SetOpenShiftDefaults(&config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
client, err := restclient.RESTClientFor(&config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Client{client}, nil
|
||||
}
|
||||
|
||||
// DiscoveryClient returns a discovery client.
|
||||
func (c *Client) Discovery() discovery.DiscoveryInterface {
|
||||
d := NewDiscoveryClient(c.RESTClient)
|
||||
return d
|
||||
}
|
||||
|
||||
// SetOpenShiftDefaults sets the default settings on the passed
|
||||
// client configuration
|
||||
func SetOpenShiftDefaults(config *restclient.Config) error {
|
||||
if len(config.UserAgent) == 0 {
|
||||
config.UserAgent = DefaultOpenShiftUserAgent()
|
||||
}
|
||||
if config.GroupVersion == nil {
|
||||
// Clients default to the preferred code API version
|
||||
groupVersionCopy := latest.Version
|
||||
config.GroupVersion = &groupVersionCopy
|
||||
}
|
||||
if config.APIPath == "" {
|
||||
config.APIPath = "/oapi"
|
||||
}
|
||||
if config.NegotiatedSerializer == nil {
|
||||
config.NegotiatedSerializer = kapi.Codecs
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewOrDie creates an OpenShift client and panics if the provided API version is not recognized.
|
||||
func NewOrDie(c *restclient.Config) *Client {
|
||||
client, err := New(c)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return client
|
||||
}
|
||||
|
||||
// DefaultOpenShiftUserAgent returns the default user agent that clients can use.
|
||||
func DefaultOpenShiftUserAgent() string {
|
||||
commit := version.Get().GitCommit
|
||||
if len(commit) > 7 {
|
||||
commit = commit[:7]
|
||||
}
|
||||
if len(commit) == 0 {
|
||||
commit = "unknown"
|
||||
}
|
||||
version := version.Get().GitVersion
|
||||
seg := strings.SplitN(version, "-", 2)
|
||||
version = seg[0]
|
||||
return fmt.Sprintf("%s/%s (%s/%s) openshift/%s", path.Base(os.Args[0]), version, runtime.GOOS, runtime.GOARCH, commit)
|
||||
}
|
||||
|
||||
// IsStatusErrorKind returns true if this error describes the provided kind.
|
||||
func IsStatusErrorKind(err error, kind string) bool {
|
||||
if s, ok := err.(errors.APIStatus); ok {
|
||||
if details := s.Status().Details; details != nil {
|
||||
return kind == details.Kind
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
kapi "k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/watch"
|
||||
|
||||
quotaapi "github.com/openshift/origin/pkg/quota/api"
|
||||
)
|
||||
|
||||
type ClusterResourceQuotasInterface interface {
|
||||
ClusterResourceQuotas() ClusterResourceQuotaInterface
|
||||
}
|
||||
|
||||
type ClusterResourceQuotaInterface interface {
|
||||
List(opts kapi.ListOptions) (*quotaapi.ClusterResourceQuotaList, error)
|
||||
Get(name string) (*quotaapi.ClusterResourceQuota, error)
|
||||
Create(resourceQuota *quotaapi.ClusterResourceQuota) (*quotaapi.ClusterResourceQuota, error)
|
||||
Update(resourceQuota *quotaapi.ClusterResourceQuota) (*quotaapi.ClusterResourceQuota, error)
|
||||
Delete(name string) error
|
||||
Watch(opts kapi.ListOptions) (watch.Interface, error)
|
||||
|
||||
UpdateStatus(resourceQuota *quotaapi.ClusterResourceQuota) (*quotaapi.ClusterResourceQuota, error)
|
||||
}
|
||||
|
||||
type clusterResourceQuotas struct {
|
||||
r *Client
|
||||
}
|
||||
|
||||
// newClusterResourceQuotas returns a clusterResourceQuotas
|
||||
func newClusterResourceQuotas(c *Client) *clusterResourceQuotas {
|
||||
return &clusterResourceQuotas{
|
||||
r: c,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *clusterResourceQuotas) List(opts kapi.ListOptions) (result *quotaapi.ClusterResourceQuotaList, err error) {
|
||||
result = "aapi.ClusterResourceQuotaList{}
|
||||
err = c.r.Get().Resource("clusterresourcequotas").VersionedParams(&opts, kapi.ParameterCodec).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
func (c *clusterResourceQuotas) Get(name string) (result *quotaapi.ClusterResourceQuota, err error) {
|
||||
result = "aapi.ClusterResourceQuota{}
|
||||
err = c.r.Get().Resource("clusterresourcequotas").Name(name).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
func (c *clusterResourceQuotas) Create(resourceQuota *quotaapi.ClusterResourceQuota) (result *quotaapi.ClusterResourceQuota, err error) {
|
||||
result = "aapi.ClusterResourceQuota{}
|
||||
err = c.r.Post().Resource("clusterresourcequotas").Body(resourceQuota).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
func (c *clusterResourceQuotas) Update(resourceQuota *quotaapi.ClusterResourceQuota) (result *quotaapi.ClusterResourceQuota, err error) {
|
||||
result = "aapi.ClusterResourceQuota{}
|
||||
err = c.r.Put().Resource("clusterresourcequotas").Name(resourceQuota.Name).Body(resourceQuota).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
func (c *clusterResourceQuotas) Delete(name string) (err error) {
|
||||
err = c.r.Delete().Resource("clusterresourcequotas").Name(name).Do().Error()
|
||||
return
|
||||
}
|
||||
|
||||
func (c *clusterResourceQuotas) Watch(opts kapi.ListOptions) (watch.Interface, error) {
|
||||
return c.r.Get().Prefix("watch").Resource("clusterresourcequotas").VersionedParams(&opts, kapi.ParameterCodec).Watch()
|
||||
}
|
||||
|
||||
func (c *clusterResourceQuotas) UpdateStatus(resourceQuota *quotaapi.ClusterResourceQuota) (result *quotaapi.ClusterResourceQuota, err error) {
|
||||
result = "aapi.ClusterResourceQuota{}
|
||||
err = c.r.Put().Resource("clusterresourcequotas").Name(resourceQuota.Name).SubResource("status").Body(resourceQuota).Do().Into(result)
|
||||
return
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
sdnapi "github.com/openshift/origin/pkg/sdn/api"
|
||||
)
|
||||
|
||||
// ClusterNetworkingInterface has methods to work with ClusterNetwork resources
|
||||
type ClusterNetworkingInterface interface {
|
||||
ClusterNetwork() ClusterNetworkInterface
|
||||
}
|
||||
|
||||
// ClusterNetworkInterface exposes methods on clusterNetwork resources.
|
||||
type ClusterNetworkInterface interface {
|
||||
Get(name string) (*sdnapi.ClusterNetwork, error)
|
||||
Create(sub *sdnapi.ClusterNetwork) (*sdnapi.ClusterNetwork, error)
|
||||
Update(sub *sdnapi.ClusterNetwork) (*sdnapi.ClusterNetwork, error)
|
||||
}
|
||||
|
||||
// clusterNetwork implements ClusterNetworkInterface interface
|
||||
type clusterNetwork struct {
|
||||
r *Client
|
||||
}
|
||||
|
||||
// newClusterNetwork returns a clusterNetwork
|
||||
func newClusterNetwork(c *Client) *clusterNetwork {
|
||||
return &clusterNetwork{
|
||||
r: c,
|
||||
}
|
||||
}
|
||||
|
||||
// Get returns information about a particular network
|
||||
func (c *clusterNetwork) Get(networkName string) (result *sdnapi.ClusterNetwork, err error) {
|
||||
result = &sdnapi.ClusterNetwork{}
|
||||
err = c.r.Get().Resource("clusterNetworks").Name(networkName).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Create creates a new ClusterNetwork. Returns the server's representation of ClusterNetwork and error if one occurs.
|
||||
func (c *clusterNetwork) Create(cn *sdnapi.ClusterNetwork) (result *sdnapi.ClusterNetwork, err error) {
|
||||
result = &sdnapi.ClusterNetwork{}
|
||||
err = c.r.Post().Resource("clusterNetworks").Body(cn).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Update updates the ClusterNetwork on the server. Returns the server's representation of the ClusterNetwork and error if one occurs.
|
||||
func (c *clusterNetwork) Update(cn *sdnapi.ClusterNetwork) (result *sdnapi.ClusterNetwork, err error) {
|
||||
result = &sdnapi.ClusterNetwork{}
|
||||
err = c.r.Put().Resource("clusterNetworks").Name(cn.Name).Body(cn).Do().Into(result)
|
||||
return
|
||||
}
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
kapi "k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/watch"
|
||||
|
||||
authorizationapi "github.com/openshift/origin/pkg/authorization/api"
|
||||
)
|
||||
|
||||
// ClusterPoliciesInterface has methods to work with ClusterPolicies resources in a namespace
|
||||
type ClusterPoliciesInterface interface {
|
||||
ClusterPolicies() ClusterPolicyInterface
|
||||
}
|
||||
|
||||
// ClusterPolicyInterface exposes methods on ClusterPolicies resources
|
||||
type ClusterPolicyInterface interface {
|
||||
List(opts kapi.ListOptions) (*authorizationapi.ClusterPolicyList, error)
|
||||
Get(name string) (*authorizationapi.ClusterPolicy, error)
|
||||
Delete(name string) error
|
||||
Watch(opts kapi.ListOptions) (watch.Interface, error)
|
||||
}
|
||||
|
||||
type ClusterPoliciesListerInterface interface {
|
||||
ClusterPolicies() ClusterPolicyLister
|
||||
}
|
||||
type ClusterPolicyLister interface {
|
||||
List(options kapi.ListOptions) (*authorizationapi.ClusterPolicyList, error)
|
||||
Get(name string) (*authorizationapi.ClusterPolicy, error)
|
||||
}
|
||||
type SyncedClusterPoliciesListerInterface interface {
|
||||
ClusterPoliciesListerInterface
|
||||
LastSyncResourceVersion() string
|
||||
}
|
||||
|
||||
type clusterPolicies struct {
|
||||
r *Client
|
||||
}
|
||||
|
||||
func newClusterPolicies(c *Client) *clusterPolicies {
|
||||
return &clusterPolicies{
|
||||
r: c,
|
||||
}
|
||||
}
|
||||
|
||||
// List returns a list of policies that match the label and field selectors.
|
||||
func (c *clusterPolicies) List(opts kapi.ListOptions) (result *authorizationapi.ClusterPolicyList, err error) {
|
||||
result = &authorizationapi.ClusterPolicyList{}
|
||||
err = c.r.Get().Resource("clusterPolicies").VersionedParams(&opts, kapi.ParameterCodec).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Get returns information about a particular policy and error if one occurs.
|
||||
func (c *clusterPolicies) Get(name string) (result *authorizationapi.ClusterPolicy, err error) {
|
||||
result = &authorizationapi.ClusterPolicy{}
|
||||
err = c.r.Get().Resource("clusterPolicies").Name(name).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Delete deletes a policy, returns error if one occurs.
|
||||
func (c *clusterPolicies) Delete(name string) (err error) {
|
||||
err = c.r.Delete().Resource("clusterPolicies").Name(name).Do().Error()
|
||||
return
|
||||
}
|
||||
|
||||
// Watch returns a watch.Interface that watches the requested clusterPolicies
|
||||
func (c *clusterPolicies) Watch(opts kapi.ListOptions) (watch.Interface, error) {
|
||||
return c.r.Get().Prefix("watch").Resource("clusterPolicies").VersionedParams(&opts, kapi.ParameterCodec).Watch()
|
||||
}
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
kapi "k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/watch"
|
||||
|
||||
authorizationapi "github.com/openshift/origin/pkg/authorization/api"
|
||||
)
|
||||
|
||||
// ClusterPolicyBindingsInterface has methods to work with ClusterPolicyBindings resources in a namespace
|
||||
type ClusterPolicyBindingsInterface interface {
|
||||
ClusterPolicyBindings() ClusterPolicyBindingInterface
|
||||
}
|
||||
|
||||
// ClusterPolicyBindingInterface exposes methods on ClusterPolicyBindings resources
|
||||
type ClusterPolicyBindingInterface interface {
|
||||
List(opts kapi.ListOptions) (*authorizationapi.ClusterPolicyBindingList, error)
|
||||
Get(name string) (*authorizationapi.ClusterPolicyBinding, error)
|
||||
Create(policyBinding *authorizationapi.ClusterPolicyBinding) (*authorizationapi.ClusterPolicyBinding, error)
|
||||
Delete(name string) error
|
||||
Watch(opts kapi.ListOptions) (watch.Interface, error)
|
||||
}
|
||||
|
||||
type ClusterPolicyBindingsListerInterface interface {
|
||||
ClusterPolicyBindings() ClusterPolicyBindingLister
|
||||
}
|
||||
type ClusterPolicyBindingLister interface {
|
||||
List(options kapi.ListOptions) (*authorizationapi.ClusterPolicyBindingList, error)
|
||||
Get(name string) (*authorizationapi.ClusterPolicyBinding, error)
|
||||
}
|
||||
type SyncedClusterPolicyBindingsListerInterface interface {
|
||||
ClusterPolicyBindingsListerInterface
|
||||
LastSyncResourceVersion() string
|
||||
}
|
||||
|
||||
type clusterPolicyBindings struct {
|
||||
r *Client
|
||||
}
|
||||
|
||||
// newClusterPolicyBindings returns a clusterPolicyBindings
|
||||
func newClusterPolicyBindings(c *Client) *clusterPolicyBindings {
|
||||
return &clusterPolicyBindings{
|
||||
r: c,
|
||||
}
|
||||
}
|
||||
|
||||
// List returns a list of clusterPolicyBindings that match the label and field selectors.
|
||||
func (c *clusterPolicyBindings) List(opts kapi.ListOptions) (result *authorizationapi.ClusterPolicyBindingList, err error) {
|
||||
result = &authorizationapi.ClusterPolicyBindingList{}
|
||||
err = c.r.Get().Resource("clusterPolicyBindings").VersionedParams(&opts, kapi.ParameterCodec).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Get returns information about a particular clusterPolicyBindings and error if one occurs.
|
||||
func (c *clusterPolicyBindings) Get(name string) (result *authorizationapi.ClusterPolicyBinding, err error) {
|
||||
result = &authorizationapi.ClusterPolicyBinding{}
|
||||
err = c.r.Get().Resource("clusterPolicyBindings").Name(name).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Create creates new policyBinding. Returns the server's representation of the clusterPolicyBindings and error if one occurs.
|
||||
func (c *clusterPolicyBindings) Create(policyBinding *authorizationapi.ClusterPolicyBinding) (result *authorizationapi.ClusterPolicyBinding, err error) {
|
||||
result = &authorizationapi.ClusterPolicyBinding{}
|
||||
err = c.r.Post().Resource("clusterPolicyBindings").Body(policyBinding).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Delete deletes a policyBinding, returns error if one occurs.
|
||||
func (c *clusterPolicyBindings) Delete(name string) (err error) {
|
||||
err = c.r.Delete().Resource("clusterPolicyBindings").Name(name).Do().Error()
|
||||
return
|
||||
}
|
||||
|
||||
// Watch returns a watch.Interface that watches the requested clusterPolicyBindings
|
||||
func (c *clusterPolicyBindings) Watch(opts kapi.ListOptions) (watch.Interface, error) {
|
||||
return c.r.Get().Prefix("watch").Resource("clusterPolicyBindings").VersionedParams(&opts, kapi.ParameterCodec).Watch()
|
||||
}
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
kapi "k8s.io/kubernetes/pkg/api"
|
||||
|
||||
authorizationapi "github.com/openshift/origin/pkg/authorization/api"
|
||||
)
|
||||
|
||||
// ClusterRoleBindingsInterface has methods to work with ClusterRoleBindings resources in a namespace
|
||||
type ClusterRoleBindingsInterface interface {
|
||||
ClusterRoleBindings() ClusterRoleBindingInterface
|
||||
}
|
||||
|
||||
// ClusterRoleBindingInterface exposes methods on ClusterRoleBindings resources
|
||||
type ClusterRoleBindingInterface interface {
|
||||
List(opts kapi.ListOptions) (*authorizationapi.ClusterRoleBindingList, error)
|
||||
Get(name string) (*authorizationapi.ClusterRoleBinding, error)
|
||||
Update(roleBinding *authorizationapi.ClusterRoleBinding) (*authorizationapi.ClusterRoleBinding, error)
|
||||
Create(roleBinding *authorizationapi.ClusterRoleBinding) (*authorizationapi.ClusterRoleBinding, error)
|
||||
Delete(name string) error
|
||||
}
|
||||
|
||||
type clusterRoleBindings struct {
|
||||
r *Client
|
||||
}
|
||||
|
||||
// newClusterRoleBindings returns a clusterRoleBindings
|
||||
func newClusterRoleBindings(c *Client) *clusterRoleBindings {
|
||||
return &clusterRoleBindings{
|
||||
r: c,
|
||||
}
|
||||
}
|
||||
|
||||
// List returns a list of clusterRoleBindings that match the label and field selectors.
|
||||
func (c *clusterRoleBindings) List(opts kapi.ListOptions) (result *authorizationapi.ClusterRoleBindingList, err error) {
|
||||
result = &authorizationapi.ClusterRoleBindingList{}
|
||||
err = c.r.Get().Resource("clusterRoleBindings").VersionedParams(&opts, kapi.ParameterCodec).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Get returns information about a particular roleBinding and error if one occurs.
|
||||
func (c *clusterRoleBindings) Get(name string) (result *authorizationapi.ClusterRoleBinding, err error) {
|
||||
result = &authorizationapi.ClusterRoleBinding{}
|
||||
err = c.r.Get().Resource("clusterRoleBindings").Name(name).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Create creates new roleBinding. Returns the server's representation of the roleBinding and error if one occurs.
|
||||
func (c *clusterRoleBindings) Create(roleBinding *authorizationapi.ClusterRoleBinding) (result *authorizationapi.ClusterRoleBinding, err error) {
|
||||
result = &authorizationapi.ClusterRoleBinding{}
|
||||
err = c.r.Post().Resource("clusterRoleBindings").Body(roleBinding).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Update updates the roleBinding on server. Returns the server's representation of the roleBinding and error if one occurs.
|
||||
func (c *clusterRoleBindings) Update(roleBinding *authorizationapi.ClusterRoleBinding) (result *authorizationapi.ClusterRoleBinding, err error) {
|
||||
result = &authorizationapi.ClusterRoleBinding{}
|
||||
err = c.r.Put().Resource("clusterRoleBindings").Name(roleBinding.Name).Body(roleBinding).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Delete deletes a roleBinding, returns error if one occurs.
|
||||
func (c *clusterRoleBindings) Delete(name string) (err error) {
|
||||
err = c.r.Delete().Resource("clusterRoleBindings").Name(name).Do().Error()
|
||||
return
|
||||
}
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
kapi "k8s.io/kubernetes/pkg/api"
|
||||
|
||||
authorizationapi "github.com/openshift/origin/pkg/authorization/api"
|
||||
)
|
||||
|
||||
// ClusterRolesInterface has methods to work with ClusterRoles resources in a namespace
|
||||
type ClusterRolesInterface interface {
|
||||
ClusterRoles() ClusterRoleInterface
|
||||
}
|
||||
|
||||
// ClusterRoleInterface exposes methods on ClusterRoles resources
|
||||
type ClusterRoleInterface interface {
|
||||
List(opts kapi.ListOptions) (*authorizationapi.ClusterRoleList, error)
|
||||
Get(name string) (*authorizationapi.ClusterRole, error)
|
||||
Create(role *authorizationapi.ClusterRole) (*authorizationapi.ClusterRole, error)
|
||||
Update(role *authorizationapi.ClusterRole) (*authorizationapi.ClusterRole, error)
|
||||
Delete(name string) error
|
||||
}
|
||||
|
||||
type clusterRoles struct {
|
||||
r *Client
|
||||
}
|
||||
|
||||
// newClusterRoles returns a clusterRoles
|
||||
func newClusterRoles(c *Client) *clusterRoles {
|
||||
return &clusterRoles{
|
||||
r: c,
|
||||
}
|
||||
}
|
||||
|
||||
// List returns a list of clusterRoles that match the label and field selectors.
|
||||
func (c *clusterRoles) List(opts kapi.ListOptions) (result *authorizationapi.ClusterRoleList, err error) {
|
||||
result = &authorizationapi.ClusterRoleList{}
|
||||
err = c.r.Get().Resource("clusterRoles").VersionedParams(&opts, kapi.ParameterCodec).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Get returns information about a particular role and error if one occurs.
|
||||
func (c *clusterRoles) Get(name string) (result *authorizationapi.ClusterRole, err error) {
|
||||
result = &authorizationapi.ClusterRole{}
|
||||
err = c.r.Get().Resource("clusterRoles").Name(name).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Create creates new role. Returns the server's representation of the role and error if one occurs.
|
||||
func (c *clusterRoles) Create(role *authorizationapi.ClusterRole) (result *authorizationapi.ClusterRole, err error) {
|
||||
result = &authorizationapi.ClusterRole{}
|
||||
err = c.r.Post().Resource("clusterRoles").Body(role).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Update updates the roleBinding on server. Returns the server's representation of the roleBinding and error if one occurs.
|
||||
func (c *clusterRoles) Update(role *authorizationapi.ClusterRole) (result *authorizationapi.ClusterRole, err error) {
|
||||
result = &authorizationapi.ClusterRole{}
|
||||
err = c.r.Put().Resource("clusterRoles").Name(role.Name).Body(role).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Delete deletes a role, returns error if one occurs.
|
||||
func (c *clusterRoles) Delete(name string) (err error) {
|
||||
err = c.r.Delete().Resource("clusterRoles").Name(name).Do().Error()
|
||||
return
|
||||
}
|
||||
+176
@@ -0,0 +1,176 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
kapi "k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||
extensionsv1beta1 "k8s.io/kubernetes/pkg/apis/extensions/v1beta1"
|
||||
kclient "k8s.io/kubernetes/pkg/client/unversioned"
|
||||
"k8s.io/kubernetes/pkg/runtime"
|
||||
"k8s.io/kubernetes/pkg/watch"
|
||||
|
||||
deployapi "github.com/openshift/origin/pkg/deploy/api"
|
||||
)
|
||||
|
||||
// DeploymentConfigsNamespacer has methods to work with DeploymentConfig resources in a namespace
|
||||
type DeploymentConfigsNamespacer interface {
|
||||
DeploymentConfigs(namespace string) DeploymentConfigInterface
|
||||
}
|
||||
|
||||
// DeploymentConfigInterface contains methods for working with DeploymentConfigs
|
||||
type DeploymentConfigInterface interface {
|
||||
List(opts kapi.ListOptions) (*deployapi.DeploymentConfigList, error)
|
||||
Get(name string) (*deployapi.DeploymentConfig, error)
|
||||
Create(config *deployapi.DeploymentConfig) (*deployapi.DeploymentConfig, error)
|
||||
Update(config *deployapi.DeploymentConfig) (*deployapi.DeploymentConfig, error)
|
||||
Delete(name string) error
|
||||
Watch(opts kapi.ListOptions) (watch.Interface, error)
|
||||
Generate(name string) (*deployapi.DeploymentConfig, error)
|
||||
Rollback(config *deployapi.DeploymentConfigRollback) (*deployapi.DeploymentConfig, error)
|
||||
RollbackDeprecated(config *deployapi.DeploymentConfigRollback) (*deployapi.DeploymentConfig, error)
|
||||
GetScale(name string) (*extensions.Scale, error)
|
||||
UpdateScale(scale *extensions.Scale) (*extensions.Scale, error)
|
||||
UpdateStatus(config *deployapi.DeploymentConfig) (*deployapi.DeploymentConfig, error)
|
||||
}
|
||||
|
||||
// deploymentConfigs implements DeploymentConfigsNamespacer interface
|
||||
type deploymentConfigs struct {
|
||||
r *Client
|
||||
ns string
|
||||
}
|
||||
|
||||
// newDeploymentConfigs returns a deploymentConfigs
|
||||
func newDeploymentConfigs(c *Client, namespace string) *deploymentConfigs {
|
||||
return &deploymentConfigs{
|
||||
r: c,
|
||||
ns: namespace,
|
||||
}
|
||||
}
|
||||
|
||||
// List takes a label and field selectors, and returns the list of deploymentConfigs that match that selectors
|
||||
func (c *deploymentConfigs) List(opts kapi.ListOptions) (result *deployapi.DeploymentConfigList, err error) {
|
||||
result = &deployapi.DeploymentConfigList{}
|
||||
err = c.r.Get().
|
||||
Namespace(c.ns).
|
||||
Resource("deploymentConfigs").
|
||||
VersionedParams(&opts, kapi.ParameterCodec).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Get returns information about a particular deploymentConfig
|
||||
func (c *deploymentConfigs) Get(name string) (result *deployapi.DeploymentConfig, err error) {
|
||||
result = &deployapi.DeploymentConfig{}
|
||||
err = c.r.Get().Namespace(c.ns).Resource("deploymentConfigs").Name(name).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Create creates a new deploymentConfig
|
||||
func (c *deploymentConfigs) Create(deploymentConfig *deployapi.DeploymentConfig) (result *deployapi.DeploymentConfig, err error) {
|
||||
result = &deployapi.DeploymentConfig{}
|
||||
err = c.r.Post().Namespace(c.ns).Resource("deploymentConfigs").Body(deploymentConfig).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Update updates an existing deploymentConfig
|
||||
func (c *deploymentConfigs) Update(deploymentConfig *deployapi.DeploymentConfig) (result *deployapi.DeploymentConfig, err error) {
|
||||
result = &deployapi.DeploymentConfig{}
|
||||
err = c.r.Put().Namespace(c.ns).Resource("deploymentConfigs").Name(deploymentConfig.Name).Body(deploymentConfig).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Delete deletes an existing deploymentConfig.
|
||||
func (c *deploymentConfigs) Delete(name string) error {
|
||||
return c.r.Delete().Namespace(c.ns).Resource("deploymentConfigs").Name(name).Do().Error()
|
||||
}
|
||||
|
||||
// Watch returns a watch.Interface that watches the requested deploymentConfigs.
|
||||
func (c *deploymentConfigs) Watch(opts kapi.ListOptions) (watch.Interface, error) {
|
||||
return c.r.Get().
|
||||
Prefix("watch").
|
||||
Namespace(c.ns).
|
||||
Resource("deploymentConfigs").
|
||||
VersionedParams(&opts, kapi.ParameterCodec).
|
||||
Watch()
|
||||
}
|
||||
|
||||
// Generate generates a new deploymentConfig for the given name.
|
||||
func (c *deploymentConfigs) Generate(name string) (result *deployapi.DeploymentConfig, err error) {
|
||||
result = &deployapi.DeploymentConfig{}
|
||||
err = c.r.Get().Namespace(c.ns).Resource("generateDeploymentConfigs").Name(name).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Rollback rolls a deploymentConfig back to a previous configuration
|
||||
func (c *deploymentConfigs) Rollback(config *deployapi.DeploymentConfigRollback) (result *deployapi.DeploymentConfig, err error) {
|
||||
result = &deployapi.DeploymentConfig{}
|
||||
err = c.r.Post().
|
||||
Namespace(c.ns).
|
||||
Resource("deploymentConfigs").
|
||||
Name(config.Name).
|
||||
SubResource("rollback").
|
||||
Body(config).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// RollbackDeprecated rolls a deploymentConfig back to a previous configuration
|
||||
func (c *deploymentConfigs) RollbackDeprecated(config *deployapi.DeploymentConfigRollback) (result *deployapi.DeploymentConfig, err error) {
|
||||
result = &deployapi.DeploymentConfig{}
|
||||
err = c.r.Post().
|
||||
Namespace(c.ns).
|
||||
Resource("deploymentConfigRollbacks").
|
||||
Body(config).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// GetScale returns information about a particular deploymentConfig via its scale subresource
|
||||
func (c *deploymentConfigs) GetScale(name string) (result *extensions.Scale, err error) {
|
||||
result = &extensions.Scale{}
|
||||
err = c.r.Get().Namespace(c.ns).Resource("deploymentConfigs").Name(name).SubResource("scale").Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// UpdateScale scales an existing deploymentConfig via its scale subresource
|
||||
func (c *deploymentConfigs) UpdateScale(scale *extensions.Scale) (result *extensions.Scale, err error) {
|
||||
result = &extensions.Scale{}
|
||||
|
||||
// TODO fix by making the client understand how to encode using different codecs for different resources
|
||||
encodedBytes, err := runtime.Encode(kapi.Codecs.LegacyCodec(extensionsv1beta1.SchemeGroupVersion), scale)
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
|
||||
err = c.r.Put().Namespace(c.ns).Resource("deploymentConfigs").Name(scale.Name).SubResource("scale").Body(encodedBytes).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// UpdateStatus updates the status for an existing deploymentConfig.
|
||||
func (c *deploymentConfigs) UpdateStatus(deploymentConfig *deployapi.DeploymentConfig) (result *deployapi.DeploymentConfig, err error) {
|
||||
result = &deployapi.DeploymentConfig{}
|
||||
err = c.r.Put().Namespace(c.ns).Resource("deploymentConfigs").Name(deploymentConfig.Name).SubResource("status").Body(deploymentConfig).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
type updateConfigFunc func(d *deployapi.DeploymentConfig)
|
||||
|
||||
// UpdateConfigWithRetries will try to update a deployment config and ignore any update conflicts.
|
||||
func UpdateConfigWithRetries(dn DeploymentConfigsNamespacer, namespace, name string, applyUpdate updateConfigFunc) (*deployapi.DeploymentConfig, error) {
|
||||
var config *deployapi.DeploymentConfig
|
||||
|
||||
resultErr := kclient.RetryOnConflict(kclient.DefaultBackoff, func() error {
|
||||
var err error
|
||||
config, err = dn.DeploymentConfigs(namespace).Get(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Apply the update, then attempt to push it to the apiserver.
|
||||
applyUpdate(config)
|
||||
config, err = dn.DeploymentConfigs(namespace).Update(config)
|
||||
return err
|
||||
})
|
||||
return config, resultErr
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
kapi "k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/client/restclient"
|
||||
|
||||
"github.com/openshift/origin/pkg/deploy/api"
|
||||
)
|
||||
|
||||
// DeploymentLogsNamespacer has methods to work with DeploymentLogs resources in a namespace
|
||||
type DeploymentLogsNamespacer interface {
|
||||
DeploymentLogs(namespace string) DeploymentLogInterface
|
||||
}
|
||||
|
||||
// DeploymentLogInterface exposes methods on DeploymentLogs resources.
|
||||
type DeploymentLogInterface interface {
|
||||
Get(name string, opts api.DeploymentLogOptions) *restclient.Request
|
||||
}
|
||||
|
||||
// deploymentLogs implements DeploymentLogsNamespacer interface
|
||||
type deploymentLogs struct {
|
||||
r *Client
|
||||
ns string
|
||||
}
|
||||
|
||||
// newDeploymentLogs returns a deploymentLogs
|
||||
func newDeploymentLogs(c *Client, namespace string) *deploymentLogs {
|
||||
return &deploymentLogs{
|
||||
r: c,
|
||||
ns: namespace,
|
||||
}
|
||||
}
|
||||
|
||||
// Get gets the deploymentlogs and return a deploymentLog request
|
||||
func (c *deploymentLogs) Get(name string, opts api.DeploymentLogOptions) *restclient.Request {
|
||||
return c.r.Get().Namespace(c.ns).Resource("deploymentConfigs").Name(name).SubResource("log").VersionedParams(&opts, kapi.ParameterCodec)
|
||||
}
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api/errors"
|
||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||
"k8s.io/kubernetes/pkg/client/restclient"
|
||||
"k8s.io/kubernetes/pkg/client/typed/discovery"
|
||||
)
|
||||
|
||||
// DiscoveryClient implements the functions that discovery server-supported API groups,
|
||||
// versions and resources.
|
||||
type DiscoveryClient struct {
|
||||
*discovery.DiscoveryClient
|
||||
}
|
||||
|
||||
// ServerResourcesForGroupVersion returns the supported resources for a group and version.
|
||||
func (d *DiscoveryClient) ServerResourcesForGroupVersion(groupVersion string) (resources *unversioned.APIResourceList, err error) {
|
||||
parentList, err := d.DiscoveryClient.ServerResourcesForGroupVersion(groupVersion)
|
||||
if err != nil {
|
||||
return parentList, err
|
||||
}
|
||||
|
||||
if groupVersion != "v1" {
|
||||
return parentList, nil
|
||||
}
|
||||
|
||||
// we request v1, we must combine the parent list with the list from /oapi
|
||||
|
||||
url := url.URL{}
|
||||
url.Path = "/oapi/" + groupVersion
|
||||
originResources := &unversioned.APIResourceList{}
|
||||
err = d.Get().AbsPath(url.String()).Do().Into(originResources)
|
||||
if err != nil {
|
||||
// ignore 403 or 404 error to be compatible with an v1.0 server.
|
||||
if groupVersion == "v1" && (errors.IsNotFound(err) || errors.IsForbidden(err)) {
|
||||
return parentList, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
parentList.APIResources = append(parentList.APIResources, originResources.APIResources...)
|
||||
return parentList, nil
|
||||
}
|
||||
|
||||
// ServerResources returns the supported resources for all groups and versions.
|
||||
func (d *DiscoveryClient) ServerResources() (map[string]*unversioned.APIResourceList, error) {
|
||||
apiGroups, err := d.ServerGroups()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
groupVersions := unversioned.ExtractGroupVersions(apiGroups)
|
||||
result := map[string]*unversioned.APIResourceList{}
|
||||
for _, groupVersion := range groupVersions {
|
||||
resources, err := d.ServerResourcesForGroupVersion(groupVersion)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result[groupVersion] = resources
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// New creates a new DiscoveryClient for the given RESTClient.
|
||||
func NewDiscoveryClient(c *restclient.RESTClient) *DiscoveryClient {
|
||||
return &DiscoveryClient{discovery.NewDiscoveryClient(c)}
|
||||
}
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
kapi "k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/watch"
|
||||
|
||||
sdnapi "github.com/openshift/origin/pkg/sdn/api"
|
||||
)
|
||||
|
||||
// EgressNetworkPoliciesNamespacer has methods to work with EgressNetworkPolicy resources in a namespace
|
||||
type EgressNetworkPoliciesNamespacer interface {
|
||||
EgressNetworkPolicies(namespace string) EgressNetworkPolicyInterface
|
||||
}
|
||||
|
||||
// EgressNetworkPolicyInterface exposes methods on egressNetworkPolicy resources.
|
||||
type EgressNetworkPolicyInterface interface {
|
||||
List(opts kapi.ListOptions) (*sdnapi.EgressNetworkPolicyList, error)
|
||||
Get(name string) (*sdnapi.EgressNetworkPolicy, error)
|
||||
Create(sub *sdnapi.EgressNetworkPolicy) (*sdnapi.EgressNetworkPolicy, error)
|
||||
Update(sub *sdnapi.EgressNetworkPolicy) (*sdnapi.EgressNetworkPolicy, error)
|
||||
Delete(name string) error
|
||||
Watch(opts kapi.ListOptions) (watch.Interface, error)
|
||||
}
|
||||
|
||||
// egressNetworkPolicy implements EgressNetworkPolicyInterface interface
|
||||
type egressNetworkPolicy struct {
|
||||
r *Client
|
||||
ns string
|
||||
}
|
||||
|
||||
// newEgressNetworkPolicy returns a egressNetworkPolicy
|
||||
func newEgressNetworkPolicy(c *Client, namespace string) *egressNetworkPolicy {
|
||||
return &egressNetworkPolicy{
|
||||
r: c,
|
||||
ns: namespace,
|
||||
}
|
||||
}
|
||||
|
||||
// List returns a list of EgressNetworkPolicy that match the label and field selectors.
|
||||
func (c *egressNetworkPolicy) List(opts kapi.ListOptions) (result *sdnapi.EgressNetworkPolicyList, err error) {
|
||||
result = &sdnapi.EgressNetworkPolicyList{}
|
||||
err = c.r.Get().
|
||||
Namespace(c.ns).
|
||||
Resource("egressNetworkPolicies").
|
||||
VersionedParams(&opts, kapi.ParameterCodec).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Get returns information about a particular firewall
|
||||
func (c *egressNetworkPolicy) Get(name string) (result *sdnapi.EgressNetworkPolicy, err error) {
|
||||
result = &sdnapi.EgressNetworkPolicy{}
|
||||
err = c.r.Get().Namespace(c.ns).Resource("egressNetworkPolicies").Name(name).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Create creates a new EgressNetworkPolicy. Returns the server's representation of EgressNetworkPolicy and error if one occurs.
|
||||
func (c *egressNetworkPolicy) Create(fw *sdnapi.EgressNetworkPolicy) (result *sdnapi.EgressNetworkPolicy, err error) {
|
||||
result = &sdnapi.EgressNetworkPolicy{}
|
||||
err = c.r.Post().Namespace(c.ns).Resource("egressNetworkPolicies").Body(fw).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Update updates the EgressNetworkPolicy on the server. Returns the server's representation of the EgressNetworkPolicy and error if one occurs.
|
||||
func (c *egressNetworkPolicy) Update(fw *sdnapi.EgressNetworkPolicy) (result *sdnapi.EgressNetworkPolicy, err error) {
|
||||
result = &sdnapi.EgressNetworkPolicy{}
|
||||
err = c.r.Put().Namespace(c.ns).Resource("egressNetworkPolicies").Name(fw.Name).Body(fw).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Delete takes the name of the EgressNetworkPolicy, and returns an error if one occurs during deletion of the EgressNetworkPolicy
|
||||
func (c *egressNetworkPolicy) Delete(name string) error {
|
||||
return c.r.Delete().Namespace(c.ns).Resource("egressNetworkPolicies").Name(name).Do().Error()
|
||||
}
|
||||
|
||||
// Watch returns a watch.Interface that watches the requested EgressNetworkPolicies
|
||||
func (c *egressNetworkPolicy) Watch(opts kapi.ListOptions) (watch.Interface, error) {
|
||||
return c.r.Get().
|
||||
Prefix("watch").
|
||||
Namespace(c.ns).
|
||||
Resource("egressNetworkPolicies").
|
||||
VersionedParams(&opts, kapi.ParameterCodec).
|
||||
Watch()
|
||||
}
|
||||
+81
@@ -0,0 +1,81 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
kapi "k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/watch"
|
||||
|
||||
userapi "github.com/openshift/origin/pkg/user/api"
|
||||
)
|
||||
|
||||
// GroupsInterface has methods to work with Group resources
|
||||
type GroupsInterface interface {
|
||||
Groups() GroupInterface
|
||||
}
|
||||
|
||||
// GroupInterface exposes methods on group resources.
|
||||
type GroupInterface interface {
|
||||
List(opts kapi.ListOptions) (*userapi.GroupList, error)
|
||||
Get(name string) (*userapi.Group, error)
|
||||
Create(group *userapi.Group) (*userapi.Group, error)
|
||||
Update(group *userapi.Group) (*userapi.Group, error)
|
||||
Delete(name string) error
|
||||
Watch(opts kapi.ListOptions) (watch.Interface, error)
|
||||
}
|
||||
|
||||
// groups implements GroupInterface interface
|
||||
type groups struct {
|
||||
r *Client
|
||||
}
|
||||
|
||||
// newGroups returns a groups
|
||||
func newGroups(c *Client) *groups {
|
||||
return &groups{
|
||||
r: c,
|
||||
}
|
||||
}
|
||||
|
||||
// List returns a list of groups that match the label and field selectors.
|
||||
func (c *groups) List(opts kapi.ListOptions) (result *userapi.GroupList, err error) {
|
||||
result = &userapi.GroupList{}
|
||||
err = c.r.Get().
|
||||
Resource("groups").
|
||||
VersionedParams(&opts, kapi.ParameterCodec).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Get returns information about a particular group or an error
|
||||
func (c *groups) Get(name string) (result *userapi.Group, err error) {
|
||||
result = &userapi.Group{}
|
||||
err = c.r.Get().Resource("groups").Name(name).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Create creates a new group. Returns the server's representation of the group and error if one occurs.
|
||||
func (c *groups) Create(group *userapi.Group) (result *userapi.Group, err error) {
|
||||
result = &userapi.Group{}
|
||||
err = c.r.Post().Resource("groups").Body(group).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Update updates the group on server. Returns the server's representation of the group and error if one occurs.
|
||||
func (c *groups) Update(group *userapi.Group) (result *userapi.Group, err error) {
|
||||
result = &userapi.Group{}
|
||||
err = c.r.Put().Resource("groups").Name(group.Name).Body(group).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Delete takes the name of the groups, and returns an error if one occurs during deletion of the groups
|
||||
func (c *groups) Delete(name string) error {
|
||||
return c.r.Delete().Resource("groups").Name(name).Do().Error()
|
||||
}
|
||||
|
||||
// Watch returns a watch.Interface that watches the requested groups.
|
||||
func (c *groups) Watch(opts kapi.ListOptions) (watch.Interface, error) {
|
||||
return c.r.Get().
|
||||
Prefix("watch").
|
||||
Resource("groups").
|
||||
VersionedParams(&opts, kapi.ParameterCodec).
|
||||
Watch()
|
||||
}
|
||||
+81
@@ -0,0 +1,81 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
kapi "k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/watch"
|
||||
|
||||
sdnapi "github.com/openshift/origin/pkg/sdn/api"
|
||||
)
|
||||
|
||||
// HostSubnetInterface has methods to work with HostSubnet resources
|
||||
type HostSubnetsInterface interface {
|
||||
HostSubnets() HostSubnetInterface
|
||||
}
|
||||
|
||||
// HostSubnetInterface exposes methods on HostSubnet resources.
|
||||
type HostSubnetInterface interface {
|
||||
List(opts kapi.ListOptions) (*sdnapi.HostSubnetList, error)
|
||||
Get(name string) (*sdnapi.HostSubnet, error)
|
||||
Create(sub *sdnapi.HostSubnet) (*sdnapi.HostSubnet, error)
|
||||
Update(sub *sdnapi.HostSubnet) (*sdnapi.HostSubnet, error)
|
||||
Delete(name string) error
|
||||
Watch(opts kapi.ListOptions) (watch.Interface, error)
|
||||
}
|
||||
|
||||
// hostSubnet implements HostSubnetInterface interface
|
||||
type hostSubnet struct {
|
||||
r *Client
|
||||
}
|
||||
|
||||
// newHostSubnet returns a hostsubnet
|
||||
func newHostSubnet(c *Client) *hostSubnet {
|
||||
return &hostSubnet{
|
||||
r: c,
|
||||
}
|
||||
}
|
||||
|
||||
// List returns a list of hostsubnets that match the label and field selectors.
|
||||
func (c *hostSubnet) List(opts kapi.ListOptions) (result *sdnapi.HostSubnetList, err error) {
|
||||
result = &sdnapi.HostSubnetList{}
|
||||
err = c.r.Get().
|
||||
Resource("hostSubnets").
|
||||
VersionedParams(&opts, kapi.ParameterCodec).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Get returns host subnet information for a given host or an error
|
||||
func (c *hostSubnet) Get(hostName string) (result *sdnapi.HostSubnet, err error) {
|
||||
result = &sdnapi.HostSubnet{}
|
||||
err = c.r.Get().Resource("hostSubnets").Name(hostName).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Create creates a new host subnet. Returns the server's representation of the host subnet and error if one occurs.
|
||||
func (c *hostSubnet) Create(hostSubnet *sdnapi.HostSubnet) (result *sdnapi.HostSubnet, err error) {
|
||||
result = &sdnapi.HostSubnet{}
|
||||
err = c.r.Post().Resource("hostSubnets").Body(hostSubnet).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Update updates existing host subnet. Returns the server's representation of the host subnet and error if one occurs.
|
||||
func (c *hostSubnet) Update(hostSubnet *sdnapi.HostSubnet) (result *sdnapi.HostSubnet, err error) {
|
||||
result = &sdnapi.HostSubnet{}
|
||||
err = c.r.Put().Resource("hostSubnets").Name(hostSubnet.Name).Body(hostSubnet).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Delete takes the name of the host, and returns an error if one occurs during deletion of the subnet
|
||||
func (c *hostSubnet) Delete(name string) error {
|
||||
return c.r.Delete().Resource("hostSubnets").Name(name).Do().Error()
|
||||
}
|
||||
|
||||
// Watch returns a watch.Interface that watches the requested subnets
|
||||
func (c *hostSubnet) Watch(opts kapi.ListOptions) (watch.Interface, error) {
|
||||
return c.r.Get().
|
||||
Prefix("watch").
|
||||
Resource("hostSubnets").
|
||||
VersionedParams(&opts, kapi.ParameterCodec).
|
||||
Watch()
|
||||
}
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
kapi "k8s.io/kubernetes/pkg/api"
|
||||
|
||||
userapi "github.com/openshift/origin/pkg/user/api"
|
||||
)
|
||||
|
||||
// IdentitiesInterface has methods to work with Identity resources
|
||||
type IdentitiesInterface interface {
|
||||
Identities() IdentityInterface
|
||||
}
|
||||
|
||||
// IdentityInterface exposes methods on identity resources.
|
||||
type IdentityInterface interface {
|
||||
List(opts kapi.ListOptions) (*userapi.IdentityList, error)
|
||||
Get(name string) (*userapi.Identity, error)
|
||||
Create(identity *userapi.Identity) (*userapi.Identity, error)
|
||||
Update(identity *userapi.Identity) (*userapi.Identity, error)
|
||||
Delete(name string) error
|
||||
}
|
||||
|
||||
// identities implements IdentityInterface interface
|
||||
type identities struct {
|
||||
r *Client
|
||||
}
|
||||
|
||||
// newIdentities returns an identities client
|
||||
func newIdentities(c *Client) *identities {
|
||||
return &identities{
|
||||
r: c,
|
||||
}
|
||||
}
|
||||
|
||||
// List returns a list of identities that match the label and field selectors.
|
||||
func (c *identities) List(opts kapi.ListOptions) (result *userapi.IdentityList, err error) {
|
||||
result = &userapi.IdentityList{}
|
||||
err = c.r.Get().
|
||||
Resource("identities").
|
||||
VersionedParams(&opts, kapi.ParameterCodec).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Get returns information about a particular identity or an error
|
||||
func (c *identities) Get(name string) (result *userapi.Identity, err error) {
|
||||
result = &userapi.Identity{}
|
||||
err = c.r.Get().Resource("identities").Name(name).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Create creates a new identity. Returns the server's representation of the identity and error if one occurs.
|
||||
func (c *identities) Create(identity *userapi.Identity) (result *userapi.Identity, err error) {
|
||||
result = &userapi.Identity{}
|
||||
err = c.r.Post().Resource("identities").Body(identity).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Update updates the identity on server. Returns the server's representation of the identity and error if one occurs.
|
||||
func (c *identities) Update(identity *userapi.Identity) (result *userapi.Identity, err error) {
|
||||
result = &userapi.Identity{}
|
||||
err = c.r.Put().Resource("identities").Name(identity.Name).Body(identity).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Delete deletes the identity on server. Returns an error if one occurs.
|
||||
func (c *identities) Delete(name string) (err error) {
|
||||
return c.r.Delete().Resource("identities").Name(name).Do().Error()
|
||||
}
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
kapi "k8s.io/kubernetes/pkg/api"
|
||||
|
||||
imageapi "github.com/openshift/origin/pkg/image/api"
|
||||
)
|
||||
|
||||
// ImagesInterfacer has methods to work with Image resources
|
||||
type ImagesInterfacer interface {
|
||||
Images() ImageInterface
|
||||
}
|
||||
|
||||
// ImageInterface exposes methods on Image resources.
|
||||
type ImageInterface interface {
|
||||
List(opts kapi.ListOptions) (*imageapi.ImageList, error)
|
||||
Get(name string) (*imageapi.Image, error)
|
||||
Create(image *imageapi.Image) (*imageapi.Image, error)
|
||||
Update(image *imageapi.Image) (*imageapi.Image, error)
|
||||
Delete(name string) error
|
||||
}
|
||||
|
||||
// images implements ImagesInterface.
|
||||
type images struct {
|
||||
r *Client
|
||||
}
|
||||
|
||||
// newImages returns an images
|
||||
func newImages(c *Client) ImageInterface {
|
||||
return &images{
|
||||
r: c,
|
||||
}
|
||||
}
|
||||
|
||||
// List returns a list of images that match the label and field selectors.
|
||||
func (c *images) List(opts kapi.ListOptions) (result *imageapi.ImageList, err error) {
|
||||
result = &imageapi.ImageList{}
|
||||
err = c.r.Get().
|
||||
Resource("images").
|
||||
VersionedParams(&opts, kapi.ParameterCodec).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Get returns information about a particular image and error if one occurs.
|
||||
func (c *images) Get(name string) (result *imageapi.Image, err error) {
|
||||
result = &imageapi.Image{}
|
||||
err = c.r.Get().Resource("images").Name(name).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Create creates a new image. Returns the server's representation of the image and error if one occurs.
|
||||
func (c *images) Create(image *imageapi.Image) (result *imageapi.Image, err error) {
|
||||
result = &imageapi.Image{}
|
||||
err = c.r.Post().Resource("images").Body(image).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Update allows to modify existing image. Since most of image's attributes are immutable, this call allows
|
||||
// mainly for updating image signatures.
|
||||
func (c *images) Update(image *imageapi.Image) (result *imageapi.Image, err error) {
|
||||
result = &imageapi.Image{}
|
||||
err = c.r.Put().Resource("images").Name(image.Name).Body(image).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Delete deletes an image, returns error if one occurs.
|
||||
func (c *images) Delete(name string) (err error) {
|
||||
err = c.r.Delete().Resource("images").Name(name).Do().Error()
|
||||
return
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
imageapi "github.com/openshift/origin/pkg/image/api"
|
||||
)
|
||||
|
||||
// ImageSignaturesInterfacer has methods to work with ImageSignature resource.
|
||||
type ImageSignaturesInterfacer interface {
|
||||
ImageSignatures() ImageSignatureInterface
|
||||
}
|
||||
|
||||
// ImageSignatureInterface exposes methods on ImageSignature virtual resource.
|
||||
type ImageSignatureInterface interface {
|
||||
Create(signature *imageapi.ImageSignature) (*imageapi.ImageSignature, error)
|
||||
Delete(name string) error
|
||||
}
|
||||
|
||||
// imageSignatures implements ImageSignatureInterface.
|
||||
type imageSignatures struct {
|
||||
r *Client
|
||||
}
|
||||
|
||||
// newImageSignatures returns imageSignatures
|
||||
func newImageSignatures(c *Client) ImageSignatureInterface {
|
||||
return &imageSignatures{
|
||||
r: c,
|
||||
}
|
||||
}
|
||||
|
||||
// Create creates a new ImageSignature. Returns the server's representation of the signature and error if one
|
||||
// occurs.
|
||||
func (c *imageSignatures) Create(signature *imageapi.ImageSignature) (result *imageapi.ImageSignature, err error) {
|
||||
result = &imageapi.ImageSignature{}
|
||||
err = c.r.Post().Resource("imageSignatures").Body(signature).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Delete deletes an ImageSignature, returns error if one occurs.
|
||||
func (c *imageSignatures) Delete(name string) error {
|
||||
return c.r.Delete().Resource("imageSignatures").Name(name).Do().Error()
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"github.com/openshift/origin/pkg/image/api"
|
||||
)
|
||||
|
||||
// ImageStreamImagesNamespacer has methods to work with ImageStreamImage resources in a namespace
|
||||
type ImageStreamImagesNamespacer interface {
|
||||
ImageStreamImages(namespace string) ImageStreamImageInterface
|
||||
}
|
||||
|
||||
// ImageStreamImageInterface exposes methods on ImageStreamImage resources.
|
||||
type ImageStreamImageInterface interface {
|
||||
Get(name, id string) (*api.ImageStreamImage, error)
|
||||
}
|
||||
|
||||
// imageStreamImages implements ImageStreamImagesNamespacer interface
|
||||
type imageStreamImages struct {
|
||||
r *Client
|
||||
ns string
|
||||
}
|
||||
|
||||
// newImageStreamImages returns an imageStreamImages
|
||||
func newImageStreamImages(c *Client, namespace string) *imageStreamImages {
|
||||
return &imageStreamImages{
|
||||
r: c,
|
||||
ns: namespace,
|
||||
}
|
||||
}
|
||||
|
||||
// Get finds the specified image by name of an image repository and id.
|
||||
func (c *imageStreamImages) Get(name, id string) (result *api.ImageStreamImage, err error) {
|
||||
result = &api.ImageStreamImage{}
|
||||
err = c.r.Get().Namespace(c.ns).Resource("imageStreamImages").Name(api.MakeImageStreamImageName(name, id)).Do().Into(result)
|
||||
return
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
imageapi "github.com/openshift/origin/pkg/image/api"
|
||||
)
|
||||
|
||||
// ImageStreamMappingsNamespacer has methods to work with ImageStreamMapping resources in a namespace
|
||||
type ImageStreamMappingsNamespacer interface {
|
||||
ImageStreamMappings(namespace string) ImageStreamMappingInterface
|
||||
}
|
||||
|
||||
// ImageStreamMappingInterface exposes methods on ImageStreamMapping resources.
|
||||
type ImageStreamMappingInterface interface {
|
||||
Create(mapping *imageapi.ImageStreamMapping) error
|
||||
}
|
||||
|
||||
// imageStreamMappings implements ImageStreamMappingsNamespacer interface
|
||||
type imageStreamMappings struct {
|
||||
r *Client
|
||||
ns string
|
||||
}
|
||||
|
||||
// newImageStreamMappings returns an imageStreamMappings
|
||||
func newImageStreamMappings(c *Client, namespace string) *imageStreamMappings {
|
||||
return &imageStreamMappings{
|
||||
r: c,
|
||||
ns: namespace,
|
||||
}
|
||||
}
|
||||
|
||||
// Create creates a new image stream mapping on the server. Returns error if one occurs.
|
||||
func (c *imageStreamMappings) Create(mapping *imageapi.ImageStreamMapping) error {
|
||||
return c.r.Post().Namespace(c.ns).Resource("imageStreamMappings").Body(mapping).Do().Error()
|
||||
}
|
||||
+147
@@ -0,0 +1,147 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
kapi "k8s.io/kubernetes/pkg/api"
|
||||
apierrs "k8s.io/kubernetes/pkg/api/errors"
|
||||
"k8s.io/kubernetes/pkg/watch"
|
||||
|
||||
imageapi "github.com/openshift/origin/pkg/image/api"
|
||||
quotautil "github.com/openshift/origin/pkg/quota/util"
|
||||
)
|
||||
|
||||
var ErrImageStreamImportUnsupported = errors.New("the server does not support directly importing images - create an image stream with tags or the dockerImageRepository field set")
|
||||
|
||||
// ImageStreamsNamespacer has methods to work with ImageStream resources in a namespace
|
||||
type ImageStreamsNamespacer interface {
|
||||
ImageStreams(namespace string) ImageStreamInterface
|
||||
}
|
||||
|
||||
// ImageStreamInterface exposes methods on ImageStream resources.
|
||||
type ImageStreamInterface interface {
|
||||
List(opts kapi.ListOptions) (*imageapi.ImageStreamList, error)
|
||||
Get(name string) (*imageapi.ImageStream, error)
|
||||
Create(stream *imageapi.ImageStream) (*imageapi.ImageStream, error)
|
||||
Update(stream *imageapi.ImageStream) (*imageapi.ImageStream, error)
|
||||
Delete(name string) error
|
||||
Watch(opts kapi.ListOptions) (watch.Interface, error)
|
||||
UpdateStatus(stream *imageapi.ImageStream) (*imageapi.ImageStream, error)
|
||||
Import(isi *imageapi.ImageStreamImport) (*imageapi.ImageStreamImport, error)
|
||||
}
|
||||
|
||||
// ImageStreamNamespaceGetter exposes methods to get ImageStreams by Namespace
|
||||
type ImageStreamNamespaceGetter interface {
|
||||
GetByNamespace(namespace, name string) (*imageapi.ImageStream, error)
|
||||
}
|
||||
|
||||
// imageStreams implements ImageStreamsNamespacer interface
|
||||
type imageStreams struct {
|
||||
r *Client
|
||||
ns string
|
||||
}
|
||||
|
||||
// newImageStreams returns an imageStreams
|
||||
func newImageStreams(c *Client, namespace string) *imageStreams {
|
||||
return &imageStreams{
|
||||
r: c,
|
||||
ns: namespace,
|
||||
}
|
||||
}
|
||||
|
||||
// List returns a list of image streams that match the label and field selectors.
|
||||
func (c *imageStreams) List(opts kapi.ListOptions) (result *imageapi.ImageStreamList, err error) {
|
||||
result = &imageapi.ImageStreamList{}
|
||||
err = c.r.Get().
|
||||
Namespace(c.ns).
|
||||
Resource("imageStreams").
|
||||
VersionedParams(&opts, kapi.ParameterCodec).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Get returns information about a particular image stream and error if one occurs.
|
||||
func (c *imageStreams) Get(name string) (result *imageapi.ImageStream, err error) {
|
||||
result = &imageapi.ImageStream{}
|
||||
err = c.r.Get().Namespace(c.ns).Resource("imageStreams").Name(name).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// GetByNamespace returns information about a particular image stream in a particular namespace and error if one occurs.
|
||||
func (c *imageStreams) GetByNamespace(namespace, name string) (result *imageapi.ImageStream, err error) {
|
||||
result = &imageapi.ImageStream{}
|
||||
c.r.Get().Namespace(namespace).Resource("imageStreams").Name(name).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Create create a new image stream. Returns the server's representation of the image stream and error if one occurs.
|
||||
func (c *imageStreams) Create(stream *imageapi.ImageStream) (result *imageapi.ImageStream, err error) {
|
||||
result = &imageapi.ImageStream{}
|
||||
err = c.r.Post().Namespace(c.ns).Resource("imageStreams").Body(stream).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Update updates the image stream on the server. Returns the server's representation of the image stream and error if one occurs.
|
||||
func (c *imageStreams) Update(stream *imageapi.ImageStream) (result *imageapi.ImageStream, err error) {
|
||||
result = &imageapi.ImageStream{}
|
||||
err = c.r.Put().Namespace(c.ns).Resource("imageStreams").Name(stream.Name).Body(stream).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Delete deletes an image stream, returns error if one occurs.
|
||||
func (c *imageStreams) Delete(name string) (err error) {
|
||||
err = c.r.Delete().Namespace(c.ns).Resource("imageStreams").Name(name).Do().Error()
|
||||
return
|
||||
}
|
||||
|
||||
// Watch returns a watch.Interface that watches the requested image streams.
|
||||
func (c *imageStreams) Watch(opts kapi.ListOptions) (watch.Interface, error) {
|
||||
return c.r.Get().
|
||||
Prefix("watch").
|
||||
Namespace(c.ns).
|
||||
Resource("imageStreams").
|
||||
VersionedParams(&opts, kapi.ParameterCodec).
|
||||
Watch()
|
||||
}
|
||||
|
||||
// UpdateStatus updates the image stream's status. Returns the server's representation of the image stream, and an error, if it occurs.
|
||||
func (c *imageStreams) UpdateStatus(stream *imageapi.ImageStream) (result *imageapi.ImageStream, err error) {
|
||||
result = &imageapi.ImageStream{}
|
||||
err = c.r.Put().Namespace(c.ns).Resource("imageStreams").Name(stream.Name).SubResource("status").Body(stream).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Import makes a call to the server to retrieve information about the requested images or to perform an import. ImageStreamImport
|
||||
// will be returned if no actual import was requested (the to fields were not set), or an ImageStream if import was requested.
|
||||
func (c *imageStreams) Import(isi *imageapi.ImageStreamImport) (*imageapi.ImageStreamImport, error) {
|
||||
result := &imageapi.ImageStreamImport{}
|
||||
if err := c.r.Post().Namespace(c.ns).Resource("imageStreamImports").Body(isi).Do().Into(result); err != nil {
|
||||
return nil, transformUnsupported(err)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// transformUnsupported converts specific error conditions to unsupported
|
||||
func transformUnsupported(err error) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
if apierrs.IsNotFound(err) {
|
||||
status, ok := err.(apierrs.APIStatus)
|
||||
if !ok {
|
||||
return ErrImageStreamImportUnsupported
|
||||
}
|
||||
if status.Status().Details == nil || status.Status().Details.Kind == "" {
|
||||
return ErrImageStreamImportUnsupported
|
||||
}
|
||||
}
|
||||
// The ImageStreamImport resource exists in v1.1.1 of origin but is not yet
|
||||
// enabled by policy. A create request will return a Forbidden(403) error.
|
||||
// We want to return ErrImageStreamImportUnsupported to allow fallback behavior
|
||||
// in clients.
|
||||
if apierrs.IsForbidden(err) && !quotautil.IsErrorQuotaExceeded(err) {
|
||||
return ErrImageStreamImportUnsupported
|
||||
}
|
||||
return err
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
kapi "k8s.io/kubernetes/pkg/api"
|
||||
)
|
||||
|
||||
// ImageStreamSecretsNamespacer has methods to work with ImageStreamSecret resources in a namespace
|
||||
type ImageStreamSecretsNamespacer interface {
|
||||
ImageStreamSecrets(namespace string) ImageStreamSecretInterface
|
||||
}
|
||||
|
||||
// ImageStreamSecretInterface exposes methods on ImageStreamSecret resources.
|
||||
type ImageStreamSecretInterface interface {
|
||||
// Secrets retrieves the secrets for a named image stream with the provided list options.
|
||||
Secrets(name string, options kapi.ListOptions) (*kapi.SecretList, error)
|
||||
}
|
||||
|
||||
// imageStreamSecrets implements ImageStreamSecretsNamespacer interface
|
||||
type imageStreamSecrets struct {
|
||||
r *Client
|
||||
ns string
|
||||
}
|
||||
|
||||
// newImageStreamSecrets returns an imageStreamSecrets
|
||||
func newImageStreamSecrets(c *Client, namespace string) *imageStreamSecrets {
|
||||
return &imageStreamSecrets{
|
||||
r: c,
|
||||
ns: namespace,
|
||||
}
|
||||
}
|
||||
|
||||
// GetSecrets returns a list of secrets for the named image stream
|
||||
func (c *imageStreamSecrets) Secrets(name string, options kapi.ListOptions) (result *kapi.SecretList, err error) {
|
||||
result = &kapi.SecretList{}
|
||||
err = c.r.Get().
|
||||
Namespace(c.ns).
|
||||
Resource("imageStreams").
|
||||
Name(name).
|
||||
SubResource("secrets").
|
||||
VersionedParams(&options, kapi.ParameterCodec).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"github.com/openshift/origin/pkg/image/api"
|
||||
)
|
||||
|
||||
// ImageStreamTagsNamespacer has methods to work with ImageStreamTag resources in a namespace
|
||||
type ImageStreamTagsNamespacer interface {
|
||||
ImageStreamTags(namespace string) ImageStreamTagInterface
|
||||
}
|
||||
|
||||
// ImageStreamTagInterface exposes methods on ImageStreamTag resources.
|
||||
type ImageStreamTagInterface interface {
|
||||
Get(name, tag string) (*api.ImageStreamTag, error)
|
||||
Create(tag *api.ImageStreamTag) (*api.ImageStreamTag, error)
|
||||
Update(tag *api.ImageStreamTag) (*api.ImageStreamTag, error)
|
||||
Delete(name, tag string) error
|
||||
}
|
||||
|
||||
// imageStreamTags implements ImageStreamTagsNamespacer interface
|
||||
type imageStreamTags struct {
|
||||
r *Client
|
||||
ns string
|
||||
}
|
||||
|
||||
// newImageStreamTags returns an imageStreamTags
|
||||
func newImageStreamTags(c *Client, namespace string) *imageStreamTags {
|
||||
return &imageStreamTags{
|
||||
r: c,
|
||||
ns: namespace,
|
||||
}
|
||||
}
|
||||
|
||||
// Get finds the specified image by name of an image stream and tag.
|
||||
func (c *imageStreamTags) Get(name, tag string) (result *api.ImageStreamTag, err error) {
|
||||
result = &api.ImageStreamTag{}
|
||||
err = c.r.Get().Namespace(c.ns).Resource("imageStreamTags").Name(api.JoinImageStreamTag(name, tag)).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Update updates an image stream tag (creating it if it does not exist).
|
||||
func (c *imageStreamTags) Update(tag *api.ImageStreamTag) (result *api.ImageStreamTag, err error) {
|
||||
result = &api.ImageStreamTag{}
|
||||
err = c.r.Put().Namespace(c.ns).Resource("imageStreamTags").Name(tag.Name).Body(tag).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
func (c *imageStreamTags) Create(tag *api.ImageStreamTag) (result *api.ImageStreamTag, err error) {
|
||||
result = &api.ImageStreamTag{}
|
||||
err = c.r.Post().Namespace(c.ns).Resource("imageStreamTags").Body(tag).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Delete deletes the specified tag from the image stream.
|
||||
func (c *imageStreamTags) Delete(name, tag string) error {
|
||||
return c.r.Delete().Namespace(c.ns).Resource("imageStreamTags").Name(api.JoinImageStreamTag(name, tag)).Do().Error()
|
||||
}
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
kapierrors "k8s.io/kubernetes/pkg/api/errors"
|
||||
|
||||
authorizationapi "github.com/openshift/origin/pkg/authorization/api"
|
||||
)
|
||||
|
||||
// LocalResourceAccessReviewsNamespacer has methods to work with LocalResourceAccessReview resources in a namespace
|
||||
type LocalResourceAccessReviewsNamespacer interface {
|
||||
LocalResourceAccessReviews(namespace string) LocalResourceAccessReviewInterface
|
||||
}
|
||||
|
||||
// LocalResourceAccessReviewInterface exposes methods on LocalResourceAccessReview resources.
|
||||
type LocalResourceAccessReviewInterface interface {
|
||||
Create(policy *authorizationapi.LocalResourceAccessReview) (*authorizationapi.ResourceAccessReviewResponse, error)
|
||||
}
|
||||
|
||||
// localResourceAccessReviews implements ResourceAccessReviewsNamespacer interface
|
||||
type localResourceAccessReviews struct {
|
||||
r *Client
|
||||
ns string
|
||||
}
|
||||
|
||||
// newLocalResourceAccessReviews returns a localLocalResourceAccessReviews
|
||||
func newLocalResourceAccessReviews(c *Client, namespace string) *localResourceAccessReviews {
|
||||
return &localResourceAccessReviews{
|
||||
r: c,
|
||||
ns: namespace,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *localResourceAccessReviews) Create(rar *authorizationapi.LocalResourceAccessReview) (result *authorizationapi.ResourceAccessReviewResponse, err error) {
|
||||
result = &authorizationapi.ResourceAccessReviewResponse{}
|
||||
err = c.r.Post().Namespace(c.ns).Resource("localResourceAccessReviews").Body(rar).Do().Into(result)
|
||||
|
||||
// if we get one of these failures, we may be talking to an older openshift. In that case, we need to try hitting ns/namespace-name/subjectaccessreview
|
||||
if kapierrors.IsForbidden(err) || kapierrors.IsNotFound(err) {
|
||||
deprecatedRAR := &authorizationapi.ResourceAccessReview{
|
||||
Action: rar.Action,
|
||||
}
|
||||
deprecatedResponse := &authorizationapi.ResourceAccessReviewResponse{}
|
||||
deprecatedAttemptErr := c.r.Post().Namespace(c.ns).Resource("resourceAccessReviews").Body(deprecatedRAR).Do().Into(deprecatedResponse)
|
||||
if deprecatedAttemptErr == nil {
|
||||
err = nil
|
||||
result = deprecatedResponse
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
kapierrors "k8s.io/kubernetes/pkg/api/errors"
|
||||
|
||||
authorizationapi "github.com/openshift/origin/pkg/authorization/api"
|
||||
)
|
||||
|
||||
type LocalSubjectAccessReviewsImpersonator interface {
|
||||
ImpersonateLocalSubjectAccessReviews(namespace, token string) LocalSubjectAccessReviewInterface
|
||||
}
|
||||
|
||||
// LocalSubjectAccessReviewsNamespacer has methods to work with LocalSubjectAccessReview resources in a namespace
|
||||
type LocalSubjectAccessReviewsNamespacer interface {
|
||||
LocalSubjectAccessReviews(namespace string) LocalSubjectAccessReviewInterface
|
||||
}
|
||||
|
||||
// LocalSubjectAccessReviewInterface exposes methods on LocalSubjectAccessReview resources.
|
||||
type LocalSubjectAccessReviewInterface interface {
|
||||
Create(policy *authorizationapi.LocalSubjectAccessReview) (*authorizationapi.SubjectAccessReviewResponse, error)
|
||||
}
|
||||
|
||||
// localSubjectAccessReviews implements LocalSubjectAccessReviewsNamespacer interface
|
||||
type localSubjectAccessReviews struct {
|
||||
r *Client
|
||||
ns string
|
||||
token *string
|
||||
}
|
||||
|
||||
// newImpersonatingLocalSubjectAccessReviews returns a subjectAccessReviews
|
||||
func newImpersonatingLocalSubjectAccessReviews(c *Client, namespace, token string) *localSubjectAccessReviews {
|
||||
return &localSubjectAccessReviews{
|
||||
r: c,
|
||||
ns: namespace,
|
||||
token: &token,
|
||||
}
|
||||
}
|
||||
|
||||
// newLocalSubjectAccessReviews returns a localSubjectAccessReviews
|
||||
func newLocalSubjectAccessReviews(c *Client, namespace string) *localSubjectAccessReviews {
|
||||
return &localSubjectAccessReviews{
|
||||
r: c,
|
||||
ns: namespace,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *localSubjectAccessReviews) Create(sar *authorizationapi.LocalSubjectAccessReview) (*authorizationapi.SubjectAccessReviewResponse, error) {
|
||||
result := &authorizationapi.SubjectAccessReviewResponse{}
|
||||
|
||||
req, err := overrideAuth(c.token, c.r.Post().Namespace(c.ns).Resource("localSubjectAccessReviews"))
|
||||
if err != nil {
|
||||
return &authorizationapi.SubjectAccessReviewResponse{}, err
|
||||
}
|
||||
|
||||
err = req.Body(sar).Do().Into(result)
|
||||
|
||||
// if we get one of these failures, we may be talking to an older openshift. In that case, we need to try hitting ns/namespace-name/subjectaccessreview
|
||||
if kapierrors.IsForbidden(err) || kapierrors.IsNotFound(err) {
|
||||
deprecatedSAR := &authorizationapi.SubjectAccessReview{
|
||||
Action: sar.Action,
|
||||
User: sar.User,
|
||||
Groups: sar.Groups,
|
||||
}
|
||||
deprecatedResponse := &authorizationapi.SubjectAccessReviewResponse{}
|
||||
|
||||
deprecatedReq, deprecatedAttemptErr := overrideAuth(c.token, c.r.Post().Namespace(c.ns).Resource("subjectAccessReviews"))
|
||||
if deprecatedAttemptErr != nil {
|
||||
return &authorizationapi.SubjectAccessReviewResponse{}, deprecatedAttemptErr
|
||||
}
|
||||
deprecatedAttemptErr = deprecatedReq.Body(deprecatedSAR).Do().Into(deprecatedResponse)
|
||||
if deprecatedAttemptErr == nil {
|
||||
err = nil
|
||||
result = deprecatedResponse
|
||||
}
|
||||
}
|
||||
|
||||
return result, err
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"k8s.io/kubernetes/pkg/api/meta"
|
||||
"k8s.io/kubernetes/pkg/apimachinery/registered"
|
||||
"k8s.io/kubernetes/pkg/util/sets"
|
||||
)
|
||||
|
||||
// DefaultMultiRESTMapper returns the multi REST mapper with all OpenShift and
|
||||
// Kubernetes objects already registered.
|
||||
func DefaultMultiRESTMapper() meta.MultiRESTMapper {
|
||||
var restMapper meta.MultiRESTMapper
|
||||
seenGroups := sets.String{}
|
||||
for _, gv := range registered.EnabledVersions() {
|
||||
if seenGroups.Has(gv.Group) {
|
||||
continue
|
||||
}
|
||||
seenGroups.Insert(gv.Group)
|
||||
groupMeta, err := registered.Group(gv.Group)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
restMapper = meta.MultiRESTMapper(append(restMapper, groupMeta.RESTMapper))
|
||||
}
|
||||
return restMapper
|
||||
}
|
||||
+81
@@ -0,0 +1,81 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
kapi "k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/watch"
|
||||
|
||||
sdnapi "github.com/openshift/origin/pkg/sdn/api"
|
||||
)
|
||||
|
||||
// NetNamespaceInterface has methods to work with NetNamespace resources
|
||||
type NetNamespacesInterface interface {
|
||||
NetNamespaces() NetNamespaceInterface
|
||||
}
|
||||
|
||||
// NetNamespaceInterface exposes methods on NetNamespace resources.
|
||||
type NetNamespaceInterface interface {
|
||||
List(opts kapi.ListOptions) (*sdnapi.NetNamespaceList, error)
|
||||
Get(name string) (*sdnapi.NetNamespace, error)
|
||||
Create(sub *sdnapi.NetNamespace) (*sdnapi.NetNamespace, error)
|
||||
Update(sub *sdnapi.NetNamespace) (*sdnapi.NetNamespace, error)
|
||||
Delete(name string) error
|
||||
Watch(opts kapi.ListOptions) (watch.Interface, error)
|
||||
}
|
||||
|
||||
// netNamespace implements NetNamespaceInterface interface
|
||||
type netNamespace struct {
|
||||
r *Client
|
||||
}
|
||||
|
||||
// newNetNamespace returns a NetNamespace
|
||||
func newNetNamespace(c *Client) *netNamespace {
|
||||
return &netNamespace{
|
||||
r: c,
|
||||
}
|
||||
}
|
||||
|
||||
// List returns a list of NetNamespaces that match the label and field selectors.
|
||||
func (c *netNamespace) List(opts kapi.ListOptions) (result *sdnapi.NetNamespaceList, err error) {
|
||||
result = &sdnapi.NetNamespaceList{}
|
||||
err = c.r.Get().
|
||||
Resource("netNamespaces").
|
||||
VersionedParams(&opts, kapi.ParameterCodec).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Get returns information about a particular NetNamespace or an error
|
||||
func (c *netNamespace) Get(netname string) (result *sdnapi.NetNamespace, err error) {
|
||||
result = &sdnapi.NetNamespace{}
|
||||
err = c.r.Get().Resource("netNamespaces").Name(netname).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Create creates a new NetNamespace. Returns the server's representation of the NetNamespace and error if one occurs.
|
||||
func (c *netNamespace) Create(netNamespace *sdnapi.NetNamespace) (result *sdnapi.NetNamespace, err error) {
|
||||
result = &sdnapi.NetNamespace{}
|
||||
err = c.r.Post().Resource("netNamespaces").Body(netNamespace).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Update updates the NetNamespace. Returns the server's representation of the NetNamespace and error if one occurs.
|
||||
func (c *netNamespace) Update(netNamespace *sdnapi.NetNamespace) (result *sdnapi.NetNamespace, err error) {
|
||||
result = &sdnapi.NetNamespace{}
|
||||
err = c.r.Put().Resource("netNamespaces").Name(netNamespace.Name).Body(netNamespace).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Delete takes the name of the NetNamespace, and returns an error if one occurs during deletion of the NetNamespace
|
||||
func (c *netNamespace) Delete(name string) error {
|
||||
return c.r.Delete().Resource("netNamespaces").Name(name).Do().Error()
|
||||
}
|
||||
|
||||
// Watch returns a watch.Interface that watches the requested NetNamespaces
|
||||
func (c *netNamespace) Watch(opts kapi.ListOptions) (watch.Interface, error) {
|
||||
return c.r.Get().
|
||||
Prefix("watch").
|
||||
Resource("netNamespaces").
|
||||
VersionedParams(&opts, kapi.ParameterCodec).
|
||||
Watch()
|
||||
}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
oauthapi "github.com/openshift/origin/pkg/oauth/api"
|
||||
)
|
||||
|
||||
// OAuthAccessTokensInterface has methods to work with OAuthAccessTokens resources in a namespace
|
||||
type OAuthAccessTokensInterface interface {
|
||||
OAuthAccessTokens() OAuthAccessTokenInterface
|
||||
}
|
||||
|
||||
// OAuthAccessTokenInterface exposes methods on OAuthAccessTokens resources.
|
||||
type OAuthAccessTokenInterface interface {
|
||||
Create(token *oauthapi.OAuthAccessToken) (*oauthapi.OAuthAccessToken, error)
|
||||
Get(name string) (*oauthapi.OAuthAccessToken, error)
|
||||
Delete(name string) error
|
||||
}
|
||||
|
||||
type oauthAccessTokenInterface struct {
|
||||
r *Client
|
||||
}
|
||||
|
||||
func newOAuthAccessTokens(c *Client) *oauthAccessTokenInterface {
|
||||
return &oauthAccessTokenInterface{
|
||||
r: c,
|
||||
}
|
||||
}
|
||||
|
||||
// Get returns information about a particular image and error if one occurs.
|
||||
func (c *oauthAccessTokenInterface) Get(name string) (result *oauthapi.OAuthAccessToken, err error) {
|
||||
result = &oauthapi.OAuthAccessToken{}
|
||||
err = c.r.Get().Resource("oAuthAccessTokens").Name(name).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Delete removes the OAuthAccessToken on server
|
||||
func (c *oauthAccessTokenInterface) Delete(name string) (err error) {
|
||||
err = c.r.Delete().Resource("oAuthAccessTokens").Name(name).Do().Error()
|
||||
return
|
||||
}
|
||||
|
||||
func (c *oauthAccessTokenInterface) Create(token *oauthapi.OAuthAccessToken) (result *oauthapi.OAuthAccessToken, err error) {
|
||||
result = &oauthapi.OAuthAccessToken{}
|
||||
err = c.r.Post().Resource("oAuthAccessTokens").Body(token).Do().Into(result)
|
||||
return
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
oauthapi "github.com/openshift/origin/pkg/oauth/api"
|
||||
)
|
||||
|
||||
type OAuthAuthorizeTokensInterface interface {
|
||||
OAuthAuthorizeTokens() OAuthAuthorizeTokenInterface
|
||||
}
|
||||
|
||||
type OAuthAuthorizeTokenInterface interface {
|
||||
Create(token *oauthapi.OAuthAuthorizeToken) (*oauthapi.OAuthAuthorizeToken, error)
|
||||
Delete(name string) error
|
||||
}
|
||||
|
||||
type oauthAuthorizeTokenInterface struct {
|
||||
r *Client
|
||||
}
|
||||
|
||||
func newOAuthAuthorizeTokens(c *Client) *oauthAuthorizeTokenInterface {
|
||||
return &oauthAuthorizeTokenInterface{
|
||||
r: c,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *oauthAuthorizeTokenInterface) Delete(name string) (err error) {
|
||||
err = c.r.Delete().Resource("oAuthAuthorizeTokens").Name(name).Do().Error()
|
||||
return
|
||||
}
|
||||
|
||||
func (c *oauthAuthorizeTokenInterface) Create(token *oauthapi.OAuthAuthorizeToken) (result *oauthapi.OAuthAuthorizeToken, err error) {
|
||||
result = &oauthapi.OAuthAuthorizeToken{}
|
||||
err = c.r.Post().Resource("oAuthAuthorizeTokens").Body(token).Do().Into(result)
|
||||
return
|
||||
}
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
kapi "k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/watch"
|
||||
|
||||
oauthapi "github.com/openshift/origin/pkg/oauth/api"
|
||||
)
|
||||
|
||||
type OAuthClientsInterface interface {
|
||||
OAuthClients() OAuthClientInterface
|
||||
}
|
||||
|
||||
type OAuthClientInterface interface {
|
||||
Create(obj *oauthapi.OAuthClient) (*oauthapi.OAuthClient, error)
|
||||
List(opts kapi.ListOptions) (*oauthapi.OAuthClientList, error)
|
||||
Get(name string) (*oauthapi.OAuthClient, error)
|
||||
Delete(name string) error
|
||||
Watch(opts kapi.ListOptions) (watch.Interface, error)
|
||||
}
|
||||
|
||||
type oauthClients struct {
|
||||
r *Client
|
||||
}
|
||||
|
||||
func newOAuthClients(c *Client) *oauthClients {
|
||||
return &oauthClients{
|
||||
r: c,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *oauthClients) Create(obj *oauthapi.OAuthClient) (result *oauthapi.OAuthClient, err error) {
|
||||
result = &oauthapi.OAuthClient{}
|
||||
err = c.r.Post().Resource("oAuthClients").Body(obj).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
func (c *oauthClients) List(opts kapi.ListOptions) (result *oauthapi.OAuthClientList, err error) {
|
||||
result = &oauthapi.OAuthClientList{}
|
||||
err = c.r.Get().Resource("oAuthClients").VersionedParams(&opts, kapi.ParameterCodec).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
func (c *oauthClients) Get(name string) (result *oauthapi.OAuthClient, err error) {
|
||||
result = &oauthapi.OAuthClient{}
|
||||
err = c.r.Get().Resource("oAuthClients").Name(name).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
func (c *oauthClients) Delete(name string) (err error) {
|
||||
err = c.r.Delete().Resource("oAuthClients").Name(name).Do().Error()
|
||||
return
|
||||
}
|
||||
|
||||
func (c *oauthClients) Watch(opts kapi.ListOptions) (watch.Interface, error) {
|
||||
return c.r.Get().Prefix("watch").Resource("oAuthClients").VersionedParams(&opts, kapi.ParameterCodec).Watch()
|
||||
}
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
kapi "k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/watch"
|
||||
|
||||
oauthapi "github.com/openshift/origin/pkg/oauth/api"
|
||||
)
|
||||
|
||||
type OAuthClientAuthorizationsInterface interface {
|
||||
OAuthClientAuthorizations() OAuthClientAuthorizationInterface
|
||||
}
|
||||
|
||||
type OAuthClientAuthorizationInterface interface {
|
||||
Create(obj *oauthapi.OAuthClientAuthorization) (*oauthapi.OAuthClientAuthorization, error)
|
||||
List(opts kapi.ListOptions) (*oauthapi.OAuthClientAuthorizationList, error)
|
||||
Get(name string) (*oauthapi.OAuthClientAuthorization, error)
|
||||
Update(obj *oauthapi.OAuthClientAuthorization) (*oauthapi.OAuthClientAuthorization, error)
|
||||
Delete(name string) error
|
||||
Watch(opts kapi.ListOptions) (watch.Interface, error)
|
||||
}
|
||||
|
||||
type oauthClientAuthorizations struct {
|
||||
r *Client
|
||||
}
|
||||
|
||||
func newOAuthClientAuthorizations(c *Client) *oauthClientAuthorizations {
|
||||
return &oauthClientAuthorizations{
|
||||
r: c,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *oauthClientAuthorizations) Create(obj *oauthapi.OAuthClientAuthorization) (result *oauthapi.OAuthClientAuthorization, err error) {
|
||||
result = &oauthapi.OAuthClientAuthorization{}
|
||||
err = c.r.Post().Resource("oAuthClientAuthorizations").Body(obj).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
func (c *oauthClientAuthorizations) Update(obj *oauthapi.OAuthClientAuthorization) (result *oauthapi.OAuthClientAuthorization, err error) {
|
||||
result = &oauthapi.OAuthClientAuthorization{}
|
||||
err = c.r.Put().Resource("oAuthClientAuthorizations").Name(obj.Name).Body(obj).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
func (c *oauthClientAuthorizations) List(opts kapi.ListOptions) (result *oauthapi.OAuthClientAuthorizationList, err error) {
|
||||
result = &oauthapi.OAuthClientAuthorizationList{}
|
||||
err = c.r.Get().Resource("oAuthClientAuthorizations").VersionedParams(&opts, kapi.ParameterCodec).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
func (c *oauthClientAuthorizations) Get(name string) (result *oauthapi.OAuthClientAuthorization, err error) {
|
||||
result = &oauthapi.OAuthClientAuthorization{}
|
||||
err = c.r.Get().Resource("oAuthClientAuthorizations").Name(name).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
func (c *oauthClientAuthorizations) Delete(name string) (err error) {
|
||||
err = c.r.Delete().Resource("oAuthClientAuthorizations").Name(name).Do().Error()
|
||||
return
|
||||
}
|
||||
|
||||
func (c *oauthClientAuthorizations) Watch(opts kapi.ListOptions) (watch.Interface, error) {
|
||||
return c.r.Get().Prefix("watch").Resource("oAuthClientAuthorizations").VersionedParams(&opts, kapi.ParameterCodec).Watch()
|
||||
}
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
kapi "k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/watch"
|
||||
|
||||
authorizationapi "github.com/openshift/origin/pkg/authorization/api"
|
||||
)
|
||||
|
||||
// PoliciesNamespacer has methods to work with Policy resources in a namespace
|
||||
type PoliciesNamespacer interface {
|
||||
Policies(namespace string) PolicyInterface
|
||||
}
|
||||
|
||||
// PolicyInterface exposes methods on Policy resources.
|
||||
type PolicyInterface interface {
|
||||
List(opts kapi.ListOptions) (*authorizationapi.PolicyList, error)
|
||||
Get(name string) (*authorizationapi.Policy, error)
|
||||
Delete(name string) error
|
||||
Watch(opts kapi.ListOptions) (watch.Interface, error)
|
||||
}
|
||||
|
||||
type PoliciesListerNamespacer interface {
|
||||
Policies(namespace string) PolicyLister
|
||||
}
|
||||
type SyncedPoliciesListerNamespacer interface {
|
||||
PoliciesListerNamespacer
|
||||
LastSyncResourceVersion() string
|
||||
}
|
||||
type PolicyLister interface {
|
||||
List(options kapi.ListOptions) (*authorizationapi.PolicyList, error)
|
||||
Get(name string) (*authorizationapi.Policy, error)
|
||||
}
|
||||
|
||||
// policies implements PoliciesNamespacer interface
|
||||
type policies struct {
|
||||
r *Client
|
||||
ns string
|
||||
}
|
||||
|
||||
// newPolicies returns a policies
|
||||
func newPolicies(c *Client, namespace string) *policies {
|
||||
return &policies{
|
||||
r: c,
|
||||
ns: namespace,
|
||||
}
|
||||
}
|
||||
|
||||
// List returns a list of policies that match the label and field selectors.
|
||||
func (c *policies) List(opts kapi.ListOptions) (result *authorizationapi.PolicyList, err error) {
|
||||
result = &authorizationapi.PolicyList{}
|
||||
err = c.r.Get().Namespace(c.ns).Resource("policies").VersionedParams(&opts, kapi.ParameterCodec).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Get returns information about a particular policy and error if one occurs.
|
||||
func (c *policies) Get(name string) (result *authorizationapi.Policy, err error) {
|
||||
result = &authorizationapi.Policy{}
|
||||
err = c.r.Get().Namespace(c.ns).Resource("policies").Name(name).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Delete deletes a policy, returns error if one occurs.
|
||||
func (c *policies) Delete(name string) (err error) {
|
||||
err = c.r.Delete().Namespace(c.ns).Resource("policies").Name(name).Do().Error()
|
||||
return
|
||||
}
|
||||
|
||||
// Watch returns a watch.Interface that watches the requested policies
|
||||
func (c *policies) Watch(opts kapi.ListOptions) (watch.Interface, error) {
|
||||
return c.r.Get().Prefix("watch").Namespace(c.ns).Resource("policies").VersionedParams(&opts, kapi.ParameterCodec).Watch()
|
||||
}
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
kapi "k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/watch"
|
||||
|
||||
authorizationapi "github.com/openshift/origin/pkg/authorization/api"
|
||||
)
|
||||
|
||||
// PolicyBindingsNamespacer has methods to work with PolicyBinding resources in a namespace
|
||||
type PolicyBindingsNamespacer interface {
|
||||
PolicyBindings(namespace string) PolicyBindingInterface
|
||||
}
|
||||
|
||||
// PolicyBindingInterface exposes methods on PolicyBinding resources.
|
||||
type PolicyBindingInterface interface {
|
||||
List(opts kapi.ListOptions) (*authorizationapi.PolicyBindingList, error)
|
||||
Get(name string) (*authorizationapi.PolicyBinding, error)
|
||||
Create(policyBinding *authorizationapi.PolicyBinding) (*authorizationapi.PolicyBinding, error)
|
||||
Delete(name string) error
|
||||
Watch(opts kapi.ListOptions) (watch.Interface, error)
|
||||
}
|
||||
|
||||
type PolicyBindingsListerNamespacer interface {
|
||||
PolicyBindings(namespace string) PolicyBindingLister
|
||||
}
|
||||
type SyncedPolicyBindingsListerNamespacer interface {
|
||||
PolicyBindingsListerNamespacer
|
||||
LastSyncResourceVersion() string
|
||||
}
|
||||
type PolicyBindingLister interface {
|
||||
List(options kapi.ListOptions) (*authorizationapi.PolicyBindingList, error)
|
||||
Get(name string) (*authorizationapi.PolicyBinding, error)
|
||||
}
|
||||
|
||||
// policyBindings implements PolicyBindingsNamespacer interface
|
||||
type policyBindings struct {
|
||||
r *Client
|
||||
ns string
|
||||
}
|
||||
|
||||
// newPolicyBindings returns a policyBindings
|
||||
func newPolicyBindings(c *Client, namespace string) *policyBindings {
|
||||
return &policyBindings{
|
||||
r: c,
|
||||
ns: namespace,
|
||||
}
|
||||
}
|
||||
|
||||
// List returns a list of policyBindings that match the label and field selectors.
|
||||
func (c *policyBindings) List(opts kapi.ListOptions) (result *authorizationapi.PolicyBindingList, err error) {
|
||||
result = &authorizationapi.PolicyBindingList{}
|
||||
err = c.r.Get().Namespace(c.ns).Resource("policyBindings").VersionedParams(&opts, kapi.ParameterCodec).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Get returns information about a particular policyBinding and error if one occurs.
|
||||
func (c *policyBindings) Get(name string) (result *authorizationapi.PolicyBinding, err error) {
|
||||
result = &authorizationapi.PolicyBinding{}
|
||||
err = c.r.Get().Namespace(c.ns).Resource("policyBindings").Name(name).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Create creates new policyBinding. Returns the server's representation of the policyBinding and error if one occurs.
|
||||
func (c *policyBindings) Create(policyBinding *authorizationapi.PolicyBinding) (result *authorizationapi.PolicyBinding, err error) {
|
||||
result = &authorizationapi.PolicyBinding{}
|
||||
err = c.r.Post().Namespace(c.ns).Resource("policyBindings").Body(policyBinding).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Delete deletes a policyBinding, returns error if one occurs.
|
||||
func (c *policyBindings) Delete(name string) (err error) {
|
||||
err = c.r.Delete().Namespace(c.ns).Resource("policyBindings").Name(name).Do().Error()
|
||||
return
|
||||
}
|
||||
|
||||
// Watch returns a watch.Interface that watches the requested policyBindings
|
||||
func (c *policyBindings) Watch(opts kapi.ListOptions) (watch.Interface, error) {
|
||||
return c.r.Get().Prefix("watch").Namespace(c.ns).Resource("policyBindings").VersionedParams(&opts, kapi.ParameterCodec).Watch()
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
kapi "k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||
|
||||
projectapi "github.com/openshift/origin/pkg/project/api"
|
||||
)
|
||||
|
||||
// ProjectRequestsInterface has methods to work with ProjectRequest resources in a namespace
|
||||
type ProjectRequestsInterface interface {
|
||||
ProjectRequests() ProjectRequestInterface
|
||||
}
|
||||
|
||||
// ProjectRequestInterface exposes methods on projectRequest resources.
|
||||
type ProjectRequestInterface interface {
|
||||
Create(p *projectapi.ProjectRequest) (*projectapi.Project, error)
|
||||
List(opts kapi.ListOptions) (*unversioned.Status, error)
|
||||
}
|
||||
|
||||
type projectRequests struct {
|
||||
r *Client
|
||||
}
|
||||
|
||||
// newUsers returns a users
|
||||
func newProjectRequests(c *Client) *projectRequests {
|
||||
return &projectRequests{
|
||||
r: c,
|
||||
}
|
||||
}
|
||||
|
||||
// Create creates a new Project
|
||||
func (c *projectRequests) Create(p *projectapi.ProjectRequest) (result *projectapi.Project, err error) {
|
||||
result = &projectapi.Project{}
|
||||
err = c.r.Post().Resource("projectRequests").Body(p).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// List returns a status object indicating that a user can call the Create or an error indicating why not
|
||||
func (c *projectRequests) List(opts kapi.ListOptions) (result *unversioned.Status, err error) {
|
||||
result = &unversioned.Status{}
|
||||
err = c.r.Get().Resource("projectRequests").VersionedParams(&opts, kapi.ParameterCodec).Do().Into(result)
|
||||
return result, err
|
||||
}
|
||||
+81
@@ -0,0 +1,81 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
kapi "k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/watch"
|
||||
|
||||
projectapi "github.com/openshift/origin/pkg/project/api"
|
||||
)
|
||||
|
||||
// ProjectsInterface has methods to work with Project resources in a namespace
|
||||
type ProjectsInterface interface {
|
||||
Projects() ProjectInterface
|
||||
}
|
||||
|
||||
// ProjectInterface exposes methods on project resources.
|
||||
type ProjectInterface interface {
|
||||
Create(p *projectapi.Project) (*projectapi.Project, error)
|
||||
Update(p *projectapi.Project) (*projectapi.Project, error)
|
||||
Delete(name string) error
|
||||
Get(name string) (*projectapi.Project, error)
|
||||
List(opts kapi.ListOptions) (*projectapi.ProjectList, error)
|
||||
Watch(opts kapi.ListOptions) (watch.Interface, error)
|
||||
}
|
||||
|
||||
type projects struct {
|
||||
r *Client
|
||||
}
|
||||
|
||||
// newUsers returns a project
|
||||
func newProjects(c *Client) *projects {
|
||||
return &projects{
|
||||
r: c,
|
||||
}
|
||||
}
|
||||
|
||||
// Get returns information about a particular project or an error
|
||||
func (c *projects) Get(name string) (result *projectapi.Project, err error) {
|
||||
result = &projectapi.Project{}
|
||||
err = c.r.Get().Resource("projects").Name(name).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// List returns all projects matching the label selector
|
||||
func (c *projects) List(opts kapi.ListOptions) (result *projectapi.ProjectList, err error) {
|
||||
result = &projectapi.ProjectList{}
|
||||
err = c.r.Get().
|
||||
Resource("projects").
|
||||
VersionedParams(&opts, kapi.ParameterCodec).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Create creates a new Project
|
||||
func (c *projects) Create(p *projectapi.Project) (result *projectapi.Project, err error) {
|
||||
result = &projectapi.Project{}
|
||||
err = c.r.Post().Resource("projects").Body(p).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Update updates the project on server
|
||||
func (c *projects) Update(p *projectapi.Project) (result *projectapi.Project, err error) {
|
||||
result = &projectapi.Project{}
|
||||
err = c.r.Put().Resource("projects").Name(p.Name).Body(p).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Delete removes the project on server
|
||||
func (c *projects) Delete(name string) (err error) {
|
||||
err = c.r.Delete().Resource("projects").Name(name).Do().Error()
|
||||
return
|
||||
}
|
||||
|
||||
// Watch returns a watch.Interface that watches the requested namespaces.
|
||||
func (c *projects) Watch(opts kapi.ListOptions) (watch.Interface, error) {
|
||||
return c.r.Get().
|
||||
Prefix("watch").
|
||||
Resource("projects").
|
||||
VersionedParams(&opts, kapi.ParameterCodec).
|
||||
Watch()
|
||||
}
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
kapierrors "k8s.io/kubernetes/pkg/api/errors"
|
||||
|
||||
authorizationapi "github.com/openshift/origin/pkg/authorization/api"
|
||||
)
|
||||
|
||||
// ResourceAccessReviews has methods to work with ResourceAccessReview resources in the cluster scope
|
||||
type ResourceAccessReviews interface {
|
||||
ResourceAccessReviews() ResourceAccessReviewInterface
|
||||
}
|
||||
|
||||
// ResourceAccessReviewInterface exposes methods on ResourceAccessReview resources.
|
||||
type ResourceAccessReviewInterface interface {
|
||||
Create(policy *authorizationapi.ResourceAccessReview) (*authorizationapi.ResourceAccessReviewResponse, error)
|
||||
}
|
||||
|
||||
// resourceAccessReviews implements ResourceAccessReviews interface
|
||||
type resourceAccessReviews struct {
|
||||
r *Client
|
||||
}
|
||||
|
||||
// newResourceAccessReviews returns a resourceAccessReviews
|
||||
func newResourceAccessReviews(c *Client) *resourceAccessReviews {
|
||||
return &resourceAccessReviews{
|
||||
r: c,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *resourceAccessReviews) Create(rar *authorizationapi.ResourceAccessReview) (result *authorizationapi.ResourceAccessReviewResponse, err error) {
|
||||
result = &authorizationapi.ResourceAccessReviewResponse{}
|
||||
|
||||
// if this a cluster RAR, then no special handling
|
||||
if len(rar.Action.Namespace) == 0 {
|
||||
err = c.r.Post().Resource("resourceAccessReviews").Body(rar).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
err = c.r.Post().Resource("resourceAccessReviews").Body(rar).Do().Into(result)
|
||||
|
||||
// if the namespace values don't match then we definitely hit an old server. If we got a forbidden, then we might have hit an old server
|
||||
// and should try the old endpoint
|
||||
if (rar.Action.Namespace != result.Namespace) || kapierrors.IsForbidden(err) {
|
||||
deprecatedResponse := &authorizationapi.ResourceAccessReviewResponse{}
|
||||
deprecatedAttemptErr := c.r.Post().Namespace(rar.Action.Namespace).Resource("resourceAccessReviews").Body(rar).Do().Into(deprecatedResponse)
|
||||
|
||||
// if we definitely hit an old server, then return the error and result you get from the older server.
|
||||
if rar.Action.Namespace != result.Namespace {
|
||||
return deprecatedResponse, deprecatedAttemptErr
|
||||
}
|
||||
|
||||
// if we're not certain it was an old server, success overwrites the previous error, but failure doesn't overwrite the previous error
|
||||
if deprecatedAttemptErr == nil {
|
||||
err = nil
|
||||
result = deprecatedResponse
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
kapi "k8s.io/kubernetes/pkg/api"
|
||||
|
||||
authorizationapi "github.com/openshift/origin/pkg/authorization/api"
|
||||
)
|
||||
|
||||
// RoleBindingsNamespacer has methods to work with RoleBinding resources in a namespace
|
||||
type RoleBindingsNamespacer interface {
|
||||
RoleBindings(namespace string) RoleBindingInterface
|
||||
}
|
||||
|
||||
// RoleBindingInterface exposes methods on RoleBinding resources.
|
||||
type RoleBindingInterface interface {
|
||||
List(opts kapi.ListOptions) (*authorizationapi.RoleBindingList, error)
|
||||
Get(name string) (*authorizationapi.RoleBinding, error)
|
||||
Create(roleBinding *authorizationapi.RoleBinding) (*authorizationapi.RoleBinding, error)
|
||||
Update(roleBinding *authorizationapi.RoleBinding) (*authorizationapi.RoleBinding, error)
|
||||
Delete(name string) error
|
||||
}
|
||||
|
||||
// roleBindings implements RoleBindingsNamespacer interface
|
||||
type roleBindings struct {
|
||||
r *Client
|
||||
ns string
|
||||
}
|
||||
|
||||
// newRoleBindings returns a roleBindings
|
||||
func newRoleBindings(c *Client, namespace string) *roleBindings {
|
||||
return &roleBindings{
|
||||
r: c,
|
||||
ns: namespace,
|
||||
}
|
||||
}
|
||||
|
||||
// List returns a list of roleBindings that match the label and field selectors.
|
||||
func (c *roleBindings) List(opts kapi.ListOptions) (result *authorizationapi.RoleBindingList, err error) {
|
||||
result = &authorizationapi.RoleBindingList{}
|
||||
err = c.r.Get().Namespace(c.ns).Resource("roleBindings").VersionedParams(&opts, kapi.ParameterCodec).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Get returns information about a particular roleBinding and error if one occurs.
|
||||
func (c *roleBindings) Get(name string) (result *authorizationapi.RoleBinding, err error) {
|
||||
result = &authorizationapi.RoleBinding{}
|
||||
err = c.r.Get().Namespace(c.ns).Resource("roleBindings").Name(name).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Create creates new roleBinding. Returns the server's representation of the roleBinding and error if one occurs.
|
||||
func (c *roleBindings) Create(roleBinding *authorizationapi.RoleBinding) (result *authorizationapi.RoleBinding, err error) {
|
||||
result = &authorizationapi.RoleBinding{}
|
||||
err = c.r.Post().Namespace(c.ns).Resource("roleBindings").Body(roleBinding).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Update updates the roleBinding on server. Returns the server's representation of the roleBinding and error if one occurs.
|
||||
func (c *roleBindings) Update(roleBinding *authorizationapi.RoleBinding) (result *authorizationapi.RoleBinding, err error) {
|
||||
result = &authorizationapi.RoleBinding{}
|
||||
err = c.r.Put().Namespace(c.ns).Resource("roleBindings").Name(roleBinding.Name).Body(roleBinding).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Delete deletes a roleBinding, returns error if one occurs.
|
||||
func (c *roleBindings) Delete(name string) (err error) {
|
||||
err = c.r.Delete().Namespace(c.ns).Resource("roleBindings").Name(name).Do().Error()
|
||||
return
|
||||
}
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
kapi "k8s.io/kubernetes/pkg/api"
|
||||
|
||||
authorizationapi "github.com/openshift/origin/pkg/authorization/api"
|
||||
)
|
||||
|
||||
// RolesNamespacer has methods to work with Role resources in a namespace
|
||||
type RolesNamespacer interface {
|
||||
Roles(namespace string) RoleInterface
|
||||
}
|
||||
|
||||
// RoleInterface exposes methods on Role resources.
|
||||
type RoleInterface interface {
|
||||
List(opts kapi.ListOptions) (*authorizationapi.RoleList, error)
|
||||
Get(name string) (*authorizationapi.Role, error)
|
||||
Create(role *authorizationapi.Role) (*authorizationapi.Role, error)
|
||||
Update(role *authorizationapi.Role) (*authorizationapi.Role, error)
|
||||
Delete(name string) error
|
||||
}
|
||||
|
||||
// roles implements RolesNamespacer interface
|
||||
type roles struct {
|
||||
r *Client
|
||||
ns string
|
||||
}
|
||||
|
||||
// newRoles returns a roles
|
||||
func newRoles(c *Client, namespace string) *roles {
|
||||
return &roles{
|
||||
r: c,
|
||||
ns: namespace,
|
||||
}
|
||||
}
|
||||
|
||||
// List returns a list of roles that match the label and field selectors.
|
||||
func (c *roles) List(opts kapi.ListOptions) (result *authorizationapi.RoleList, err error) {
|
||||
result = &authorizationapi.RoleList{}
|
||||
err = c.r.Get().Namespace(c.ns).Resource("roles").VersionedParams(&opts, kapi.ParameterCodec).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Get returns information about a particular role and error if one occurs.
|
||||
func (c *roles) Get(name string) (result *authorizationapi.Role, err error) {
|
||||
result = &authorizationapi.Role{}
|
||||
err = c.r.Get().Namespace(c.ns).Resource("roles").Name(name).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Create creates new role. Returns the server's representation of the role and error if one occurs.
|
||||
func (c *roles) Create(role *authorizationapi.Role) (result *authorizationapi.Role, err error) {
|
||||
result = &authorizationapi.Role{}
|
||||
err = c.r.Post().Namespace(c.ns).Resource("roles").Body(role).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Update updates the role on server. Returns the server's representation of the role and error if one occurs.
|
||||
func (c *roles) Update(role *authorizationapi.Role) (result *authorizationapi.Role, err error) {
|
||||
result = &authorizationapi.Role{}
|
||||
err = c.r.Put().Namespace(c.ns).Resource("roles").Name(role.Name).Body(role).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Delete deletes a role, returns error if one occurs.
|
||||
func (c *roles) Delete(name string) (err error) {
|
||||
err = c.r.Delete().Namespace(c.ns).Resource("roles").Name(name).Do().Error()
|
||||
return
|
||||
}
|
||||
+93
@@ -0,0 +1,93 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
kapi "k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/watch"
|
||||
|
||||
routeapi "github.com/openshift/origin/pkg/route/api"
|
||||
)
|
||||
|
||||
// RoutesNamespacer has methods to work with Route resources in a namespace
|
||||
type RoutesNamespacer interface {
|
||||
Routes(namespace string) RouteInterface
|
||||
}
|
||||
|
||||
// RouteInterface exposes methods on Route resources
|
||||
type RouteInterface interface {
|
||||
List(opts kapi.ListOptions) (*routeapi.RouteList, error)
|
||||
Get(name string) (*routeapi.Route, error)
|
||||
Create(route *routeapi.Route) (*routeapi.Route, error)
|
||||
Update(route *routeapi.Route) (*routeapi.Route, error)
|
||||
UpdateStatus(route *routeapi.Route) (*routeapi.Route, error)
|
||||
Delete(name string) error
|
||||
Watch(opts kapi.ListOptions) (watch.Interface, error)
|
||||
}
|
||||
|
||||
// routes implements RouteInterface interface
|
||||
type routes struct {
|
||||
r *Client
|
||||
ns string
|
||||
}
|
||||
|
||||
// newRoutes returns a routes
|
||||
func newRoutes(c *Client, namespace string) *routes {
|
||||
return &routes{
|
||||
r: c,
|
||||
ns: namespace,
|
||||
}
|
||||
}
|
||||
|
||||
// List takes a label and field selector, and returns the list of routes that match that selectors
|
||||
func (c *routes) List(opts kapi.ListOptions) (result *routeapi.RouteList, err error) {
|
||||
result = &routeapi.RouteList{}
|
||||
err = c.r.Get().
|
||||
Namespace(c.ns).
|
||||
Resource("routes").
|
||||
VersionedParams(&opts, kapi.ParameterCodec).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Get takes the name of the route, and returns the corresponding Route object, and an error if it occurs
|
||||
func (c *routes) Get(name string) (result *routeapi.Route, err error) {
|
||||
result = &routeapi.Route{}
|
||||
err = c.r.Get().Namespace(c.ns).Resource("routes").Name(name).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Delete takes the name of the route, and returns an error if one occurs
|
||||
func (c *routes) Delete(name string) error {
|
||||
return c.r.Delete().Namespace(c.ns).Resource("routes").Name(name).Do().Error()
|
||||
}
|
||||
|
||||
// Create takes the representation of a route. Returns the server's representation of the route, and an error, if it occurs
|
||||
func (c *routes) Create(route *routeapi.Route) (result *routeapi.Route, err error) {
|
||||
result = &routeapi.Route{}
|
||||
err = c.r.Post().Namespace(c.ns).Resource("routes").Body(route).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Update takes the representation of a route to update. Returns the server's representation of the route, and an error, if it occurs
|
||||
func (c *routes) Update(route *routeapi.Route) (result *routeapi.Route, err error) {
|
||||
result = &routeapi.Route{}
|
||||
err = c.r.Put().Namespace(c.ns).Resource("routes").Name(route.Name).Body(route).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// UpdateStatus takes the route with altered status. Returns the server's representation of the route, and an error, if it occurs.
|
||||
func (c *routes) UpdateStatus(route *routeapi.Route) (result *routeapi.Route, err error) {
|
||||
result = &routeapi.Route{}
|
||||
err = c.r.Put().Namespace(c.ns).Resource("routes").Name(route.Name).SubResource("status").Body(route).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Watch returns a watch.Interface that watches the requested routes.
|
||||
func (c *routes) Watch(opts kapi.ListOptions) (watch.Interface, error) {
|
||||
return c.r.Get().
|
||||
Prefix("watch").
|
||||
Namespace(c.ns).
|
||||
Resource("routes").
|
||||
VersionedParams(&opts, kapi.ParameterCodec).
|
||||
Watch()
|
||||
}
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api/errors"
|
||||
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||
unversioned_extensions "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/extensions/unversioned"
|
||||
kclient "k8s.io/kubernetes/pkg/client/unversioned"
|
||||
|
||||
"github.com/openshift/origin/pkg/api/latest"
|
||||
)
|
||||
|
||||
type delegatingScaleInterface struct {
|
||||
dcs DeploymentConfigInterface
|
||||
scales kclient.ScaleInterface
|
||||
}
|
||||
|
||||
type delegatingScaleNamespacer struct {
|
||||
dcNS DeploymentConfigsNamespacer
|
||||
scaleNS kclient.ScaleNamespacer
|
||||
}
|
||||
|
||||
func (c *delegatingScaleNamespacer) Scales(namespace string) unversioned_extensions.ScaleInterface {
|
||||
return &delegatingScaleInterface{
|
||||
dcs: c.dcNS.DeploymentConfigs(namespace),
|
||||
scales: c.scaleNS.Scales(namespace),
|
||||
}
|
||||
}
|
||||
|
||||
func NewDelegatingScaleNamespacer(dcNamespacer DeploymentConfigsNamespacer, sNamespacer kclient.ScaleNamespacer) unversioned_extensions.ScalesGetter {
|
||||
return &delegatingScaleNamespacer{
|
||||
dcNS: dcNamespacer,
|
||||
scaleNS: sNamespacer,
|
||||
}
|
||||
}
|
||||
|
||||
// Get takes the reference to scale subresource and returns the subresource or error, if one occurs.
|
||||
func (c *delegatingScaleInterface) Get(kind string, name string) (result *extensions.Scale, err error) {
|
||||
switch {
|
||||
case kind == "DeploymentConfig":
|
||||
return c.dcs.GetScale(name)
|
||||
// TODO: This is borked because the interface for Get is broken. Kind is insufficient.
|
||||
case latest.IsKindInAnyOriginGroup(kind):
|
||||
return nil, errors.NewBadRequest(fmt.Sprintf("Kind %s has no Scale subresource", kind))
|
||||
default:
|
||||
return c.scales.Get(kind, name)
|
||||
}
|
||||
}
|
||||
|
||||
// Update takes a scale subresource object, updates the stored version to match it, and
|
||||
// returns the subresource or error, if one occurs.
|
||||
func (c *delegatingScaleInterface) Update(kind string, scale *extensions.Scale) (result *extensions.Scale, err error) {
|
||||
switch {
|
||||
case kind == "DeploymentConfig":
|
||||
return c.dcs.UpdateScale(scale)
|
||||
// TODO: This is borked because the interface for Update is broken. Kind is insufficient.
|
||||
case latest.IsKindInAnyOriginGroup(kind):
|
||||
return nil, errors.NewBadRequest(fmt.Sprintf("Kind %s has no Scale subresource", kind))
|
||||
default:
|
||||
return c.scales.Update(kind, scale)
|
||||
}
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
authorizationapi "github.com/openshift/origin/pkg/authorization/api"
|
||||
)
|
||||
|
||||
type SelfSubjectRulesReviewsNamespacer interface {
|
||||
SelfSubjectRulesReviews(namespace string) SelfSubjectRulesReviewInterface
|
||||
}
|
||||
|
||||
type SelfSubjectRulesReviewInterface interface {
|
||||
Create(*authorizationapi.SelfSubjectRulesReview) (*authorizationapi.SelfSubjectRulesReview, error)
|
||||
}
|
||||
|
||||
type selfSubjectRulesReviews struct {
|
||||
r *Client
|
||||
ns string
|
||||
}
|
||||
|
||||
func newSelfSubjectRulesReviews(c *Client, namespace string) *selfSubjectRulesReviews {
|
||||
return &selfSubjectRulesReviews{
|
||||
r: c,
|
||||
ns: namespace,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *selfSubjectRulesReviews) Create(selfSubjectRulesReview *authorizationapi.SelfSubjectRulesReview) (result *authorizationapi.SelfSubjectRulesReview, err error) {
|
||||
result = &authorizationapi.SelfSubjectRulesReview{}
|
||||
err = c.r.Post().Namespace(c.ns).Resource("selfSubjectRulesReviews").Body(selfSubjectRulesReview).Do().Into(result)
|
||||
|
||||
return
|
||||
}
|
||||
+100
@@ -0,0 +1,100 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
kapierrors "k8s.io/kubernetes/pkg/api/errors"
|
||||
"k8s.io/kubernetes/pkg/client/restclient"
|
||||
|
||||
authorizationapi "github.com/openshift/origin/pkg/authorization/api"
|
||||
)
|
||||
|
||||
type SubjectAccessReviewsImpersonator interface {
|
||||
ImpersonateSubjectAccessReviews(token string) SubjectAccessReviewInterface
|
||||
}
|
||||
|
||||
// SubjectAccessReviews has methods to work with SubjectAccessReview resources in the cluster scope
|
||||
type SubjectAccessReviews interface {
|
||||
SubjectAccessReviews() SubjectAccessReviewInterface
|
||||
}
|
||||
|
||||
// SubjectAccessReviewInterface exposes methods on SubjectAccessReview resources.
|
||||
type SubjectAccessReviewInterface interface {
|
||||
Create(policy *authorizationapi.SubjectAccessReview) (*authorizationapi.SubjectAccessReviewResponse, error)
|
||||
}
|
||||
|
||||
// subjectAccessReviews implements SubjectAccessReviews interface
|
||||
type subjectAccessReviews struct {
|
||||
r *Client
|
||||
token *string
|
||||
}
|
||||
|
||||
// newImpersonatingSubjectAccessReviews returns a subjectAccessReviews
|
||||
func newImpersonatingSubjectAccessReviews(c *Client, token string) *subjectAccessReviews {
|
||||
return &subjectAccessReviews{
|
||||
r: c,
|
||||
token: &token,
|
||||
}
|
||||
}
|
||||
|
||||
// newSubjectAccessReviews returns a subjectAccessReviews
|
||||
func newSubjectAccessReviews(c *Client) *subjectAccessReviews {
|
||||
return &subjectAccessReviews{
|
||||
r: c,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *subjectAccessReviews) Create(sar *authorizationapi.SubjectAccessReview) (*authorizationapi.SubjectAccessReviewResponse, error) {
|
||||
result := &authorizationapi.SubjectAccessReviewResponse{}
|
||||
|
||||
// if this a cluster SAR, then no special handling
|
||||
if len(sar.Action.Namespace) == 0 {
|
||||
req, err := overrideAuth(c.token, c.r.Post().Resource("subjectAccessReviews"))
|
||||
if err != nil {
|
||||
return &authorizationapi.SubjectAccessReviewResponse{}, err
|
||||
}
|
||||
|
||||
err = req.Body(sar).Do().Into(result)
|
||||
return result, err
|
||||
}
|
||||
|
||||
err := c.r.Post().Resource("subjectAccessReviews").Body(sar).Do().Into(result)
|
||||
|
||||
// if the namespace values don't match then we definitely hit an old server. If we got a forbidden, then we might have hit an old server
|
||||
// and should try the old endpoint
|
||||
if (sar.Action.Namespace != result.Namespace) || kapierrors.IsForbidden(err) {
|
||||
deprecatedReq, deprecatedAttemptErr := overrideAuth(c.token, c.r.Post().Namespace(sar.Action.Namespace).Resource("subjectAccessReviews"))
|
||||
if deprecatedAttemptErr != nil {
|
||||
return &authorizationapi.SubjectAccessReviewResponse{}, deprecatedAttemptErr
|
||||
}
|
||||
|
||||
deprecatedResponse := &authorizationapi.SubjectAccessReviewResponse{}
|
||||
deprecatedAttemptErr = deprecatedReq.Body(sar).Do().Into(deprecatedResponse)
|
||||
|
||||
// if we definitely hit an old server, then return the error and result you get from the older server.
|
||||
if sar.Action.Namespace != result.Namespace {
|
||||
return deprecatedResponse, deprecatedAttemptErr
|
||||
}
|
||||
|
||||
// if we're not certain it was an old server, success overwrites the previous error, but failure doesn't overwrite the previous error
|
||||
if deprecatedAttemptErr == nil {
|
||||
err = nil
|
||||
result = deprecatedResponse
|
||||
}
|
||||
}
|
||||
|
||||
return result, err
|
||||
}
|
||||
|
||||
// overrideAuth specifies the token to authenticate the request with. token == "" is not allowed
|
||||
func overrideAuth(token *string, req *restclient.Request) (*restclient.Request, error) {
|
||||
if token != nil {
|
||||
if len(*token) == 0 {
|
||||
return nil, errors.New("impersonating token may not be empty")
|
||||
}
|
||||
|
||||
req.SetHeader("Authorization", fmt.Sprintf("Bearer %s", *token))
|
||||
}
|
||||
return req, nil
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
templateapi "github.com/openshift/origin/pkg/template/api"
|
||||
)
|
||||
|
||||
// TemplateConfigNamespacer has methods to work with Image resources in a namespace
|
||||
// TODO: Rename to ProcessedTemplates
|
||||
type TemplateConfigsNamespacer interface {
|
||||
TemplateConfigs(namespace string) TemplateConfigInterface
|
||||
}
|
||||
|
||||
// TemplateConfigInterface exposes methods on Image resources.
|
||||
type TemplateConfigInterface interface {
|
||||
Create(t *templateapi.Template) (*templateapi.Template, error)
|
||||
}
|
||||
|
||||
// templateConfigs implements TemplateConfigsNamespacer interface
|
||||
type templateConfigs struct {
|
||||
r *Client
|
||||
ns string
|
||||
}
|
||||
|
||||
// newTemplateConfigs returns an TemplateConfigInterface
|
||||
func newTemplateConfigs(c *Client, namespace string) TemplateConfigInterface {
|
||||
return &templateConfigs{
|
||||
r: c,
|
||||
ns: namespace,
|
||||
}
|
||||
}
|
||||
|
||||
// Create process the Template and returns its current state
|
||||
func (c *templateConfigs) Create(in *templateapi.Template) (*templateapi.Template, error) {
|
||||
template := &templateapi.Template{}
|
||||
err := c.r.Post().Namespace(c.ns).Resource("processedTemplates").Body(in).Do().Into(template)
|
||||
return template, err
|
||||
}
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
kapi "k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/watch"
|
||||
|
||||
templateapi "github.com/openshift/origin/pkg/template/api"
|
||||
)
|
||||
|
||||
// TemplatesNamespacer has methods to work with Template resources in a namespace
|
||||
type TemplatesNamespacer interface {
|
||||
Templates(namespace string) TemplateInterface
|
||||
}
|
||||
|
||||
// TemplateInterface exposes methods on Template resources.
|
||||
type TemplateInterface interface {
|
||||
List(opts kapi.ListOptions) (*templateapi.TemplateList, error)
|
||||
Get(name string) (*templateapi.Template, error)
|
||||
Create(template *templateapi.Template) (*templateapi.Template, error)
|
||||
Update(template *templateapi.Template) (*templateapi.Template, error)
|
||||
Delete(name string) error
|
||||
Watch(opts kapi.ListOptions) (watch.Interface, error)
|
||||
}
|
||||
|
||||
// templates implements TemplatesNamespacer interface
|
||||
type templates struct {
|
||||
r *Client
|
||||
ns string
|
||||
}
|
||||
|
||||
// newTemplates returns a templates
|
||||
func newTemplates(c *Client, namespace string) *templates {
|
||||
return &templates{
|
||||
r: c,
|
||||
ns: namespace,
|
||||
}
|
||||
}
|
||||
|
||||
// List returns a list of templates that match the label and field selectors.
|
||||
func (c *templates) List(opts kapi.ListOptions) (result *templateapi.TemplateList, err error) {
|
||||
result = &templateapi.TemplateList{}
|
||||
err = c.r.Get().
|
||||
Namespace(c.ns).
|
||||
Resource("templates").
|
||||
VersionedParams(&opts, kapi.ParameterCodec).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Get returns information about a particular template and error if one occurs.
|
||||
func (c *templates) Get(name string) (result *templateapi.Template, err error) {
|
||||
result = &templateapi.Template{}
|
||||
err = c.r.Get().Namespace(c.ns).Resource("templates").Name(name).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Create creates new template. Returns the server's representation of the template and error if one occurs.
|
||||
func (c *templates) Create(template *templateapi.Template) (result *templateapi.Template, err error) {
|
||||
result = &templateapi.Template{}
|
||||
err = c.r.Post().Namespace(c.ns).Resource("templates").Body(template).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Update updates the template on server. Returns the server's representation of the template and error if one occurs.
|
||||
func (c *templates) Update(template *templateapi.Template) (result *templateapi.Template, err error) {
|
||||
result = &templateapi.Template{}
|
||||
err = c.r.Put().Namespace(c.ns).Resource("templates").Name(template.Name).Body(template).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Delete deletes a template, returns error if one occurs.
|
||||
func (c *templates) Delete(name string) (err error) {
|
||||
err = c.r.Delete().Namespace(c.ns).Resource("templates").Name(name).Do().Error()
|
||||
return
|
||||
}
|
||||
|
||||
// Watch returns a watch.Interface that watches the requested templates
|
||||
func (c *templates) Watch(opts kapi.ListOptions) (watch.Interface, error) {
|
||||
return c.r.Get().
|
||||
Prefix("watch").
|
||||
Namespace(c.ns).
|
||||
Resource("templates").
|
||||
VersionedParams(&opts, kapi.ParameterCodec).
|
||||
Watch()
|
||||
}
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
userapi "github.com/openshift/origin/pkg/user/api"
|
||||
)
|
||||
|
||||
// UserIdentityMappingsInterface has methods to work with UserIdentityMapping resources in a namespace
|
||||
type UserIdentityMappingsInterface interface {
|
||||
UserIdentityMappings() UserIdentityMappingInterface
|
||||
}
|
||||
|
||||
// UserIdentityMappingInterface exposes methods on UserIdentityMapping resources.
|
||||
type UserIdentityMappingInterface interface {
|
||||
Get(string) (*userapi.UserIdentityMapping, error)
|
||||
Create(*userapi.UserIdentityMapping) (*userapi.UserIdentityMapping, error)
|
||||
Update(*userapi.UserIdentityMapping) (*userapi.UserIdentityMapping, error)
|
||||
Delete(string) error
|
||||
}
|
||||
|
||||
// userIdentityMappings implements UserIdentityMappingsNamespacer interface
|
||||
type userIdentityMappings struct {
|
||||
r *Client
|
||||
}
|
||||
|
||||
// newUserIdentityMappings returns a userIdentityMappings
|
||||
func newUserIdentityMappings(c *Client) *userIdentityMappings {
|
||||
return &userIdentityMappings{
|
||||
r: c,
|
||||
}
|
||||
}
|
||||
|
||||
// Get returns information about a particular mapping or an error
|
||||
func (c *userIdentityMappings) Get(name string) (result *userapi.UserIdentityMapping, err error) {
|
||||
result = &userapi.UserIdentityMapping{}
|
||||
err = c.r.Get().Resource("userIdentityMappings").Name(name).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Create creates a new mapping. Returns the server's representation of the mapping and error if one occurs.
|
||||
func (c *userIdentityMappings) Create(mapping *userapi.UserIdentityMapping) (result *userapi.UserIdentityMapping, err error) {
|
||||
result = &userapi.UserIdentityMapping{}
|
||||
err = c.r.Post().Resource("userIdentityMappings").Body(mapping).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Update updates the mapping on server. Returns the server's representation of the mapping and error if one occurs.
|
||||
func (c *userIdentityMappings) Update(mapping *userapi.UserIdentityMapping) (result *userapi.UserIdentityMapping, err error) {
|
||||
result = &userapi.UserIdentityMapping{}
|
||||
err = c.r.Put().Resource("userIdentityMappings").Name(mapping.Name).Body(mapping).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Delete deletes the mapping on server.
|
||||
func (c *userIdentityMappings) Delete(name string) (err error) {
|
||||
err = c.r.Delete().Resource("userIdentityMappings").Name(name).Do().Error()
|
||||
return
|
||||
}
|
||||
+81
@@ -0,0 +1,81 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
kapi "k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/watch"
|
||||
|
||||
userapi "github.com/openshift/origin/pkg/user/api"
|
||||
)
|
||||
|
||||
// UsersInterface has methods to work with User resources
|
||||
type UsersInterface interface {
|
||||
Users() UserInterface
|
||||
}
|
||||
|
||||
// UserInterface exposes methods on user resources.
|
||||
type UserInterface interface {
|
||||
List(opts kapi.ListOptions) (*userapi.UserList, error)
|
||||
Get(name string) (*userapi.User, error)
|
||||
Create(user *userapi.User) (*userapi.User, error)
|
||||
Update(user *userapi.User) (*userapi.User, error)
|
||||
Delete(name string) error
|
||||
Watch(opts kapi.ListOptions) (watch.Interface, error)
|
||||
}
|
||||
|
||||
// users implements UserInterface interface
|
||||
type users struct {
|
||||
r *Client
|
||||
}
|
||||
|
||||
// newUsers returns a users
|
||||
func newUsers(c *Client) *users {
|
||||
return &users{
|
||||
r: c,
|
||||
}
|
||||
}
|
||||
|
||||
// List returns a list of users that match the label and field selectors.
|
||||
func (c *users) List(opts kapi.ListOptions) (result *userapi.UserList, err error) {
|
||||
result = &userapi.UserList{}
|
||||
err = c.r.Get().
|
||||
Resource("users").
|
||||
VersionedParams(&opts, kapi.ParameterCodec).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Get returns information about a particular user or an error
|
||||
func (c *users) Get(name string) (result *userapi.User, err error) {
|
||||
result = &userapi.User{}
|
||||
err = c.r.Get().Resource("users").Name(name).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Create creates a new user. Returns the server's representation of the user and error if one occurs.
|
||||
func (c *users) Create(user *userapi.User) (result *userapi.User, err error) {
|
||||
result = &userapi.User{}
|
||||
err = c.r.Post().Resource("users").Body(user).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Update updates the user on server. Returns the server's representation of the user and error if one occurs.
|
||||
func (c *users) Update(user *userapi.User) (result *userapi.User, err error) {
|
||||
result = &userapi.User{}
|
||||
err = c.r.Put().Resource("users").Name(user.Name).Body(user).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Delete deletes the user on server. Returns an error if one occurs.
|
||||
func (c *users) Delete(name string) (err error) {
|
||||
return c.r.Delete().Resource("users").Name(name).Do().Error()
|
||||
}
|
||||
|
||||
// Watch returns a watch.Interface that watches the requested users.
|
||||
func (c *users) Watch(opts kapi.ListOptions) (watch.Interface, error) {
|
||||
return c.r.Get().
|
||||
Prefix("watch").
|
||||
Resource("users").
|
||||
VersionedParams(&opts, kapi.ParameterCodec).
|
||||
Watch()
|
||||
}
|
||||
+103
@@ -0,0 +1,103 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/openshift/origin/pkg/cmd/util"
|
||||
clientcmdapi "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api"
|
||||
)
|
||||
|
||||
// TODO should be moved upstream
|
||||
func RelativizeClientConfigPaths(cfg *clientcmdapi.Config, base string) (err error) {
|
||||
for k, cluster := range cfg.Clusters {
|
||||
if len(cluster.CertificateAuthority) > 0 {
|
||||
if cluster.CertificateAuthority, err = util.MakeAbs(cluster.CertificateAuthority, ""); err != nil {
|
||||
return err
|
||||
}
|
||||
if cluster.CertificateAuthority, err = util.MakeRelative(cluster.CertificateAuthority, base); err != nil {
|
||||
return err
|
||||
}
|
||||
cfg.Clusters[k] = cluster
|
||||
}
|
||||
}
|
||||
for k, authInfo := range cfg.AuthInfos {
|
||||
if len(authInfo.ClientCertificate) > 0 {
|
||||
if authInfo.ClientCertificate, err = util.MakeAbs(authInfo.ClientCertificate, ""); err != nil {
|
||||
return err
|
||||
}
|
||||
if authInfo.ClientCertificate, err = util.MakeRelative(authInfo.ClientCertificate, base); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if len(authInfo.ClientKey) > 0 {
|
||||
if authInfo.ClientKey, err = util.MakeAbs(authInfo.ClientKey, ""); err != nil {
|
||||
return err
|
||||
}
|
||||
if authInfo.ClientKey, err = util.MakeRelative(authInfo.ClientKey, base); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
cfg.AuthInfos[k] = authInfo
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var validURLSchemes = []string{"https://", "http://", "tcp://"}
|
||||
|
||||
// NormalizeServerURL is opinionated normalization of a string that represents a URL. Returns the URL provided matching the format
|
||||
// expected when storing a URL in a config. Sets a scheme and port if not present, removes unnecessary trailing
|
||||
// slashes, etc. Can be used to normalize a URL provided by user input.
|
||||
func NormalizeServerURL(s string) (string, error) {
|
||||
// normalize scheme
|
||||
if !hasScheme(s) {
|
||||
s = validURLSchemes[0] + s
|
||||
}
|
||||
|
||||
addr, err := url.Parse(s)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("Not a valid URL: %v.", err)
|
||||
}
|
||||
|
||||
// normalize host:port
|
||||
if strings.Contains(addr.Host, ":") {
|
||||
_, port, err := net.SplitHostPort(addr.Host)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("Not a valid host:port: %v.", err)
|
||||
}
|
||||
_, err = strconv.ParseUint(port, 10, 16)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("Not a valid port: %v. Port numbers must be between 0 and 65535.", port)
|
||||
}
|
||||
} else {
|
||||
port := 0
|
||||
switch addr.Scheme {
|
||||
case "http":
|
||||
port = 80
|
||||
case "https":
|
||||
port = 443
|
||||
default:
|
||||
return "", fmt.Errorf("No port specified.")
|
||||
}
|
||||
addr.Host = net.JoinHostPort(addr.Host, strconv.FormatInt(int64(port), 10))
|
||||
}
|
||||
|
||||
// remove trailing slash if that's the only path we have
|
||||
if addr.Path == "/" {
|
||||
addr.Path = ""
|
||||
}
|
||||
|
||||
return addr.String(), nil
|
||||
}
|
||||
|
||||
func hasScheme(s string) bool {
|
||||
for _, p := range validURLSchemes {
|
||||
if strings.HasPrefix(s, p) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
|
||||
kclientcmd "k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
|
||||
kcmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/util/homedir"
|
||||
)
|
||||
|
||||
const (
|
||||
OpenShiftConfigPathEnvVar = "KUBECONFIG"
|
||||
OpenShiftConfigFlagName = "config"
|
||||
OpenShiftConfigHomeDir = ".kube"
|
||||
OpenShiftConfigHomeFileName = "config"
|
||||
OpenShiftConfigHomeDirFileName = OpenShiftConfigHomeDir + "/" + OpenShiftConfigHomeFileName
|
||||
)
|
||||
|
||||
var RecommendedHomeFile = path.Join(homedir.HomeDir(), OpenShiftConfigHomeDirFileName)
|
||||
|
||||
// currentMigrationRules returns a map that holds the history of recommended home directories used in previous versions.
|
||||
// Any future changes to RecommendedHomeFile and related are expected to add a migration rule here, in order to make
|
||||
// sure existing config files are migrated to their new locations properly.
|
||||
func currentMigrationRules() map[string]string {
|
||||
oldRecommendedHomeFile := path.Join(homedir.HomeDir(), ".kube/.config")
|
||||
oldRecommendedWindowsHomeFile := path.Join(os.Getenv("HOME"), OpenShiftConfigHomeDirFileName)
|
||||
|
||||
migrationRules := map[string]string{}
|
||||
migrationRules[RecommendedHomeFile] = oldRecommendedHomeFile
|
||||
if runtime.GOOS == "windows" {
|
||||
migrationRules[RecommendedHomeFile] = oldRecommendedWindowsHomeFile
|
||||
}
|
||||
return migrationRules
|
||||
}
|
||||
|
||||
// NewOpenShiftClientConfigLoadingRules returns file priority loading rules for OpenShift.
|
||||
// 1. --config value
|
||||
// 2. if KUBECONFIG env var has a value, use it. Otherwise, ~/.kube/config file
|
||||
func NewOpenShiftClientConfigLoadingRules() *clientcmd.ClientConfigLoadingRules {
|
||||
chain := []string{}
|
||||
|
||||
envVarFile := os.Getenv(OpenShiftConfigPathEnvVar)
|
||||
if len(envVarFile) != 0 {
|
||||
chain = append(chain, filepath.SplitList(envVarFile)...)
|
||||
} else {
|
||||
chain = append(chain, RecommendedHomeFile)
|
||||
}
|
||||
|
||||
return &clientcmd.ClientConfigLoadingRules{
|
||||
Precedence: chain,
|
||||
MigrationRules: currentMigrationRules(),
|
||||
}
|
||||
}
|
||||
|
||||
func NewPathOptions(cmd *cobra.Command) *kclientcmd.PathOptions {
|
||||
return NewPathOptionsWithConfig(kcmdutil.GetFlagString(cmd, OpenShiftConfigFlagName))
|
||||
}
|
||||
|
||||
func NewPathOptionsWithConfig(configPath string) *kclientcmd.PathOptions {
|
||||
return &kclientcmd.PathOptions{
|
||||
GlobalFile: RecommendedHomeFile,
|
||||
|
||||
EnvVar: OpenShiftConfigPathEnvVar,
|
||||
ExplicitFileFlag: OpenShiftConfigFlagName,
|
||||
|
||||
LoadingRules: &kclientcmd.ClientConfigLoadingRules{
|
||||
ExplicitPath: configPath,
|
||||
},
|
||||
}
|
||||
}
|
||||
+194
@@ -0,0 +1,194 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"crypto/x509"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"k8s.io/kubernetes/pkg/client/restclient"
|
||||
clientcmdapi "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api"
|
||||
"k8s.io/kubernetes/third_party/forked/golang/netutil"
|
||||
|
||||
"github.com/openshift/origin/pkg/auth/authenticator/request/x509request"
|
||||
osclient "github.com/openshift/origin/pkg/client"
|
||||
)
|
||||
|
||||
// GetClusterNicknameFromConfig returns host:port of the clientConfig.Host, with .'s replaced by -'s
|
||||
func GetClusterNicknameFromConfig(clientCfg *restclient.Config) (string, error) {
|
||||
return GetClusterNicknameFromURL(clientCfg.Host)
|
||||
}
|
||||
|
||||
// GetClusterNicknameFromURL returns host:port of the apiServerLocation, with .'s replaced by -'s
|
||||
func GetClusterNicknameFromURL(apiServerLocation string) (string, error) {
|
||||
u, err := url.Parse(apiServerLocation)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
hostPort := netutil.CanonicalAddr(u)
|
||||
|
||||
// we need a character other than "." to avoid conflicts with. replace with '-'
|
||||
return strings.Replace(hostPort, ".", "-", -1), nil
|
||||
}
|
||||
|
||||
// GetUserNicknameFromConfig returns "username(as known by the server)/GetClusterNicknameFromConfig". This allows tab completion for switching users to
|
||||
// work easily and obviously.
|
||||
func GetUserNicknameFromConfig(clientCfg *restclient.Config) (string, error) {
|
||||
client, err := osclient.New(clientCfg)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
userInfo, err := client.Users().Get("~")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
clusterNick, err := GetClusterNicknameFromConfig(clientCfg)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return userInfo.Name + "/" + clusterNick, nil
|
||||
}
|
||||
|
||||
func GetUserNicknameFromCert(clusterNick string, chain ...*x509.Certificate) (string, error) {
|
||||
userInfo, _, err := x509request.SubjectToUserConversion(chain)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return userInfo.GetName() + "/" + clusterNick, nil
|
||||
}
|
||||
|
||||
// GetContextNicknameFromConfig returns "namespace/GetClusterNicknameFromConfig/username(as known by the server)". This allows tab completion for switching projects/context
|
||||
// to work easily. First tab is the most selective on project. Second stanza in the next most selective on cluster name. The chances of a user trying having
|
||||
// one projects on a single server that they want to operate against with two identities is low, so username is last.
|
||||
func GetContextNicknameFromConfig(namespace string, clientCfg *restclient.Config) (string, error) {
|
||||
client, err := osclient.New(clientCfg)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
userInfo, err := client.Users().Get("~")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
clusterNick, err := GetClusterNicknameFromConfig(clientCfg)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return namespace + "/" + clusterNick + "/" + userInfo.Name, nil
|
||||
}
|
||||
|
||||
func GetContextNickname(namespace, clusterNick, userNick string) string {
|
||||
tokens := strings.SplitN(userNick, "/", 2)
|
||||
return namespace + "/" + clusterNick + "/" + tokens[0]
|
||||
}
|
||||
|
||||
// CreateConfig takes a clientCfg and builds a config (kubeconfig style) from it.
|
||||
func CreateConfig(namespace string, clientCfg *restclient.Config) (*clientcmdapi.Config, error) {
|
||||
clusterNick, err := GetClusterNicknameFromConfig(clientCfg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
userNick, err := GetUserNicknameFromConfig(clientCfg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
contextNick, err := GetContextNicknameFromConfig(namespace, clientCfg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
config := clientcmdapi.NewConfig()
|
||||
|
||||
credentials := clientcmdapi.NewAuthInfo()
|
||||
credentials.Token = clientCfg.BearerToken
|
||||
credentials.ClientCertificate = clientCfg.TLSClientConfig.CertFile
|
||||
if len(credentials.ClientCertificate) == 0 {
|
||||
credentials.ClientCertificateData = clientCfg.TLSClientConfig.CertData
|
||||
}
|
||||
credentials.ClientKey = clientCfg.TLSClientConfig.KeyFile
|
||||
if len(credentials.ClientKey) == 0 {
|
||||
credentials.ClientKeyData = clientCfg.TLSClientConfig.KeyData
|
||||
}
|
||||
config.AuthInfos[userNick] = credentials
|
||||
|
||||
cluster := clientcmdapi.NewCluster()
|
||||
cluster.Server = clientCfg.Host
|
||||
cluster.CertificateAuthority = clientCfg.CAFile
|
||||
if len(cluster.CertificateAuthority) == 0 {
|
||||
cluster.CertificateAuthorityData = clientCfg.CAData
|
||||
}
|
||||
cluster.InsecureSkipTLSVerify = clientCfg.Insecure
|
||||
if clientCfg.GroupVersion != nil {
|
||||
cluster.APIVersion = clientCfg.GroupVersion.String()
|
||||
}
|
||||
config.Clusters[clusterNick] = cluster
|
||||
|
||||
context := clientcmdapi.NewContext()
|
||||
context.Cluster = clusterNick
|
||||
context.AuthInfo = userNick
|
||||
context.Namespace = namespace
|
||||
config.Contexts[contextNick] = context
|
||||
config.CurrentContext = contextNick
|
||||
|
||||
return config, nil
|
||||
}
|
||||
|
||||
// MergeConfig adds the additional Config stanzas to the startingConfig. It blindly stomps clusters and users, but
|
||||
// it searches for a matching context before writing a new one.
|
||||
func MergeConfig(startingConfig, addition clientcmdapi.Config) (*clientcmdapi.Config, error) {
|
||||
ret := startingConfig
|
||||
|
||||
for requestedKey, value := range addition.Clusters {
|
||||
ret.Clusters[requestedKey] = value
|
||||
}
|
||||
|
||||
for requestedKey, value := range addition.AuthInfos {
|
||||
ret.AuthInfos[requestedKey] = value
|
||||
}
|
||||
|
||||
requestedContextNamesToActualContextNames := map[string]string{}
|
||||
for requestedKey, newContext := range addition.Contexts {
|
||||
actualContext := clientcmdapi.NewContext()
|
||||
actualContext.AuthInfo = newContext.AuthInfo
|
||||
actualContext.Cluster = newContext.Cluster
|
||||
actualContext.Namespace = newContext.Namespace
|
||||
actualContext.Extensions = newContext.Extensions
|
||||
|
||||
if existingName := FindExistingContextName(startingConfig, *actualContext); len(existingName) > 0 {
|
||||
// if this already exists, just move to the next, our job is done
|
||||
requestedContextNamesToActualContextNames[requestedKey] = existingName
|
||||
continue
|
||||
}
|
||||
|
||||
requestedContextNamesToActualContextNames[requestedKey] = requestedKey
|
||||
ret.Contexts[requestedKey] = actualContext
|
||||
}
|
||||
|
||||
if len(addition.CurrentContext) > 0 {
|
||||
if newCurrentContext, exists := requestedContextNamesToActualContextNames[addition.CurrentContext]; exists {
|
||||
ret.CurrentContext = newCurrentContext
|
||||
} else {
|
||||
ret.CurrentContext = addition.CurrentContext
|
||||
}
|
||||
}
|
||||
|
||||
return &ret, nil
|
||||
}
|
||||
|
||||
// FindExistingContextName finds the nickname for the passed context
|
||||
func FindExistingContextName(haystack clientcmdapi.Config, needle clientcmdapi.Context) string {
|
||||
for key, context := range haystack.Contexts {
|
||||
context.LocationOfOrigin = ""
|
||||
if reflect.DeepEqual(context, needle) {
|
||||
return key
|
||||
}
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
+319
@@ -0,0 +1,319 @@
|
||||
package describe
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/gonum/graph"
|
||||
"github.com/gonum/graph/encoding/dot"
|
||||
"github.com/gonum/graph/path"
|
||||
kapi "k8s.io/kubernetes/pkg/api"
|
||||
utilerrors "k8s.io/kubernetes/pkg/util/errors"
|
||||
"k8s.io/kubernetes/pkg/util/sets"
|
||||
|
||||
osgraph "github.com/openshift/origin/pkg/api/graph"
|
||||
buildedges "github.com/openshift/origin/pkg/build/graph"
|
||||
buildanalysis "github.com/openshift/origin/pkg/build/graph/analysis"
|
||||
buildgraph "github.com/openshift/origin/pkg/build/graph/nodes"
|
||||
"github.com/openshift/origin/pkg/client"
|
||||
imageapi "github.com/openshift/origin/pkg/image/api"
|
||||
imagegraph "github.com/openshift/origin/pkg/image/graph/nodes"
|
||||
dotutil "github.com/openshift/origin/pkg/util/dot"
|
||||
"github.com/openshift/origin/pkg/util/parallel"
|
||||
)
|
||||
|
||||
// NotFoundErr is returned when the imageStreamTag (ist) of interest cannot
|
||||
// be found in the graph. This doesn't mean though that the IST does not
|
||||
// exist. A user may have an image stream without a build configuration
|
||||
// pointing at it. In that case, the IST of interest simply doesn't have
|
||||
// other dependant ists
|
||||
type NotFoundErr string
|
||||
|
||||
func (e NotFoundErr) Error() string {
|
||||
return fmt.Sprintf("couldn't find image stream tag: %q", string(e))
|
||||
}
|
||||
|
||||
// ChainDescriber generates extended information about a chain of
|
||||
// dependencies of an image stream
|
||||
type ChainDescriber struct {
|
||||
c client.BuildConfigsNamespacer
|
||||
namespaces sets.String
|
||||
outputFormat string
|
||||
namer osgraph.Namer
|
||||
}
|
||||
|
||||
// NewChainDescriber returns a new ChainDescriber
|
||||
func NewChainDescriber(c client.BuildConfigsNamespacer, namespaces sets.String, out string) *ChainDescriber {
|
||||
return &ChainDescriber{c: c, namespaces: namespaces, outputFormat: out, namer: namespacedFormatter{hideNamespace: true}}
|
||||
}
|
||||
|
||||
// MakeGraph will create the graph of all build configurations and the image streams
|
||||
// they point to via image change triggers in the provided namespace(s)
|
||||
func (d *ChainDescriber) MakeGraph() (osgraph.Graph, error) {
|
||||
g := osgraph.New()
|
||||
|
||||
loaders := []GraphLoader{}
|
||||
for namespace := range d.namespaces {
|
||||
glog.V(4).Infof("Loading build configurations from %q", namespace)
|
||||
loaders = append(loaders, &bcLoader{namespace: namespace, lister: d.c})
|
||||
}
|
||||
loadingFuncs := []func() error{}
|
||||
for _, loader := range loaders {
|
||||
loadingFuncs = append(loadingFuncs, loader.Load)
|
||||
}
|
||||
|
||||
if errs := parallel.Run(loadingFuncs...); len(errs) > 0 {
|
||||
return g, utilerrors.NewAggregate(errs)
|
||||
}
|
||||
|
||||
for _, loader := range loaders {
|
||||
loader.AddToGraph(g)
|
||||
}
|
||||
|
||||
buildedges.AddAllInputOutputEdges(g)
|
||||
|
||||
return g, nil
|
||||
}
|
||||
|
||||
// Describe returns the output of the graph starting from the provided
|
||||
// image stream tag (name:tag) in namespace. Namespace is needed here
|
||||
// because image stream tags with the same name can be found across
|
||||
// different namespaces.
|
||||
func (d *ChainDescriber) Describe(ist *imageapi.ImageStreamTag, includeInputImages, reverse bool) (string, error) {
|
||||
g, err := d.MakeGraph()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// Retrieve the imageStreamTag node of interest
|
||||
istNode := g.Find(imagegraph.ImageStreamTagNodeName(ist))
|
||||
if istNode == nil {
|
||||
return "", NotFoundErr(fmt.Sprintf("%q", ist.Name))
|
||||
}
|
||||
|
||||
markers := buildanalysis.FindCircularBuilds(g, d.namer)
|
||||
if len(markers) > 0 {
|
||||
for _, marker := range markers {
|
||||
if strings.Contains(marker.Message, ist.Name) {
|
||||
return marker.Message, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
buildInputEdgeKinds := []string{buildedges.BuildTriggerImageEdgeKind}
|
||||
if includeInputImages {
|
||||
buildInputEdgeKinds = append(buildInputEdgeKinds, buildedges.BuildInputImageEdgeKind)
|
||||
}
|
||||
|
||||
// Partition down to the subgraph containing the imagestreamtag of interest
|
||||
var partitioned osgraph.Graph
|
||||
if reverse {
|
||||
partitioned = partitionReverse(g, istNode, buildInputEdgeKinds)
|
||||
} else {
|
||||
partitioned = partition(g, istNode, buildInputEdgeKinds)
|
||||
}
|
||||
|
||||
switch strings.ToLower(d.outputFormat) {
|
||||
case "dot":
|
||||
data, err := dot.Marshal(partitioned, dotutil.Quote(ist.Name), "", " ", false)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(data), nil
|
||||
case "":
|
||||
return d.humanReadableOutput(partitioned, d.namer, istNode, reverse), nil
|
||||
}
|
||||
|
||||
return "", fmt.Errorf("unknown specified format %q", d.outputFormat)
|
||||
}
|
||||
|
||||
// partition the graph down to a subgraph starting from the given root
|
||||
func partition(g osgraph.Graph, root graph.Node, buildInputEdgeKinds []string) osgraph.Graph {
|
||||
// Filter out all but BuildConfig and ImageStreamTag nodes
|
||||
nodeFn := osgraph.NodesOfKind(buildgraph.BuildConfigNodeKind, imagegraph.ImageStreamTagNodeKind)
|
||||
// Filter out all but BuildInputImage and BuildOutput edges
|
||||
edgeKinds := []string{}
|
||||
edgeKinds = append(edgeKinds, buildInputEdgeKinds...)
|
||||
edgeKinds = append(edgeKinds, buildedges.BuildOutputEdgeKind)
|
||||
edgeFn := osgraph.EdgesOfKind(edgeKinds...)
|
||||
sub := g.Subgraph(nodeFn, edgeFn)
|
||||
|
||||
// Filter out inbound edges to the IST of interest
|
||||
edgeFn = osgraph.RemoveInboundEdges([]graph.Node{root})
|
||||
sub = sub.Subgraph(nodeFn, edgeFn)
|
||||
|
||||
// Check all paths leading from the root node, collect any
|
||||
// node found in them, and create the desired subgraph
|
||||
desired := []graph.Node{root}
|
||||
paths := path.DijkstraAllPaths(sub)
|
||||
for _, node := range sub.Nodes() {
|
||||
if node == root {
|
||||
continue
|
||||
}
|
||||
path, _, _ := paths.Between(root, node)
|
||||
if len(path) != 0 {
|
||||
desired = append(desired, node)
|
||||
}
|
||||
}
|
||||
return sub.SubgraphWithNodes(desired, osgraph.ExistingDirectEdge)
|
||||
}
|
||||
|
||||
// partitionReverse the graph down to a subgraph starting from the given root
|
||||
func partitionReverse(g osgraph.Graph, root graph.Node, buildInputEdgeKinds []string) osgraph.Graph {
|
||||
// Filter out all but BuildConfig and ImageStreamTag nodes
|
||||
nodeFn := osgraph.NodesOfKind(buildgraph.BuildConfigNodeKind, imagegraph.ImageStreamTagNodeKind)
|
||||
// Filter out all but BuildInputImage and BuildOutput edges
|
||||
edgeKinds := []string{}
|
||||
edgeKinds = append(edgeKinds, buildInputEdgeKinds...)
|
||||
edgeKinds = append(edgeKinds, buildedges.BuildOutputEdgeKind)
|
||||
edgeFn := osgraph.EdgesOfKind(edgeKinds...)
|
||||
sub := g.Subgraph(nodeFn, edgeFn)
|
||||
|
||||
// Filter out inbound edges to the IST of interest
|
||||
edgeFn = osgraph.RemoveOutboundEdges([]graph.Node{root})
|
||||
sub = sub.Subgraph(nodeFn, edgeFn)
|
||||
|
||||
// Check all paths leading from the root node, collect any
|
||||
// node found in them, and create the desired subgraph
|
||||
desired := []graph.Node{root}
|
||||
paths := path.DijkstraAllPaths(sub)
|
||||
for _, node := range sub.Nodes() {
|
||||
if node == root {
|
||||
continue
|
||||
}
|
||||
path, _, _ := paths.Between(node, root)
|
||||
if len(path) != 0 {
|
||||
desired = append(desired, node)
|
||||
}
|
||||
}
|
||||
return sub.SubgraphWithNodes(desired, osgraph.ExistingDirectEdge)
|
||||
}
|
||||
|
||||
// humanReadableOutput traverses the provided graph using DFS and outputs it
|
||||
// in a human-readable format. It starts from the provided root, assuming it
|
||||
// is an imageStreamTag node and continues to the rest of the graph handling
|
||||
// only imageStreamTag and buildConfig nodes.
|
||||
func (d *ChainDescriber) humanReadableOutput(g osgraph.Graph, f osgraph.Namer, root graph.Node, reverse bool) string {
|
||||
if reverse {
|
||||
g = g.EdgeSubgraph(osgraph.ReverseExistingDirectEdge)
|
||||
}
|
||||
|
||||
var singleNamespace bool
|
||||
if len(d.namespaces) == 1 && !d.namespaces.Has(kapi.NamespaceAll) {
|
||||
singleNamespace = true
|
||||
}
|
||||
depth := map[graph.Node]int{
|
||||
root: 0,
|
||||
}
|
||||
out := ""
|
||||
|
||||
dfs := &DepthFirst{
|
||||
Visit: func(u, v graph.Node) {
|
||||
depth[v] = depth[u] + 1
|
||||
},
|
||||
}
|
||||
|
||||
until := func(node graph.Node) bool {
|
||||
var info string
|
||||
|
||||
switch t := node.(type) {
|
||||
case *imagegraph.ImageStreamTagNode:
|
||||
info = outputHelper(f.ResourceName(t), t.Namespace, singleNamespace)
|
||||
case *buildgraph.BuildConfigNode:
|
||||
info = outputHelper(f.ResourceName(t), t.BuildConfig.Namespace, singleNamespace)
|
||||
default:
|
||||
panic("this graph contains node kinds other than imageStreamTags and buildConfigs")
|
||||
}
|
||||
|
||||
if depth[node] != 0 {
|
||||
out += "\n"
|
||||
}
|
||||
out += fmt.Sprintf("%s", strings.Repeat("\t", depth[node]))
|
||||
out += fmt.Sprintf("%s", info)
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
dfs.Walk(g, root, until)
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
// outputHelper returns resource/name in a single namespace, <namespace resource/name>
|
||||
// in multiple namespaces
|
||||
func outputHelper(info, namespace string, singleNamespace bool) string {
|
||||
if singleNamespace {
|
||||
return info
|
||||
}
|
||||
return fmt.Sprintf("<%s %s>", namespace, info)
|
||||
}
|
||||
|
||||
// DepthFirst implements stateful depth-first graph traversal.
|
||||
// Modifies behavior of visitor.DepthFirst to allow nodes to be visited multiple
|
||||
// times as long as they're not in the current stack
|
||||
type DepthFirst struct {
|
||||
EdgeFilter func(graph.Edge) bool
|
||||
Visit func(u, v graph.Node)
|
||||
stack NodeStack
|
||||
}
|
||||
|
||||
// Walk performs a depth-first traversal of the graph g starting from the given node
|
||||
func (d *DepthFirst) Walk(g graph.Graph, from graph.Node, until func(graph.Node) bool) graph.Node {
|
||||
return d.visit(g, from, until)
|
||||
}
|
||||
|
||||
func (d *DepthFirst) visit(g graph.Graph, t graph.Node, until func(graph.Node) bool) graph.Node {
|
||||
if until != nil && until(t) {
|
||||
return t
|
||||
}
|
||||
d.stack.Push(t)
|
||||
children := osgraph.ByID(g.From(t))
|
||||
sort.Sort(children)
|
||||
for _, n := range children {
|
||||
if d.EdgeFilter != nil && !d.EdgeFilter(g.Edge(t, n)) {
|
||||
continue
|
||||
}
|
||||
if d.visited(n.ID()) {
|
||||
continue
|
||||
}
|
||||
if d.Visit != nil {
|
||||
d.Visit(t, n)
|
||||
}
|
||||
result := d.visit(g, n, until)
|
||||
if result != nil {
|
||||
return result
|
||||
}
|
||||
}
|
||||
d.stack.Pop()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *DepthFirst) visited(id int) bool {
|
||||
for _, n := range d.stack {
|
||||
if n.ID() == id {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// NodeStack implements a LIFO stack of graph.Node.
|
||||
// NodeStack is internal only in go 1.5.
|
||||
type NodeStack []graph.Node
|
||||
|
||||
// Len returns the number of graph.Nodes on the stack.
|
||||
func (s *NodeStack) Len() int { return len(*s) }
|
||||
|
||||
// Pop returns the last graph.Node on the stack and removes it
|
||||
// from the stack.
|
||||
func (s *NodeStack) Pop() graph.Node {
|
||||
v := *s
|
||||
v, n := v[:len(v)-1], v[len(v)-1]
|
||||
*s = v
|
||||
return n
|
||||
}
|
||||
|
||||
// Push adds the node n to the stack at the last position.
|
||||
func (s *NodeStack) Push(n graph.Node) { *s = append(*s, n) }
|
||||
+417
@@ -0,0 +1,417 @@
|
||||
package describe
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
|
||||
kapi "k8s.io/kubernetes/pkg/api"
|
||||
kerrors "k8s.io/kubernetes/pkg/api/errors"
|
||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||
"k8s.io/kubernetes/pkg/apis/autoscaling"
|
||||
kclient "k8s.io/kubernetes/pkg/client/unversioned"
|
||||
rcutils "k8s.io/kubernetes/pkg/controller/replication"
|
||||
kctl "k8s.io/kubernetes/pkg/kubectl"
|
||||
"k8s.io/kubernetes/pkg/labels"
|
||||
|
||||
"github.com/openshift/origin/pkg/api/graph"
|
||||
kubegraph "github.com/openshift/origin/pkg/api/kubegraph/nodes"
|
||||
"github.com/openshift/origin/pkg/client"
|
||||
deployapi "github.com/openshift/origin/pkg/deploy/api"
|
||||
deployedges "github.com/openshift/origin/pkg/deploy/graph"
|
||||
deploygraph "github.com/openshift/origin/pkg/deploy/graph/nodes"
|
||||
deployutil "github.com/openshift/origin/pkg/deploy/util"
|
||||
imageapi "github.com/openshift/origin/pkg/image/api"
|
||||
)
|
||||
|
||||
const (
|
||||
// maxDisplayDeployments is the number of deployments to show when describing
|
||||
// deployment configuration.
|
||||
maxDisplayDeployments = 3
|
||||
|
||||
// maxDisplayDeploymentsEvents is the number of events to display when
|
||||
// describing the deployment configuration.
|
||||
// TODO: Make the estimation of this number more sophisticated and make this
|
||||
// number configurable via DescriberSettings
|
||||
maxDisplayDeploymentsEvents = 8
|
||||
)
|
||||
|
||||
// DeploymentConfigDescriber generates information about a DeploymentConfig
|
||||
type DeploymentConfigDescriber struct {
|
||||
osClient client.Interface
|
||||
kubeClient kclient.Interface
|
||||
|
||||
config *deployapi.DeploymentConfig
|
||||
}
|
||||
|
||||
// NewDeploymentConfigDescriber returns a new DeploymentConfigDescriber
|
||||
func NewDeploymentConfigDescriber(client client.Interface, kclient kclient.Interface, config *deployapi.DeploymentConfig) *DeploymentConfigDescriber {
|
||||
return &DeploymentConfigDescriber{
|
||||
osClient: client,
|
||||
kubeClient: kclient,
|
||||
config: config,
|
||||
}
|
||||
}
|
||||
|
||||
// Describe returns the description of a DeploymentConfig
|
||||
func (d *DeploymentConfigDescriber) Describe(namespace, name string, settings kctl.DescriberSettings) (string, error) {
|
||||
var deploymentConfig *deployapi.DeploymentConfig
|
||||
if d.config != nil {
|
||||
// If a deployment config is already provided use that.
|
||||
// This is used by `oc rollback --dry-run`.
|
||||
deploymentConfig = d.config
|
||||
} else {
|
||||
var err error
|
||||
deploymentConfig, err = d.osClient.DeploymentConfigs(namespace).Get(name)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
return tabbedString(func(out *tabwriter.Writer) error {
|
||||
formatMeta(out, deploymentConfig.ObjectMeta)
|
||||
var (
|
||||
deploymentsHistory []kapi.ReplicationController
|
||||
activeDeploymentName string
|
||||
)
|
||||
|
||||
if d.config == nil {
|
||||
if rcs, err := d.kubeClient.ReplicationControllers(namespace).List(kapi.ListOptions{LabelSelector: deployutil.ConfigSelector(deploymentConfig.Name)}); err == nil {
|
||||
deploymentsHistory = rcs.Items
|
||||
}
|
||||
}
|
||||
|
||||
if deploymentConfig.Status.LatestVersion == 0 {
|
||||
formatString(out, "Latest Version", "Not deployed")
|
||||
} else {
|
||||
formatString(out, "Latest Version", strconv.FormatInt(deploymentConfig.Status.LatestVersion, 10))
|
||||
}
|
||||
|
||||
printDeploymentConfigSpec(d.kubeClient, *deploymentConfig, out)
|
||||
fmt.Fprintln(out)
|
||||
|
||||
latestDeploymentName := deployutil.LatestDeploymentNameForConfig(deploymentConfig)
|
||||
if activeDeployment := deployutil.ActiveDeployment(deploymentConfig, deploymentsHistory); activeDeployment != nil {
|
||||
activeDeploymentName = activeDeployment.Name
|
||||
}
|
||||
|
||||
var deployment *kapi.ReplicationController
|
||||
isNotDeployed := len(deploymentsHistory) == 0
|
||||
for _, item := range deploymentsHistory {
|
||||
if item.Name == latestDeploymentName {
|
||||
deployment = &item
|
||||
}
|
||||
}
|
||||
|
||||
if isNotDeployed {
|
||||
formatString(out, "Latest Deployment", "<none>")
|
||||
} else {
|
||||
header := fmt.Sprintf("Deployment #%d (latest)", deployutil.DeploymentVersionFor(deployment))
|
||||
// Show details if the current deployment is the active one or it is the
|
||||
// initial deployment.
|
||||
printDeploymentRc(deployment, d.kubeClient, out, header, (deployment.Name == activeDeploymentName) || len(deploymentsHistory) == 1)
|
||||
}
|
||||
|
||||
// We don't show the deployment history when running `oc rollback --dry-run`.
|
||||
if d.config == nil && !isNotDeployed {
|
||||
sorted := deploymentsHistory
|
||||
sort.Sort(sort.Reverse(rcutils.OverlappingControllers(sorted)))
|
||||
counter := 1
|
||||
for _, item := range sorted {
|
||||
if item.Name != latestDeploymentName && deploymentConfig.Name == deployutil.DeploymentConfigNameFor(&item) {
|
||||
header := fmt.Sprintf("Deployment #%d", deployutil.DeploymentVersionFor(&item))
|
||||
printDeploymentRc(&item, d.kubeClient, out, header, item.Name == activeDeploymentName)
|
||||
counter++
|
||||
}
|
||||
if counter == maxDisplayDeployments {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if settings.ShowEvents {
|
||||
// Events
|
||||
if events, err := d.kubeClient.Events(deploymentConfig.Namespace).Search(deploymentConfig); err == nil && events != nil {
|
||||
latestDeploymentEvents := &kapi.EventList{Items: []kapi.Event{}}
|
||||
for i := len(events.Items); i != 0 && i > len(events.Items)-maxDisplayDeploymentsEvents; i-- {
|
||||
latestDeploymentEvents.Items = append(latestDeploymentEvents.Items, events.Items[i-1])
|
||||
}
|
||||
fmt.Fprintln(out)
|
||||
kctl.DescribeEvents(latestDeploymentEvents, out)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func multilineStringArray(sep, indent string, args ...string) string {
|
||||
for i, s := range args {
|
||||
if strings.HasSuffix(s, "\n") {
|
||||
s = strings.TrimSuffix(s, "\n")
|
||||
}
|
||||
if strings.Contains(s, "\n") {
|
||||
s = "\n" + indent + strings.Join(strings.Split(s, "\n"), "\n"+indent)
|
||||
}
|
||||
args[i] = s
|
||||
}
|
||||
strings.TrimRight(args[len(args)-1], "\n ")
|
||||
return strings.Join(args, " ")
|
||||
}
|
||||
|
||||
func printStrategy(strategy deployapi.DeploymentStrategy, indent string, w *tabwriter.Writer) {
|
||||
if strategy.CustomParams != nil {
|
||||
if len(strategy.CustomParams.Image) == 0 {
|
||||
fmt.Fprintf(w, "%sImage:\t%s\n", indent, "<default>")
|
||||
} else {
|
||||
fmt.Fprintf(w, "%sImage:\t%s\n", indent, strategy.CustomParams.Image)
|
||||
}
|
||||
|
||||
if len(strategy.CustomParams.Environment) > 0 {
|
||||
fmt.Fprintf(w, "%sEnvironment:\t%s\n", indent, formatLabels(convertEnv(strategy.CustomParams.Environment)))
|
||||
}
|
||||
|
||||
if len(strategy.CustomParams.Command) > 0 {
|
||||
fmt.Fprintf(w, "%sCommand:\t%v\n", indent, multilineStringArray(" ", "\t ", strategy.CustomParams.Command...))
|
||||
}
|
||||
}
|
||||
|
||||
if strategy.RecreateParams != nil {
|
||||
pre := strategy.RecreateParams.Pre
|
||||
mid := strategy.RecreateParams.Mid
|
||||
post := strategy.RecreateParams.Post
|
||||
if pre != nil {
|
||||
printHook("Pre-deployment", pre, indent, w)
|
||||
}
|
||||
if mid != nil {
|
||||
printHook("Mid-deployment", mid, indent, w)
|
||||
}
|
||||
if post != nil {
|
||||
printHook("Post-deployment", post, indent, w)
|
||||
}
|
||||
}
|
||||
|
||||
if strategy.RollingParams != nil {
|
||||
pre := strategy.RollingParams.Pre
|
||||
post := strategy.RollingParams.Post
|
||||
if pre != nil {
|
||||
printHook("Pre-deployment", pre, indent, w)
|
||||
}
|
||||
if post != nil {
|
||||
printHook("Post-deployment", post, indent, w)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func printHook(prefix string, hook *deployapi.LifecycleHook, indent string, w io.Writer) {
|
||||
if hook.ExecNewPod != nil {
|
||||
fmt.Fprintf(w, "%s%s hook (pod type, failure policy: %s):\n", indent, prefix, hook.FailurePolicy)
|
||||
fmt.Fprintf(w, "%s Container:\t%s\n", indent, hook.ExecNewPod.ContainerName)
|
||||
fmt.Fprintf(w, "%s Command:\t%v\n", indent, multilineStringArray(" ", "\t ", hook.ExecNewPod.Command...))
|
||||
if len(hook.ExecNewPod.Env) > 0 {
|
||||
fmt.Fprintf(w, "%s Env:\t%s\n", indent, formatLabels(convertEnv(hook.ExecNewPod.Env)))
|
||||
}
|
||||
}
|
||||
if len(hook.TagImages) > 0 {
|
||||
fmt.Fprintf(w, "%s%s hook (tag images, failure policy: %s):\n", indent, prefix, hook.FailurePolicy)
|
||||
for _, image := range hook.TagImages {
|
||||
fmt.Fprintf(w, "%s Tag:\tcontainer %s to %s %s %s\n", indent, image.ContainerName, image.To.Kind, image.To.Name, image.To.Namespace)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func printTriggers(triggers []deployapi.DeploymentTriggerPolicy, w *tabwriter.Writer) {
|
||||
if len(triggers) == 0 {
|
||||
formatString(w, "Triggers", "<none>")
|
||||
return
|
||||
}
|
||||
|
||||
labels := []string{}
|
||||
|
||||
for _, t := range triggers {
|
||||
switch t.Type {
|
||||
case deployapi.DeploymentTriggerOnConfigChange:
|
||||
labels = append(labels, "Config")
|
||||
case deployapi.DeploymentTriggerOnImageChange:
|
||||
if len(t.ImageChangeParams.From.Name) > 0 {
|
||||
name, tag, _ := imageapi.SplitImageStreamTag(t.ImageChangeParams.From.Name)
|
||||
labels = append(labels, fmt.Sprintf("Image(%s@%s, auto=%v)", name, tag, t.ImageChangeParams.Automatic))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
desc := strings.Join(labels, ", ")
|
||||
formatString(w, "Triggers", desc)
|
||||
}
|
||||
|
||||
func printDeploymentConfigSpec(kc kclient.Interface, dc deployapi.DeploymentConfig, w *tabwriter.Writer) error {
|
||||
spec := dc.Spec
|
||||
// Selector
|
||||
formatString(w, "Selector", formatLabels(spec.Selector))
|
||||
|
||||
// Replicas
|
||||
test := ""
|
||||
if spec.Test {
|
||||
test = " (test, will be scaled down between deployments)"
|
||||
}
|
||||
formatString(w, "Replicas", fmt.Sprintf("%d%s", spec.Replicas, test))
|
||||
|
||||
if spec.Paused {
|
||||
formatString(w, "Paused", "yes")
|
||||
}
|
||||
|
||||
// Autoscaling info
|
||||
printAutoscalingInfo(deployapi.Resource("DeploymentConfig"), dc.Namespace, dc.Name, kc, w)
|
||||
|
||||
// Triggers
|
||||
printTriggers(spec.Triggers, w)
|
||||
|
||||
// Strategy
|
||||
formatString(w, "Strategy", spec.Strategy.Type)
|
||||
printStrategy(spec.Strategy, " ", w)
|
||||
|
||||
if dc.Spec.MinReadySeconds > 0 {
|
||||
formatString(w, "MinReadySeconds", fmt.Sprintf("%d", spec.MinReadySeconds))
|
||||
}
|
||||
|
||||
// Pod template
|
||||
fmt.Fprintf(w, "Template:\n")
|
||||
kctl.DescribePodTemplate(spec.Template, w)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// TODO: Move this upstream
|
||||
func printAutoscalingInfo(res unversioned.GroupResource, namespace, name string, kclient kclient.Interface, w *tabwriter.Writer) {
|
||||
hpaList, err := kclient.Autoscaling().HorizontalPodAutoscalers(namespace).List(kapi.ListOptions{LabelSelector: labels.Everything()})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
scaledBy := []autoscaling.HorizontalPodAutoscaler{}
|
||||
for _, hpa := range hpaList.Items {
|
||||
if hpa.Spec.ScaleTargetRef.Name == name && hpa.Spec.ScaleTargetRef.Kind == res.String() {
|
||||
scaledBy = append(scaledBy, hpa)
|
||||
}
|
||||
}
|
||||
|
||||
for _, hpa := range scaledBy {
|
||||
cpuUtil := ""
|
||||
if hpa.Spec.TargetCPUUtilizationPercentage != nil {
|
||||
cpuUtil = fmt.Sprintf(", triggered at %d%% CPU usage", *hpa.Spec.TargetCPUUtilizationPercentage)
|
||||
}
|
||||
fmt.Fprintf(w, "Autoscaling:\tbetween %d and %d replicas%s\n", *hpa.Spec.MinReplicas, hpa.Spec.MaxReplicas, cpuUtil)
|
||||
// TODO: Print a warning in case of multiple hpas.
|
||||
// Related oc status PR: https://github.com/openshift/origin/pull/7799
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
func printDeploymentRc(deployment *kapi.ReplicationController, kubeClient kclient.Interface, w io.Writer, header string, verbose bool) error {
|
||||
if len(header) > 0 {
|
||||
fmt.Fprintf(w, "%v:\n", header)
|
||||
}
|
||||
|
||||
if verbose {
|
||||
fmt.Fprintf(w, "\tName:\t%s\n", deployment.Name)
|
||||
}
|
||||
timeAt := strings.ToLower(formatRelativeTime(deployment.CreationTimestamp.Time))
|
||||
fmt.Fprintf(w, "\tCreated:\t%s ago\n", timeAt)
|
||||
fmt.Fprintf(w, "\tStatus:\t%s\n", deployutil.DeploymentStatusFor(deployment))
|
||||
fmt.Fprintf(w, "\tReplicas:\t%d current / %d desired\n", deployment.Status.Replicas, deployment.Spec.Replicas)
|
||||
|
||||
if verbose {
|
||||
fmt.Fprintf(w, "\tSelector:\t%s\n", formatLabels(deployment.Spec.Selector))
|
||||
fmt.Fprintf(w, "\tLabels:\t%s\n", formatLabels(deployment.Labels))
|
||||
running, waiting, succeeded, failed, err := getPodStatusForDeployment(deployment, kubeClient)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Fprintf(w, "\tPods Status:\t%d Running / %d Waiting / %d Succeeded / %d Failed\n", running, waiting, succeeded, failed)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getPodStatusForDeployment(deployment *kapi.ReplicationController, kubeClient kclient.Interface) (running, waiting, succeeded, failed int, err error) {
|
||||
rcPods, err := kubeClient.Pods(deployment.Namespace).List(kapi.ListOptions{LabelSelector: labels.Set(deployment.Spec.Selector).AsSelector()})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for _, pod := range rcPods.Items {
|
||||
switch pod.Status.Phase {
|
||||
case kapi.PodRunning:
|
||||
running++
|
||||
case kapi.PodPending:
|
||||
waiting++
|
||||
case kapi.PodSucceeded:
|
||||
succeeded++
|
||||
case kapi.PodFailed:
|
||||
failed++
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
type LatestDeploymentsDescriber struct {
|
||||
count int
|
||||
osClient client.Interface
|
||||
kubeClient kclient.Interface
|
||||
}
|
||||
|
||||
// NewLatestDeploymentsDescriber lists the latest deployments limited to "count". In case count == -1, list back to the last successful.
|
||||
func NewLatestDeploymentsDescriber(client client.Interface, kclient kclient.Interface, count int) *LatestDeploymentsDescriber {
|
||||
return &LatestDeploymentsDescriber{
|
||||
count: count,
|
||||
osClient: client,
|
||||
kubeClient: kclient,
|
||||
}
|
||||
}
|
||||
|
||||
// Describe returns the description of the latest deployments for a config
|
||||
func (d *LatestDeploymentsDescriber) Describe(namespace, name string) (string, error) {
|
||||
var f formatter
|
||||
|
||||
config, err := d.osClient.DeploymentConfigs(namespace).Get(name)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
var deployments []kapi.ReplicationController
|
||||
if d.count == -1 || d.count > 1 {
|
||||
list, err := d.kubeClient.ReplicationControllers(namespace).List(kapi.ListOptions{LabelSelector: deployutil.ConfigSelector(name)})
|
||||
if err != nil && !kerrors.IsNotFound(err) {
|
||||
return "", err
|
||||
}
|
||||
deployments = list.Items
|
||||
} else {
|
||||
deploymentName := deployutil.LatestDeploymentNameForConfig(config)
|
||||
deployment, err := d.kubeClient.ReplicationControllers(config.Namespace).Get(deploymentName)
|
||||
if err != nil && !kerrors.IsNotFound(err) {
|
||||
return "", err
|
||||
}
|
||||
if deployment != nil {
|
||||
deployments = []kapi.ReplicationController{*deployment}
|
||||
}
|
||||
}
|
||||
|
||||
g := graph.New()
|
||||
dcNode := deploygraph.EnsureDeploymentConfigNode(g, config)
|
||||
for i := range deployments {
|
||||
kubegraph.EnsureReplicationControllerNode(g, &deployments[i])
|
||||
}
|
||||
deployedges.AddTriggerEdges(g, dcNode)
|
||||
deployedges.AddDeploymentEdges(g, dcNode)
|
||||
activeDeployment, inactiveDeployments := deployedges.RelevantDeployments(g, dcNode)
|
||||
|
||||
return tabbedString(func(out *tabwriter.Writer) error {
|
||||
descriptions := describeDeployments(f, dcNode, activeDeployment, inactiveDeployments, nil, d.count)
|
||||
for i, description := range descriptions {
|
||||
descriptions[i] = fmt.Sprintf("%v %v", name, description)
|
||||
}
|
||||
printLines(out, "", 0, descriptions...)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user