<commit_before>// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package runtime

import "unsafe"

const (
	c0 = uintptr((8-uint64(ptrSize))/4*2860486313 + (uint64(ptrSize)-4)/4*33054211828000289)
	c1 = uintptr((8-uint64(ptrSize))/4*3267000013 + (uint64(ptrSize)-4)/4*23344194077549503)
)

const (
	alg_MEM = iota
	alg_MEM0
	alg_MEM8
	alg_MEM16
	alg_MEM32
	alg_MEM64
	alg_MEM128
	alg_NOEQ
	alg_NOEQ0
	alg_NOEQ8
	alg_NOEQ16
	alg_NOEQ32
	alg_NOEQ64
	alg_NOEQ128
	alg_STRING
	alg_INTER
	alg_NILINTER
	alg_SLICE
	alg_FLOAT32
	alg_FLOAT64
	alg_CPLX64
	alg_CPLX128
	alg_max
)

const nacl = GOOS == "nacl"

var use_aeshash bool

// in asm_*.s
func aeshash(p unsafe.Pointer, s, h uintptr) uintptr

func memhash(p unsafe.Pointer, s, h uintptr) uintptr {
	if !nacl && use_aeshash {
		return aeshash(p, s, h)
	}

	h ^= c0
	for s > 0 {
		h = (h ^ uintptr(*(*byte)(p))) * c1
		p = add(p, 1)
		s--
	}
	return h
}

func strhash(a *string, s, h uintptr) uintptr {
	return memhash((*stringStruct)(unsafe.Pointer(a)).str, uintptr(len(*a)), h)
}

// NOTE: Because NaN != NaN, a map can contain any
// number of (mostly useless) entries keyed with NaNs.
// To avoid long hash chains, we assign a random number
// as the hash value for a NaN.

func f32hash(a *float32, s, h uintptr) uintptr {
	f := *a
	switch {
	case f == 0:
		return c1 * (c0 ^ h) // +0, -0
	case f != f:
		return c1 * (c0 ^ h ^ uintptr(fastrand2())) // any kind of NaN
	default:
		return c1 * (c0 ^ h ^ uintptr(*(*uint32)(unsafe.Pointer(a))))
	}
}

func f64hash(a *float64, s, h uintptr) uintptr {
	f := *a
	switch {
	case f == 0:
		return c1 * (c0 ^ h) // +0, -0
	case f != f:
		return c1 * (c0 ^ h ^ uintptr(fastrand2())) // any kind of NaN
	case ptrSize == 4:
		x := (*[2]uintptr)(unsafe.Pointer(a))
		return c1 * (c0 ^ h ^ (x[1] * c1) ^ x[0])
	default:
		return c1 * (c0 ^ h ^ *(*uintptr)(unsafe.Pointer(a)))
	}
}

func c64hash(a *complex64, s, h uintptr) uintptr {
	x := (*[2]float32)(unsafe.Pointer(a))
	return f32hash(&x[1], 4, f32hash(&x[0], 4, h))
}

func c128hash(a *complex128, s, h uintptr) uintptr {
	x := (*[2]float64)(unsafe.Pointer(a))
	return f64hash(&x[1], 4, f64hash(&x[0], 4, h))
}

func nohash(a unsafe.Pointer, s, h uintptr) uintptr {
	panic(errorString("hash of unhashable type"))
}

func interhash(a *iface, s, h uintptr) uintptr {
	tab := a.tab
	if tab == nil {
		return h
	}
	t := tab._type
	fn := goalg(t.alg).hash
	if **(**uintptr)(unsafe.Pointer(&fn)) == nohashcode {
		// calling nohash will panic too,
		// but we can print a better error.
		panic(errorString("hash of unhashable type " + *t._string))
	}
	if uintptr(t.size) <= ptrSize {
		return c1 * fn(unsafe.Pointer(&a.data), uintptr(t.size), h^c0)
	} else {
		return c1 * fn(a.data, uintptr(t.size), h^c0)
	}
}

func nilinterhash(a *eface, s, h uintptr) uintptr {
	t := a._type
	if t == nil {
		return h
	}
	fn := goalg(t.alg).hash
	if **(**uintptr)(unsafe.Pointer(&fn)) == nohashcode {
		// calling nohash will panic too,
		// but we can print a better error.
		panic(errorString("hash of unhashable type " + *t._string))
	}
	if uintptr(t.size) <= ptrSize {
		return c1 * fn(unsafe.Pointer(&a.data), uintptr(t.size), h^c0)
	} else {
		return c1 * fn(a.data, uintptr(t.size), h^c0)
	}
}

// Testing adapters for hash quality tests (see hash_test.go)
func haveGoodHash() bool {
	return use_aeshash
}

func stringHash(s string, seed uintptr) uintptr {
	return goalg(&algarray[alg_STRING]).hash(noescape(unsafe.Pointer(&s)), unsafe.Sizeof(s), seed)
}

func bytesHash(b []byte, seed uintptr) uintptr {
	// TODO: use sliceStruct
	return goalg(&algarray[alg_MEM]).hash(*(*unsafe.Pointer)(unsafe.Pointer(&b)), uintptr(len(b)), seed)
}

func int32Hash(i uint32, seed uintptr) uintptr {
	return goalg(&algarray[alg_MEM32]).hash(noescape(unsafe.Pointer(&i)), 4, seed)
}

func int64Hash(i uint64, seed uintptr) uintptr {
	return goalg(&algarray[alg_MEM64]).hash(noescape(unsafe.Pointer(&i)), 8, seed)
}
<commit_msg>runtime: use better hash for floating point inputs<commit_after>// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package runtime

import "unsafe"

const (
	c0 = uintptr((8-uint64(ptrSize))/4*2860486313 + (uint64(ptrSize)-4)/4*33054211828000289)
	c1 = uintptr((8-uint64(ptrSize))/4*3267000013 + (uint64(ptrSize)-4)/4*23344194077549503)
)

const (
	alg_MEM = iota
	alg_MEM0
	alg_MEM8
	alg_MEM16
	alg_MEM32
	alg_MEM64
	alg_MEM128
	alg_NOEQ
	alg_NOEQ0
	alg_NOEQ8
	alg_NOEQ16
	alg_NOEQ32
	alg_NOEQ64
	alg_NOEQ128
	alg_STRING
	alg_INTER
	alg_NILINTER
	alg_SLICE
	alg_FLOAT32
	alg_FLOAT64
	alg_CPLX64
	alg_CPLX128
	alg_max
)

const nacl = GOOS == "nacl"

var use_aeshash bool

// in asm_*.s
func aeshash(p unsafe.Pointer, s, h uintptr) uintptr

func memhash(p unsafe.Pointer, s, h uintptr) uintptr {
	if !nacl && use_aeshash {
		return aeshash(p, s, h)
	}

	h ^= c0
	for s > 0 {
		h = (h ^ uintptr(*(*byte)(p))) * c1
		p = add(p, 1)
		s--
	}
	return h
}

func strhash(a *string, s, h uintptr) uintptr {
	return memhash((*stringStruct)(unsafe.Pointer(a)).str, uintptr(len(*a)), h)
}

// NOTE: Because NaN != NaN, a map can contain any
// number of (mostly useless) entries keyed with NaNs.
// To avoid long hash chains, we assign a random number
// as the hash value for a NaN.

func f32hash(a *float32, s, h uintptr) uintptr {
	f := *a
	switch {
	case f == 0:
		return c1 * (c0 ^ h) // +0, -0
	case f != f:
		return c1 * (c0 ^ h ^ uintptr(fastrand2())) // any kind of NaN
	default:
		return memhash(unsafe.Pointer(a), 4, h)
	}
}

func f64hash(a *float64, s, h uintptr) uintptr {
	f := *a
	switch {
	case f == 0:
		return c1 * (c0 ^ h) // +0, -0
	case f != f:
		return c1 * (c0 ^ h ^ uintptr(fastrand2())) // any kind of NaN
	default:
		return memhash(unsafe.Pointer(a), 8, h)
	}
}

func c64hash(a *complex64, s, h uintptr) uintptr {
	x := (*[2]float32)(unsafe.Pointer(a))
	return f32hash(&x[1], 4, f32hash(&x[0], 4, h))
}

func c128hash(a *complex128, s, h uintptr) uintptr {
	x := (*[2]float64)(unsafe.Pointer(a))
	return f64hash(&x[1], 4, f64hash(&x[0], 4, h))
}

func nohash(a unsafe.Pointer, s, h uintptr) uintptr {
	panic(errorString("hash of unhashable type"))
}

func interhash(a *iface, s, h uintptr) uintptr {
	tab := a.tab
	if tab == nil {
		return h
	}
	t := tab._type
	fn := goalg(t.alg).hash
	if **(**uintptr)(unsafe.Pointer(&fn)) == nohashcode {
		// calling nohash will panic too,
		// but we can print a better error.
		panic(errorString("hash of unhashable type " + *t._string))
	}
	if uintptr(t.size) <= ptrSize {
		return c1 * fn(unsafe.Pointer(&a.data), uintptr(t.size), h^c0)
	} else {
		return c1 * fn(a.data, uintptr(t.size), h^c0)
	}
}

func nilinterhash(a *eface, s, h uintptr) uintptr {
	t := a._type
	if t == nil {
		return h
	}
	fn := goalg(t.alg).hash
	if **(**uintptr)(unsafe.Pointer(&fn)) == nohashcode {
		// calling nohash will panic too,
		// but we can print a better error.
		panic(errorString("hash of unhashable type " + *t._string))
	}
	if uintptr(t.size) <= ptrSize {
		return c1 * fn(unsafe.Pointer(&a.data), uintptr(t.size), h^c0)
	} else {
		return c1 * fn(a.data, uintptr(t.size), h^c0)
	}
}

// Testing adapters for hash quality tests (see hash_test.go)
func haveGoodHash() bool {
	return use_aeshash
}

func stringHash(s string, seed uintptr) uintptr {
	return goalg(&algarray[alg_STRING]).hash(noescape(unsafe.Pointer(&s)), unsafe.Sizeof(s), seed)
}

func bytesHash(b []byte, seed uintptr) uintptr {
	// TODO: use sliceStruct
	return goalg(&algarray[alg_MEM]).hash(*(*unsafe.Pointer)(unsafe.Pointer(&b)), uintptr(len(b)), seed)
}

func int32Hash(i uint32, seed uintptr) uintptr {
	return goalg(&algarray[alg_MEM32]).hash(noescape(unsafe.Pointer(&i)), 4, seed)
}

func int64Hash(i uint64, seed uintptr) uintptr {
	return goalg(&algarray[alg_MEM64]).hash(noescape(unsafe.Pointer(&i)), 8, seed)
}
<|endoftext|>


<commit_before>package paths

import (
	"testing"

	. "github.com/VonC/godbg"
	. "github.com/smartystreets/goconvey/convey"
)

func TestArchive(t *testing.T) {

	Convey("Tests for Uncompress", t, func() {

		Convey("Uncompress fails if p is a folder", func() {
			p := NewPath(".")
			SetBuffers(nil)
			b := p.Uncompress(nil)
			So(b, ShouldBeFalse)
			So(OutString(), ShouldBeEmpty)
			So(ErrString(), ShouldEqualNL, `  [*Path.Uncompress] (func)
    Error while opening zip '.\' for '<nil>'
'read .\: The handle is invalid.'`)
		})

		Convey("Uncompress fails if p is not a zip file", func() {
			p := NewPath("paths.go")
			SetBuffers(nil)
			b := p.Uncompress(nil)
			So(b, ShouldBeFalse)
			So(OutString(), ShouldBeEmpty)
			So(ErrString(), ShouldEqualNL, `  [*Path.Uncompress] (func)
    Error while opening zip 'paths.go' for '<nil>'
'zip: not a valid zip file'`)
		})
	})
}

/*
C:\Users\vonc\prog\go\src\github.com\VonC\senvgo\paths>mkdir testzip
C:\Users\vonc\prog\go\src\github.com\VonC\senvgo\paths>echo a> testzip\a.txt
C:\Users\vonc\prog\go\src\github.com\VonC\senvgo\paths>echo ab> testzip\b.txt
C:\Users\vonc\prog\go\src\github.com\VonC\senvgo\paths>mkdir testzip\c
C:\Users\vonc\prog\go\src\github.com\VonC\senvgo\paths>echo abcd> testzip\c\abcd.txt
http://askubuntu.com/questions/58889/how-can-i-create-a-zip-archive-of-a-whole-directory-via-terminal-without-hidden
C:\Users\vonc\prog\go\src\github.com\VonC\senvgo\paths>zip -r testzip.zip testzip
  adding: testzip/ (164 bytes security) (stored 0%)
  adding: testzip/a.txt (164 bytes security) (stored 0%)
  adding: testzip/b.txt (164 bytes security) (stored 0%)
  adding: testzip/c/ (164 bytes security) (stored 0%)
  adding: testzip/c/abcd.txt (164 bytes security) (stored 0%)
C:\Users\vonc\prog\go\src\github.com\VonC\senvgo\paths>testzip.zip
C:\Users\vonc\prog\go\src\github.com\VonC\senvgo\paths>rm -Rf testzip
*/
<commit_msg>Test Path.Uncompress() when archive file does not exist<commit_after>package paths

import (
	"testing"

	. "github.com/VonC/godbg"
	. "github.com/smartystreets/goconvey/convey"
)

func TestArchive(t *testing.T) {

	Convey("Tests for Uncompress", t, func() {

		Convey("Uncompress fails if p is a folder", func() {
			p := NewPath(".")
			SetBuffers(nil)
			b := p.Uncompress(nil)
			So(b, ShouldBeFalse)
			So(OutString(), ShouldBeEmpty)
			So(ErrString(), ShouldEqualNL, `  [*Path.Uncompress] (func)
    Error while opening zip '.\' for '<nil>'
'read .\: The handle is invalid.'`)
		})

		Convey("Uncompress fails if p is a non-existing file", func() {
			p := NewPath("xxx")
			SetBuffers(nil)
			b := p.Uncompress(nil)
			So(b, ShouldBeFalse)
			So(OutString(), ShouldBeEmpty)
			So(ErrString(), ShouldEqualNL, `  [*Path.Uncompress] (func)
    Error while opening zip 'xxx' for '<nil>'
'open xxx: The system cannot find the file specified.'`)
		})

		Convey("Uncompress fails if p is not a zip file", func() {
			p := NewPath("paths.go")
			SetBuffers(nil)
			b := p.Uncompress(nil)
			So(b, ShouldBeFalse)
			So(OutString(), ShouldBeEmpty)
			So(ErrString(), ShouldEqualNL, `  [*Path.Uncompress] (func)
    Error while opening zip 'paths.go' for '<nil>'
'zip: not a valid zip file'`)
		})
	})
}

/*
C:\Users\vonc\prog\go\src\github.com\VonC\senvgo\paths>mkdir testzip
C:\Users\vonc\prog\go\src\github.com\VonC\senvgo\paths>echo a> testzip\a.txt
C:\Users\vonc\prog\go\src\github.com\VonC\senvgo\paths>echo ab> testzip\b.txt
C:\Users\vonc\prog\go\src\github.com\VonC\senvgo\paths>mkdir testzip\c
C:\Users\vonc\prog\go\src\github.com\VonC\senvgo\paths>echo abcd> testzip\c\abcd.txt
http://askubuntu.com/questions/58889/how-can-i-create-a-zip-archive-of-a-whole-directory-via-terminal-without-hidden
C:\Users\vonc\prog\go\src\github.com\VonC\senvgo\paths>zip -r testzip.zip testzip
  adding: testzip/ (164 bytes security) (stored 0%)
  adding: testzip/a.txt (164 bytes security) (stored 0%)
  adding: testzip/b.txt (164 bytes security) (stored 0%)
  adding: testzip/c/ (164 bytes security) (stored 0%)
  adding: testzip/c/abcd.txt (164 bytes security) (stored 0%)
C:\Users\vonc\prog\go\src\github.com\VonC\senvgo\paths>testzip.zip
C:\Users\vonc\prog\go\src\github.com\VonC\senvgo\paths>rm -Rf testzip
*/
<|endoftext|>


<commit_before>/*
Copyright 2019 The Knative Authors

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package networking

// The ports we setup on our services.
const (
	// ServiceHTTPPort is the port that we setup our Serving and Activator K8s services for
	// HTTP/1 endpoints.
	ServiceHTTPPort = 80

	// ServiceHTTP2Port is the port that we setup our Serving and Activator K8s services for
	// HTTP/2 endpoints.
	ServiceHTTP2Port = 81

	// ServicePortNameHTTP1 is the name of the external port of the service for HTTP/1.1
	ServicePortNameHTTP1 = "http"

	// ServicePortNameH2C is the name of the external port of the service for HTTP/2
	ServicePortNameH2C = "http2"
)

// ServicePortName returns the port for the app level protocol.
func ServicePortName(proto ProtocolType) string {
	if proto == ProtocolH2C {
		return ServicePortNameH2C
	}
	return ServicePortNameHTTP1
}

// ServicePort chooses the service (load balancer) port for the public service.
func ServicePort(proto ProtocolType) int {
	if proto == ProtocolH2C {
		return ServiceHTTP2Port
	}
	return ServiceHTTPPort
}
<commit_msg>Add HTTPS port variables (#640)<commit_after>/*
Copyright 2019 The Knative Authors

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package networking

// The ports we setup on our services.
const (
	// ServiceHTTPPort is the port that we setup our Serving and Activator K8s services for
	// HTTP/1 endpoints.
	ServiceHTTPPort = 80

	// ServiceHTTP2Port is the port that we setup our Serving and Activator K8s services for
	// HTTP/2 endpoints.
	ServiceHTTP2Port = 81

	// ServiceHTTPSPort is the port that we setup our Serving and Activator K8s services for
	// HTTPS endpoints.
	ServiceHTTPSPort = 443

	// ServicePortNameHTTP1 is the name of the external port of the service for HTTP/1.1
	ServicePortNameHTTP1 = "http"

	// ServicePortNameH2C is the name of the external port of the service for HTTP/2
	ServicePortNameH2C = "http2"

	// ServicePortNameHTTPS is the name of the external port of the service for HTTPS
	ServicePortNameHTTPS = "https"
)

// ServicePortName returns the port for the app level protocol.
func ServicePortName(proto ProtocolType) string {
	if proto == ProtocolH2C {
		return ServicePortNameH2C
	}
	return ServicePortNameHTTP1
}

// ServicePort chooses the service (load balancer) port for the public service.
func ServicePort(proto ProtocolType) int {
	if proto == ProtocolH2C {
		return ServiceHTTP2Port
	}
	return ServiceHTTPPort
}
<|endoftext|>


<commit_before>package edit

// Elvish code for default bindings, assuming the editor ns as the global ns.
const defaultBindingsElv = `
insert:binding = (binding-table [
  &Left=  $move-dot-left~
  &Right= $move-dot-right~

  &Ctrl-Left=  $move-dot-left-word~
  &Ctrl-Right= $move-dot-right-word~
  &Alt-Left=   $move-dot-left-word~
  &Alt-Right=  $move-dot-right-word~
  &Alt-b=      $move-dot-left-word~
  &Alt-f=      $move-dot-right-word~

  &Home= $move-dot-sol~
  &End=  $move-dot-eol~

  &Backspace= $kill-rune-left~
  &Ctrl-H=    $kill-rune-left~
  &Delete=    $kill-rune-right~
  &Ctrl-W=    $kill-word-left~
  &Ctrl-U=    $kill-line-left~
  &Ctrl-K=    $kill-line-right~

  &Ctrl-V= $insert-raw~

  &Alt-,=  $lastcmd:start~
  &Alt-.=  $insert-last-word~
  &Ctrl-R= $histlist:start~
  &Ctrl-L= $location:start~
  &Ctrl-N= $navigation:start~
  &Tab=    $completion:smart-start~
  &Up=     $history:start~
  &Alt-x=  $minibuf:start~

  &Enter=   $smart-enter~
  &Ctrl-D=  $return-eof~
])

command:binding = (binding-table [
 &'$'= $move-dot-eol~
 &0=   $move-dot-sol~
 &D=   $kill-line-right~
 &b=   $move-dot-left-word~
 &h=   $move-dot-left~
 &i=   $listing:close~
 &j=   $move-dot-down~
 &k=   $move-dot-up~
 &l=   $move-dot-right~
 &w=   $move-dot-right-word~
 &x=   $kill-rune-right~
])

listing:binding = (binding-table [
  &Up=        $listing:up~
  &Down=      $listing:down~
  &Tab=       $listing:down-cycle~
  &Shift-Tab= $listing:up-cycle~
  &Ctrl-'['=  $close-listing~
])

histlist:binding = (binding-table [
  &Ctrl-D= $histlist:toggle-dedup~
])

navigation:binding = (binding-table [
  &Ctrl-'['= $close-listing~
  &Left=     $navigation:left~
  &Right=    $navigation:right~
  &Up=       $navigation:up~
  &Down=     $navigation:down~
  &PageUp=   $navigation:page-up~
  &PageDown= $navigation:page-down~
  &Alt-Up=   $navigation:file-preview-up~
  &Alt-Down= $navigation:file-preview-down~
  &Enter=    $navigation:insert-selected-and-quit~
  &Alt-Enter= $navigation:insert-selected~
  &Ctrl-F=   $navigation:trigger-filter~
  &Ctrl-H=   $navigation:trigger-shown-hidden~
])

completion:binding = (binding-table [
  &Ctrl-'['= $completion:close~
  &Down=     $completion:down~
  &Up=       $completion:up~
  &Tab=      $completion:down-cycle~
  &Shift-Tab=$completion:up-cycle~
  &Left=     $completion:left~
  &Right=    $completion:right~
])

history:binding = (binding-table [
  &Up=       $history:up~
  &Down=     $history:down-or-quit~
  &Ctrl-'['= $history:close~
])

lastcmd:binding = (binding-table [
  &Alt-,=  $listing:accept~
])

-instant:binding = (binding-table [
  &Ctrl-'['= $listing:close~
])
`

// vi: set et:
<commit_msg>pkg/edit: Support closing the minibuf with Esc.<commit_after>package edit

// Elvish code for default bindings, assuming the editor ns as the global ns.
const defaultBindingsElv = `
insert:binding = (binding-table [
  &Left=  $move-dot-left~
  &Right= $move-dot-right~

  &Ctrl-Left=  $move-dot-left-word~
  &Ctrl-Right= $move-dot-right-word~
  &Alt-Left=   $move-dot-left-word~
  &Alt-Right=  $move-dot-right-word~
  &Alt-b=      $move-dot-left-word~
  &Alt-f=      $move-dot-right-word~

  &Home= $move-dot-sol~
  &End=  $move-dot-eol~

  &Backspace= $kill-rune-left~
  &Ctrl-H=    $kill-rune-left~
  &Delete=    $kill-rune-right~
  &Ctrl-W=    $kill-word-left~
  &Ctrl-U=    $kill-line-left~
  &Ctrl-K=    $kill-line-right~

  &Ctrl-V= $insert-raw~

  &Alt-,=  $lastcmd:start~
  &Alt-.=  $insert-last-word~
  &Ctrl-R= $histlist:start~
  &Ctrl-L= $location:start~
  &Ctrl-N= $navigation:start~
  &Tab=    $completion:smart-start~
  &Up=     $history:start~
  &Alt-x=  $minibuf:start~

  &Enter=   $smart-enter~
  &Ctrl-D=  $return-eof~
])

command:binding = (binding-table [
 &'$'= $move-dot-eol~
 &0=   $move-dot-sol~
 &D=   $kill-line-right~
 &b=   $move-dot-left-word~
 &h=   $move-dot-left~
 &i=   $listing:close~
 &j=   $move-dot-down~
 &k=   $move-dot-up~
 &l=   $move-dot-right~
 &w=   $move-dot-right-word~
 &x=   $kill-rune-right~
])

listing:binding = (binding-table [
  &Up=        $listing:up~
  &Down=      $listing:down~
  &Tab=       $listing:down-cycle~
  &Shift-Tab= $listing:up-cycle~
  &Ctrl-'['=  $close-listing~
])

histlist:binding = (binding-table [
  &Ctrl-D= $histlist:toggle-dedup~
])

navigation:binding = (binding-table [
  &Ctrl-'['= $close-listing~
  &Left=     $navigation:left~
  &Right=    $navigation:right~
  &Up=       $navigation:up~
  &Down=     $navigation:down~
  &PageUp=   $navigation:page-up~
  &PageDown= $navigation:page-down~
  &Alt-Up=   $navigation:file-preview-up~
  &Alt-Down= $navigation:file-preview-down~
  &Enter=    $navigation:insert-selected-and-quit~
  &Alt-Enter= $navigation:insert-selected~
  &Ctrl-F=   $navigation:trigger-filter~
  &Ctrl-H=   $navigation:trigger-shown-hidden~
])

completion:binding = (binding-table [
  &Ctrl-'['= $completion:close~
  &Down=     $completion:down~
  &Up=       $completion:up~
  &Tab=      $completion:down-cycle~
  &Shift-Tab=$completion:up-cycle~
  &Left=     $completion:left~
  &Right=    $completion:right~
])

history:binding = (binding-table [
  &Up=       $history:up~
  &Down=     $history:down-or-quit~
  &Ctrl-'['= $history:close~
])

lastcmd:binding = (binding-table [
  &Alt-,=  $listing:accept~
])

-instant:binding = (binding-table [
  &Ctrl-'['= $listing:close~
])

minibuf:binding = (binding-table [
  &Ctrl-'['= $listing:close~
])
`

// vi: set et:
<|endoftext|>


<commit_before>package experiment

import (
	"errors"
	"fmt"
	log "github.com/Sirupsen/logrus"
	experimentPhase "github.com/intelsdi-x/swan/pkg/experiment/phase"
	"github.com/nu7hatch/gouuid"
	"gopkg.in/cheggaaa/pb.v1"
	"io"
	"os"
	"path"
	"strconv"
	"time"
)

// Experiment captures the internal data for the Experiment Driver.
type Experiment struct {
	// Human-readable name.
	// TODO(bp): Push that to DB via Snap in tag or using SwanCollector.
	name string
	// Unique ID for Experiment.
	// Pushed to DB via Snap in tag.
	uuid                string
	workingDirectory    string
	phases              []experimentPhase.Phase
	startingDirectory   string
	experimentDirectory string

	logFile  *os.File
	logLevel log.Level

	textUI bool
}

// NewExperiment creates a new Experiment instance,
// initialize experiment working directory and initialize logs.
// Caller have to provide slice of Phase interfaces which are going to be executed.
func NewExperiment(name string, phases []experimentPhase.Phase,
	directory string, logLevel log.Level) (*Experiment, error) {
	if len(phases) == 0 {
		return nil, errors.New("invalid argument: no phases provided")
	}

	uuid, err := uuid.NewV4()
	if err != nil {
		return nil, err
	}
	// TODO(mpatelcz): Check if phases names are unique!
	e := &Experiment{
		name:             name,
		uuid:             uuid.String(),
		workingDirectory: directory,
		phases:           phases,
		logLevel:         logLevel,
		textUI:           logLevel == log.ErrorLevel,
	}

	err = e.createExperimentDir()
	if err != nil {
		return nil, err
	}

	err = e.logInitialize()
	if err != nil {
		os.Chdir(e.startingDirectory)
		return nil, err
	}

	return e, nil
}

// Run runs experiment.
// It runs in a sequence defined phases with given repetition count.
func (e *Experiment) Run() (err error) {
	experimentStartingTime := time.Now()

	log.Info("Starting Experiment ", e.name, " with uuid ", e.uuid)

	// Adds progress bar and some brief output when experiment is run in non-verbose
	// mode.
	var bar *pb.ProgressBar
	var increment int
	if e.textUI {
		fmt.Printf("Experiment '%s' with uuid '%s'\n", e.name, e.uuid)
		bar = pb.StartNew(100)
		bar.ShowCounters = false
		bar.ShowTimeLeft = true
		totalPhases := 0
		for _, phase := range e.phases {
			totalPhases += phase.Repetitions()
		}
		increment = 100 / totalPhases
	}

	for id, phase := range e.phases {
		if e.textUI {
				prefix := fmt.Sprintf("[%02d / %02d] %s ", id, len(e.phases), phase.Name())
				bar.Prefix(prefix)
		}

		for i := 0; i < phase.Repetitions(); i++ {
			// Create phase session.
			session := experimentPhase.Session{
				PhaseID:      phase.Name(),
				ExperimentID: e.uuid,
				RepetitionID: i,
			}

			// Start timer.
			phaseStartingTime := time.Now()
			log.Info("Starting ", session.PhaseID, " repetition ", session.RepetitionID)

			// Create and step into unique phase dir.
			err = e.createPhaseDir(session)
			if err != nil {
				return err
			}

			// Start phase.
			err := phase.Run(session)
			if err != nil {
				// When phase return error we stop the whole experiment.
				log.Error(phase.Name(), " returned error ", err)
				return err
			}

			if e.textUI {
				bar.Add(increment)
			}

			log.Info("Ended ", phase.Name(), " repetition ", i,
				" in ", time.Since(phaseStartingTime))
		}

		// Give a chance for phase to finalize.
		// E.g to check statistical confidence of a result based on repetitions results.
		log.Info("Finalizing ", phase.Name(),
			" after ", phase.Repetitions(), " repetitions")
		err := phase.Finalize()
		if err != nil {
			// When phase return error we stop the whole experiment.
			log.Error(phase.Name(), " returned error ", err,
				" while finalizing.")
			return err
		}
	}

	if e.textUI {
		bar.Finish()
	}

	log.Info("Ended experiment ", e.name, " with uuid ", e.uuid,
		" in ", time.Since(experimentStartingTime))

	// Print uuid on stdout to be able to draw sensitivity profile automatically.
	fmt.Println(e.uuid)
	return err
}

// createExperimentDir creates unique directory for experiment logs and results.
func (e *Experiment) createExperimentDir() error {
	if len(e.workingDirectory) > 0 {
		e.startingDirectory = e.workingDirectory
	} else {
		e.startingDirectory, _ = os.Getwd()
	}

	e.experimentDirectory = path.Join(
		e.startingDirectory,
		e.name,
		time.Now().Format("2006-01-02T15h04m05s_")+e.uuid)

	err := os.MkdirAll(e.experimentDirectory, 0777)
	if err != nil {
		return err
	}

	err = os.Chdir(e.experimentDirectory)
	return err
}

// Finalize closes log file and returns to the previous working directory.
func (e *Experiment) Finalize() {
	// Exit experiment directory
	os.Chdir(e.startingDirectory)
}

func (e *Experiment) createPhaseDir(session experimentPhase.Session) error {
	phaseDir := path.Join(e.experimentDirectory,
		session.PhaseID, strconv.FormatInt(int64(session.RepetitionID), 10))

	err := os.MkdirAll(phaseDir, 0777)
	if err != nil {
		return err
	}

	err = os.Chdir(phaseDir)
	if err != nil {
		return err
	}

	return err
}

func (e *Experiment) logInitialize() error {
	var err error

	// Create master log file "master.log".
	e.logFile, err = os.OpenFile(e.experimentDirectory+"/master.log", os.O_WRONLY|os.O_CREATE, 0755)
	if err != nil {
		return err
	}

	// Setup logging set to both output and logFile.
	log.SetLevel(e.logLevel)
	log.SetFormatter(new(log.TextFormatter))
	log.SetOutput(io.MultiWriter(e.logFile, os.Stderr))

	return err
}
<commit_msg>Indentation errors<commit_after>package experiment

import (
	"errors"
	"fmt"
	log "github.com/Sirupsen/logrus"
	experimentPhase "github.com/intelsdi-x/swan/pkg/experiment/phase"
	"github.com/nu7hatch/gouuid"
	"gopkg.in/cheggaaa/pb.v1"
	"io"
	"os"
	"path"
	"strconv"
	"time"
)

// Experiment captures the internal data for the Experiment Driver.
type Experiment struct {
	// Human-readable name.
	// TODO(bp): Push that to DB via Snap in tag or using SwanCollector.
	name string
	// Unique ID for Experiment.
	// Pushed to DB via Snap in tag.
	uuid                string
	workingDirectory    string
	phases              []experimentPhase.Phase
	startingDirectory   string
	experimentDirectory string

	logFile  *os.File
	logLevel log.Level

	textUI bool
}

// NewExperiment creates a new Experiment instance,
// initialize experiment working directory and initialize logs.
// Caller have to provide slice of Phase interfaces which are going to be executed.
func NewExperiment(name string, phases []experimentPhase.Phase,
	directory string, logLevel log.Level) (*Experiment, error) {
	if len(phases) == 0 {
		return nil, errors.New("invalid argument: no phases provided")
	}

	uuid, err := uuid.NewV4()
	if err != nil {
		return nil, err
	}
	// TODO(mpatelcz): Check if phases names are unique!
	e := &Experiment{
		name:             name,
		uuid:             uuid.String(),
		workingDirectory: directory,
		phases:           phases,
		logLevel:         logLevel,
		textUI:           logLevel == log.ErrorLevel,
	}

	err = e.createExperimentDir()
	if err != nil {
		return nil, err
	}

	err = e.logInitialize()
	if err != nil {
		os.Chdir(e.startingDirectory)
		return nil, err
	}

	return e, nil
}

// Run runs experiment.
// It runs in a sequence defined phases with given repetition count.
func (e *Experiment) Run() (err error) {
	experimentStartingTime := time.Now()

	log.Info("Starting Experiment ", e.name, " with uuid ", e.uuid)

	// Adds progress bar and some brief output when experiment is run in non-verbose
	// mode.
	var bar *pb.ProgressBar
	var increment int
	if e.textUI {
		fmt.Printf("Experiment '%s' with uuid '%s'\n", e.name, e.uuid)
		bar = pb.StartNew(100)
		bar.ShowCounters = false
		bar.ShowTimeLeft = true
		totalPhases := 0
		for _, phase := range e.phases {
			totalPhases += phase.Repetitions()
		}
		increment = 100 / totalPhases
	}

	for id, phase := range e.phases {
		if e.textUI {
			prefix := fmt.Sprintf("[%02d / %02d] %s ", id, len(e.phases), phase.Name())
			bar.Prefix(prefix)
		}

		for i := 0; i < phase.Repetitions(); i++ {
			// Create phase session.
			session := experimentPhase.Session{
				PhaseID:      phase.Name(),
				ExperimentID: e.uuid,
				RepetitionID: i,
			}

			// Start timer.
			phaseStartingTime := time.Now()
			log.Info("Starting ", session.PhaseID, " repetition ", session.RepetitionID)

			// Create and step into unique phase dir.
			err = e.createPhaseDir(session)
			if err != nil {
				return err
			}

			// Start phase.
			err := phase.Run(session)
			if err != nil {
				// When phase return error we stop the whole experiment.
				log.Error(phase.Name(), " returned error ", err)
				return err
			}

			if e.textUI {
				bar.Add(increment)
			}

			log.Info("Ended ", phase.Name(), " repetition ", i,
				" in ", time.Since(phaseStartingTime))
		}

		// Give a chance for phase to finalize.
		// E.g to check statistical confidence of a result based on repetitions results.
		log.Info("Finalizing ", phase.Name(),
			" after ", phase.Repetitions(), " repetitions")
		err := phase.Finalize()
		if err != nil {
			// When phase return error we stop the whole experiment.
			log.Error(phase.Name(), " returned error ", err,
				" while finalizing.")
			return err
		}
	}

	if e.textUI {
		bar.Finish()
	}

	log.Info("Ended experiment ", e.name, " with uuid ", e.uuid,
		" in ", time.Since(experimentStartingTime))

	// Print uuid on stdout to be able to draw sensitivity profile automatically.
	fmt.Println(e.uuid)
	return err
}

// createExperimentDir creates unique directory for experiment logs and results.
func (e *Experiment) createExperimentDir() error {
	if len(e.workingDirectory) > 0 {
		e.startingDirectory = e.workingDirectory
	} else {
		e.startingDirectory, _ = os.Getwd()
	}

	e.experimentDirectory = path.Join(
		e.startingDirectory,
		e.name,
		time.Now().Format("2006-01-02T15h04m05s_")+e.uuid)

	err := os.MkdirAll(e.experimentDirectory, 0777)
	if err != nil {
		return err
	}

	err = os.Chdir(e.experimentDirectory)
	return err
}

// Finalize closes log file and returns to the previous working directory.
func (e *Experiment) Finalize() {
	// Exit experiment directory
	os.Chdir(e.startingDirectory)
}

func (e *Experiment) createPhaseDir(session experimentPhase.Session) error {
	phaseDir := path.Join(e.experimentDirectory,
		session.PhaseID, strconv.FormatInt(int64(session.RepetitionID), 10))

	err := os.MkdirAll(phaseDir, 0777)
	if err != nil {
		return err
	}

	err = os.Chdir(phaseDir)
	if err != nil {
		return err
	}

	return err
}

func (e *Experiment) logInitialize() error {
	var err error

	// Create master log file "master.log".
	e.logFile, err = os.OpenFile(e.experimentDirectory+"/master.log", os.O_WRONLY|os.O_CREATE, 0755)
	if err != nil {
		return err
	}

	// Setup logging set to both output and logFile.
	log.SetLevel(e.logLevel)
	log.SetFormatter(new(log.TextFormatter))
	log.SetOutput(io.MultiWriter(e.logFile, os.Stderr))

	return err
}
<|endoftext|>


<commit_before>/*
Copyright 2020 The cert-manager Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package http

import (
	"context"
	"crypto/tls"
	"fmt"
	"io"
	"net"
	"net/http"
	"net/url"
	"strings"
	"time"

	corev1 "k8s.io/api/core/v1"
	utilerrors "k8s.io/apimachinery/pkg/util/errors"
	corev1listers "k8s.io/client-go/listers/core/v1"
	k8snet "k8s.io/utils/net"
	gwapilisters "sigs.k8s.io/gateway-api/pkg/client/listers/apis/v1alpha1"

	cmacme "github.com/jetstack/cert-manager/pkg/apis/acme/v1"
	v1 "github.com/jetstack/cert-manager/pkg/apis/certmanager/v1"
	"github.com/jetstack/cert-manager/pkg/controller"
	"github.com/jetstack/cert-manager/pkg/internal/ingress"
	"github.com/jetstack/cert-manager/pkg/issuer/acme/http/solver"
	logf "github.com/jetstack/cert-manager/pkg/logs"
	pkgutil "github.com/jetstack/cert-manager/pkg/util"
)

const (
	// HTTP01Timeout is the max amount of time to wait for an HTTP01 challenge
	// to succeed
	HTTP01Timeout = time.Minute * 15
	// acmeSolverListenPort is the port acmesolver should listen on
	acmeSolverListenPort = 8089
)

var (
	challengeGvk = cmacme.SchemeGroupVersion.WithKind("Challenge")
)

// Solver is an implementation of the acme http-01 challenge solver protocol
type Solver struct {
	*controller.Context

	podLister            corev1listers.PodLister
	serviceLister        corev1listers.ServiceLister
	ingressLister        ingress.InternalIngressLister
	ingressCreateUpdater ingress.InternalIngressCreateUpdater
	httpRouteLister      gwapilisters.HTTPRouteLister

	testReachability reachabilityTest
	requiredPasses   int
}

type reachabilityTest func(ctx context.Context, url *url.URL, key string) error

// NewSolver returns a new ACME HTTP01 solver for the given *controller.Context.
func NewSolver(ctx *controller.Context) (*Solver, error) {
	ingressLister, _, err := ingress.NewListerInformer(ctx)
	if err != nil {
		return nil, err
	}
	ingressCreateUpdater, err := ingress.NewCreateUpdater(ctx)
	if err != nil {
		return nil, err
	}
	return &Solver{
		Context:              ctx,
		podLister:            ctx.KubeSharedInformerFactory.Core().V1().Pods().Lister(),
		serviceLister:        ctx.KubeSharedInformerFactory.Core().V1().Services().Lister(),
		ingressLister:        ingressLister,
		ingressCreateUpdater: ingressCreateUpdater,
		httpRouteLister:      ctx.GWShared.Networking().V1alpha1().HTTPRoutes().Lister(),
		testReachability:     testReachability,
		requiredPasses:       5,
	}, nil
}

func http01LogCtx(ctx context.Context) context.Context {
	return logf.NewContext(ctx, nil, "http01")
}

func httpDomainCfgForChallenge(ch *cmacme.Challenge) (*cmacme.ACMEChallengeSolverHTTP01Ingress, error) {
	if ch.Spec.Solver.HTTP01 == nil || ch.Spec.Solver.HTTP01.Ingress == nil {
		return nil, fmt.Errorf("challenge's 'solver' field is specified but no HTTP01 ingress config provided. " +
			"Ensure solvers[].http01.ingress is specified on your issuer resource")
	}
	return ch.Spec.Solver.HTTP01.Ingress, nil
}

func getServiceType(ch *cmacme.Challenge) (corev1.ServiceType, error) {
	if ch.Spec.Solver.HTTP01 != nil && ch.Spec.Solver.HTTP01.Ingress != nil {
		return ch.Spec.Solver.HTTP01.Ingress.ServiceType, nil
	}
	if ch.Spec.Solver.HTTP01 != nil && ch.Spec.Solver.HTTP01.GatewayHTTPRoute != nil {
		return ch.Spec.Solver.HTTP01.GatewayHTTPRoute.ServiceType, nil
	}
	return "", fmt.Errorf("neither HTTP01 Ingress nor Gateway solvers were found")
}

// Present will realise the resources required to solve the given HTTP01
// challenge validation in the apiserver. If those resources already exist, it
// will return nil (i.e. this function is idempotent).
func (s *Solver) Present(ctx context.Context, issuer v1.GenericIssuer, ch *cmacme.Challenge) error {
	ctx = http01LogCtx(ctx)

	_, podErr := s.ensurePod(ctx, ch)
	svc, svcErr := s.ensureService(ctx, ch)
	if svcErr != nil {
		return utilerrors.NewAggregate([]error{podErr, svcErr})
	}
	var ingressErr, gatewayErr error
	if ch.Spec.Solver.HTTP01 != nil {
		if ch.Spec.Solver.HTTP01.Ingress != nil {
			_, ingressErr = s.ensureIngress(ctx, ch, svc.Name)
			return utilerrors.NewAggregate([]error{podErr, svcErr, ingressErr})
		}
		if ch.Spec.Solver.HTTP01.GatewayHTTPRoute != nil {
			_, gatewayErr = s.ensureGatewayHTTPRoute(ctx, ch, svc.Name)
			return utilerrors.NewAggregate([]error{podErr, svcErr, gatewayErr})
		}
	}
	return utilerrors.NewAggregate(
		[]error{
			podErr,
			svcErr,
			ingressErr,
			gatewayErr,
			fmt.Errorf("couldn't Present challenge %s/%s: no Ingress nor Gateway HTTP01 solvers were specified", ch.Namespace, ch.Name),
		},
	)
}

func (s *Solver) Check(ctx context.Context, issuer v1.GenericIssuer, ch *cmacme.Challenge) error {
	ctx = logf.NewContext(http01LogCtx(ctx), nil, "selfCheck")
	log := logf.FromContext(ctx)

	// HTTP Present is idempotent and the state of the system may have
	// changed since present was called by the controllers (killed pods, drained nodes)
	// Call present again to be certain.
	// if the listers are nil, that means we're in the present checks
	// test
	if s.podLister != nil && s.serviceLister != nil && s.ingressLister != nil {
		log.V(logf.DebugLevel).Info("calling Present function before running self check to ensure required resources exist")
		err := s.Present(ctx, issuer, ch)
		if err != nil {
			log.V(logf.DebugLevel).Info("failed to call Present function", "error", err)
			return err
		}
	}

	ctx, cancel := context.WithTimeout(ctx, HTTP01Timeout)
	defer cancel()
	url := s.buildChallengeUrl(ch)
	log = log.WithValues("url", url)
	ctx = logf.NewContext(ctx, log)

	log.V(logf.DebugLevel).Info("running self check multiple times to ensure challenge has propagated", "required_passes", s.requiredPasses)
	for i := 0; i < s.requiredPasses; i++ {
		err := s.testReachability(ctx, url, ch.Spec.Key)
		if err != nil {
			return err
		}
		log.V(logf.DebugLevel).Info("reachability test passed, re-checking in 2s time")
		time.Sleep(time.Second * 2)
	}

	log.V(logf.DebugLevel).Info("self check succeeded")

	return nil
}

// CleanUp will ensure the created service, ingress and pod are clean/deleted of any
// cert-manager created data.
func (s *Solver) CleanUp(ctx context.Context, issuer v1.GenericIssuer, ch *cmacme.Challenge) error {
	var errs []error
	errs = append(errs, s.cleanupPods(ctx, ch))
	errs = append(errs, s.cleanupServices(ctx, ch))
	errs = append(errs, s.cleanupIngresses(ctx, ch))
	return utilerrors.NewAggregate(errs)
}

func (s *Solver) buildChallengeUrl(ch *cmacme.Challenge) *url.URL {
	url := &url.URL{}
	url.Scheme = "http"
	url.Host = ch.Spec.DNSName

	// we need brackets for IPv6 addresses for the HTTP client to work
	if k8snet.IsIPv6(net.ParseIP(url.Host)) {
		url.Host = fmt.Sprintf("[%s]", url.Host)
	}
	url.Path = fmt.Sprintf("%s/%s", solver.HTTPChallengePath, ch.Spec.Token)

	return url
}

// testReachability will attempt to connect to the 'domain' with 'path' and
// check if the returned body equals 'key'
func testReachability(ctx context.Context, url *url.URL, key string) error {
	log := logf.FromContext(ctx)
	log.V(logf.DebugLevel).Info("performing HTTP01 reachability check")

	req, err := http.NewRequestWithContext(ctx, http.MethodGet, url.String(), nil)
	if err != nil {
		return err
	}
	req.Header.Set("User-Agent", pkgutil.CertManagerUserAgent)

	// The ACME spec says that a verifier should try on http port 80 first, but to follow any
	// redirects which may be returned. Let's Encrypt, in practice, follows redirects for HTTP
	// and HTTPS services on ports 80 and 443 respectively, but the spec doesn't seem to require
	// anything other than the initial connection being on port 80.

	// For further reading, the spec also discusses redirect following in section 10.2:
	// https://datatracker.ietf.org/doc/html/rfc8555#section-10.2

	// TODO: Since Let's Encrypt will only accept redirects to port 80 and port 443, and we follow
	// any redirect here, this could lead to a failure mode where we determine that the endpoint is reachable
	// but it'll certainly fail when tried by the actual verifier; it's an edge case, but we might be able
	// to handle this better.

	// The timeouts here are inspired by the timeouts used by Boulder - i.e., Let's Encrypt - when
	// validating HTTP01 challenges for real.
	// Boulder http.Transport: https://github.com/letsencrypt/boulder/blob/30a516737c9daa4c88c8c47070c25a5e7033cdcf/va/http.go#L146-L160
	// Boulder http.Client:    https://github.com/letsencrypt/boulder/blob/30a516737c9daa4c88c8c47070c25a5e7033cdcf/va/http.go#L567-L572

	// Boulder uses a much more complex timeout setup involving shaving time off the deadline to be able to differentiate
	// between timeouts at different stages of the connection and in turn provide for better error messages. We're a little
	// more blunt than that, and just use a static timeout of 10 seconds in http.Client.

	// That said, IdleConnTimeout is not covered by `Timeout` in http.Client, so we also set it in our Transport

	// See https://blog.cloudflare.com/the-complete-guide-to-golang-net-http-timeouts/#clienttimeouts for details on timeouts
	transport := &http.Transport{
		Proxy: http.ProxyFromEnvironment,
		// we're only doing 1 request, make the code around this
		// simpler by disabling keepalives
		DisableKeepAlives: true,

		// boulder sets this to 1 because "0" means "unlimited"
		MaxIdleConns: 1,

		// IdleConnTimeout's value is taken from Boulder
		IdleConnTimeout: time.Second,

		TLSClientConfig: &tls.Config{
			// If we're following a redirect, it's permissible for it to be HTTPS and
			// its certificate may be invalid (they are trying to get a certificate, after all!)
			// See: https://letsencrypt.org/docs/challenge-types/#http-01-challenge
			// > When redirected to an HTTPS URL, it does not validate certificates (since
			// > this challenge is intended to bootstrap valid certificates, it may encounter
			// > self-signed or expired certificates along the way).
			InsecureSkipVerify: true,
		},
	}

	client := &http.Client{
		Transport: transport,
		Timeout:   time.Second * 10,
	}

	response, err := client.Do(req)
	if err != nil {
		log.V(logf.DebugLevel).Info("failed to perform self check GET request", "error", err)
		return fmt.Errorf("failed to perform self check GET request '%s': %v", url, err)
	}

	if response.StatusCode != http.StatusOK {
		log.V(logf.DebugLevel).Info("received HTTP status code was not StatusOK (200)", "code", response.StatusCode)
		return fmt.Errorf("wrong status code '%d', expected '%d'", response.StatusCode, http.StatusOK)
	}

	defer response.Body.Close()
	presentedKey, err := io.ReadAll(response.Body)
	if err != nil {
		log.V(logf.DebugLevel).Info("failed to decode response body", "error", err)
		return fmt.Errorf("failed to read response body: %v", err)
	}

	if string(presentedKey) != key {
		// truncate the response before displaying it to avoid extra long strings
		// being displayed to users
		keyToPrint := string(presentedKey)
		if len(keyToPrint) > 24 {
			// trim spaces to make output look right if it ends with whitespace
			keyToPrint = strings.TrimSpace(keyToPrint[:24]) + "... (truncated)"
		}
		log.V(logf.DebugLevel).Info("key returned by server did not match expected", "actual", keyToPrint, "expected", key)
		return fmt.Errorf("did not get expected response when querying endpoint, expected %q but got: %s", key, keyToPrint)
	}

	log.V(logf.DebugLevel).Info("reachability test succeeded")

	return nil
}
<commit_msg>Rename httpDomainCfg function to http01IngressCfg<commit_after>/*
Copyright 2020 The cert-manager Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package http

import (
	"context"
	"crypto/tls"
	"fmt"
	"io"
	"net"
	"net/http"
	"net/url"
	"strings"
	"time"

	corev1 "k8s.io/api/core/v1"
	utilerrors "k8s.io/apimachinery/pkg/util/errors"
	corev1listers "k8s.io/client-go/listers/core/v1"
	k8snet "k8s.io/utils/net"
	gwapilisters "sigs.k8s.io/gateway-api/pkg/client/listers/apis/v1alpha1"

	cmacme "github.com/jetstack/cert-manager/pkg/apis/acme/v1"
	v1 "github.com/jetstack/cert-manager/pkg/apis/certmanager/v1"
	"github.com/jetstack/cert-manager/pkg/controller"
	"github.com/jetstack/cert-manager/pkg/internal/ingress"
	"github.com/jetstack/cert-manager/pkg/issuer/acme/http/solver"
	logf "github.com/jetstack/cert-manager/pkg/logs"
	pkgutil "github.com/jetstack/cert-manager/pkg/util"
)

const (
	// HTTP01Timeout is the max amount of time to wait for an HTTP01 challenge
	// to succeed
	HTTP01Timeout = time.Minute * 15
	// acmeSolverListenPort is the port acmesolver should listen on
	acmeSolverListenPort = 8089
)

var (
	challengeGvk = cmacme.SchemeGroupVersion.WithKind("Challenge")
)

// Solver is an implementation of the acme http-01 challenge solver protocol
type Solver struct {
	*controller.Context

	podLister            corev1listers.PodLister
	serviceLister        corev1listers.ServiceLister
	ingressLister        ingress.InternalIngressLister
	ingressCreateUpdater ingress.InternalIngressCreateUpdater
	httpRouteLister      gwapilisters.HTTPRouteLister

	testReachability reachabilityTest
	requiredPasses   int
}

type reachabilityTest func(ctx context.Context, url *url.URL, key string) error

// NewSolver returns a new ACME HTTP01 solver for the given *controller.Context.
func NewSolver(ctx *controller.Context) (*Solver, error) {
	ingressLister, _, err := ingress.NewListerInformer(ctx)
	if err != nil {
		return nil, err
	}
	ingressCreateUpdater, err := ingress.NewCreateUpdater(ctx)
	if err != nil {
		return nil, err
	}
	return &Solver{
		Context:              ctx,
		podLister:            ctx.KubeSharedInformerFactory.Core().V1().Pods().Lister(),
		serviceLister:        ctx.KubeSharedInformerFactory.Core().V1().Services().Lister(),
		ingressLister:        ingressLister,
		ingressCreateUpdater: ingressCreateUpdater,
		httpRouteLister:      ctx.GWShared.Networking().V1alpha1().HTTPRoutes().Lister(),
		testReachability:     testReachability,
		requiredPasses:       5,
	}, nil
}

func http01LogCtx(ctx context.Context) context.Context {
	return logf.NewContext(ctx, nil, "http01")
}

func http01IngressCfgForChallenge(ch *cmacme.Challenge) (*cmacme.ACMEChallengeSolverHTTP01Ingress, error) {
	if ch.Spec.Solver.HTTP01 == nil || ch.Spec.Solver.HTTP01.Ingress == nil {
		return nil, fmt.Errorf("challenge's 'solver' field is specified but no HTTP01 ingress config provided. " +
			"Ensure solvers[].http01.ingress is specified on your issuer resource")
	}
	return ch.Spec.Solver.HTTP01.Ingress, nil
}

func getServiceType(ch *cmacme.Challenge) (corev1.ServiceType, error) {
	if ch.Spec.Solver.HTTP01 != nil && ch.Spec.Solver.HTTP01.Ingress != nil {
		return ch.Spec.Solver.HTTP01.Ingress.ServiceType, nil
	}
	if ch.Spec.Solver.HTTP01 != nil && ch.Spec.Solver.HTTP01.GatewayHTTPRoute != nil {
		return ch.Spec.Solver.HTTP01.GatewayHTTPRoute.ServiceType, nil
	}
	return "", fmt.Errorf("neither HTTP01 Ingress nor Gateway solvers were found")
}

// Present will realise the resources required to solve the given HTTP01
// challenge validation in the apiserver. If those resources already exist, it
// will return nil (i.e. this function is idempotent).
func (s *Solver) Present(ctx context.Context, issuer v1.GenericIssuer, ch *cmacme.Challenge) error {
	ctx = http01LogCtx(ctx)

	_, podErr := s.ensurePod(ctx, ch)
	svc, svcErr := s.ensureService(ctx, ch)
	if svcErr != nil {
		return utilerrors.NewAggregate([]error{podErr, svcErr})
	}
	var ingressErr, gatewayErr error
	if ch.Spec.Solver.HTTP01 != nil {
		if ch.Spec.Solver.HTTP01.Ingress != nil {
			_, ingressErr = s.ensureIngress(ctx, ch, svc.Name)
			return utilerrors.NewAggregate([]error{podErr, svcErr, ingressErr})
		}
		if ch.Spec.Solver.HTTP01.GatewayHTTPRoute != nil {
			_, gatewayErr = s.ensureGatewayHTTPRoute(ctx, ch, svc.Name)
			return utilerrors.NewAggregate([]error{podErr, svcErr, gatewayErr})
		}
	}
	return utilerrors.NewAggregate(
		[]error{
			podErr,
			svcErr,
			ingressErr,
			gatewayErr,
			fmt.Errorf("couldn't Present challenge %s/%s: no Ingress nor Gateway HTTP01 solvers were specified", ch.Namespace, ch.Name),
		},
	)
}

func (s *Solver) Check(ctx context.Context, issuer v1.GenericIssuer, ch *cmacme.Challenge) error {
	ctx = logf.NewContext(http01LogCtx(ctx), nil, "selfCheck")
	log := logf.FromContext(ctx)

	// HTTP Present is idempotent and the state of the system may have
	// changed since present was called by the controllers (killed pods, drained nodes)
	// Call present again to be certain.
	// if the listers are nil, that means we're in the present checks
	// test
	if s.podLister != nil && s.serviceLister != nil && s.ingressLister != nil {
		log.V(logf.DebugLevel).Info("calling Present function before running self check to ensure required resources exist")
		err := s.Present(ctx, issuer, ch)
		if err != nil {
			log.V(logf.DebugLevel).Info("failed to call Present function", "error", err)
			return err
		}
	}

	ctx, cancel := context.WithTimeout(ctx, HTTP01Timeout)
	defer cancel()
	url := s.buildChallengeUrl(ch)
	log = log.WithValues("url", url)
	ctx = logf.NewContext(ctx, log)

	log.V(logf.DebugLevel).Info("running self check multiple times to ensure challenge has propagated", "required_passes", s.requiredPasses)
	for i := 0; i < s.requiredPasses; i++ {
		err := s.testReachability(ctx, url, ch.Spec.Key)
		if err != nil {
			return err
		}
		log.V(logf.DebugLevel).Info("reachability test passed, re-checking in 2s time")
		time.Sleep(time.Second * 2)
	}

	log.V(logf.DebugLevel).Info("self check succeeded")

	return nil
}

// CleanUp will ensure the created service, ingress and pod are clean/deleted of any
// cert-manager created data.
func (s *Solver) CleanUp(ctx context.Context, issuer v1.GenericIssuer, ch *cmacme.Challenge) error {
	var errs []error
	errs = append(errs, s.cleanupPods(ctx, ch))
	errs = append(errs, s.cleanupServices(ctx, ch))
	errs = append(errs, s.cleanupIngresses(ctx, ch))
	return utilerrors.NewAggregate(errs)
}

func (s *Solver) buildChallengeUrl(ch *cmacme.Challenge) *url.URL {
	url := &url.URL{}
	url.Scheme = "http"
	url.Host = ch.Spec.DNSName

	// we need brackets for IPv6 addresses for the HTTP client to work
	if k8snet.IsIPv6(net.ParseIP(url.Host)) {
		url.Host = fmt.Sprintf("[%s]", url.Host)
	}
	url.Path = fmt.Sprintf("%s/%s", solver.HTTPChallengePath, ch.Spec.Token)

	return url
}

// testReachability will attempt to connect to the 'domain' with 'path' and
// check if the returned body equals 'key'
func testReachability(ctx context.Context, url *url.URL, key string) error {
	log := logf.FromContext(ctx)
	log.V(logf.DebugLevel).Info("performing HTTP01 reachability check")

	req, err := http.NewRequestWithContext(ctx, http.MethodGet, url.String(), nil)
	if err != nil {
		return err
	}
	req.Header.Set("User-Agent", pkgutil.CertManagerUserAgent)

	// The ACME spec says that a verifier should try on http port 80 first, but to follow any
	// redirects which may be returned. Let's Encrypt, in practice, follows redirects for HTTP
	// and HTTPS services on ports 80 and 443 respectively, but the spec doesn't seem to require
	// anything other than the initial connection being on port 80.

	// For further reading, the spec also discusses redirect following in section 10.2:
	// https://datatracker.ietf.org/doc/html/rfc8555#section-10.2

	// TODO: Since Let's Encrypt will only accept redirects to port 80 and port 443, and we follow
	// any redirect here, this could lead to a failure mode where we determine that the endpoint is reachable
	// but it'll certainly fail when tried by the actual verifier; it's an edge case, but we might be able
	// to handle this better.

	// The timeouts here are inspired by the timeouts used by Boulder - i.e., Let's Encrypt - when
	// validating HTTP01 challenges for real.
	// Boulder http.Transport: https://github.com/letsencrypt/boulder/blob/30a516737c9daa4c88c8c47070c25a5e7033cdcf/va/http.go#L146-L160
	// Boulder http.Client:    https://github.com/letsencrypt/boulder/blob/30a516737c9daa4c88c8c47070c25a5e7033cdcf/va/http.go#L567-L572

	// Boulder uses a much more complex timeout setup involving shaving time off the deadline to be able to differentiate
	// between timeouts at different stages of the connection and in turn provide for better error messages. We're a little
	// more blunt than that, and just use a static timeout of 10 seconds in http.Client.

	// That said, IdleConnTimeout is not covered by `Timeout` in http.Client, so we also set it in our Transport

	// See https://blog.cloudflare.com/the-complete-guide-to-golang-net-http-timeouts/#clienttimeouts for details on timeouts
	transport := &http.Transport{
		Proxy: http.ProxyFromEnvironment,
		// we're only doing 1 request, make the code around this
		// simpler by disabling keepalives
		DisableKeepAlives: true,

		// boulder sets this to 1 because "0" means "unlimited"
		MaxIdleConns: 1,

		// IdleConnTimeout's value is taken from Boulder
		IdleConnTimeout: time.Second,

		TLSClientConfig: &tls.Config{
			// If we're following a redirect, it's permissible for it to be HTTPS and
			// its certificate may be invalid (they are trying to get a certificate, after all!)
			// See: https://letsencrypt.org/docs/challenge-types/#http-01-challenge
			// > When redirected to an HTTPS URL, it does not validate certificates (since
			// > this challenge is intended to bootstrap valid certificates, it may encounter
			// > self-signed or expired certificates along the way).
			InsecureSkipVerify: true,
		},
	}

	client := &http.Client{
		Transport: transport,
		Timeout:   time.Second * 10,
	}

	response, err := client.Do(req)
	if err != nil {
		log.V(logf.DebugLevel).Info("failed to perform self check GET request", "error", err)
		return fmt.Errorf("failed to perform self check GET request '%s': %v", url, err)
	}

	if response.StatusCode != http.StatusOK {
		log.V(logf.DebugLevel).Info("received HTTP status code was not StatusOK (200)", "code", response.StatusCode)
		return fmt.Errorf("wrong status code '%d', expected '%d'", response.StatusCode, http.StatusOK)
	}

	defer response.Body.Close()
	presentedKey, err := io.ReadAll(response.Body)
	if err != nil {
		log.V(logf.DebugLevel).Info("failed to decode response body", "error", err)
		return fmt.Errorf("failed to read response body: %v", err)
	}

	if string(presentedKey) != key {
		// truncate the response before displaying it to avoid extra long strings
		// being displayed to users
		keyToPrint := string(presentedKey)
		if len(keyToPrint) > 24 {
			// trim spaces to make output look right if it ends with whitespace
			keyToPrint = strings.TrimSpace(keyToPrint[:24]) + "... (truncated)"
		}
		log.V(logf.DebugLevel).Info("key returned by server did not match expected", "actual", keyToPrint, "expected", key)
		return fmt.Errorf("did not get expected response when querying endpoint, expected %q but got: %s", key, keyToPrint)
	}

	log.V(logf.DebugLevel).Info("reachability test succeeded")

	return nil
}
<|endoftext|>


<commit_before>/*
Copyright 2017 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package auth

import (
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"strings"

	"github.com/spf13/cobra"

	"k8s.io/apimachinery/pkg/api/meta"
	"k8s.io/apimachinery/pkg/runtime/schema"
	utilerrors "k8s.io/apimachinery/pkg/util/errors"
	authorizationapi "k8s.io/kubernetes/pkg/apis/authorization"
	internalauthorizationclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/authorization/internalversion"
	"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
	cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
)

// CanIOptions is the start of the data required to perform the operation.  As new fields are added, add them here instead of
// referencing the cmd.Flags()
type CanIOptions struct {
	AllNamespaces bool
	Quiet         bool
	Namespace     string
	SelfSARClient internalauthorizationclient.SelfSubjectAccessReviewsGetter

	Verb         string
	Resource     schema.GroupVersionResource
	ResourceName string

	Out io.Writer
	Err io.Writer
}

var (
	canILong = templates.LongDesc(`
		Check whether an action is allowed.

		VERB is a logical Kubernetes API verb like 'get', 'list', 'watch', 'delete', etc.
		TYPE is a Kubernetes resource.  Shortcuts and groups will be resolved.
		NAME is the name of a particular Kubernetes resource.`)

	canIExample = templates.Examples(`
		# Check to see if I can create pods in any namespace
		kubectl auth can-i create pods --all-namespaces

		# Check to see if I can list deployments in my current namespace
		kubectl auth can-i list deployments.extensions

		# Check to see if I can do everything in my current namespace ("*" means all)
		kubectl auth can-i '*' '*'

		# Check to see if I can get the job named "bar" in namespace "foo"
		kubectl auth can-i list jobs.batch/bar -n foo`)
)

func NewCmdCanI(f cmdutil.Factory, out, err io.Writer) *cobra.Command {
	o := &CanIOptions{
		Out: out,
		Err: err,
	}

	cmd := &cobra.Command{
		Use:     "can-i VERB [TYPE | TYPE/NAME]",
		Short:   "Check whether an action is allowed",
		Long:    canILong,
		Example: canIExample,
		Run: func(cmd *cobra.Command, args []string) {
			cmdutil.CheckErr(o.Complete(f, args))
			cmdutil.CheckErr(o.Validate())

			allowed, err := o.RunAccessCheck()
			if err == nil {
				if o.Quiet && !allowed {
					os.Exit(1)
				}
			}

			cmdutil.CheckErr(err)
		},
	}

	cmd.Flags().BoolVar(&o.AllNamespaces, "all-namespaces", o.AllNamespaces, "If true, check the specified action in all namespaces.")
	cmd.Flags().BoolVarP(&o.Quiet, "quiet", "q", o.Quiet, "If true, suppress output and just return the exit code.")
	return cmd
}

func (o *CanIOptions) Complete(f cmdutil.Factory, args []string) error {
	if o.Quiet {
		o.Out = ioutil.Discard
	}

	switch len(args) {
	case 2:
		resourceTokens := strings.SplitN(args[1], "/", 2)
		restMapper, _ := f.Object()
		o.Verb = args[0]
		o.Resource = o.resourceFor(restMapper, resourceTokens[0])
		if len(resourceTokens) > 1 {
			o.ResourceName = resourceTokens[1]
		}
	default:
		return errors.New("you must specify two or three arguments: verb, resource, and optional resourceName")
	}

	var err error
	client, err := f.ClientSet()
	if err != nil {
		return err
	}
	o.SelfSARClient = client.Authorization()

	o.Namespace = ""
	if !o.AllNamespaces {
		o.Namespace, _, err = f.DefaultNamespace()
		if err != nil {
			return err
		}
	}

	return nil
}

func (o *CanIOptions) Validate() error {
	errors := []error{}
	return utilerrors.NewAggregate(errors)
}

func (o *CanIOptions) RunAccessCheck() (bool, error) {
	sar := &authorizationapi.SelfSubjectAccessReview{
		Spec: authorizationapi.SelfSubjectAccessReviewSpec{
			ResourceAttributes: &authorizationapi.ResourceAttributes{
				Namespace: o.Namespace,
				Verb:      o.Verb,
				Group:     o.Resource.Group,
				Resource:  o.Resource.Resource,
				Name:      o.ResourceName,
			},
		},
	}

	response, err := o.SelfSARClient.SelfSubjectAccessReviews().Create(sar)
	if err != nil {
		return false, err
	}

	if response.Status.Allowed {
		fmt.Fprintln(o.Out, "yes")
	} else {
		fmt.Fprint(o.Out, "no")
		if len(response.Status.Reason) > 0 {
			fmt.Fprintf(o.Out, " - %v", response.Status.Reason)
		}
		if len(response.Status.EvaluationError) > 0 {
			fmt.Fprintf(o.Out, " - %v", response.Status.EvaluationError)
		}
		fmt.Fprintln(o.Out)
	}

	return response.Status.Allowed, nil
}

func (o *CanIOptions) resourceFor(mapper meta.RESTMapper, resourceArg string) schema.GroupVersionResource {
	fullySpecifiedGVR, groupResource := schema.ParseResourceArg(strings.ToLower(resourceArg))
	gvr := schema.GroupVersionResource{}
	if fullySpecifiedGVR != nil {
		gvr, _ = mapper.ResourceFor(*fullySpecifiedGVR)
	}
	if gvr.Empty() {
		var err error
		gvr, err = mapper.ResourceFor(groupResource.WithVersion(""))
		if err != nil {
			if len(groupResource.Group) == 0 {
				fmt.Fprintf(o.Err, "Warning: the server doesn't have a resource type '%s'\n", groupResource.Resource)
			} else {
				fmt.Fprintf(o.Err, "Warning: the server doesn't have a resource type '%s' in group '%s'\n", groupResource.Resource, groupResource.Group)
			}
			return schema.GroupVersionResource{Resource: resourceArg}
		}
	}

	return gvr
}
<commit_msg>remove warning infomation when use '*'<commit_after>/*
Copyright 2017 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package auth

import (
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"strings"

	"github.com/spf13/cobra"

	"k8s.io/apimachinery/pkg/api/meta"
	"k8s.io/apimachinery/pkg/runtime/schema"
	utilerrors "k8s.io/apimachinery/pkg/util/errors"
	authorizationapi "k8s.io/kubernetes/pkg/apis/authorization"
	internalauthorizationclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/authorization/internalversion"
	"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
	cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
)

// CanIOptions is the start of the data required to perform the operation.  As new fields are added, add them here instead of
// referencing the cmd.Flags()
type CanIOptions struct {
	AllNamespaces bool
	Quiet         bool
	Namespace     string
	SelfSARClient internalauthorizationclient.SelfSubjectAccessReviewsGetter

	Verb         string
	Resource     schema.GroupVersionResource
	ResourceName string

	Out io.Writer
	Err io.Writer
}

var (
	canILong = templates.LongDesc(`
		Check whether an action is allowed.

		VERB is a logical Kubernetes API verb like 'get', 'list', 'watch', 'delete', etc.
		TYPE is a Kubernetes resource.  Shortcuts and groups will be resolved.
		NAME is the name of a particular Kubernetes resource.`)

	canIExample = templates.Examples(`
		# Check to see if I can create pods in any namespace
		kubectl auth can-i create pods --all-namespaces

		# Check to see if I can list deployments in my current namespace
		kubectl auth can-i list deployments.extensions

		# Check to see if I can do everything in my current namespace ("*" means all)
		kubectl auth can-i '*' '*'

		# Check to see if I can get the job named "bar" in namespace "foo"
		kubectl auth can-i list jobs.batch/bar -n foo`)
)

func NewCmdCanI(f cmdutil.Factory, out, err io.Writer) *cobra.Command {
	o := &CanIOptions{
		Out: out,
		Err: err,
	}

	cmd := &cobra.Command{
		Use:     "can-i VERB [TYPE | TYPE/NAME]",
		Short:   "Check whether an action is allowed",
		Long:    canILong,
		Example: canIExample,
		Run: func(cmd *cobra.Command, args []string) {
			cmdutil.CheckErr(o.Complete(f, args))
			cmdutil.CheckErr(o.Validate())

			allowed, err := o.RunAccessCheck()
			if err == nil {
				if o.Quiet && !allowed {
					os.Exit(1)
				}
			}

			cmdutil.CheckErr(err)
		},
	}

	cmd.Flags().BoolVar(&o.AllNamespaces, "all-namespaces", o.AllNamespaces, "If true, check the specified action in all namespaces.")
	cmd.Flags().BoolVarP(&o.Quiet, "quiet", "q", o.Quiet, "If true, suppress output and just return the exit code.")
	return cmd
}

func (o *CanIOptions) Complete(f cmdutil.Factory, args []string) error {
	if o.Quiet {
		o.Out = ioutil.Discard
	}

	switch len(args) {
	case 2:
		resourceTokens := strings.SplitN(args[1], "/", 2)
		restMapper, _ := f.Object()
		o.Verb = args[0]
		o.Resource = o.resourceFor(restMapper, resourceTokens[0])
		if len(resourceTokens) > 1 {
			o.ResourceName = resourceTokens[1]
		}
	default:
		return errors.New("you must specify two or three arguments: verb, resource, and optional resourceName")
	}

	var err error
	client, err := f.ClientSet()
	if err != nil {
		return err
	}
	o.SelfSARClient = client.Authorization()

	o.Namespace = ""
	if !o.AllNamespaces {
		o.Namespace, _, err = f.DefaultNamespace()
		if err != nil {
			return err
		}
	}

	return nil
}

func (o *CanIOptions) Validate() error {
	errors := []error{}
	return utilerrors.NewAggregate(errors)
}

func (o *CanIOptions) RunAccessCheck() (bool, error) {
	sar := &authorizationapi.SelfSubjectAccessReview{
		Spec: authorizationapi.SelfSubjectAccessReviewSpec{
			ResourceAttributes: &authorizationapi.ResourceAttributes{
				Namespace: o.Namespace,
				Verb:      o.Verb,
				Group:     o.Resource.Group,
				Resource:  o.Resource.Resource,
				Name:      o.ResourceName,
			},
		},
	}

	response, err := o.SelfSARClient.SelfSubjectAccessReviews().Create(sar)
	if err != nil {
		return false, err
	}

	if response.Status.Allowed {
		fmt.Fprintln(o.Out, "yes")
	} else {
		fmt.Fprint(o.Out, "no")
		if len(response.Status.Reason) > 0 {
			fmt.Fprintf(o.Out, " - %v", response.Status.Reason)
		}
		if len(response.Status.EvaluationError) > 0 {
			fmt.Fprintf(o.Out, " - %v", response.Status.EvaluationError)
		}
		fmt.Fprintln(o.Out)
	}

	return response.Status.Allowed, nil
}

func (o *CanIOptions) resourceFor(mapper meta.RESTMapper, resourceArg string) schema.GroupVersionResource {
	if resourceArg == "*" {
		return schema.GroupVersionResource{Resource: resourceArg}
	}

	fullySpecifiedGVR, groupResource := schema.ParseResourceArg(strings.ToLower(resourceArg))
	gvr := schema.GroupVersionResource{}
	if fullySpecifiedGVR != nil {
		gvr, _ = mapper.ResourceFor(*fullySpecifiedGVR)
	}
	if gvr.Empty() {
		var err error
		gvr, err = mapper.ResourceFor(groupResource.WithVersion(""))
		if err != nil {
			if len(groupResource.Group) == 0 {
				fmt.Fprintf(o.Err, "Warning: the server doesn't have a resource type '%s'\n", groupResource.Resource)
			} else {
				fmt.Fprintf(o.Err, "Warning: the server doesn't have a resource type '%s' in group '%s'\n", groupResource.Resource, groupResource.Group)
			}
			return schema.GroupVersionResource{Resource: resourceArg}
		}
	}

	return gvr
}
<|endoftext|>


<commit_before>// Copyright 2015 CoreOS, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// +build !windows,!plan9

// InterruptHandler is a function that is called on receiving a
// SIGTERM or SIGINT signal.

package osutil

import (
	"log"
	"os"
	"os/signal"
	"sync"
	"syscall"
)

type InterruptHandler func()

var (
	interruptRegisterMu, interruptExitMu sync.Mutex
	// interruptHandlers holds all registered InterruptHandlers in order
	// they will be executed.
	interruptHandlers = []InterruptHandler{}
)

// RegisterInterruptHandler registers a new InterruptHandler. Handlers registered
// after interrupt handing was initiated will not be executed.
func RegisterInterruptHandler(h InterruptHandler) {
	interruptRegisterMu.Lock()
	defer interruptRegisterMu.Unlock()
	interruptHandlers = append(interruptHandlers, h)
}

// HandleInterrupts calls the handler functions on receiving a SIGINT or SIGTERM.
func HandleInterrupts() {
	notifier := make(chan os.Signal, 1)
	signal.Notify(notifier, syscall.SIGINT, syscall.SIGTERM)

	go func() {
		sig := <-notifier

		interruptRegisterMu.Lock()
		ihs := make([]InterruptHandler, len(interruptHandlers))
		copy(ihs, interruptHandlers)
		interruptRegisterMu.Unlock()

		interruptExitMu.Lock()

		log.Printf("received %v signal, shutting down", sig)

		for _, h := range ihs {
			h()
		}
		signal.Stop(notifier)
		syscall.Kill(syscall.Getpid(), sig.(syscall.Signal))
	}()
}

// Exit relays to os.Exit if no interrupt handlers are running, blocks otherwise.
func Exit(code int) {
	interruptExitMu.Lock()
	os.Exit(code)
}
<commit_msg>osutil: pid 1 should exit directly instead of trying to kill itself<commit_after>// Copyright 2015 CoreOS, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// +build !windows,!plan9

// InterruptHandler is a function that is called on receiving a
// SIGTERM or SIGINT signal.

package osutil

import (
	"log"
	"os"
	"os/signal"
	"sync"
	"syscall"
)

type InterruptHandler func()

var (
	interruptRegisterMu, interruptExitMu sync.Mutex
	// interruptHandlers holds all registered InterruptHandlers in order
	// they will be executed.
	interruptHandlers = []InterruptHandler{}
)

// RegisterInterruptHandler registers a new InterruptHandler. Handlers registered
// after interrupt handing was initiated will not be executed.
func RegisterInterruptHandler(h InterruptHandler) {
	interruptRegisterMu.Lock()
	defer interruptRegisterMu.Unlock()
	interruptHandlers = append(interruptHandlers, h)
}

// HandleInterrupts calls the handler functions on receiving a SIGINT or SIGTERM.
func HandleInterrupts() {
	notifier := make(chan os.Signal, 1)
	signal.Notify(notifier, syscall.SIGINT, syscall.SIGTERM)

	go func() {
		sig := <-notifier

		interruptRegisterMu.Lock()
		ihs := make([]InterruptHandler, len(interruptHandlers))
		copy(ihs, interruptHandlers)
		interruptRegisterMu.Unlock()

		interruptExitMu.Lock()

		log.Printf("received %v signal, shutting down...", sig)

		for _, h := range ihs {
			h()
		}
		signal.Stop(notifier)
		pid := syscall.Getpid()
		// exit directly if it is the "init" process, since the kernel will not help to kill pid 1.
		if pid == 1 {
			os.Exit(0)
		}
		syscall.Kill(pid, sig.(syscall.Signal))
	}()
}

// Exit relays to os.Exit if no interrupt handlers are running, blocks otherwise.
func Exit(code int) {
	interruptExitMu.Lock()
	os.Exit(code)
}
<|endoftext|>


<commit_before>package platform

import (
	"bytes"
	"errors"
	"fmt"
	"os"
	"path/filepath"
	"strings"

	boshdpresolv "github.com/cloudfoundry/bosh-agent/infrastructure/devicepathresolver"
	boshcert "github.com/cloudfoundry/bosh-agent/platform/cert"
	boshnet "github.com/cloudfoundry/bosh-agent/platform/net"
	boshstats "github.com/cloudfoundry/bosh-agent/platform/stats"
	boshvitals "github.com/cloudfoundry/bosh-agent/platform/vitals"
	boshsettings "github.com/cloudfoundry/bosh-agent/settings"
	boshdir "github.com/cloudfoundry/bosh-agent/settings/directories"
	boshdirs "github.com/cloudfoundry/bosh-agent/settings/directories"
	bosherr "github.com/cloudfoundry/bosh-utils/errors"
	boshcmd "github.com/cloudfoundry/bosh-utils/fileutil"
	boshlog "github.com/cloudfoundry/bosh-utils/logger"
	boshsys "github.com/cloudfoundry/bosh-utils/system"
	boshuuid "github.com/cloudfoundry/bosh-utils/uuid"
)

type WindowsPlatform struct {
	collector              boshstats.Collector
	fs                     boshsys.FileSystem
	cmdRunner              boshsys.CmdRunner
	compressor             boshcmd.Compressor
	copier                 boshcmd.Copier
	dirProvider            boshdirs.Provider
	vitalsService          boshvitals.Service
	netManager             boshnet.Manager
	devicePathResolver     boshdpresolv.DevicePathResolver
	certManager            boshcert.Manager
	defaultNetworkResolver boshsettings.DefaultNetworkResolver
	auditLogger            AuditLogger
	uuidGenerator          boshuuid.Generator
}

func NewWindowsPlatform(
	collector boshstats.Collector,
	fs boshsys.FileSystem,
	cmdRunner boshsys.CmdRunner,
	dirProvider boshdirs.Provider,
	netManager boshnet.Manager,
	certManager boshcert.Manager,
	devicePathResolver boshdpresolv.DevicePathResolver,
	logger boshlog.Logger,
	defaultNetworkResolver boshsettings.DefaultNetworkResolver,
	auditLogger AuditLogger,
	uuidGenerator boshuuid.Generator,
) Platform {
	return &WindowsPlatform{
		fs:                     fs,
		cmdRunner:              cmdRunner,
		collector:              collector,
		compressor:             boshcmd.NewTarballCompressor(cmdRunner, fs),
		copier:                 boshcmd.NewGenericCpCopier(fs, logger),
		dirProvider:            dirProvider,
		netManager:             netManager,
		devicePathResolver:     devicePathResolver,
		vitalsService:          boshvitals.NewService(collector, dirProvider),
		certManager:            certManager,
		defaultNetworkResolver: defaultNetworkResolver,
		auditLogger:            auditLogger,
		uuidGenerator:          uuidGenerator,
	}
}

func (p WindowsPlatform) AssociateDisk(name string, settings boshsettings.DiskSettings) error {
	return errors.New("unimplemented")
}

func (p WindowsPlatform) GetFs() (fs boshsys.FileSystem) {
	return p.fs
}

func (p WindowsPlatform) GetRunner() (runner boshsys.CmdRunner) {
	return p.cmdRunner
}

func (p WindowsPlatform) GetCompressor() (compressor boshcmd.Compressor) {
	return p.compressor
}

func (p WindowsPlatform) GetCopier() (copier boshcmd.Copier) {
	return p.copier
}

func (p WindowsPlatform) GetDirProvider() (dirProvider boshdir.Provider) {
	return p.dirProvider
}

func (p WindowsPlatform) GetVitalsService() (service boshvitals.Service) {
	return p.vitalsService
}

func (p WindowsPlatform) GetDevicePathResolver() (devicePathResolver boshdpresolv.DevicePathResolver) {
	return p.devicePathResolver
}

func (p WindowsPlatform) GetAuditLogger() AuditLogger {
	return p.auditLogger
}

func (p WindowsPlatform) SetupRuntimeConfiguration() (err error) {
	return
}

func (p WindowsPlatform) CreateUser(username, basePath string) (err error) {
	return
}

func (p WindowsPlatform) AddUserToGroups(username string, groups []string) (err error) {
	return
}

func (p WindowsPlatform) DeleteEphemeralUsersMatching(regex string) (err error) {
	return
}

func (p WindowsPlatform) SetupRootDisk(ephemeralDiskPath string) (err error) {
	return
}

func (p WindowsPlatform) SetupSSH(publicKey []string, username string) (err error) {
	return
}

func (p WindowsPlatform) SetUserPassword(user, encryptedPwd string) (err error) {
	return
}

func (p WindowsPlatform) SaveDNSRecords(dnsRecords boshsettings.DNSRecords, hostname string) (err error) {
	windir := os.Getenv("windir")
	if windir == "" {
		return bosherr.Error("SaveDNSRecords: missing %WINDIR% env variable")
	}
	etcdir := filepath.Join(windir, "System32", "Drivers", "etc")
	if err := p.fs.MkdirAll(etcdir, 0755); err != nil {
		return bosherr.WrapError(err, "SaveDNSRecords: creating etc directory")
	}

	uuid, err := p.uuidGenerator.Generate()
	if err != nil {
		return bosherr.WrapError(err, "SaveDNSRecords: generating UUID")
	}

	tmpfile := filepath.Join(etcdir, "hosts-"+uuid)
	f, err := p.fs.OpenFile(tmpfile, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0644)
	if err != nil {
		return bosherr.WrapError(err, "SaveDNSRecords: opening hosts file")
	}

	var buf bytes.Buffer
	for _, rec := range dnsRecords.Records {
		fmt.Fprintf(&buf, "%s %s\n", rec[0], rec[1])
	}
	if _, err := buf.WriteTo(f); err != nil {
		f.Close()
		return bosherr.WrapErrorf(err, "SaveDNSRecords: writing DNS records to: %s", tmpfile)
	}
	f.Close() // Explicitly close before renaming - required to release handle

	hostfile := filepath.Join(etcdir, "hosts")
	if err := p.fs.Rename(tmpfile, hostfile); err != nil {
		return bosherr.WrapErrorf(err, "SaveDNSRecords: renaming %s to %s", tmpfile, hostfile)
	}
	return
}

func (p WindowsPlatform) SetupIPv6(config boshsettings.IPv6) error {
	return nil
}

func (p WindowsPlatform) SetupHostname(hostname string) (err error) {
	return
}

func (p WindowsPlatform) SetupNetworking(networks boshsettings.Networks) (err error) {
	return p.netManager.SetupNetworking(networks, nil)
}

func (p WindowsPlatform) GetConfiguredNetworkInterfaces() (interfaces []string, err error) {
	return
}

func (p WindowsPlatform) GetCertManager() (certManager boshcert.Manager) {
	return p.certManager
}

func (p WindowsPlatform) SetupLogrotate(groupName, basePath, size string) (err error) {
	return
}

func (p WindowsPlatform) SetTimeWithNtpServers(servers []string) (err error) {
	if len(servers) == 0 {
		return
	}
	var (
		stderr string
	)
	ntpServers := strings.Join(servers, " ")
	_, stderr, _, err = p.cmdRunner.RunCommand("powershell.exe",
		"new-netfirewallrule",
		"-displayname", "NTP",
		"-direction", "outbound",
		"-action", "allow",
		"-protocol", "udp",
		"-RemotePort", "123")
	if err != nil {
		err = bosherr.WrapErrorf(err, "SetTimeWithNtpServers  %s", stderr)
		return
	}

	_, _, _, _ = p.cmdRunner.RunCommand("net", "stop", "w32time")
	manualPeerList := fmt.Sprintf("/manualpeerlist:\"%s\"", ntpServers)
	_, stderr, _, err = p.cmdRunner.RunCommand("w32tm", "/config", "/syncfromflags:manual", manualPeerList)
	if err != nil {
		err = bosherr.WrapErrorf(err, "SetTimeWithNtpServers %s", stderr)
		return
	}
	_, _, _, _ = p.cmdRunner.RunCommand("net", "start", "w32time")
	_, stderr, _, err = p.cmdRunner.RunCommand("w32tm", "/config", "/update")
	if err != nil {
		err = bosherr.WrapErrorf(err, "SetTimeWithNtpServers %s", stderr)
		return
	}
	_, stderr, _, err = p.cmdRunner.RunCommand("w32tm", "/resync", "/rediscover")
	if err != nil {
		err = bosherr.WrapErrorf(err, "SetTimeWithNtpServers %s", stderr)
		return
	}
	return
}

func (p WindowsPlatform) SetupEphemeralDiskWithPath(devicePath string, desiredSwapSizeInBytes *uint64) (err error) {
	return
}

func (p WindowsPlatform) SetupRawEphemeralDisks(devices []boshsettings.DiskSettings) (err error) {
	return
}

func (p WindowsPlatform) SetupDataDir() error {
	return nil
}

func (p WindowsPlatform) SetupHomeDir() error {
	return nil
}

func (p WindowsPlatform) SetupTmpDir() error {
	boshTmpDir := p.dirProvider.TmpDir()

	err := p.fs.MkdirAll(boshTmpDir, tmpDirPermissions)
	if err != nil {
		return bosherr.WrapError(err, "Creating temp dir")
	}

	err = os.Setenv("TMP", boshTmpDir)
	if err != nil {
		return bosherr.WrapError(err, "Setting TMP")
	}

	err = os.Setenv("TEMP", boshTmpDir)
	if err != nil {
		return bosherr.WrapError(err, "Setting TEMP")
	}

	return nil
}

func (p WindowsPlatform) SetupLogDir() error {
	return nil
}

func (p WindowsPlatform) SetupBlobsDir() error {
	return nil
}

func (p WindowsPlatform) SetupLoggingAndAuditing() error {
	return nil
}

func (p WindowsPlatform) MountPersistentDisk(diskSettings boshsettings.DiskSettings, mountPoint string) (err error) {
	return
}

func (p WindowsPlatform) UnmountPersistentDisk(diskSettings boshsettings.DiskSettings) (didUnmount bool, err error) {
	return
}

func (p WindowsPlatform) GetEphemeralDiskPath(diskSettings boshsettings.DiskSettings) string {
	return ""
}

func (p WindowsPlatform) GetFileContentsFromCDROM(filePath string) (contents []byte, err error) {
	return p.fs.ReadFile("D:/" + filePath)
}

func (p WindowsPlatform) GetFilesContentsFromDisk(diskPath string, fileNames []string) (contents [][]byte, err error) {
	return
}

func (p WindowsPlatform) MigratePersistentDisk(fromMountPoint, toMountPoint string) (err error) {
	return
}

func (p WindowsPlatform) IsMountPoint(path string) (string, bool, error) {
	return "", true, nil
}

func (p WindowsPlatform) IsPersistentDiskMounted(diskSettings boshsettings.DiskSettings) (bool, error) {
	return true, nil
}

func (p WindowsPlatform) IsPersistentDiskMountable(diskSettings boshsettings.DiskSettings) (bool, error) {
	return true, nil
}

func (p WindowsPlatform) StartMonit() (err error) {
	return
}

func (p WindowsPlatform) SetupMonitUser() (err error) {
	return
}

func (p WindowsPlatform) GetMonitCredentials() (username, password string, err error) {
	return
}

func (p WindowsPlatform) PrepareForNetworkingChange() error {
	return nil
}

func (p WindowsPlatform) CleanIPMacAddressCache(ip string) error {
	return nil
}

func (p WindowsPlatform) RemoveDevTools(packageFileListPath string) error {
	return nil
}

func (p WindowsPlatform) RemoveStaticLibraries(packageFileListPath string) error {
	return nil
}

func (p WindowsPlatform) GetDefaultNetwork() (boshsettings.Network, error) {
	return p.defaultNetworkResolver.GetDefaultNetwork()
}

func (p WindowsPlatform) GetHostPublicKey() (string, error) {
	return "", nil
}

func (p WindowsPlatform) DeleteARPEntryWithIP(ip string) error {
	_, _, _, err := p.cmdRunner.RunCommand("arp", "-d", ip)
	if err != nil {
		return bosherr.WrapError(err, "Deleting arp entry")
	}

	return nil
}

func (p WindowsPlatform) SetupRecordsJSONPermission(path string) error {
	return nil
}
<commit_msg>Windows Platform: implement SetupBlobsDir<commit_after>package platform

import (
	"bytes"
	"errors"
	"fmt"
	"os"
	"path/filepath"
	"strings"

	boshdpresolv "github.com/cloudfoundry/bosh-agent/infrastructure/devicepathresolver"
	boshcert "github.com/cloudfoundry/bosh-agent/platform/cert"
	boshnet "github.com/cloudfoundry/bosh-agent/platform/net"
	boshstats "github.com/cloudfoundry/bosh-agent/platform/stats"
	boshvitals "github.com/cloudfoundry/bosh-agent/platform/vitals"
	boshsettings "github.com/cloudfoundry/bosh-agent/settings"
	boshdir "github.com/cloudfoundry/bosh-agent/settings/directories"
	boshdirs "github.com/cloudfoundry/bosh-agent/settings/directories"
	bosherr "github.com/cloudfoundry/bosh-utils/errors"
	boshcmd "github.com/cloudfoundry/bosh-utils/fileutil"
	boshlog "github.com/cloudfoundry/bosh-utils/logger"
	boshsys "github.com/cloudfoundry/bosh-utils/system"
	boshuuid "github.com/cloudfoundry/bosh-utils/uuid"
)

type WindowsPlatform struct {
	collector              boshstats.Collector
	fs                     boshsys.FileSystem
	cmdRunner              boshsys.CmdRunner
	compressor             boshcmd.Compressor
	copier                 boshcmd.Copier
	dirProvider            boshdirs.Provider
	vitalsService          boshvitals.Service
	netManager             boshnet.Manager
	devicePathResolver     boshdpresolv.DevicePathResolver
	certManager            boshcert.Manager
	defaultNetworkResolver boshsettings.DefaultNetworkResolver
	auditLogger            AuditLogger
	uuidGenerator          boshuuid.Generator
}

func NewWindowsPlatform(
	collector boshstats.Collector,
	fs boshsys.FileSystem,
	cmdRunner boshsys.CmdRunner,
	dirProvider boshdirs.Provider,
	netManager boshnet.Manager,
	certManager boshcert.Manager,
	devicePathResolver boshdpresolv.DevicePathResolver,
	logger boshlog.Logger,
	defaultNetworkResolver boshsettings.DefaultNetworkResolver,
	auditLogger AuditLogger,
	uuidGenerator boshuuid.Generator,
) Platform {
	return &WindowsPlatform{
		fs:                     fs,
		cmdRunner:              cmdRunner,
		collector:              collector,
		compressor:             boshcmd.NewTarballCompressor(cmdRunner, fs),
		copier:                 boshcmd.NewGenericCpCopier(fs, logger),
		dirProvider:            dirProvider,
		netManager:             netManager,
		devicePathResolver:     devicePathResolver,
		vitalsService:          boshvitals.NewService(collector, dirProvider),
		certManager:            certManager,
		defaultNetworkResolver: defaultNetworkResolver,
		auditLogger:            auditLogger,
		uuidGenerator:          uuidGenerator,
	}
}

func (p WindowsPlatform) AssociateDisk(name string, settings boshsettings.DiskSettings) error {
	return errors.New("unimplemented")
}

func (p WindowsPlatform) GetFs() (fs boshsys.FileSystem) {
	return p.fs
}

func (p WindowsPlatform) GetRunner() (runner boshsys.CmdRunner) {
	return p.cmdRunner
}

func (p WindowsPlatform) GetCompressor() (compressor boshcmd.Compressor) {
	return p.compressor
}

func (p WindowsPlatform) GetCopier() (copier boshcmd.Copier) {
	return p.copier
}

func (p WindowsPlatform) GetDirProvider() (dirProvider boshdir.Provider) {
	return p.dirProvider
}

func (p WindowsPlatform) GetVitalsService() (service boshvitals.Service) {
	return p.vitalsService
}

func (p WindowsPlatform) GetDevicePathResolver() (devicePathResolver boshdpresolv.DevicePathResolver) {
	return p.devicePathResolver
}

func (p WindowsPlatform) GetAuditLogger() AuditLogger {
	return p.auditLogger
}

func (p WindowsPlatform) SetupRuntimeConfiguration() (err error) {
	return
}

func (p WindowsPlatform) CreateUser(username, basePath string) (err error) {
	return
}

func (p WindowsPlatform) AddUserToGroups(username string, groups []string) (err error) {
	return
}

func (p WindowsPlatform) DeleteEphemeralUsersMatching(regex string) (err error) {
	return
}

func (p WindowsPlatform) SetupRootDisk(ephemeralDiskPath string) (err error) {
	return
}

func (p WindowsPlatform) SetupSSH(publicKey []string, username string) (err error) {
	return
}

func (p WindowsPlatform) SetUserPassword(user, encryptedPwd string) (err error) {
	return
}

func (p WindowsPlatform) SaveDNSRecords(dnsRecords boshsettings.DNSRecords, hostname string) (err error) {
	windir := os.Getenv("windir")
	if windir == "" {
		return bosherr.Error("SaveDNSRecords: missing %WINDIR% env variable")
	}
	etcdir := filepath.Join(windir, "System32", "Drivers", "etc")
	if err := p.fs.MkdirAll(etcdir, 0755); err != nil {
		return bosherr.WrapError(err, "SaveDNSRecords: creating etc directory")
	}

	uuid, err := p.uuidGenerator.Generate()
	if err != nil {
		return bosherr.WrapError(err, "SaveDNSRecords: generating UUID")
	}

	tmpfile := filepath.Join(etcdir, "hosts-"+uuid)
	f, err := p.fs.OpenFile(tmpfile, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0644)
	if err != nil {
		return bosherr.WrapError(err, "SaveDNSRecords: opening hosts file")
	}

	var buf bytes.Buffer
	for _, rec := range dnsRecords.Records {
		fmt.Fprintf(&buf, "%s %s\n", rec[0], rec[1])
	}
	if _, err := buf.WriteTo(f); err != nil {
		f.Close()
		return bosherr.WrapErrorf(err, "SaveDNSRecords: writing DNS records to: %s", tmpfile)
	}
	f.Close() // Explicitly close before renaming - required to release handle

	hostfile := filepath.Join(etcdir, "hosts")
	if err := p.fs.Rename(tmpfile, hostfile); err != nil {
		return bosherr.WrapErrorf(err, "SaveDNSRecords: renaming %s to %s", tmpfile, hostfile)
	}
	return
}

func (p WindowsPlatform) SetupIPv6(config boshsettings.IPv6) error {
	return nil
}

func (p WindowsPlatform) SetupHostname(hostname string) (err error) {
	return
}

func (p WindowsPlatform) SetupNetworking(networks boshsettings.Networks) (err error) {
	return p.netManager.SetupNetworking(networks, nil)
}

func (p WindowsPlatform) GetConfiguredNetworkInterfaces() (interfaces []string, err error) {
	return
}

func (p WindowsPlatform) GetCertManager() (certManager boshcert.Manager) {
	return p.certManager
}

func (p WindowsPlatform) SetupLogrotate(groupName, basePath, size string) (err error) {
	return
}

func (p WindowsPlatform) SetTimeWithNtpServers(servers []string) (err error) {
	if len(servers) == 0 {
		return
	}
	var (
		stderr string
	)
	ntpServers := strings.Join(servers, " ")
	_, stderr, _, err = p.cmdRunner.RunCommand("powershell.exe",
		"new-netfirewallrule",
		"-displayname", "NTP",
		"-direction", "outbound",
		"-action", "allow",
		"-protocol", "udp",
		"-RemotePort", "123")
	if err != nil {
		err = bosherr.WrapErrorf(err, "SetTimeWithNtpServers  %s", stderr)
		return
	}

	_, _, _, _ = p.cmdRunner.RunCommand("net", "stop", "w32time")
	manualPeerList := fmt.Sprintf("/manualpeerlist:\"%s\"", ntpServers)
	_, stderr, _, err = p.cmdRunner.RunCommand("w32tm", "/config", "/syncfromflags:manual", manualPeerList)
	if err != nil {
		err = bosherr.WrapErrorf(err, "SetTimeWithNtpServers %s", stderr)
		return
	}
	_, _, _, _ = p.cmdRunner.RunCommand("net", "start", "w32time")
	_, stderr, _, err = p.cmdRunner.RunCommand("w32tm", "/config", "/update")
	if err != nil {
		err = bosherr.WrapErrorf(err, "SetTimeWithNtpServers %s", stderr)
		return
	}
	_, stderr, _, err = p.cmdRunner.RunCommand("w32tm", "/resync", "/rediscover")
	if err != nil {
		err = bosherr.WrapErrorf(err, "SetTimeWithNtpServers %s", stderr)
		return
	}
	return
}

func (p WindowsPlatform) SetupEphemeralDiskWithPath(devicePath string, desiredSwapSizeInBytes *uint64) (err error) {
	return
}

func (p WindowsPlatform) SetupRawEphemeralDisks(devices []boshsettings.DiskSettings) (err error) {
	return
}

func (p WindowsPlatform) SetupDataDir() error {
	return nil
}

func (p WindowsPlatform) SetupHomeDir() error {
	return nil
}

func (p WindowsPlatform) SetupTmpDir() error {
	boshTmpDir := p.dirProvider.TmpDir()

	err := p.fs.MkdirAll(boshTmpDir, tmpDirPermissions)
	if err != nil {
		return bosherr.WrapError(err, "Creating temp dir")
	}

	err = os.Setenv("TMP", boshTmpDir)
	if err != nil {
		return bosherr.WrapError(err, "Setting TMP")
	}

	err = os.Setenv("TEMP", boshTmpDir)
	if err != nil {
		return bosherr.WrapError(err, "Setting TEMP")
	}

	return nil
}

func (p WindowsPlatform) SetupLogDir() error {
	return nil
}

func (p WindowsPlatform) SetupBlobsDir() error {
	blobsDirPath := p.dirProvider.BlobsDir()
	err := p.fs.MkdirAll(blobsDirPath, blobsDirPermissions)
	if err != nil {
		return bosherr.WrapError(err, "Creating blobs dir")
	}
	return nil
}

func (p WindowsPlatform) SetupLoggingAndAuditing() error {
	return nil
}

func (p WindowsPlatform) MountPersistentDisk(diskSettings boshsettings.DiskSettings, mountPoint string) (err error) {
	return
}

func (p WindowsPlatform) UnmountPersistentDisk(diskSettings boshsettings.DiskSettings) (didUnmount bool, err error) {
	return
}

func (p WindowsPlatform) GetEphemeralDiskPath(diskSettings boshsettings.DiskSettings) string {
	return ""
}

func (p WindowsPlatform) GetFileContentsFromCDROM(filePath string) (contents []byte, err error) {
	return p.fs.ReadFile("D:/" + filePath)
}

func (p WindowsPlatform) GetFilesContentsFromDisk(diskPath string, fileNames []string) (contents [][]byte, err error) {
	return
}

func (p WindowsPlatform) MigratePersistentDisk(fromMountPoint, toMountPoint string) (err error) {
	return
}

func (p WindowsPlatform) IsMountPoint(path string) (string, bool, error) {
	return "", true, nil
}

func (p WindowsPlatform) IsPersistentDiskMounted(diskSettings boshsettings.DiskSettings) (bool, error) {
	return true, nil
}

func (p WindowsPlatform) IsPersistentDiskMountable(diskSettings boshsettings.DiskSettings) (bool, error) {
	return true, nil
}

func (p WindowsPlatform) StartMonit() (err error) {
	return
}

func (p WindowsPlatform) SetupMonitUser() (err error) {
	return
}

func (p WindowsPlatform) GetMonitCredentials() (username, password string, err error) {
	return
}

func (p WindowsPlatform) PrepareForNetworkingChange() error {
	return nil
}

func (p WindowsPlatform) CleanIPMacAddressCache(ip string) error {
	return nil
}

func (p WindowsPlatform) RemoveDevTools(packageFileListPath string) error {
	return nil
}

func (p WindowsPlatform) RemoveStaticLibraries(packageFileListPath string) error {
	return nil
}

func (p WindowsPlatform) GetDefaultNetwork() (boshsettings.Network, error) {
	return p.defaultNetworkResolver.GetDefaultNetwork()
}

func (p WindowsPlatform) GetHostPublicKey() (string, error) {
	return "", nil
}

func (p WindowsPlatform) DeleteARPEntryWithIP(ip string) error {
	_, _, _, err := p.cmdRunner.RunCommand("arp", "-d", ip)
	if err != nil {
		return bosherr.WrapError(err, "Deleting arp entry")
	}

	return nil
}

func (p WindowsPlatform) SetupRecordsJSONPermission(path string) error {
	return nil
}
<|endoftext|>