<commit_before>/*
 Copyright 2017 Crunchy Data Solutions, 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.
*/

// Crunchy Container Test
package cct

import (
    "context"
    "database/sql"
    "fmt"
    "path"
    "strings"
    "time"

    "github.com/docker/docker/api/types"
    "github.com/docker/docker/client"

    _ "github.com/lib/pq"
)

// returns the HostIP and Port reported by the service on 5432/tcp, which should always be postgresql
func pgHostFromContainer(
    docker *client.Client,
    containerId string) (host string, port string, err error) {

    inspect, err := docker.ContainerInspect(
        context.Background(), containerId)
    if err != nil {
        return
    }
    pb := inspect.HostConfig.PortBindings
    if pb == nil || len(pb) == 0 {
        err = fmt.Errorf(
            "Container network in an incomplete state; no PortBindings\n%#v\n",
            inspect.HostConfig)
        return
    }
    binding := inspect.HostConfig.PortBindings["5432/tcp"][0]

    host, port = binding.HostIP, binding.HostPort
    return
}

func isShutdownErr(err error) bool {
    return strings.HasPrefix(string(err.Error()),
        "pq: the database system is shutting down")
}

func isPasswordErr(err error) bool {
    return strings.HasPrefix(string(err.Error()),
        "pq: password authentication failed")
}

func isAcceptingConnectionString(conStr string) (ok bool, err error) {
    ok = false
    pg, _ := sql.Open("postgres", conStr)
    defer pg.Close()

    err = pg.Ping()
    if err != nil {
        switch {
        case isShutdownErr(err):
            return false, nil
        case isPasswordErr(err):
            return false, nil
        default:
            err := fmt.Errorf("Database Ping error\n%s\n", err.Error())
            return false, err
        }
    }

    ok = true
    return
}

// returns ok when container_setup script is not running
func isFinishedSetup(conStr string) (ok bool, err error) {
    ok = false
    pg, _ := sql.Open("postgres", conStr)
    defer pg.Close()

    query := `SELECT NOT EXISTS (
        SELECT 1 from pg_stat_activity
        WHERE application_name = 'container_setup');`

    err = pg.QueryRow(query).Scan(&ok)
    if err != nil {
        return
    }

    return
}

// returns pg_is_in_backup()
func isInBackup(conStr string) (ok bool, err error) {
    ok = false
    pg, _ := sql.Open("postgres", conStr)
    defer pg.Close()

    err = pg.QueryRow("SELECT pg_is_in_backup();").Scan(&ok)
    if err != nil {
        return
    }

    return
}

// assert a configurable parameter is set to value
func assertPostgresConf(
    conStr string,
    setting string,
    value string) (ok bool, foundval string, err error) {

    pg, _ := sql.Open("postgres", conStr)
    defer pg.Close()

    // SHOW command does not support $1 style variable replacement
    show := fmt.Sprintf("SHOW %s;", setting)

    err = pg.QueryRow(show).Scan(&foundval)
    if err != nil {
        return
    }

    ok = (foundval == value)
    return
}

// streams some vital columns from pg_stat_activity in tab form as they are retrieved
func pgStatActivity(conStr string) error {

    type activityrow struct {
        Pid int64 `json:"pid"`
        Database string `json:"database"`
        User string `json:"user"`
        ApplicationName string `json:"application_name"`
        State string `json:"state"`
        WaitEventType string `json:"wait_event_type"`
        WaitEvent string `json:"wait_event"`
        Query string `json:"query"`
        StartTime time.Time `json:"backend_start"`
    }

    pg, _ := sql.Open("postgres", conStr)
    defer pg.Close()

    query := `SELECT pid, datname, usename, application_name
        , state, coalesce(wait_event_type, ''), coalesce(wait_event, ''), query, backend_start
        from pg_stat_activity WHERE pid != pg_backend_pid();`

    rows, err := pg.Query(query)
    if err != nil {
        return err
    }

    for rows.Next() {
        var r activityrow
        err = rows.Scan(&r.Pid, &r.Database, &r.User, &r.ApplicationName,
            &r.State, &r.WaitEventType, &r.WaitEvent, &r.Query, &r.StartTime)
        if err != nil {
            return err
        }
        fmt.Printf("%+v\n", r)
    }

    return nil
}

// returns pg_is_in_backup()
func isVacuuming(conStr string) (ok bool, err error) {
    ok = false
    pg, _ := sql.Open("postgres", conStr)
    defer pg.Close()

    query := `SELECT EXISTS (SELECT * from pg_stat_activity WHERE query like 'VACUUM%');`
    err = pg.QueryRow(query).Scan(&ok)
    if err != nil {
        return
    }

    return
}

func waitForVacuum(
    conStr string,
    timeoutSeconds int64) (err error) {

    fmt.Printf("Waiting maximum %d seconds for VACUUM", timeoutSeconds)

    escape := func() (bool, error) {
        return false, nil
    }
    condition1 := func() (bool, error) {
        v, err := isVacuuming(conStr)
        return ! v, err
    }
    var pollingMilliseconds int64 = 500
    if ok, err := timeoutOrReady(
        timeoutSeconds,
        escape,
        []func() (bool, error){condition1},
        pollingMilliseconds); err != nil {
        return err
    } else if ! ok {
        return fmt.Errorf("Timeout expired and VACUUM has not finished")
    }

    return
}

// print some basics on table vacuum & analyze
func pgTableStat(conStr string, tableName string) error {

    type tablestatrow struct {
        Relid int64 `json:"relid"`
        SchemaName string `json:"schemaname"`
        RelName string `json:"relname"`
        RowEstimate int64 `json:"row_estimate"`
        LastVacuum time.Time `json:"last_vacuum"`
        LastAnalyze time.Time `json:"last_analyze"`
        VacuumCount int64 `json:"vacuum_count"`
        AnalyzeCount int64 `json:"analyze_count"`
    }

    pg, _ := sql.Open("postgres", conStr)
    defer pg.Close()

    query := `SELECT relid, schemaname, relname, n_live_tup
        , coalesce(last_vacuum, '2000-01-01'), coalesce(last_analyze, '2000-01-01')
        , vacuum_count, analyze_count
        FROM pg_stat_all_tables WHERE relname = $1;`

    rows, err := pg.Query(query, tableName)
    if err != nil {
        return err
    }

    for rows.Next() {
        var r tablestatrow
        err = rows.Scan(&r.Relid, &r.SchemaName, &r.RelName, &r.RowEstimate,
            &r.LastVacuum, &r.LastAnalyze, &r.VacuumCount, &r.AnalyzeCount)
        if err != nil {
            return err
        }
        fmt.Printf("%+v\n", r)
    }

    return nil
}

// CREATE, INSERT INTO, DROP TABLE
func relCreateInsertDrop(conStr string, temporary bool) (ok bool, err error) {
    ok = false

    pg, _ := sql.Open("postgres", conStr)

    defer pg.Close()

    var create string
    if temporary {
        create = "CREATE TEMPORARY TABLE"
    } else {
        create = "CREATE TABLE"
    }
    create += ` some_table(some_id integer NOT NULL PRIMARY KEY);`
    insert := `INSERT INTO some_table(some_id) VALUES(1), (2), (3);`
    drop := `DROP TABLE some_table;`

    _, err = pg.Exec(create)
    if err != nil {
        err = fmt.Errorf("ON CREATE TABLE\n%s", err.Error())
        return
    }

    if result, e := pg.Exec(insert); e != nil {
        err = fmt.Errorf("ON INSERT\n%s", e.Error())
        return
    } else {
        rc, e := result.RowsAffected();
        if e != nil || rc != 3 {
            err = fmt.Errorf(
                "Error or rowcount mismatch. Expected rc 3, got %d\n%s", rc, e.Error())
            return
        }
    }
    _, err = pg.Exec(drop)
    if err != nil {
        err = fmt.Errorf("ON DROP TABLE\n%s", err.Error())
        return
    }

    ok = true
    return
}

// does role exist on specified host?
func roleExists(conStr string, roleName string) (ok bool, err error) {
    pg, _ := sql.Open("postgres", conStr)
    defer pg.Close()

    query := `SELECT EXISTS (SELECT 1 from pg_roles WHERE rolname = $1);`

    err = pg.QueryRow(query, roleName).Scan(&ok)
    if err != nil {
        return
    }

    return
}

// does database exist on specified host?
func dbExists(conStr string, dbName string) (ok bool, err error) {
    pg, _ := sql.Open("postgres", conStr)
    defer pg.Close()

    query := `SELECT EXISTS (SELECT 1 from pg_database WHERE datname = $1);`

    err = pg.QueryRow(query, dbName).Scan(&ok)
    if err != nil {
        return
    }

    return
}

// wraps pg_isready via docker exec
func isPostgresReady(
    docker *client.Client,
    containerId string) (ok bool, err error) {

    ok = false

    pgroot, err := envValueFromContainer(docker, containerId, "PGROOT")
    if err != nil {
        return
    }
    cmd := []string{path.Join(pgroot, "bin/pg_isready")}

    execConf := types.ExecConfig{
        User: "postgres",
        Detach: true,
        Cmd: cmd,
    }
    execId, err := docker.ContainerExecCreate(
        context.Background(), containerId, execConf)
    if err != nil {
        return
    }

    err = docker.ContainerExecStart(
        context.Background(), execId.ID, types.ExecStartCheck{})
    if err != nil {
        return
    }

    // allow pg_isready to complete
    doneC := make(chan bool)
    timer := time.AfterFunc(time.Second * 2, func() {
        close(doneC)
    })

    ticker := time.NewTicker(time.Millisecond * 100)
    defer ticker.Stop()

    tick := func() (bool, error) {
        inspect, err := docker.ContainerExecInspect(
            context.Background(), execId.ID)

        if inspect.Running || err != nil {
            return false, err
        }

        close(doneC)
        return (inspect.ExitCode == 0), nil
    }

    for {
        select {
        case <- ticker.C:
            ok, err = tick()
            if err != nil {
                close(doneC)
            }
        case <- doneC:
            _ = timer.Stop()
            return
        }
    }
}

func waitForPostgresContainer(
    docker *client.Client,
    name string,
    timeoutSeconds int64) (containerId string, err error) {

    if c, err := ContainerFromName(docker, name); err != nil {
        return "", err
    } else {
        containerId = c.ID
    }

    conStr, err := buildConnectionString(docker, containerId, "postgres", "postgres")
    if err != nil {
        return "", fmt.Errorf("Connection String error\n%s\n", err.Error())
    }

    escape := func () (bool, error) {
        return isContainerDead(docker, containerId)
    }
    condition1 := func () (bool, error) {
        return isContainerRunning(docker, containerId)
    }
    condition2 := func () (bool, error) {
        if ok, err := isPostgresReady(docker, containerId); ! ok || err != nil {
            return false, err
        }
        return isAcceptingConnectionString(conStr)
    }
    condition3 := func () (bool, error) {
        return isFinishedSetup(conStr)
    }

    var ok bool
    var pollingMilliseconds int64 = 750
    if ok, err = timeoutOrReady(
        timeoutSeconds,
        escape,
        []func() (bool, error){condition1, condition2, condition3},
        pollingMilliseconds); err != nil {
        return
    } else if ! ok {
        return containerId, fmt.Errorf("Container stopped; or timeout expired, and container is not ready.")
    }

    // the container receives a stop at the end of setup. Make sure we haven't missed this, and let the db start again if we have.
    time.Sleep(1 * time.Second)

    if ok, err = timeoutOrReady(
        timeoutSeconds,
        escape,
        []func() (bool, error) {condition1, condition2, condition3},
        pollingMilliseconds); err != nil {
        return
    } else if ! ok {
        return containerId, fmt.Errorf("Container stopped; or timeout expired, and container is not ready.")
    }

    return
}

// Waits maximum of timeout seconds to see if all conditions are true.
// Will escape if escape is true. Returns false if timeout expired without meeting conditions
func timeoutOrReady(
    timeoutSeconds int64,
    escape func() (bool, error),
    conditions []func() (bool, error),
    pollingIntervalMilliseconds int64) (ready bool, err error) {

    ready = false

    doneC := make(chan bool)

    timer := time.AfterFunc(time.Second * time.Duration(timeoutSeconds), func() {
        close(doneC)
    })

    ticker := time.NewTicker(time.Millisecond * time.Duration(pollingIntervalMilliseconds))
    defer ticker.Stop()

    tick := func() error {
        fmt.Printf(".")
        if esc, err := escape(); esc || err != nil {
            fmt.Println("Escape!")
            close(doneC)
            return err
        }

        for _, f := range conditions {
            if ok, err := f(); err != nil || ! ok {
                return err
            }
        }

        fmt.Printf("\n")
        ready = true
        close(doneC)
        return nil
    }

    for {
        select {
        case <- ticker.C:
            err = tick()
            if err != nil {
                close(doneC)
            }
        case <- doneC:
            _ = timer.Stop()
            return
        }
    }
}
<commit_msg>Add comments<commit_after>/*
 Copyright 2017 Crunchy Data Solutions, 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.
*/

// Crunchy Container Test
package cct

import (
    "context"
    "database/sql"
    "fmt"
    "path"
    "strings"
    "time"

    "github.com/docker/docker/api/types"
    "github.com/docker/docker/client"

    _ "github.com/lib/pq"
)

// returns the HostIP and Port reported by the service on 5432/tcp, which should always be postgresql
func pgHostFromContainer(
    docker *client.Client,
    containerId string) (host string, port string, err error) {

    inspect, err := docker.ContainerInspect(
        context.Background(), containerId)
    if err != nil {
        return
    }
    pb := inspect.HostConfig.PortBindings
    if pb == nil || len(pb) == 0 {
        err = fmt.Errorf(
            "Container network in an incomplete state; no PortBindings\n%#v\n",
            inspect.HostConfig)
        return
    }
    binding := inspect.HostConfig.PortBindings["5432/tcp"][0]

    host, port = binding.HostIP, binding.HostPort
    return
}

func isShutdownErr(err error) bool {
    return strings.HasPrefix(string(err.Error()),
        "pq: the database system is shutting down")
}

func isPasswordErr(err error) bool {
    return strings.HasPrefix(string(err.Error()),
        "pq: password authentication failed")
}

func isAcceptingConnectionString(conStr string) (ok bool, err error) {
    ok = false
    pg, _ := sql.Open("postgres", conStr)
    defer pg.Close()

    err = pg.Ping()
    if err != nil {
        switch {
        case isShutdownErr(err):
            return false, nil
        case isPasswordErr(err):
            return false, nil
        default:
            err := fmt.Errorf("Database Ping error\n%s\n", err.Error())
            return false, err
        }
    }

    ok = true
    return
}

// returns ok when container_setup script is not running
func isFinishedSetup(conStr string) (ok bool, err error) {
    ok = false
    pg, _ := sql.Open("postgres", conStr)
    defer pg.Close()

    query := `SELECT NOT EXISTS (
        SELECT 1 from pg_stat_activity
        WHERE application_name = 'container_setup');`

    err = pg.QueryRow(query).Scan(&ok)
    if err != nil {
        return
    }

    return
}

// returns pg_is_in_backup()
func isInBackup(conStr string) (ok bool, err error) {
    ok = false
    pg, _ := sql.Open("postgres", conStr)
    defer pg.Close()

    err = pg.QueryRow("SELECT pg_is_in_backup();").Scan(&ok)
    if err != nil {
        return
    }

    return
}

// assert a configurable parameter is set to value
func assertPostgresConf(
    conStr string,
    setting string,
    value string) (ok bool, foundval string, err error) {

    pg, _ := sql.Open("postgres", conStr)
    defer pg.Close()

    // SHOW command does not support $1 style variable replacement
    show := fmt.Sprintf("SHOW %s;", setting)

    err = pg.QueryRow(show).Scan(&foundval)
    if err != nil {
        return
    }

    ok = (foundval == value)
    return
}

// streams some vital columns from pg_stat_activity in tab form as they are retrieved
func pgStatActivity(conStr string) error {

    type activityrow struct {
        Pid int64 `json:"pid"`
        Database string `json:"database"`
        User string `json:"user"`
        ApplicationName string `json:"application_name"`
        State string `json:"state"`
        WaitEventType string `json:"wait_event_type"`
        WaitEvent string `json:"wait_event"`
        Query string `json:"query"`
        StartTime time.Time `json:"backend_start"`
    }

    pg, _ := sql.Open("postgres", conStr)
    defer pg.Close()

    query := `SELECT pid, datname, usename, application_name
        , state, coalesce(wait_event_type, ''), coalesce(wait_event, ''), query, backend_start
        from pg_stat_activity WHERE pid != pg_backend_pid();`

    rows, err := pg.Query(query)
    if err != nil {
        return err
    }

    for rows.Next() {
        var r activityrow
        err = rows.Scan(&r.Pid, &r.Database, &r.User, &r.ApplicationName,
            &r.State, &r.WaitEventType, &r.WaitEvent, &r.Query, &r.StartTime)
        if err != nil {
            return err
        }
        fmt.Printf("%+v\n", r)
    }

    return nil
}

// returns pg_is_in_backup()
func isVacuuming(conStr string) (ok bool, err error) {
    ok = false
    pg, _ := sql.Open("postgres", conStr)
    defer pg.Close()

    query := `SELECT EXISTS (SELECT * from pg_stat_activity WHERE query like 'VACUUM%');`
    err = pg.QueryRow(query).Scan(&ok)
    if err != nil {
        return
    }

    return
}

func waitForVacuum(
    conStr string,
    timeoutSeconds int64) (err error) {

    fmt.Printf("Waiting maximum %d seconds for VACUUM", timeoutSeconds)

    escape := func() (bool, error) {
        return false, nil
    }
    condition1 := func() (bool, error) {
        v, err := isVacuuming(conStr)
        return ! v, err
    }
    var pollingMilliseconds int64 = 500
    if ok, err := timeoutOrReady(
        timeoutSeconds,
        escape,
        []func() (bool, error){condition1},
        pollingMilliseconds); err != nil {
        return err
    } else if ! ok {
        return fmt.Errorf("Timeout expired and VACUUM has not finished")
    }

    return
}

// print some basics on table vacuum & analyze
func pgTableStat(conStr string, tableName string) error {

    type tablestatrow struct {
        Relid int64 `json:"relid"`
        SchemaName string `json:"schemaname"`
        RelName string `json:"relname"`
        RowEstimate int64 `json:"row_estimate"`
        LastVacuum time.Time `json:"last_vacuum"`
        LastAnalyze time.Time `json:"last_analyze"`
        VacuumCount int64 `json:"vacuum_count"`
        AnalyzeCount int64 `json:"analyze_count"`
    }

    pg, _ := sql.Open("postgres", conStr)
    defer pg.Close()

    query := `SELECT relid, schemaname, relname, n_live_tup
        , coalesce(last_vacuum, '2000-01-01'), coalesce(last_analyze, '2000-01-01')
        , vacuum_count, analyze_count
        FROM pg_stat_all_tables WHERE relname = $1;`

    rows, err := pg.Query(query, tableName)
    if err != nil {
        return err
    }

    for rows.Next() {
        var r tablestatrow
        err = rows.Scan(&r.Relid, &r.SchemaName, &r.RelName, &r.RowEstimate,
            &r.LastVacuum, &r.LastAnalyze, &r.VacuumCount, &r.AnalyzeCount)
        if err != nil {
            return err
        }
        fmt.Printf("%+v\n", r)
    }

    return nil
}

// CREATE, INSERT INTO, DROP TABLE
func relCreateInsertDrop(conStr string, temporary bool) (ok bool, err error) {
    ok = false

    pg, _ := sql.Open("postgres", conStr)

    defer pg.Close()

    var create string
    if temporary {
        create = "CREATE TEMPORARY TABLE"
    } else {
        create = "CREATE TABLE"
    }
    create += ` some_table(some_id integer NOT NULL PRIMARY KEY);`
    insert := `INSERT INTO some_table(some_id) VALUES(1), (2), (3);`
    drop := `DROP TABLE some_table;`

    _, err = pg.Exec(create)
    if err != nil {
        err = fmt.Errorf("ON CREATE TABLE\n%s", err.Error())
        return
    }

    if result, e := pg.Exec(insert); e != nil {
        err = fmt.Errorf("ON INSERT\n%s", e.Error())
        return
    } else {
        rc, e := result.RowsAffected();
        if e != nil || rc != 3 {
            err = fmt.Errorf(
                "Error or rowcount mismatch. Expected rc 3, got %d\n%s", rc, e.Error())
            return
        }
    }
    _, err = pg.Exec(drop)
    if err != nil {
        err = fmt.Errorf("ON DROP TABLE\n%s", err.Error())
        return
    }

    ok = true
    return
}

// does role exist on specified host?
func roleExists(conStr string, roleName string) (ok bool, err error) {
    pg, _ := sql.Open("postgres", conStr)
    defer pg.Close()

    query := `SELECT EXISTS (SELECT 1 from pg_roles WHERE rolname = $1);`

    err = pg.QueryRow(query, roleName).Scan(&ok)
    if err != nil {
        return
    }

    return
}

// does database exist on specified host?
func dbExists(conStr string, dbName string) (ok bool, err error) {
    pg, _ := sql.Open("postgres", conStr)
    defer pg.Close()

    query := `SELECT EXISTS (SELECT 1 from pg_database WHERE datname = $1);`

    err = pg.QueryRow(query, dbName).Scan(&ok)
    if err != nil {
        return
    }

    return
}

// wraps pg_isready via docker exec
func isPostgresReady(
    docker *client.Client,
    containerId string) (ok bool, err error) {

    ok = false

    pgroot, err := envValueFromContainer(docker, containerId, "PGROOT")
    if err != nil {
        return
    }
    cmd := []string{path.Join(pgroot, "bin/pg_isready")}

    execConf := types.ExecConfig{
        User: "postgres",
        Detach: true,
        Cmd: cmd,
    }
    execId, err := docker.ContainerExecCreate(
        context.Background(), containerId, execConf)
    if err != nil {
        return
    }

    err = docker.ContainerExecStart(
        context.Background(), execId.ID, types.ExecStartCheck{})
    if err != nil {
        return
    }

    // allow pg_isready to complete
    doneC := make(chan bool)
    timer := time.AfterFunc(time.Second * 2, func() {
        close(doneC)
    })

    ticker := time.NewTicker(time.Millisecond * 100)
    defer ticker.Stop()

    tick := func() (bool, error) {
        inspect, err := docker.ContainerExecInspect(
            context.Background(), execId.ID)

        if inspect.Running || err != nil {
            return false, err
        }

        close(doneC)
        return (inspect.ExitCode == 0), nil
    }

    for {
        select {
        case <- ticker.C:
            ok, err = tick()
            if err != nil {
                close(doneC)
            }
        case <- doneC:
            _ = timer.Stop()
            return
        }
    }
}

func waitForPostgresContainer(
    docker *client.Client,
    name string,
    timeoutSeconds int64) (containerId string, err error) {

    if c, err := ContainerFromName(docker, name); err != nil {
        return "", err
    } else {
        containerId = c.ID
    }

    conStr, err := buildConnectionString(docker, containerId, "postgres", "postgres")
    if err != nil {
        return "", fmt.Errorf("Connection String error\n%s\n", err.Error())
    }

    escape := func () (bool, error) {
        return isContainerDead(docker, containerId)
    }
    condition1 := func () (bool, error) {
        return isContainerRunning(docker, containerId)
    }
    condition2 := func () (bool, error) {
        if ok, err := isPostgresReady(docker, containerId); ! ok || err != nil {
            return false, err
        }
        return isAcceptingConnectionString(conStr)
    }
    condition3 := func () (bool, error) {
        return isFinishedSetup(conStr)
    }

    var ok bool
    var pollingMilliseconds int64 = 500
    if ok, err = timeoutOrReady(
        timeoutSeconds,
        escape,
        []func() (bool, error){condition1, condition2, condition3},
        pollingMilliseconds); err != nil {
        return
    } else if ! ok {
        return containerId, fmt.Errorf("Container stopped; or timeout expired, and container is not ready.")
    }

    // the container receives a stop at the end of setup. Make sure we haven't missed this, and let the db start again if we have.
    time.Sleep(1 * time.Second)

    if ok, err = timeoutOrReady(
        timeoutSeconds,
        escape,
        []func() (bool, error) {condition1, condition2, condition3},
        pollingMilliseconds); err != nil {
        return
    } else if ! ok {
        return containerId, fmt.Errorf("Container stopped; or timeout expired, and container is not ready.")
    }

    return
}

// Waits maximum of timeout seconds, or passes when all conditions are true, or will escape if escape function returns true. Returns false if timeout expired without meeting conditions.
func timeoutOrReady(
    timeoutSeconds int64,
    escape func() (bool, error),
    conditions []func() (bool, error),
    pollingIntervalMilliseconds int64) (ready bool, err error) {

    ready = false

    doneC := make(chan bool)

    timer := time.AfterFunc(time.Second * time.Duration(timeoutSeconds), func() {
        close(doneC)
    })

    ticker := time.NewTicker(time.Millisecond * time.Duration(pollingIntervalMilliseconds))
    defer ticker.Stop()

    tick := func() error {
        fmt.Printf(".")
        if esc, err := escape(); esc || err != nil {
            fmt.Println("Escape!")
            close(doneC)
            return err
        }

        for _, f := range conditions {
            if ok, err := f(); err != nil || ! ok {
                return err
            }
        }

        fmt.Printf("\n")
        ready = true
        close(doneC)
        return nil
    }

    for {
        select {
        case <- ticker.C:
            err = tick()
            if err != nil {
                close(doneC)
            }
        case <- doneC:
            _ = timer.Stop()
            return
        }
    }
}
<|endoftext|>


<commit_before>package delta

import (
	"bytes"
	"html/template"
	"strconv"
)

// DiffSolution contains a set of lines, where each element of
// lines comprises the left and right line, and whether the change
// was from A or B.
type DiffSolution struct {
	lines [][3]string
}

func (d *DiffSolution) addLineA(a string) {
	d.addLine(a, "", LineFromA)
}

func (d *DiffSolution) addLineB(b string) {
	d.addLine("", b, LineFromB)
}

func (d *DiffSolution) addLine(a, b string, l lineSource) {
	d.lines = append(d.lines, [3]string{a, b, string(l)})
}

func (d *DiffSolution) Raw() [][3]string {
	return d.lines
}

var tpl = template.Must(template.New("div").Parse("
{{.Contents}}
\n"))

type div struct {
	Classes  string
	Contents interface{}
}

// HTML builds up a html-friendly diff.
func (d *DiffSolution) HTML() string {
	// closest contains the number of lines to the next changed lines
	maxContext := 10
	maxContext++ // + 1 for lines to hide
	nextChange := make([]int, len(d.lines))
	lastChangedLine := len(d.lines) + 10
	for i := len(d.lines) - 1; i > -1; i-- {
		switch lineSource(d.lines[i][2]) {
		case LineFromA, LineFromB, LineFromBothEdit:
			lastChangedLine = i
		case LineFromBoth:
			if d.lines[i][0] != d.lines[i][1] {
				lastChangedLine = i
			}
		}
		nextChange[i] = lastChangedLine - i
		if nextChange[i] > maxContext {
			nextChange[i] = maxContext
		}
	}

	li, ri := 0, 0
	lg := bytes.NewBufferString("
\n")
	rg := bytes.NewBufferString("
\n")
	lb := bytes.NewBufferString("

\n")
	rb := bytes.NewBufferString("

\n")
	lastChangedLine = -maxContext
	for i, l := range d.lines {
		ls := lineSource(l[2])
		closestChange := 0
		if ls == LineFromBoth && l[0] == l[1] {
			closestChange = i - lastChangedLine
			if closestChange > nextChange[i] {
				closestChange = nextChange[i]
			}
		} else {
			lastChangedLine = i
		}
		lc := "line-context-" + strconv.Itoa(closestChange) + " line "
		if ls == LineFromA {
			li++
			must(tpl.Execute(lg, div{lc + "line-a line-addition", li}))
			must(tpl.Execute(rg, div{lc + "line-b", ""}))
			must(tpl.Execute(lb, div{lc + "line-a line-addition", l[0]}))
			must(tpl.Execute(rb, div{lc + "line-b", ""}))
		} else if ls == LineFromB {
			ri++
			must(tpl.Execute(lg, div{lc + "line-a", ""}))
			must(tpl.Execute(rg, div{lc + "line-b line-addition", ri}))
			must(tpl.Execute(lb, div{lc + "line-a", ""}))
			must(tpl.Execute(rb, div{lc + "line-b line-addition", l[1]}))
		} else if ls == LineFromBothEdit {
			li++
			ri++
			must(tpl.Execute(lg, div{lc + "line-a line-mismatch", li}))
			must(tpl.Execute(rg, div{lc + "line-b line-mismatch", ri}))
			must(tpl.Execute(lb, div{lc + "line-a line-mismatch", l[0]}))
			must(tpl.Execute(rb, div{lc + "line-b line-mismatch", l[1]}))
		} else if l[0] != l[1] {
			li++
			ri++
			must(tpl.Execute(lg, div{lc + "line-a line-ws", li}))
			must(tpl.Execute(rg, div{lc + "line-b line-ws", ri}))
			must(tpl.Execute(lb, div{lc + "line-a line-ws", l[0]}))
			must(tpl.Execute(rb, div{lc + "line-b line-ws", l[1]}))
		} else if ls == LineFromBoth {
			li++
			ri++
			must(tpl.Execute(lg, div{lc + "line-a line-match", li}))
			must(tpl.Execute(rg, div{lc + "line-b line-match", ri}))
			must(tpl.Execute(lb, div{lc + "line-a line-match", l[0]}))
			must(tpl.Execute(rb, div{lc + "line-b line-match", l[1]}))
		}
	}

	lg.WriteString("
")
	rg.WriteString("
")
	lb.WriteString("

")
	rb.WriteString("

")
	if li == 0 {
		return rg.String() + rb.String()
	}
	if ri == 0 {
		return lg.String() + lb.String()
	}
	return lg.String() + lb.String() + rg.String() + rb.String()
}

func must(err error) {
	if err != nil {
		panic(err)
	}
}
<commit_msg>Annotate tabs for html.<commit_after>package delta

import (
	"bytes"
	"html/template"
	"strconv"
	"strings"
)

// DiffSolution contains a set of lines, where each element of
// lines comprises the left and right line, and whether the change
// was from A or B.
type DiffSolution struct {
	lines [][3]string
}

func (d *DiffSolution) addLineA(a string) {
	d.addLine(a, "", LineFromA)
}

func (d *DiffSolution) addLineB(b string) {
	d.addLine("", b, LineFromB)
}

func (d *DiffSolution) addLine(a, b string, l lineSource) {
	d.lines = append(d.lines, [3]string{a, b, string(l)})
}

func (d *DiffSolution) Raw() [][3]string {
	return d.lines
}

var tpl = template.Must(template.New("div").Parse("
{{.Contents}}
\n"))

type div struct {
	Classes  string
	Contents interface{}
}

// HTML builds up a html-friendly diff.
func (d *DiffSolution) HTML() string {
	// closest contains the number of lines to the next changed lines
	maxContext := 10
	maxContext++ // + 1 for lines to hide
	nextChange := make([]int, len(d.lines))
	lastChangedLine := len(d.lines) + 10
	for i := len(d.lines) - 1; i > -1; i-- {
		switch lineSource(d.lines[i][2]) {
		case LineFromA, LineFromB, LineFromBothEdit:
			lastChangedLine = i
		case LineFromBoth:
			if d.lines[i][0] != d.lines[i][1] {
				lastChangedLine = i
			}
		}
		nextChange[i] = lastChangedLine - i
		if nextChange[i] > maxContext {
			nextChange[i] = maxContext
		}
	}

	li, ri := 0, 0
	lg := bytes.NewBufferString("
\n")
	rg := bytes.NewBufferString("
\n")
	lb := bytes.NewBufferString("

\n")
	rb := bytes.NewBufferString("

\n")
	lastChangedLine = -maxContext
	for i, l := range d.lines {
		ls := lineSource(l[2])
		closestChange := 0
		if ls == LineFromBoth && l[0] == l[1] {
			closestChange = i - lastChangedLine
			if closestChange > nextChange[i] {
				closestChange = nextChange[i]
			}
		} else {
			lastChangedLine = i
		}
		lc := "line-context-" + strconv.Itoa(closestChange) + " line "
		if ls == LineFromA {
			li++
			must(tpl.Execute(lg, div{lc + "line-a line-addition", li}))
			must(tpl.Execute(rg, div{lc + "line-b", ""}))
			must(tpl.Execute(lb, div{lc + "line-a line-addition", l[0]}))
			must(tpl.Execute(rb, div{lc + "line-b", ""}))
		} else if ls == LineFromB {
			ri++
			must(tpl.Execute(lg, div{lc + "line-a", ""}))
			must(tpl.Execute(rg, div{lc + "line-b line-addition", ri}))
			must(tpl.Execute(lb, div{lc + "line-a", ""}))
			must(tpl.Execute(rb, div{lc + "line-b line-addition", l[1]}))
		} else if ls == LineFromBothEdit {
			li++
			ri++
			must(tpl.Execute(lg, div{lc + "line-a line-mismatch", li}))
			must(tpl.Execute(rg, div{lc + "line-b line-mismatch", ri}))
			must(tpl.Execute(lb, div{lc + "line-a line-mismatch", l[0]}))
			must(tpl.Execute(rb, div{lc + "line-b line-mismatch", l[1]}))
		} else if l[0] != l[1] {
			li++
			ri++
			must(tpl.Execute(lg, div{lc + "line-a line-ws", li}))
			must(tpl.Execute(rg, div{lc + "line-b line-ws", ri}))
			must(tpl.Execute(lb, div{lc + "line-a line-ws", l[0]}))
			must(tpl.Execute(rb, div{lc + "line-b line-ws", l[1]}))
		} else if ls == LineFromBoth {
			li++
			ri++
			must(tpl.Execute(lg, div{lc + "line-a line-match", li}))
			must(tpl.Execute(rg, div{lc + "line-b line-match", ri}))
			must(tpl.Execute(lb, div{lc + "line-a line-match", l[0]}))
			must(tpl.Execute(rb, div{lc + "line-b line-match", l[1]}))
		}
	}

	lg.WriteString("
")
	rg.WriteString("
")
	lb.WriteString("

")
	rb.WriteString("

")
	if li == 0 {
		return rg.String() + rb.String()
	}
	if ri == 0 {
		return lg.String() + lb.String()
	}
	lbs := strings.Replace(lb.String(), "\t", "\t", -1)
	rbs := strings.Replace(rb.String(), "\t", "\t", -1)
	return lg.String() + lbs + rg.String() + rbs
}

func must(err error) {
	if err != nil {
		panic(err)
	}
}
<|endoftext|>


<commit_before>// Copyright 2012, Hailiang Wang. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

/*
A complete example using this package:
	package main

	import (
		"github.com/hailiang/gosocks"
		"fmt"
		"net/http"
		"io/ioutil"
	)

	func main() {
		dialSocksProxy := socks.DialSocksProxy(socks.SOCKS5, "127.0.0.1:1080")
		tr := &http.Transport{Dial: dialSocksProxy}
		httpClient := &http.Client{Transport: tr}

		bodyText, err := TestHttpsGet(httpClient, "https://github.com/about")
		if err != nil {
			fmt.Println(err.Error())
		}
		fmt.Print(bodyText)
	}

	func TestHttpsGet(c *http.Client, url string) (bodyText string, err error) {
		resp, err := c.Get(url)
		if err != nil { return }
		defer resp.Body.Close()

		body, err := ioutil.ReadAll(resp.Body)
		if err != nil { return }
		bodyText = string(body)
		return
	}
*/
package socks
import (
	"fmt"
	"net"
	"strconv"
	"errors"
)

// Constants to choose which version of SOCKS protocol to use.
const (
	SOCKS4	= 1
	SOCKS4A	= 2
	SOCKS5	= 3
)

// DialSocksProxy returns the dial function to be used in http.Transport object.
// Argument socksType should be one of SOCKS4, SOCKS4A and SOCKS5.
// Argument proxy should be in this format "127.0.0.1:1080".
func DialSocksProxy(socksType int, proxy string) func(string, string) (net.Conn, error) {
	if socksType == SOCKS5 {
		return func (_, targetAddr string) (conn net.Conn, err error) {
			return dialSocks5(proxy, targetAddr)
		}
	}

	// SOCKS4, SOCKS4A
	return func (_, targetAddr string) (conn net.Conn, err error) {
		return dialSocks4(socksType, proxy, targetAddr)
	}
}

func dialSocks5(proxy, targetAddr string) (conn net.Conn, err error) {
	// dial TCP
	conn, err = net.Dial("tcp", proxy)
	if err != nil { return }

	// version identifier/method selection request
	req := []byte{
		5,	// version number
		1,	// number of methods
		0,	// method 0: no authentication (only anonymous access supported for now)
	}
	resp, err := sendReceive(conn, req)
	if err != nil {
		return
	} else if len(resp) != 2 {
		err = errors.New("Server does not respond properly.")
	} else if resp[0] != 5 {
		err = errors.New("Server does not support Socks 5.")
	} else if resp[1] != 0 {	// no auth
		err = errors.New("socks method negotiation failed.")
		return
	}

	// detail request
	host, port, err := splitHostPort(targetAddr)
	req = []byte{
		5,	// version number
		1,	// connect command
		0,	// reserved, must be zero
		3,	// address type, 3 means domain name
		byte(len(host)), // address length
	}
	req = append(req, []byte(host)...)
	req = append(req, []byte{
		byte(port >> 8),	// higher byte of destination port
		byte(port),			// lower byte of destination port (big endian)
	}...)
	resp, err = sendReceive(conn, req)
	if err != nil {
		return
	} else if len(resp) != 10 {
		err = errors.New("Server does not respond properly.")
	} else if resp[1] != 0 {
		err = errors.New("Can't complete SOCKS5 connection.")
	}

	return
}

func dialSocks4(socksType int, proxy, targetAddr string) (conn net.Conn, err error) {
	// dial TCP
	conn, err = net.Dial("tcp", proxy)
	if err != nil { return }

	// connection request
	host, port, err := splitHostPort(targetAddr)
	if err != nil { return }
	ip := net.IPv4(0, 0, 0, 1)
	if socksType == SOCKS4 {
		ip, err = lookupIP(host)
		if err != nil { return }
	}
	req := []byte{
		4,							// version number
		1,							// command CONNECT
		byte(port >> 8),			// higher byte of destination port
		byte(port),					// lower byte of destination port (big endian)
		ip[0], ip[1], ip[2], ip[3],	// special invalid IP address to indicate the host name is provided
		0,							// user id is empty, anonymous proxy only
	}
	if socksType == SOCKS4A {
		req = append(req, []byte(host + "\x00")...)
	}

	resp, err := sendReceive(conn, req)
	if err != nil {
		return
	} else if len(resp) != 8 {
			err = errors.New("Server does not respond properly.")
	}
	switch  resp[1] {
		case 90:
			// request granted
		case 91:
			err = errors.New("Socks connection request rejected or failed.")
		case 92:
			err = errors.New("Socks connection request rejected becasue SOCKS server cannot connect to identd on the client.")
		case 93:
			err = errors.New("Socks connection request rejected because the client program and identd report different user-ids.")
		default:
			err = errors.New("Socks connection request failed, unknown error.")
	}
	return
}

func sendReceive(conn net.Conn, req []byte) (resp []byte, err error) {
	_, err = conn.Write(req)
	if err != nil { return }
	resp, err = readAll(conn)
	return
}

func readAll(conn net.Conn) (resp []byte, err error) {
	resp = make([]byte, 1024)
	n, err := conn.Read(resp)
	resp = resp[:n]
	return
}

func lookupIP(host string) (ip net.IP, err error) {
	ips, err := net.LookupIP(host)
	if err != nil { return }
	if len(ips) == 0 {
		err = errors.New(fmt.Sprintf("Cannot resolve host: %s.", host))
		return
	}
	ip = ips[0].To4()
	if len(ip) != net.IPv4len {
		fmt.Println(len(ip), ip)
		err = errors.New("IPv6 is not supported by SOCKS4.")
		return
	}
	return
}

func splitHostPort(addr string) (host string, port uint16, err error) {
	host, portStr, err := net.SplitHostPort(addr)
	portInt, err := strconv.ParseUint(portStr, 10, 16)
	port = uint16(portInt)
	return
}
<commit_msg>Using iota instread of numbers to make code cleaner.<commit_after>// Copyright 2012, Hailiang Wang. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

/*
A complete example using this package:
	package main

	import (
		"github.com/hailiang/gosocks"
		"fmt"
		"net/http"
		"io/ioutil"
	)

	func main() {
		dialSocksProxy := socks.DialSocksProxy(socks.SOCKS5, "127.0.0.1:1080")
		tr := &http.Transport{Dial: dialSocksProxy}
		httpClient := &http.Client{Transport: tr}

		bodyText, err := TestHttpsGet(httpClient, "https://github.com/about")
		if err != nil {
			fmt.Println(err.Error())
		}
		fmt.Print(bodyText)
	}

	func TestHttpsGet(c *http.Client, url string) (bodyText string, err error) {
		resp, err := c.Get(url)
		if err != nil { return }
		defer resp.Body.Close()

		body, err := ioutil.ReadAll(resp.Body)
		if err != nil { return }
		bodyText = string(body)
		return
	}
*/
package socks
import (
	"fmt"
	"net"
	"strconv"
	"errors"
)

// Constants to choose which version of SOCKS protocol to use.
const (
	SOCKS4	= iota
	SOCKS4A
	SOCKS5
)

// DialSocksProxy returns the dial function to be used in http.Transport object.
// Argument socksType should be one of SOCKS4, SOCKS4A and SOCKS5.
// Argument proxy should be in this format "127.0.0.1:1080".
func DialSocksProxy(socksType int, proxy string) func(string, string) (net.Conn, error) {
	if socksType == SOCKS5 {
		return func (_, targetAddr string) (conn net.Conn, err error) {
			return dialSocks5(proxy, targetAddr)
		}
	}

	// SOCKS4, SOCKS4A
	return func (_, targetAddr string) (conn net.Conn, err error) {
		return dialSocks4(socksType, proxy, targetAddr)
	}
}

func dialSocks5(proxy, targetAddr string) (conn net.Conn, err error) {
	// dial TCP
	conn, err = net.Dial("tcp", proxy)
	if err != nil { return }

	// version identifier/method selection request
	req := []byte{
		5,	// version number
		1,	// number of methods
		0,	// method 0: no authentication (only anonymous access supported for now)
	}
	resp, err := sendReceive(conn, req)
	if err != nil {
		return
	} else if len(resp) != 2 {
		err = errors.New("Server does not respond properly.")
	} else if resp[0] != 5 {
		err = errors.New("Server does not support Socks 5.")
	} else if resp[1] != 0 {	// no auth
		err = errors.New("socks method negotiation failed.")
		return
	}

	// detail request
	host, port, err := splitHostPort(targetAddr)
	req = []byte{
		5,	// version number
		1,	// connect command
		0,	// reserved, must be zero
		3,	// address type, 3 means domain name
		byte(len(host)), // address length
	}
	req = append(req, []byte(host)...)
	req = append(req, []byte{
		byte(port >> 8),	// higher byte of destination port
		byte(port),			// lower byte of destination port (big endian)
	}...)
	resp, err = sendReceive(conn, req)
	if err != nil {
		return
	} else if len(resp) != 10 {
		err = errors.New("Server does not respond properly.")
	} else if resp[1] != 0 {
		err = errors.New("Can't complete SOCKS5 connection.")
	}

	return
}

func dialSocks4(socksType int, proxy, targetAddr string) (conn net.Conn, err error) {
	// dial TCP
	conn, err = net.Dial("tcp", proxy)
	if err != nil { return }

	// connection request
	host, port, err := splitHostPort(targetAddr)
	if err != nil { return }
	ip := net.IPv4(0, 0, 0, 1)
	if socksType == SOCKS4 {
		ip, err = lookupIP(host)
		if err != nil { return }
	}
	req := []byte{
		4,							// version number
		1,							// command CONNECT
		byte(port >> 8),			// higher byte of destination port
		byte(port),					// lower byte of destination port (big endian)
		ip[0], ip[1], ip[2], ip[3],	// special invalid IP address to indicate the host name is provided
		0,							// user id is empty, anonymous proxy only
	}
	if socksType == SOCKS4A {
		req = append(req, []byte(host + "\x00")...)
	}

	resp, err := sendReceive(conn, req)
	if err != nil {
		return
	} else if len(resp) != 8 {
			err = errors.New("Server does not respond properly.")
	}
	switch  resp[1] {
		case 90:
			// request granted
		case 91:
			err = errors.New("Socks connection request rejected or failed.")
		case 92:
			err = errors.New("Socks connection request rejected becasue SOCKS server cannot connect to identd on the client.")
		case 93:
			err = errors.New("Socks connection request rejected because the client program and identd report different user-ids.")
		default:
			err = errors.New("Socks connection request failed, unknown error.")
	}
	return
}

func sendReceive(conn net.Conn, req []byte) (resp []byte, err error) {
	_, err = conn.Write(req)
	if err != nil { return }
	resp, err = readAll(conn)
	return
}

func readAll(conn net.Conn) (resp []byte, err error) {
	resp = make([]byte, 1024)
	n, err := conn.Read(resp)
	resp = resp[:n]
	return
}

func lookupIP(host string) (ip net.IP, err error) {
	ips, err := net.LookupIP(host)
	if err != nil { return }
	if len(ips) == 0 {
		err = errors.New(fmt.Sprintf("Cannot resolve host: %s.", host))
		return
	}
	ip = ips[0].To4()
	if len(ip) != net.IPv4len {
		fmt.Println(len(ip), ip)
		err = errors.New("IPv6 is not supported by SOCKS4.")
		return
	}
	return
}

func splitHostPort(addr string) (host string, port uint16, err error) {
	host, portStr, err := net.SplitHostPort(addr)
	portInt, err := strconv.ParseUint(portStr, 10, 16)
	port = uint16(portInt)
	return
}
<|endoftext|>


<commit_before>/*
 *
 *  Copyright 2015 Netflix, 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.
 *
 */
package sorty

import (
	"fmt"
	"reflect"
	"sort"
)

type sorter struct {
	data  interface{}
	order KeyComps
}

// NewSorter create a new sorter struct which Sort() can be called on.
func NewSorter() *sorter {
	return &sorter{}
}

// ByKeys is used to provide a list of string to indicate which keys to sort by and in which
// order.  If the key name starts with "-" it will be sorted in Descending order otherwise
// it will be sorted in Ascending order.
func (s *sorter) ByKeys(order []string) *sorter {
	keyComps := make(KeyComps, 0)
	for _, key := range order {
		switch key[0] {
		case '-':
			keyComps = append(keyComps, KeyComp{key[1:], Descending})
		case '+':
			keyComps = append(keyComps, KeyComp{key[1:], Ascending})
		default:
			keyComps = append(keyComps, KeyComp{key, Ascending})
		}
	}
	return s.ByKeyComps(keyComps)
}

// KeyComp struct to provide custom compaitor functions
type KeyComp struct {
	Name string
	Comp func(interface{}, interface{}) CompareResult
}

type KeyComps []KeyComp

// ByKeyComps is used to provide a list of KeyComp to sort by key with an explicit comparitor.
func (s *sorter) ByKeyComps(keyComps KeyComps) *sorter {
	s.order = keyComps
	return s
}

// Sort will sort the data provided.  The data should be a slice of something.
func (s *sorter) Sort(data interface{}) {
	s.data = data
	sort.Sort(s)
}

// Len is required to implement sort.Interface
func (s *sorter) Len() int {
	return reflect.ValueOf(s.data).Len()
}

// Swap is required to implement sort.Interface
func (s *sorter) Swap(i, j int) {
	if i > j {
		i, j = j, i
	}
	arr := reflect.ValueOf(s.data)

	tmp := arr.Index(i).Interface()
	arr.Index(i).Set(arr.Index(j))
	arr.Index(j).Set(reflect.ValueOf(tmp))
}

// Less is required to implement sort.Interface
func (s *sorter) Less(i, j int) bool {
	arr := reflect.ValueOf(s.data)
	a := reflect.ValueOf(arr.Index(i).Interface())
	b := reflect.ValueOf(arr.Index(j).Interface())
	if a.Kind() != reflect.Map {
		iface := a.Interface()
		panic(fmt.Sprintf("[A] Kind: %s, Expected a map, but got a %T for %v", a.Kind(), iface, iface))
	}
	if b.Kind() != reflect.Map {
		iface := b.Interface()
		panic(fmt.Sprintf("[B] Kind: %s, Expected a map, but got a %T for %v", b.Kind(), iface, iface))
	}

	for i := 0; i < len(s.order); i += 1 {
		keyComp := s.order[i]
		af := a.MapIndex(reflect.ValueOf(keyComp.Name)).Interface()
		bf := b.MapIndex(reflect.ValueOf(keyComp.Name)).Interface()

		switch keyComp.Comp(af, bf) {
		case LESSER:
			return true
		case GREATER:
			return false
		}
	}
	return true
}

type CompareResult int8

const (
	LESSER CompareResult = -1 + iota
	EQUAL
	GREATER
)

func Ascending(a, b interface{}) CompareResult {
	switch Descending(a, b) {
	case LESSER:
		return GREATER
	case GREATER:
		return LESSER
	default:
		return EQUAL
	}
}

func Descending(a, b interface{}) CompareResult {
	if a == b {
		return EQUAL
	}
	switch a.(type) {
	case string:
		return lg(a.(string) > b.(string))
	case int:
		return lg(a.(int) > reflect.ValueOf(b).Convert(reflect.TypeOf(a)).Interface().(int))
	case int8:
		return lg(a.(int8) > reflect.ValueOf(b).Convert(reflect.TypeOf(a)).Interface().(int8))
	case int16:
		return lg(a.(int16) > reflect.ValueOf(b).Convert(reflect.TypeOf(a)).Interface().(int16))
	case int32:
		return lg(a.(int32) > reflect.ValueOf(b).Convert(reflect.TypeOf(a)).Interface().(int32))
	case int64:
		return lg(a.(int64) > reflect.ValueOf(b).Convert(reflect.TypeOf(a)).Interface().(int64))
	case uint:
		return lg(a.(uint) > reflect.ValueOf(b).Convert(reflect.TypeOf(a)).Interface().(uint))
	case uint8:
		return lg(a.(uint8) > reflect.ValueOf(b).Convert(reflect.TypeOf(a)).Interface().(uint8))
	case uint16:
		return lg(a.(uint16) > reflect.ValueOf(b).Convert(reflect.TypeOf(a)).Interface().(uint16))
	case uint32:
		return lg(a.(uint32) > reflect.ValueOf(b).Convert(reflect.TypeOf(a)).Interface().(uint32))
	case uint64:
		return lg(a.(uint64) > reflect.ValueOf(b).Convert(reflect.TypeOf(a)).Interface().(uint64))
	case float32:
		return lg(a.(float32) > reflect.ValueOf(b).Convert(reflect.TypeOf(a)).Interface().(float32))
	case float64:
		return lg(a.(float64) > reflect.ValueOf(b).Convert(reflect.TypeOf(a)).Interface().(float64))
	default:
		panic(fmt.Sprintf("dont know how to compare: %T", a))
	}
}

func lg(b bool) CompareResult {
	if b {
		return LESSER
	}
	return GREATER
}
<commit_msg>seperate copyright from package header<commit_after>/*
 *
 *  Copyright 2015 Netflix, 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.
 *
 */

package sorty

import (
	"fmt"
	"reflect"
	"sort"
)

type sorter struct {
	data  interface{}
	order KeyComps
}

// NewSorter create a new sorter struct which Sort() can be called on.
func NewSorter() *sorter {
	return &sorter{}
}

// ByKeys is used to provide a list of string to indicate which keys to sort by and in which
// order.  If the key name starts with "-" it will be sorted in Descending order otherwise
// it will be sorted in Ascending order.
func (s *sorter) ByKeys(order []string) *sorter {
	keyComps := make(KeyComps, 0)
	for _, key := range order {
		switch key[0] {
		case '-':
			keyComps = append(keyComps, KeyComp{key[1:], Descending})
		case '+':
			keyComps = append(keyComps, KeyComp{key[1:], Ascending})
		default:
			keyComps = append(keyComps, KeyComp{key, Ascending})
		}
	}
	return s.ByKeyComps(keyComps)
}

// KeyComp struct to provide custom compaitor functions
type KeyComp struct {
	Name string
	Comp func(interface{}, interface{}) CompareResult
}

type KeyComps []KeyComp

// ByKeyComps is used to provide a list of KeyComp to sort by key with an explicit comparitor.
func (s *sorter) ByKeyComps(keyComps KeyComps) *sorter {
	s.order = keyComps
	return s
}

// Sort will sort the data provided.  The data should be a slice of something.
func (s *sorter) Sort(data interface{}) {
	s.data = data
	sort.Sort(s)
}

// Len is required to implement sort.Interface
func (s *sorter) Len() int {
	return reflect.ValueOf(s.data).Len()
}

// Swap is required to implement sort.Interface
func (s *sorter) Swap(i, j int) {
	if i > j {
		i, j = j, i
	}
	arr := reflect.ValueOf(s.data)

	tmp := arr.Index(i).Interface()
	arr.Index(i).Set(arr.Index(j))
	arr.Index(j).Set(reflect.ValueOf(tmp))
}

// Less is required to implement sort.Interface
func (s *sorter) Less(i, j int) bool {
	arr := reflect.ValueOf(s.data)
	a := reflect.ValueOf(arr.Index(i).Interface())
	b := reflect.ValueOf(arr.Index(j).Interface())
	if a.Kind() != reflect.Map {
		iface := a.Interface()
		panic(fmt.Sprintf("[A] Kind: %s, Expected a map, but got a %T for %v", a.Kind(), iface, iface))
	}
	if b.Kind() != reflect.Map {
		iface := b.Interface()
		panic(fmt.Sprintf("[B] Kind: %s, Expected a map, but got a %T for %v", b.Kind(), iface, iface))
	}

	for i := 0; i < len(s.order); i += 1 {
		keyComp := s.order[i]
		af := a.MapIndex(reflect.ValueOf(keyComp.Name)).Interface()
		bf := b.MapIndex(reflect.ValueOf(keyComp.Name)).Interface()

		switch keyComp.Comp(af, bf) {
		case LESSER:
			return true
		case GREATER:
			return false
		}
	}
	return true
}

type CompareResult int8

const (
	LESSER CompareResult = -1 + iota
	EQUAL
	GREATER
)

func Ascending(a, b interface{}) CompareResult {
	switch Descending(a, b) {
	case LESSER:
		return GREATER
	case GREATER:
		return LESSER
	default:
		return EQUAL
	}
}

func Descending(a, b interface{}) CompareResult {
	if a == b {
		return EQUAL
	}
	switch a.(type) {
	case string:
		return lg(a.(string) > b.(string))
	case int:
		return lg(a.(int) > reflect.ValueOf(b).Convert(reflect.TypeOf(a)).Interface().(int))
	case int8:
		return lg(a.(int8) > reflect.ValueOf(b).Convert(reflect.TypeOf(a)).Interface().(int8))
	case int16:
		return lg(a.(int16) > reflect.ValueOf(b).Convert(reflect.TypeOf(a)).Interface().(int16))
	case int32:
		return lg(a.(int32) > reflect.ValueOf(b).Convert(reflect.TypeOf(a)).Interface().(int32))
	case int64:
		return lg(a.(int64) > reflect.ValueOf(b).Convert(reflect.TypeOf(a)).Interface().(int64))
	case uint:
		return lg(a.(uint) > reflect.ValueOf(b).Convert(reflect.TypeOf(a)).Interface().(uint))
	case uint8:
		return lg(a.(uint8) > reflect.ValueOf(b).Convert(reflect.TypeOf(a)).Interface().(uint8))
	case uint16:
		return lg(a.(uint16) > reflect.ValueOf(b).Convert(reflect.TypeOf(a)).Interface().(uint16))
	case uint32:
		return lg(a.(uint32) > reflect.ValueOf(b).Convert(reflect.TypeOf(a)).Interface().(uint32))
	case uint64:
		return lg(a.(uint64) > reflect.ValueOf(b).Convert(reflect.TypeOf(a)).Interface().(uint64))
	case float32:
		return lg(a.(float32) > reflect.ValueOf(b).Convert(reflect.TypeOf(a)).Interface().(float32))
	case float64:
		return lg(a.(float64) > reflect.ValueOf(b).Convert(reflect.TypeOf(a)).Interface().(float64))
	default:
		panic(fmt.Sprintf("dont know how to compare: %T", a))
	}
}

func lg(b bool) CompareResult {
	if b {
		return LESSER
	}
	return GREATER
}
<|endoftext|>


<commit_before>// Copyright 2012 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// 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 backup_test

import (
	"errors"
	"github.com/jacobsa/comeback/backup"
	"github.com/jacobsa/comeback/backup/mock"
	"github.com/jacobsa/comeback/blob"
	"github.com/jacobsa/comeback/blob/mock"
	"github.com/jacobsa/comeback/fs"
	"github.com/jacobsa/comeback/fs/mock"
	"github.com/jacobsa/comeback/repr"
	"github.com/jacobsa/oglemock"
	. "github.com/jacobsa/oglematchers"
	. "github.com/jacobsa/ogletest"
	"testing"
)

func TestRegisterDirsTest(t *testing.T) { RunTests(t) }

////////////////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////////////////

func saveBlob(res *[]byte) oglemock.Action {
	f := func(b []byte) (blob.Score, error) {
		*res = b
		return nil, errors.New("foo")
	}

	return oglemock.Invoke(f)
}

type readCloser struct {
	closed bool
}

func (r *readCloser) Read(b []byte) (int, error) {
	panic("Shouldn't be called.")
}

func (r *readCloser) Close() {
	if r.closed {
		panic("Close called twice.")
	}

	r.closed = true
}

type DirectorySaverTest struct {
	blobStore mock_blob.MockStore
	fileSystem mock_fs.MockFileSystem
	fileSaver mock_backup.MockFileSaver
	wrapped mock_backup.MockDirectorySaver

	dirSaver backup.DirectorySaver

	dirpath string
	score blob.Score
	err error
}

func init() { RegisterTestSuite(&DirectorySaverTest{}) }

func (t *DirectorySaverTest) SetUp(i *TestInfo) {
	t.blobStore = mock_blob.NewMockStore(i.MockController, "blobStore")
	t.fileSystem = mock_fs.NewMockFileSystem(i.MockController, "fileSystem")
	t.fileSaver = mock_backup.NewMockFileSaver(i.MockController, "fileSaver")
	t.wrapped = mock_backup.NewMockDirectorySaver(i.MockController, "wrapped")

	t.dirSaver, _ = backup.NewDirectorySaver(
		t.blobStore,
		t.fileSystem,
		t.fileSaver,
		t.wrapped,
	)
}

func (t *DirectorySaverTest) callSaver() {
	t.score, t.err = t.dirSaver.Save(t.dirpath)
}

////////////////////////////////////////////////////////////////////////
// Tests
////////////////////////////////////////////////////////////////////////

func (t *DirectorySaverTest) CallsReadDir() {
	t.dirpath = "taco"

	// ReadDir
	ExpectCall(t.fileSystem, "ReadDir")("taco").
		WillOnce(oglemock.Return(nil, errors.New("")))

	// Call
	t.callSaver()
}

func (t *DirectorySaverTest) ReadDirReturnsError() {
	// ReadDir
	ExpectCall(t.fileSystem, "ReadDir")(Any()).
		WillOnce(oglemock.Return(nil, errors.New("taco")))

	// Call
	t.callSaver()

	ExpectThat(t.err, Error(HasSubstr("Listing")))
	ExpectThat(t.err, Error(HasSubstr("taco")))
}

func (t *DirectorySaverTest) NoEntriesInDirectory() {
	// ReadDir
	ExpectCall(t.fileSystem, "ReadDir")(Any()).
		WillOnce(oglemock.Return([]*fs.DirectoryEntry{}, nil))

	// Blob store
	var blob []byte
	ExpectCall(t.blobStore, "Store")(Any()).
		WillOnce(saveBlob(&blob))

	// Call
	t.callSaver()

	AssertNe(nil, blob)
	entries, err := repr.Unmarshal(blob)
	AssertEq(nil, err)
	ExpectThat(entries, ElementsAre())
}

func (t *DirectorySaverTest) CallsFileSystemAndFileSaverForFiles() {
	t.dirpath = "/taco"

	// ReadDir
	entries := []*fs.DirectoryEntry {
		&fs.DirectoryEntry{Name: "burrito"},
		&fs.DirectoryEntry{Name: "enchilada"},
	}

	ExpectCall(t.fileSystem, "ReadDir")(Any()).
		WillOnce(oglemock.Return(entries, nil))

	// OpenForReading
	file0 := &readCloser{}
	file1 := &readCloser{}

	ExpectCall(t.fileSystem, "OpenForReading")("/taco/burrito").
		WillOnce(oglemock.Return(file0, nil))

	ExpectCall(t.fileSystem, "OpenForReading")("/taco/enchilada").
		WillOnce(oglemock.Return(file1, nil))

	// File saver
	ExpectCall(t.fileSaver, "Save")(file0).
		WillOnce(oglemock.Return([]blob.Score{}, nil))

	ExpectCall(t.fileSaver, "Save")(file1).
		WillOnce(oglemock.Return(nil, errors.New("")))

	// Call
	t.callSaver()
}

func (t *DirectorySaverTest) FileSystemReturnsErrorForOneFile() {
	ExpectEq("TODO", "")
}

func (t *DirectorySaverTest) FileSaverReturnsErrorForOneFile() {
	ExpectEq("TODO", "")
}

func (t *DirectorySaverTest) ClosesFilesOnError() {
	ExpectEq("TODO", "")
}

func (t *DirectorySaverTest) ClosesFilesOnSuccess() {
	ExpectEq("TODO", "")
}

func (t *DirectorySaverTest) CallsDirSaverForDirs() {
	ExpectEq("TODO", "")
}

func (t *DirectorySaverTest) DirSaverReturnsErrorForOneDir() {
	ExpectEq("TODO", "")
}

func (t *DirectorySaverTest) OneTypeIsUnsupported() {
	ExpectEq("TODO", "")
}

func (t *DirectorySaverTest) CallsBlobStore() {
	ExpectEq("TODO", "")
}

func (t *DirectorySaverTest) BlobStoreReturnsError() {
	ExpectEq("TODO", "")
}

func (t *DirectorySaverTest) BlobStoreSucceeds() {
	ExpectEq("TODO", "")
}
<commit_msg>Fixed test bugs.<commit_after>// Copyright 2012 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// 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 backup_test

import (
	"errors"
	"github.com/jacobsa/comeback/backup"
	"github.com/jacobsa/comeback/backup/mock"
	"github.com/jacobsa/comeback/blob"
	"github.com/jacobsa/comeback/blob/mock"
	"github.com/jacobsa/comeback/fs"
	"github.com/jacobsa/comeback/fs/mock"
	"github.com/jacobsa/comeback/repr"
	"github.com/jacobsa/oglemock"
	. "github.com/jacobsa/oglematchers"
	. "github.com/jacobsa/ogletest"
	"testing"
)

func TestRegisterDirsTest(t *testing.T) { RunTests(t) }

////////////////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////////////////

func saveBlob(res *[]byte) oglemock.Action {
	f := func(b []byte) (blob.Score, error) {
		*res = b
		return nil, errors.New("foo")
	}

	return oglemock.Invoke(f)
}

type readCloser struct {
	closed bool
}

func (r *readCloser) Read(b []byte) (int, error) {
	panic("Shouldn't be called.")
}

func (r *readCloser) Close() error {
	if r.closed {
		panic("Close called twice.")
	}

	r.closed = true
	return nil
}

type DirectorySaverTest struct {
	blobStore mock_blob.MockStore
	fileSystem mock_fs.MockFileSystem
	fileSaver mock_backup.MockFileSaver
	wrapped mock_backup.MockDirectorySaver

	dirSaver backup.DirectorySaver

	dirpath string
	score blob.Score
	err error
}

func init() { RegisterTestSuite(&DirectorySaverTest{}) }

func (t *DirectorySaverTest) SetUp(i *TestInfo) {
	t.blobStore = mock_blob.NewMockStore(i.MockController, "blobStore")
	t.fileSystem = mock_fs.NewMockFileSystem(i.MockController, "fileSystem")
	t.fileSaver = mock_backup.NewMockFileSaver(i.MockController, "fileSaver")
	t.wrapped = mock_backup.NewMockDirectorySaver(i.MockController, "wrapped")

	t.dirSaver, _ = backup.NewDirectorySaver(
		t.blobStore,
		t.fileSystem,
		t.fileSaver,
		t.wrapped,
	)
}

func (t *DirectorySaverTest) callSaver() {
	t.score, t.err = t.dirSaver.Save(t.dirpath)
}

////////////////////////////////////////////////////////////////////////
// Tests
////////////////////////////////////////////////////////////////////////

func (t *DirectorySaverTest) CallsReadDir() {
	t.dirpath = "taco"

	// ReadDir
	ExpectCall(t.fileSystem, "ReadDir")("taco").
		WillOnce(oglemock.Return(nil, errors.New("")))

	// Call
	t.callSaver()
}

func (t *DirectorySaverTest) ReadDirReturnsError() {
	// ReadDir
	ExpectCall(t.fileSystem, "ReadDir")(Any()).
		WillOnce(oglemock.Return(nil, errors.New("taco")))

	// Call
	t.callSaver()

	ExpectThat(t.err, Error(HasSubstr("Listing")))
	ExpectThat(t.err, Error(HasSubstr("taco")))
}

func (t *DirectorySaverTest) NoEntriesInDirectory() {
	// ReadDir
	ExpectCall(t.fileSystem, "ReadDir")(Any()).
		WillOnce(oglemock.Return([]*fs.DirectoryEntry{}, nil))

	// Blob store
	var blob []byte
	ExpectCall(t.blobStore, "Store")(Any()).
		WillOnce(saveBlob(&blob))

	// Call
	t.callSaver()

	AssertNe(nil, blob)
	entries, err := repr.Unmarshal(blob)
	AssertEq(nil, err)
	ExpectThat(entries, ElementsAre())
}

func (t *DirectorySaverTest) CallsFileSystemAndFileSaverForFiles() {
	t.dirpath = "/taco"

	// ReadDir
	entries := []*fs.DirectoryEntry {
		&fs.DirectoryEntry{Name: "burrito"},
		&fs.DirectoryEntry{Name: "enchilada"},
	}

	ExpectCall(t.fileSystem, "ReadDir")(Any()).
		WillOnce(oglemock.Return(entries, nil))

	// OpenForReading
	file0 := &readCloser{}
	file1 := &readCloser{}

	ExpectCall(t.fileSystem, "OpenForReading")("/taco/burrito").
		WillOnce(oglemock.Return(file0, nil))

	ExpectCall(t.fileSystem, "OpenForReading")("/taco/enchilada").
		WillOnce(oglemock.Return(file1, nil))

	// File saver
	ExpectCall(t.fileSaver, "Save")(file0).
		WillOnce(oglemock.Return([]blob.Score{}, nil))

	ExpectCall(t.fileSaver, "Save")(file1).
		WillOnce(oglemock.Return(nil, errors.New("")))

	// Call
	t.callSaver()
}

func (t *DirectorySaverTest) FileSystemReturnsErrorForOneFile() {
	ExpectEq("TODO", "")
}

func (t *DirectorySaverTest) FileSaverReturnsErrorForOneFile() {
	ExpectEq("TODO", "")
}

func (t *DirectorySaverTest) ClosesFilesOnError() {
	ExpectEq("TODO", "")
}

func (t *DirectorySaverTest) ClosesFilesOnSuccess() {
	ExpectEq("TODO", "")
}

func (t *DirectorySaverTest) CallsDirSaverForDirs() {
	ExpectEq("TODO", "")
}

func (t *DirectorySaverTest) DirSaverReturnsErrorForOneDir() {
	ExpectEq("TODO", "")
}

func (t *DirectorySaverTest) OneTypeIsUnsupported() {
	ExpectEq("TODO", "")
}

func (t *DirectorySaverTest) CallsBlobStore() {
	ExpectEq("TODO", "")
}

func (t *DirectorySaverTest) BlobStoreReturnsError() {
	ExpectEq("TODO", "")
}

func (t *DirectorySaverTest) BlobStoreSucceeds() {
	ExpectEq("TODO", "")
}
<|endoftext|>


<commit_before>package chunk

import (
	"io/ioutil"
	"os"
	"path"
	"errors"
	"strconv"
)

var (
	ErrBlockNotFound = errors.New("Block not found.")
)

// Block is storage unit of each file
type Block struct {
	Header 	BlockHeader // metadata
	Data 	[]byte	    // contents of this block
}

// BlockHeaders holds Block metadata
type BlockHeader struct {
	DatanodeID 	string	// ID of datanode which store this block
	Filename   	string  // Storage name of this block
	Size       	int64   // Size of block in bytes
	Index   	int     // Index in file
	NumberOfBlocks 	int     // Total number of blocks in file
}

func getBlockName(header BlockHeader) string {
	return "block_" + strconv.Itoa(header.Index)
}

func (c *ChunkServer) WriteBlock(block Block) error {
	list, err := ioutil.ReadDir(c.RootDir)
	storePath := path.Join(c.RootDir, block.Header.Filename, getBlockName(block.Header))
	if err != nil {
		return err
	}

	for _, dir := range list {
		if dir.Name() == block.Header.Filename {
			// write data
			ioutil.WriteFile(storePath, block.Data, os.ModeAppend)
			return nil
		}
	}

	os.Mkdir(path.Join(c.RootDir, block.Header.Filename), 0700)
	err = ioutil.WriteFile(storePath, block.Data, os.ModePerm)
	if err != nil {
		return err
	}
	return nil
}

func (c *ChunkServer) ReadBlock(header BlockHeader) (*Block, error){
	storePath := path.Join(c.RootDir, header.Filename, getBlockName(header))

	list, err := ioutil.ReadDir(c.RootDir)
	if err != nil {
		return nil, err
	}

	for _, dir := range list {
		if dir.Name() == header.Filename {
			bytes, err := ioutil.ReadFile(storePath)
			if err != nil {
				return nil, err
			}
			return &Block {Header: header, Data: bytes}, nil
		}
	}
	return nil, ErrBlockNotFound
}

<commit_msg>Delete a comment.<commit_after>package chunk

import (
	"io/ioutil"
	"os"
	"path"
	"errors"
	"strconv"
)

var (
	ErrBlockNotFound = errors.New("Block not found.")
)

// Block is storage unit of each file
type Block struct {
	Header 	BlockHeader // metadata
	Data 	[]byte	    // contents of this block
}

// BlockHeaders holds Block metadata
type BlockHeader struct {
	DatanodeID 	string	// ID of datanode which store this block
	Filename   	string  // Storage name of this block
	Size       	int64   // Size of block in bytes
	Index   	int     // Index in file
	NumberOfBlocks 	int     // Total number of blocks in file
}

func getBlockName(header BlockHeader) string {
	return "block_" + strconv.Itoa(header.Index)
}

func (c *ChunkServer) WriteBlock(block Block) error {
	list, err := ioutil.ReadDir(c.RootDir)
	storePath := path.Join(c.RootDir, block.Header.Filename, getBlockName(block.Header))
	if err != nil {
		return err
	}

	for _, dir := range list {
		if dir.Name() == block.Header.Filename {
			ioutil.WriteFile(storePath, block.Data, os.ModeAppend)
			return nil
		}
	}

	os.Mkdir(path.Join(c.RootDir, block.Header.Filename), 0700)
	err = ioutil.WriteFile(storePath, block.Data, os.ModePerm)
	if err != nil {
		return err
	}
	return nil
}

func (c *ChunkServer) ReadBlock(header BlockHeader) (*Block, error){
	storePath := path.Join(c.RootDir, header.Filename, getBlockName(header))

	list, err := ioutil.ReadDir(c.RootDir)
	if err != nil {
		return nil, err
	}

	for _, dir := range list {
		if dir.Name() == header.Filename {
			bytes, err := ioutil.ReadFile(storePath)
			if err != nil {
				return nil, err
			}
			return &Block {Header: header, Data: bytes}, nil
		}
	}
	return nil, ErrBlockNotFound
}

<|endoftext|>


<commit_before>//go:generate praxisgen -metadata=ssd/restful_doc -output=ssd -pkg=ssd -target=1.0 -client=Api
//go:generate praxisgen -metadata=ssc/restful_doc -output=ssc -pkg=ssc -target=1.0 -client=Api
//go:generate praxisgen -metadata=ssm/restful_doc -output=ssm -pkg=ssm -target=1.0 -client=Api
package ss

import (
	"fmt"
	"log"
	"net/http"

	"github.com/rightscale/rsc/cmd"
	"github.com/rightscale/rsc/metadata"
	"github.com/rightscale/rsc/rsapi"
	"github.com/rightscale/rsc/ss/ssc"
	"github.com/rightscale/rsc/ss/ssd"
	"github.com/rightscale/rsc/ss/ssm"
)

// Self-Service 1.0 common client to all self-service APIs
type Api struct {
	*rsapi.Api     // not used to make actual API calls, just to parse command line, TBD: refactor so this is not needed
	designerClient *ssd.Api
	catalogClient  *ssc.Api
	managerClient  *ssm.Api
}

// Api dispatch function type
// Used to call proper "Dispatch" method depending on service (ssm vs. ssc vs. ssd)
type DispatchFunc func(method, actionUrl string, params, payload rsapi.ApiParams) (*http.Response, error)

// New returns a client that uses User oauth authentication.
// logger and client are optional.
// host may be blank in which case client attempts to resolve it using auth.
// If no HTTP client is specified then the default client is used.
func New(accountId int, refreshToken string, host string, logger *log.Logger,
	client rsapi.HttpClient) (*Api, error) {
	a, err := rsapi.New(accountId, refreshToken, host, logger, client)
	if err != nil {
		return nil, err
	}
	d, err := ssd.New(accountId, refreshToken, host, logger, client)
	if err != nil {
		return nil, err
	}
	c, err := ssc.New(accountId, refreshToken, host, logger, client)
	if err != nil {
		return nil, err
	}
	m, err := ssm.New(accountId, refreshToken, host, logger, client)
	if err != nil {
		return nil, err
	}
	api := Api{a, d, c, m}
	setupMetadata(a, d, c, m)

	return &api, nil
}

// Build client from command line
func FromCommandLine(cmdLine *cmd.CommandLine) (*Api, error) {
	if cmdLine.RL10 {
		return nil, fmt.Errorf("RightLink 10 proxy not supported for Self-Service APIs")
	}
	a, err := rsapi.FromCommandLine(cmdLine)
	if err != nil {
		return nil, err
	}
	d, err := ssd.FromCommandLine(cmdLine)
	if err != nil {
		return nil, err
	}
	c, err := ssc.FromCommandLine(cmdLine)
	if err != nil {
		return nil, err
	}
	m, err := ssm.FromCommandLine(cmdLine)
	if err != nil {
		return nil, err
	}
	api := Api{a, d, c, m}
	setupMetadata(a, d, c, m)

	return &api, nil
}

// Merge all metadata so that Api object has access to all commands and actions for command line
// parsing.
func setupMetadata(a *rsapi.Api, d *ssd.Api, c *ssc.Api, m *ssm.Api) {
	md := map[string]*metadata.Resource{}
	for n, r := range d.Metadata {
		md[n] = r
	}
	for n, r := range c.Metadata {
		md[n] = r
	}
	for n, r := range m.Metadata {
		md[n] = r
	}
	a.Metadata = md
}
<commit_msg>Default self service client to "selfservice-3.rightscale.com"<commit_after>//go:generate praxisgen -metadata=ssd/restful_doc -output=ssd -pkg=ssd -target=1.0 -client=Api
//go:generate praxisgen -metadata=ssc/restful_doc -output=ssc -pkg=ssc -target=1.0 -client=Api
//go:generate praxisgen -metadata=ssm/restful_doc -output=ssm -pkg=ssm -target=1.0 -client=Api
package ss

import (
	"fmt"
	"log"
	"net/http"
	"strings"

	"github.com/rightscale/rsc/cmd"
	"github.com/rightscale/rsc/metadata"
	"github.com/rightscale/rsc/rsapi"
	"github.com/rightscale/rsc/ss/ssc"
	"github.com/rightscale/rsc/ss/ssd"
	"github.com/rightscale/rsc/ss/ssm"
)

// Self-Service 1.0 common client to all self-service APIs
type Api struct {
	*rsapi.Api     // not used to make actual API calls, just to parse command line, TBD: refactor so this is not needed
	designerClient *ssd.Api
	catalogClient  *ssc.Api
	managerClient  *ssm.Api
}

// Api dispatch function type
// Used to call proper "Dispatch" method depending on service (ssm vs. ssc vs. ssd)
type DispatchFunc func(method, actionUrl string, params, payload rsapi.ApiParams) (*http.Response, error)

// New returns a client that uses User oauth authentication.
// logger and client are optional.
// host may be blank in which case client attempts to resolve it using auth.
// If no HTTP client is specified then the default client is used.
func New(accountId int, refreshToken string, host string, logger *log.Logger,
	client rsapi.HttpClient) (*Api, error) {
	a, err := rsapi.New(accountId, refreshToken, host, logger, client)
	if err != nil {
		return nil, err
	}
	d, err := ssd.New(accountId, refreshToken, host, logger, client)
	if err != nil {
		return nil, err
	}
	c, err := ssc.New(accountId, refreshToken, host, logger, client)
	if err != nil {
		return nil, err
	}
	m, err := ssm.New(accountId, refreshToken, host, logger, client)
	if err != nil {
		return nil, err
	}
	api := Api{a, d, c, m}
	setupMetadata(a, d, c, m)

	return &api, nil
}

// Build client from command line
func FromCommandLine(cmdLine *cmd.CommandLine) (*Api, error) {
	// Hackyity hack
	if !strings.HasPrefix(cmdLine.Host, "selfservice") {
		cmdLine.Host = "selfservice-3.rightscale.com"
	}
	if cmdLine.RL10 {
		return nil, fmt.Errorf("RightLink 10 proxy not supported for Self-Service APIs")
	}
	a, err := rsapi.FromCommandLine(cmdLine)
	if err != nil {
		return nil, err
	}
	d, err := ssd.FromCommandLine(cmdLine)
	if err != nil {
		return nil, err
	}
	c, err := ssc.FromCommandLine(cmdLine)
	if err != nil {
		return nil, err
	}
	m, err := ssm.FromCommandLine(cmdLine)
	if err != nil {
		return nil, err
	}
	api := Api{a, d, c, m}
	setupMetadata(a, d, c, m)

	return &api, nil
}

// Merge all metadata so that Api object has access to all commands and actions for command line
// parsing.
func setupMetadata(a *rsapi.Api, d *ssd.Api, c *ssc.Api, m *ssm.Api) {
	md := map[string]*metadata.Resource{}
	for n, r := range d.Metadata {
		md[n] = r
	}
	for n, r := range c.Metadata {
		md[n] = r
	}
	for n, r := range m.Metadata {
		md[n] = r
	}
	a.Metadata = md
}
<|endoftext|>


<commit_before>/*
Copyright 2018 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 v1alpha1

import (
	"time"

	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	utilpointer "k8s.io/utils/pointer"
)

// RecommendedDefaultLeaderElectionConfiguration defaults a pointer to a
// LeaderElectionConfiguration struct. This will set the recommended default
// values, but they may be subject to change between API versions. This function
// is intentionally not registered in the scheme as a "normal" `SetDefaults_Foo`
// function to allow consumers of this type to set whatever defaults for their
// embedded configs. Forcing consumers to use these defaults would be problematic
// as defaulting in the scheme is done as part of the conversion, and there would
// be no easy way to opt-out. Instead, if you want to use this defaulting method
// run it in your wrapper struct of this type in its `SetDefaults_` method.
func RecommendedDefaultLeaderElectionConfiguration(obj *LeaderElectionConfiguration) {
	zero := metav1.Duration{}
	if obj.LeaseDuration == zero {
		obj.LeaseDuration = metav1.Duration{Duration: 15 * time.Second}
	}
	if obj.RenewDeadline == zero {
		obj.RenewDeadline = metav1.Duration{Duration: 10 * time.Second}
	}
	if obj.RetryPeriod == zero {
		obj.RetryPeriod = metav1.Duration{Duration: 2 * time.Second}
	}
	if obj.ResourceLock == "" {
		obj.ResourceLock = EndpointsResourceLock
	}
	if obj.LeaderElect == nil {
		obj.LeaderElect = utilpointer.BoolPtr(true)
	}
}

// RecommendedDefaultClientConnectionConfiguration defaults a pointer to a
// ClientConnectionConfiguration struct. This will set the recommended default
// values, but they may be subject to change between API versions. This function
// is intentionally not registered in the scheme as a "normal" `SetDefaults_Foo`
// function to allow consumers of this type to set whatever defaults for their
// embedded configs. Forcing consumers to use these defaults would be problematic
// as defaulting in the scheme is done as part of the conversion, and there would
// be no easy way to opt-out. Instead, if you want to use this defaulting method
// run it in your wrapper struct of this type in its `SetDefaults_` method.
func RecommendedDefaultClientConnectionConfiguration(obj *ClientConnectionConfiguration) {
	if len(obj.ContentType) == 0 {
		obj.ContentType = "application/vnd.kubernetes.protobuf"
	}
	if obj.QPS == 0.0 {
		obj.QPS = 50.0
	}
	if obj.Burst == 0 {
		obj.Burst = 100
	}
}
<commit_msg>Migrate components to EndpointsLeases leader election lock<commit_after>/*
Copyright 2018 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 v1alpha1

import (
	"time"

	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	utilpointer "k8s.io/utils/pointer"
)

// RecommendedDefaultLeaderElectionConfiguration defaults a pointer to a
// LeaderElectionConfiguration struct. This will set the recommended default
// values, but they may be subject to change between API versions. This function
// is intentionally not registered in the scheme as a "normal" `SetDefaults_Foo`
// function to allow consumers of this type to set whatever defaults for their
// embedded configs. Forcing consumers to use these defaults would be problematic
// as defaulting in the scheme is done as part of the conversion, and there would
// be no easy way to opt-out. Instead, if you want to use this defaulting method
// run it in your wrapper struct of this type in its `SetDefaults_` method.
func RecommendedDefaultLeaderElectionConfiguration(obj *LeaderElectionConfiguration) {
	zero := metav1.Duration{}
	if obj.LeaseDuration == zero {
		obj.LeaseDuration = metav1.Duration{Duration: 15 * time.Second}
	}
	if obj.RenewDeadline == zero {
		obj.RenewDeadline = metav1.Duration{Duration: 10 * time.Second}
	}
	if obj.RetryPeriod == zero {
		obj.RetryPeriod = metav1.Duration{Duration: 2 * time.Second}
	}
	if obj.ResourceLock == "" {
		// TODO: Migrate to LeaseLock.
		obj.ResourceLock = EndpointsResourceLock
	}
	if obj.LeaderElect == nil {
		obj.LeaderElect = utilpointer.BoolPtr(true)
	}
}

// RecommendedDefaultClientConnectionConfiguration defaults a pointer to a
// ClientConnectionConfiguration struct. This will set the recommended default
// values, but they may be subject to change between API versions. This function
// is intentionally not registered in the scheme as a "normal" `SetDefaults_Foo`
// function to allow consumers of this type to set whatever defaults for their
// embedded configs. Forcing consumers to use these defaults would be problematic
// as defaulting in the scheme is done as part of the conversion, and there would
// be no easy way to opt-out. Instead, if you want to use this defaulting method
// run it in your wrapper struct of this type in its `SetDefaults_` method.
func RecommendedDefaultClientConnectionConfiguration(obj *ClientConnectionConfiguration) {
	if len(obj.ContentType) == 0 {
		obj.ContentType = "application/vnd.kubernetes.protobuf"
	}
	if obj.QPS == 0.0 {
		obj.QPS = 50.0
	}
	if obj.Burst == 0 {
		obj.Burst = 100
	}
}
<|endoftext|>


<commit_before>// Copyright 2014 Google Inc. All Rights Reserved.
//
// 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 docker

import (
	"flag"
	"fmt"
	"path"
	"regexp"
	"strconv"
	"strings"

	"github.com/docker/libcontainer/cgroups/systemd"
	"github.com/fsouza/go-dockerclient"
	"github.com/golang/glog"
	"github.com/google/cadvisor/container"
	"github.com/google/cadvisor/info"
)

var ArgDockerEndpoint = flag.String("docker", "unix:///var/run/docker.sock", "docker endpoint")

// Basepath to all container specific information that libcontainer stores.
var dockerRootDir = flag.String("docker_root", "/var/lib/docker", "Absolute path to the Docker state root directory (default: /var/lib/docker)")

type dockerFactory struct {
	machineInfoFactory info.MachineInfoFactory

	// Whether this system is using systemd.
	useSystemd bool

	client *docker.Client
}

func (self *dockerFactory) String() string {
	return "docker"
}

func (self *dockerFactory) NewContainerHandler(name string) (handler container.ContainerHandler, err error) {
	client, err := docker.NewClient(*ArgDockerEndpoint)
	if err != nil {
		return
	}
	handler, err = newDockerContainerHandler(
		client,
		name,
		self.machineInfoFactory,
		self.useSystemd,
		*dockerRootDir,
	)
	return
}

// Docker handles all containers under /docker
func (self *dockerFactory) CanHandle(name string) (bool, error) {
	// In systemd systems the containers are: /system.slice/docker-{ID}
	if self.useSystemd {
		if !strings.HasPrefix(name, "/system.slice/docker-") {
			return false, fmt.Errorf("Expected path prefix /system.slice/docker- but got %s", name)
		}
	} else if name == "/" {
		return false, nil
	} else if name == "/docker" {
		// We need the docker driver to handle /docker. Otherwise the aggregation at the API level will break.
		return true, nil
	} else if !strings.HasPrefix(name, "/docker/") {
		return false, nil
	}
	// Check if the container is known to docker and it is active.
	id := path.Base(name)
	ctnr, err := self.client.InspectContainer(id)
	// We assume that if Inspect fails then the container is not known to docker.
	// TODO(vishh): Detect lxc containers and avoid handling them.
	if err != nil || !ctnr.State.Running {
		return false, fmt.Errorf("Error inspecting container: %v", err)
	}

	return true, nil
}

func parseDockerVersion(full_version_string string) ([]int, error) {
	version_regexp_string := "(\\d+)\\.(\\d+)\\.(\\d+)"
	version_re := regexp.MustCompile(version_regexp_string)
	matches := version_re.FindAllStringSubmatch(full_version_string, -1)
	if len(matches) != 1 {
		return nil, fmt.Errorf("Version string \"%v\" doesn't match expected regular expression: \"%v\"", full_version_string, version_regexp_string)
	}
	version_string_array := matches[0][1:]
	version_array := make([]int, 3)
	for index, version_string := range version_string_array {
		version, err := strconv.Atoi(version_string)
		if err != nil {
			return nil, fmt.Errorf("Error while parsing \"%v\" in \"%v\"", version_string, full_version_string)
		}
		version_array[index] = version
	}
	return version_array, nil
}

// Register root container before running this function!
func Register(factory info.MachineInfoFactory) error {
	client, err := docker.NewClient(*ArgDockerEndpoint)
	if err != nil {
		return fmt.Errorf("unable to communicate with docker daemon: %v", err)
	}
	if version, err := client.Version(); err != nil {
		return fmt.Errorf("unable to communicate with docker daemon: %v", err)
	} else {
		expected_version := []int{0, 11, 1}
		version_string := version.Get("Version")
		version, err := parseDockerVersion(version_string)
		if err != nil {
			return fmt.Errorf("Couldn't parse docker version: %v", err)
		}
		for index, number := range version {
			if number > expected_version[index] {
				break
			} else if number < expected_version[index] {
				return fmt.Errorf("cAdvisor requires docker version above %v but we have found version %v reported as \"%v\"", expected_version, version, version_string)
			}
		}
	}

	// Check that the libcontainer execdriver is used.
	information, err := client.Info()
	if err != nil {
		return fmt.Errorf("failed to detect Docker info: %v", err)
	}
	usesNativeDriver := false
	for _, val := range *information {
		if strings.Contains(val, "ExecutionDriver=") && strings.Contains(val, "native") {
			usesNativeDriver = true
			break
		}
	}
	if !usesNativeDriver {
		return fmt.Errorf("Docker found, but not using native exec driver")
	}

	f := &dockerFactory{
		machineInfoFactory: factory,
		useSystemd:         systemd.UseSystemd(),
		client:             client,
	}
	if f.useSystemd {
		glog.Infof("System is using systemd")
	}
	glog.Infof("Registering Docker factory")
	container.RegisterContainerHandlerFactory(f)
	return nil
}
<commit_msg>Fix misunderstanding about when CanHandle fails.<commit_after>// Copyright 2014 Google Inc. All Rights Reserved.
//
// 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 docker

import (
	"flag"
	"fmt"
	"path"
	"regexp"
	"strconv"
	"strings"

	"github.com/docker/libcontainer/cgroups/systemd"
	"github.com/fsouza/go-dockerclient"
	"github.com/golang/glog"
	"github.com/google/cadvisor/container"
	"github.com/google/cadvisor/info"
)

var ArgDockerEndpoint = flag.String("docker", "unix:///var/run/docker.sock", "docker endpoint")

// Basepath to all container specific information that libcontainer stores.
var dockerRootDir = flag.String("docker_root", "/var/lib/docker", "Absolute path to the Docker state root directory (default: /var/lib/docker)")

type dockerFactory struct {
	machineInfoFactory info.MachineInfoFactory

	// Whether this system is using systemd.
	useSystemd bool

	client *docker.Client
}

func (self *dockerFactory) String() string {
	return "docker"
}

func (self *dockerFactory) NewContainerHandler(name string) (handler container.ContainerHandler, err error) {
	client, err := docker.NewClient(*ArgDockerEndpoint)
	if err != nil {
		return
	}
	handler, err = newDockerContainerHandler(
		client,
		name,
		self.machineInfoFactory,
		self.useSystemd,
		*dockerRootDir,
	)
	return
}

// Docker handles all containers under /docker
func (self *dockerFactory) CanHandle(name string) (bool, error) {
	// In systemd systems the containers are: /system.slice/docker-{ID}
	if self.useSystemd {
		if !strings.HasPrefix(name, "/system.slice/docker-") {
			return false, nil
		}
	} else if name == "/" {
		return false, nil
	} else if name == "/docker" {
		// We need the docker driver to handle /docker. Otherwise the aggregation at the API level will break.
		return true, nil
	} else if !strings.HasPrefix(name, "/docker/") {
		return false, nil
	}
	// Check if the container is known to docker and it is active.
	id := path.Base(name)
	ctnr, err := self.client.InspectContainer(id)
	// We assume that if Inspect fails then the container is not known to docker.
	// TODO(vishh): Detect lxc containers and avoid handling them.
	if err != nil || !ctnr.State.Running {
		return false, fmt.Errorf("Error inspecting container: %v", err)
	}

	return true, nil
}

func parseDockerVersion(full_version_string string) ([]int, error) {
	version_regexp_string := "(\\d+)\\.(\\d+)\\.(\\d+)"
	version_re := regexp.MustCompile(version_regexp_string)
	matches := version_re.FindAllStringSubmatch(full_version_string, -1)
	if len(matches) != 1 {
		return nil, fmt.Errorf("Version string \"%v\" doesn't match expected regular expression: \"%v\"", full_version_string, version_regexp_string)
	}
	version_string_array := matches[0][1:]
	version_array := make([]int, 3)
	for index, version_string := range version_string_array {
		version, err := strconv.Atoi(version_string)
		if err != nil {
			return nil, fmt.Errorf("Error while parsing \"%v\" in \"%v\"", version_string, full_version_string)
		}
		version_array[index] = version
	}
	return version_array, nil
}

// Register root container before running this function!
func Register(factory info.MachineInfoFactory) error {
	client, err := docker.NewClient(*ArgDockerEndpoint)
	if err != nil {
		return fmt.Errorf("unable to communicate with docker daemon: %v", err)
	}
	if version, err := client.Version(); err != nil {
		return fmt.Errorf("unable to communicate with docker daemon: %v", err)
	} else {
		expected_version := []int{0, 11, 1}
		version_string := version.Get("Version")
		version, err := parseDockerVersion(version_string)
		if err != nil {
			return fmt.Errorf("Couldn't parse docker version: %v", err)
		}
		for index, number := range version {
			if number > expected_version[index] {
				break
			} else if number < expected_version[index] {
				return fmt.Errorf("cAdvisor requires docker version above %v but we have found version %v reported as \"%v\"", expected_version, version, version_string)
			}
		}
	}

	// Check that the libcontainer execdriver is used.
	information, err := client.Info()
	if err != nil {
		return fmt.Errorf("failed to detect Docker info: %v", err)
	}
	usesNativeDriver := false
	for _, val := range *information {
		if strings.Contains(val, "ExecutionDriver=") && strings.Contains(val, "native") {
			usesNativeDriver = true
			break
		}
	}
	if !usesNativeDriver {
		return fmt.Errorf("Docker found, but not using native exec driver")
	}

	f := &dockerFactory{
		machineInfoFactory: factory,
		useSystemd:         systemd.UseSystemd(),
		client:             client,
	}
	if f.useSystemd {
		glog.Infof("System is using systemd")
	}
	glog.Infof("Registering Docker factory")
	container.RegisterContainerHandlerFactory(f)
	return nil
}
<|endoftext|>