<commit_before>// Copyright 2019 The Chromium 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 main

const ASSEMBLE_INTERFACE_GL_ES = `/*
 * Copyright 2019 Google LLC
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 *
 * THIS FILE IS AUTOGENERATED
 * Make edits to tools/gpu/gl/interface/templates.go or they will
 * be overwritten.
 */

#include "include/gpu/gl/GrGLAssembleHelpers.h"
#include "include/gpu/gl/GrGLAssembleInterface.h"
#include "src/gpu/gl/GrGLUtil.h"

#define GET_PROC(F) functions->f##F = (GrGL##F##Fn*)get(ctx, "gl" #F)
#define GET_PROC_SUFFIX(F, S) functions->f##F = (GrGL##F##Fn*)get(ctx, "gl" #F #S)
#define GET_PROC_LOCAL(F) GrGL##F##Fn* F = (GrGL##F##Fn*)get(ctx, "gl" #F)

#define GET_EGL_PROC_SUFFIX(F, S) functions->fEGL##F = (GrEGL##F##Fn*)get(ctx, "egl" #F #S)

#if SK_DISABLE_GL_ES_INTERFACE
sk_sp<const GrGLInterface> GrGLMakeAssembledGLESInterface(void *ctx, GrGLGetProc get) {
    return nullptr;
}
#else
sk_sp<const GrGLInterface> GrGLMakeAssembledGLESInterface(void *ctx, GrGLGetProc get) {
    GET_PROC_LOCAL(GetString);
    if (nullptr == GetString) {
        return nullptr;
    }

    const char* verStr = reinterpret_cast<const char*>(GetString(GR_GL_VERSION));
    GrGLVersion glVer = GrGLGetVersionFromString(verStr);

    if (glVer < GR_GL_VER(2,0)) {
        return nullptr;
    }

    GET_PROC_LOCAL(GetIntegerv);
    GET_PROC_LOCAL(GetStringi);
    GrEGLQueryStringFn* queryString;
    GrEGLDisplay display;
    GrGetEGLQueryAndDisplay(&queryString, &display, ctx, get);
    GrGLExtensions extensions;
    if (!extensions.init(kGLES_GrGLStandard, GetString, GetStringi, GetIntegerv, queryString,
                         display)) {
        return nullptr;
    }

    sk_sp<GrGLInterface> interface(new GrGLInterface);
    GrGLInterface::Functions* functions = &interface->fFunctions;

    // Autogenerated content follows
[[content]]
    // End autogenerated content
    // TODO(kjlubick): Do we want a feature that removes the extension if it doesn't have
    // the function? This is common on some low-end GPUs.

    if (extensions.has("GL_KHR_debug")) {
        // In general we have a policy against removing extension strings when the driver does
        // not provide function pointers for an advertised extension. However, because there is a
        // known device that advertises GL_KHR_debug but fails to provide the functions and this is
        // a debugging- only extension we've made an exception. This also can happen when using
        // APITRACE.
        if (!interface->fFunctions.fDebugMessageControl) {
            extensions.remove("GL_KHR_debug");
        }
    }
    interface->fStandard = kGLES_GrGLStandard;
    interface->fExtensions.swap(&extensions);

    return std::move(interface);
}
#endif
`

const ASSEMBLE_INTERFACE_GL = `/*
 * Copyright 2019 Google LLC
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 *
 * THIS FILE IS AUTOGENERATED
 * Make edits to tools/gpu/gl/interface/templates.go or they will
 * be overwritten.
 */

#include "include/gpu/gl/GrGLAssembleHelpers.h"
#include "include/gpu/gl/GrGLAssembleInterface.h"
#include "src/gpu/gl/GrGLUtil.h"

#define GET_PROC(F) functions->f##F = (GrGL##F##Fn*)get(ctx, "gl" #F)
#define GET_PROC_SUFFIX(F, S) functions->f##F = (GrGL##F##Fn*)get(ctx, "gl" #F #S)
#define GET_PROC_LOCAL(F) GrGL##F##Fn* F = (GrGL##F##Fn*)get(ctx, "gl" #F)

#define GET_EGL_PROC_SUFFIX(F, S) functions->fEGL##F = (GrEGL##F##Fn*)get(ctx, "egl" #F #S)

#if SK_DISABLE_GL_INTERFACE
sk_sp<const GrGLInterface> GrGLMakeAssembledGLInterface(void *ctx, GrGLGetProc get) {
    return nullptr;
}
#else
sk_sp<const GrGLInterface> GrGLMakeAssembledGLInterface(void *ctx, GrGLGetProc get) {
    GET_PROC_LOCAL(GetString);
    GET_PROC_LOCAL(GetStringi);
    GET_PROC_LOCAL(GetIntegerv);

    // GetStringi may be nullptr depending on the GL version.
    if (nullptr == GetString || nullptr == GetIntegerv) {
        return nullptr;
    }

    const char* versionString = (const char*) GetString(GR_GL_VERSION);
    GrGLVersion glVer = GrGLGetVersionFromString(versionString);

    if (glVer < GR_GL_VER(2,0) || GR_GL_INVALID_VER == glVer) {
        // This is our minimum for non-ES GL.
        return nullptr;
    }

    GrEGLQueryStringFn* queryString;
    GrEGLDisplay display;
    GrGetEGLQueryAndDisplay(&queryString, &display, ctx, get);
    GrGLExtensions extensions;
    if (!extensions.init(kGL_GrGLStandard, GetString, GetStringi, GetIntegerv, queryString,
                         display)) {
        return nullptr;
    }

    sk_sp<GrGLInterface> interface(new GrGLInterface());
    GrGLInterface::Functions* functions = &interface->fFunctions;

    // Autogenerated content follows
[[content]]
    // End autogenerated content
    interface->fStandard = kGL_GrGLStandard;
    interface->fExtensions.swap(&extensions);

    return std::move(interface);
}
#endif
`

const ASSEMBLE_INTERFACE_WEBGL = `/*
 * Copyright 2019 Google LLC
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 *
 * THIS FILE IS AUTOGENERATED
 * Make edits to tools/gpu/gl/interface/templates.go or they will
 * be overwritten.
 */

#include "include/gpu/gl/GrGLAssembleHelpers.h"
#include "include/gpu/gl/GrGLAssembleInterface.h"
#include "src/gpu/gl/GrGLUtil.h"

#if SK_DISABLE_WEBGL_INTERFACE || !defined(SK_USE_WEBGL)
sk_sp<const GrGLInterface> GrGLMakeAssembledWebGLInterface(void *ctx, GrGLGetProc get) {
    return nullptr;
}
#else

// Located https://github.com/emscripten-core/emscripten/tree/7ba7700902c46734987585409502f3c63beb650f/system/include/webgl
#include "webgl/webgl1.h"
#include "webgl/webgl1_ext.h"
#include "webgl/webgl2.h"
#include "webgl/webgl2_ext.h"

#define GET_PROC(F) functions->f##F = emscripten_gl##F
#define GET_PROC_SUFFIX(F, S) functions->f##F = emscripten_gl##F##S

// Adapter from standard GL signature to emscripten.
void emscripten_glWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout) {
    uint32_t timeoutLo = timeout;
    uint32_t timeoutHi = timeout >> 32;
    emscripten_glWaitSync(sync, flags, timeoutLo, timeoutHi);
}

// Adapter from standard GL signature to emscripten.
GLenum emscripten_glClientWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout) {
    uint32_t timeoutLo = timeout;
    uint32_t timeoutHi = timeout >> 32;
    return emscripten_glClientWaitSync(sync, flags, timeoutLo, timeoutHi);
}

sk_sp<const GrGLInterface> GrGLMakeAssembledWebGLInterface(void *ctx, GrGLGetProc get) {
    const char* verStr = reinterpret_cast<const char*>(emscripten_glGetString(GR_GL_VERSION));
    GrGLVersion glVer = GrGLGetVersionFromString(verStr);
    if (glVer < GR_GL_VER(1,0)) {
        return nullptr;
    }

    GrGLExtensions extensions;
    if (!extensions.init(kWebGL_GrGLStandard, emscripten_glGetString, emscripten_glGetStringi,
                         emscripten_glGetIntegerv)) {
        return nullptr;
    }

    sk_sp<GrGLInterface> interface(new GrGLInterface);
    GrGLInterface::Functions* functions = &interface->fFunctions;

    // Autogenerated content follows
[[content]]
    // End autogenerated content

    interface->fStandard = kWebGL_GrGLStandard;
    interface->fExtensions.swap(&extensions);

    return std::move(interface);
}
#endif
`

const VALIDATE_INTERFACE = `/*
 * Copyright 2011 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 *
 * THIS FILE IS AUTOGENERATED
 * Make edits to tools/gpu/gl/interface/templates.go or they will
 * be overwritten.
 */

#include "include/gpu/gl/GrGLExtensions.h"
#include "include/gpu/gl/GrGLInterface.h"
#include "src/gpu/gl/GrGLUtil.h"

#include <stdio.h>

GrGLInterface::GrGLInterface() {
    fStandard = kNone_GrGLStandard;
}

#if GR_GL_CHECK_ERROR
static const char* get_error_string(GrGLenum err) {
    switch (err) {
        case GR_GL_NO_ERROR:
            return "";
        case GR_GL_INVALID_ENUM:
            return "Invalid Enum";
        case GR_GL_INVALID_VALUE:
            return "Invalid Value";
        case GR_GL_INVALID_OPERATION:
            return "Invalid Operation";
        case GR_GL_OUT_OF_MEMORY:
            return "Out of Memory";
        case GR_GL_CONTEXT_LOST:
            return "Context Lost";
    }
    return "Unknown";
}

GrGLenum GrGLInterface::checkError(const char* location, const char* call) const {
    GrGLenum error = fFunctions.fGetError();
    if (error != GR_GL_NO_ERROR && !fSuppressErrorLogging) {
        SkDebugf("---- glGetError 0x%x(%s)", error, get_error_string(error));
        if (location) {
            SkDebugf(" at\n\t%s", location);
        }
        if (call) {
            SkDebugf("\n\t\t%s", call);
        }
        SkDebugf("\n");
        if (error == GR_GL_OUT_OF_MEMORY) {
            fOOMed = true;
        }
    }
    return error;
}

bool GrGLInterface::checkAndResetOOMed() const {
    if (fOOMed) {
        fOOMed = false;
        return true;
    }
    return false;
}

void GrGLInterface::suppressErrorLogging() { fSuppressErrorLogging = true; }
#endif

#define RETURN_FALSE_INTERFACE                                                 \
    SkDEBUGF("%s:%d GrGLInterface::validate() failed.\n", __FILE__, __LINE__); \
    return false

bool GrGLInterface::validate() const {

    if (kNone_GrGLStandard == fStandard) {
        RETURN_FALSE_INTERFACE;
    }

    if (!fExtensions.isInitialized()) {
        RETURN_FALSE_INTERFACE;
    }

    GrGLVersion glVer = GrGLGetVersion(this);
    if (GR_GL_INVALID_VER == glVer) {
        RETURN_FALSE_INTERFACE;
    }
    // Autogenerated content follows
[[content]]
    // End autogenerated content
    return true;
}

#if GR_TEST_UTILS

void GrGLInterface::abandon() const {
    const_cast<GrGLInterface*>(this)->fFunctions = GrGLInterface::Functions();
}

#endif // GR_TEST_UTILS
`
<commit_msg>[infra] Update templates to use angle brackets<commit_after>// Copyright 2019 The Chromium 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 main

const ASSEMBLE_INTERFACE_GL_ES = `/*
 * Copyright 2019 Google LLC
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 *
 * THIS FILE IS AUTOGENERATED
 * Make edits to tools/gpu/gl/interface/templates.go or they will
 * be overwritten.
 */

#include "include/gpu/gl/GrGLAssembleHelpers.h"
#include "include/gpu/gl/GrGLAssembleInterface.h"
#include "src/gpu/gl/GrGLUtil.h"

#define GET_PROC(F) functions->f##F = (GrGL##F##Fn*)get(ctx, "gl" #F)
#define GET_PROC_SUFFIX(F, S) functions->f##F = (GrGL##F##Fn*)get(ctx, "gl" #F #S)
#define GET_PROC_LOCAL(F) GrGL##F##Fn* F = (GrGL##F##Fn*)get(ctx, "gl" #F)

#define GET_EGL_PROC_SUFFIX(F, S) functions->fEGL##F = (GrEGL##F##Fn*)get(ctx, "egl" #F #S)

#if SK_DISABLE_GL_ES_INTERFACE
sk_sp<const GrGLInterface> GrGLMakeAssembledGLESInterface(void *ctx, GrGLGetProc get) {
    return nullptr;
}
#else
sk_sp<const GrGLInterface> GrGLMakeAssembledGLESInterface(void *ctx, GrGLGetProc get) {
    GET_PROC_LOCAL(GetString);
    if (nullptr == GetString) {
        return nullptr;
    }

    const char* verStr = reinterpret_cast<const char*>(GetString(GR_GL_VERSION));
    GrGLVersion glVer = GrGLGetVersionFromString(verStr);

    if (glVer < GR_GL_VER(2,0)) {
        return nullptr;
    }

    GET_PROC_LOCAL(GetIntegerv);
    GET_PROC_LOCAL(GetStringi);
    GrEGLQueryStringFn* queryString;
    GrEGLDisplay display;
    GrGetEGLQueryAndDisplay(&queryString, &display, ctx, get);
    GrGLExtensions extensions;
    if (!extensions.init(kGLES_GrGLStandard, GetString, GetStringi, GetIntegerv, queryString,
                         display)) {
        return nullptr;
    }

    sk_sp<GrGLInterface> interface(new GrGLInterface);
    GrGLInterface::Functions* functions = &interface->fFunctions;

    // Autogenerated content follows
[[content]]
    // End autogenerated content
    // TODO(kjlubick): Do we want a feature that removes the extension if it doesn't have
    // the function? This is common on some low-end GPUs.

    if (extensions.has("GL_KHR_debug")) {
        // In general we have a policy against removing extension strings when the driver does
        // not provide function pointers for an advertised extension. However, because there is a
        // known device that advertises GL_KHR_debug but fails to provide the functions and this is
        // a debugging- only extension we've made an exception. This also can happen when using
        // APITRACE.
        if (!interface->fFunctions.fDebugMessageControl) {
            extensions.remove("GL_KHR_debug");
        }
    }
    interface->fStandard = kGLES_GrGLStandard;
    interface->fExtensions.swap(&extensions);

    return std::move(interface);
}
#endif
`

const ASSEMBLE_INTERFACE_GL = `/*
 * Copyright 2019 Google LLC
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 *
 * THIS FILE IS AUTOGENERATED
 * Make edits to tools/gpu/gl/interface/templates.go or they will
 * be overwritten.
 */

#include "include/gpu/gl/GrGLAssembleHelpers.h"
#include "include/gpu/gl/GrGLAssembleInterface.h"
#include "src/gpu/gl/GrGLUtil.h"

#define GET_PROC(F) functions->f##F = (GrGL##F##Fn*)get(ctx, "gl" #F)
#define GET_PROC_SUFFIX(F, S) functions->f##F = (GrGL##F##Fn*)get(ctx, "gl" #F #S)
#define GET_PROC_LOCAL(F) GrGL##F##Fn* F = (GrGL##F##Fn*)get(ctx, "gl" #F)

#define GET_EGL_PROC_SUFFIX(F, S) functions->fEGL##F = (GrEGL##F##Fn*)get(ctx, "egl" #F #S)

#if SK_DISABLE_GL_INTERFACE
sk_sp<const GrGLInterface> GrGLMakeAssembledGLInterface(void *ctx, GrGLGetProc get) {
    return nullptr;
}
#else
sk_sp<const GrGLInterface> GrGLMakeAssembledGLInterface(void *ctx, GrGLGetProc get) {
    GET_PROC_LOCAL(GetString);
    GET_PROC_LOCAL(GetStringi);
    GET_PROC_LOCAL(GetIntegerv);

    // GetStringi may be nullptr depending on the GL version.
    if (nullptr == GetString || nullptr == GetIntegerv) {
        return nullptr;
    }

    const char* versionString = (const char*) GetString(GR_GL_VERSION);
    GrGLVersion glVer = GrGLGetVersionFromString(versionString);

    if (glVer < GR_GL_VER(2,0) || GR_GL_INVALID_VER == glVer) {
        // This is our minimum for non-ES GL.
        return nullptr;
    }

    GrEGLQueryStringFn* queryString;
    GrEGLDisplay display;
    GrGetEGLQueryAndDisplay(&queryString, &display, ctx, get);
    GrGLExtensions extensions;
    if (!extensions.init(kGL_GrGLStandard, GetString, GetStringi, GetIntegerv, queryString,
                         display)) {
        return nullptr;
    }

    sk_sp<GrGLInterface> interface(new GrGLInterface());
    GrGLInterface::Functions* functions = &interface->fFunctions;

    // Autogenerated content follows
[[content]]
    // End autogenerated content
    interface->fStandard = kGL_GrGLStandard;
    interface->fExtensions.swap(&extensions);

    return std::move(interface);
}
#endif
`

const ASSEMBLE_INTERFACE_WEBGL = `/*
 * Copyright 2019 Google LLC
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 *
 * THIS FILE IS AUTOGENERATED
 * Make edits to tools/gpu/gl/interface/templates.go or they will
 * be overwritten.
 */

#include "include/gpu/gl/GrGLAssembleHelpers.h"
#include "include/gpu/gl/GrGLAssembleInterface.h"
#include "src/gpu/gl/GrGLUtil.h"

#if SK_DISABLE_WEBGL_INTERFACE || !defined(SK_USE_WEBGL)
sk_sp<const GrGLInterface> GrGLMakeAssembledWebGLInterface(void *ctx, GrGLGetProc get) {
    return nullptr;
}
#else

// Located https://github.com/emscripten-core/emscripten/tree/7ba7700902c46734987585409502f3c63beb650f/system/include/webgl
#include <webgl/webgl1.h>
#include <webgl/webgl1_ext.h>
#include <webgl/webgl2.h>
#include <webgl/webgl2_ext.h>

#define GET_PROC(F) functions->f##F = emscripten_gl##F
#define GET_PROC_SUFFIX(F, S) functions->f##F = emscripten_gl##F##S

// Adapter from standard GL signature to emscripten.
void emscripten_glWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout) {
    uint32_t timeoutLo = timeout;
    uint32_t timeoutHi = timeout >> 32;
    emscripten_glWaitSync(sync, flags, timeoutLo, timeoutHi);
}

// Adapter from standard GL signature to emscripten.
GLenum emscripten_glClientWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout) {
    uint32_t timeoutLo = timeout;
    uint32_t timeoutHi = timeout >> 32;
    return emscripten_glClientWaitSync(sync, flags, timeoutLo, timeoutHi);
}

sk_sp<const GrGLInterface> GrGLMakeAssembledWebGLInterface(void *ctx, GrGLGetProc get) {
    const char* verStr = reinterpret_cast<const char*>(emscripten_glGetString(GR_GL_VERSION));
    GrGLVersion glVer = GrGLGetVersionFromString(verStr);
    if (glVer < GR_GL_VER(1,0)) {
        return nullptr;
    }

    GrGLExtensions extensions;
    if (!extensions.init(kWebGL_GrGLStandard, emscripten_glGetString, emscripten_glGetStringi,
                         emscripten_glGetIntegerv)) {
        return nullptr;
    }

    sk_sp<GrGLInterface> interface(new GrGLInterface);
    GrGLInterface::Functions* functions = &interface->fFunctions;

    // Autogenerated content follows
[[content]]
    // End autogenerated content

    interface->fStandard = kWebGL_GrGLStandard;
    interface->fExtensions.swap(&extensions);

    return std::move(interface);
}
#endif
`

const VALIDATE_INTERFACE = `/*
 * Copyright 2011 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 *
 * THIS FILE IS AUTOGENERATED
 * Make edits to tools/gpu/gl/interface/templates.go or they will
 * be overwritten.
 */

#include "include/gpu/gl/GrGLExtensions.h"
#include "include/gpu/gl/GrGLInterface.h"
#include "src/gpu/gl/GrGLUtil.h"

#include <stdio.h>

GrGLInterface::GrGLInterface() {
    fStandard = kNone_GrGLStandard;
}

#if GR_GL_CHECK_ERROR
static const char* get_error_string(GrGLenum err) {
    switch (err) {
        case GR_GL_NO_ERROR:
            return "";
        case GR_GL_INVALID_ENUM:
            return "Invalid Enum";
        case GR_GL_INVALID_VALUE:
            return "Invalid Value";
        case GR_GL_INVALID_OPERATION:
            return "Invalid Operation";
        case GR_GL_OUT_OF_MEMORY:
            return "Out of Memory";
        case GR_GL_CONTEXT_LOST:
            return "Context Lost";
    }
    return "Unknown";
}

GrGLenum GrGLInterface::checkError(const char* location, const char* call) const {
    GrGLenum error = fFunctions.fGetError();
    if (error != GR_GL_NO_ERROR && !fSuppressErrorLogging) {
        SkDebugf("---- glGetError 0x%x(%s)", error, get_error_string(error));
        if (location) {
            SkDebugf(" at\n\t%s", location);
        }
        if (call) {
            SkDebugf("\n\t\t%s", call);
        }
        SkDebugf("\n");
        if (error == GR_GL_OUT_OF_MEMORY) {
            fOOMed = true;
        }
    }
    return error;
}

bool GrGLInterface::checkAndResetOOMed() const {
    if (fOOMed) {
        fOOMed = false;
        return true;
    }
    return false;
}

void GrGLInterface::suppressErrorLogging() { fSuppressErrorLogging = true; }
#endif

#define RETURN_FALSE_INTERFACE                                                 \
    SkDEBUGF("%s:%d GrGLInterface::validate() failed.\n", __FILE__, __LINE__); \
    return false

bool GrGLInterface::validate() const {

    if (kNone_GrGLStandard == fStandard) {
        RETURN_FALSE_INTERFACE;
    }

    if (!fExtensions.isInitialized()) {
        RETURN_FALSE_INTERFACE;
    }

    GrGLVersion glVer = GrGLGetVersion(this);
    if (GR_GL_INVALID_VER == glVer) {
        RETURN_FALSE_INTERFACE;
    }
    // Autogenerated content follows
[[content]]
    // End autogenerated content
    return true;
}

#if GR_TEST_UTILS

void GrGLInterface::abandon() const {
    const_cast<GrGLInterface*>(this)->fFunctions = GrGLInterface::Functions();
}

#endif // GR_TEST_UTILS
`
<|endoftext|>


<commit_before>package main

import (
	"fmt"

	"github.com/whitepages/terraform-provider-stingray/Godeps/_workspace/src/github.com/hashicorp/terraform/helper/schema"
	"github.com/whitepages/terraform-provider-stingray/Godeps/_workspace/src/github.com/whitepages/go-stingray"
)

func resourceRate() *schema.Resource {
	return &schema.Resource{
		Create: resourceRateCreate,
		Read:   resourceRateRead,
		Update: resourceRateUpdate,
		Delete: resourceRateDelete,

		Schema: map[string]*schema.Schema{
			"name": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"max_rate_per_minute": &schema.Schema{
				Type:     schema.TypeInt,
				Optional: true,
				Computed: true,
			},

			"max_rate_per_second": &schema.Schema{
				Type:     schema.TypeInt,
				Optional: true,
				Computed: true,
			},

			"note": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
			},
		},
	}
}

func resourceRateCreate(d *schema.ResourceData, meta interface{}) error {
	err := resourceRateSet(d, meta)
	if err != nil {
		return err
	}

	return resourceRateRead(d, meta)
}

func resourceRateRead(d *schema.ResourceData, meta interface{}) error {
	c := meta.(*providerConfig).client

	r, resp, err := c.GetRate(d.Get("name").(string))
	if err != nil {
		if resp != nil && resp.StatusCode == 404 {
			// The resource doesn't exist anymore
			d.SetId("")

			return nil
		}

		return fmt.Errorf("Error reading resource: %s", err)
	}

	d.Set("max_rate_per_minute", int(*r.Basic.MaxRatePerMinute))
	d.Set("max_rate_per_second", int(*r.Basic.MaxRatePerSecond))
	d.Set("note", string(*r.Basic.Note))

	return nil
}

func resourceRateUpdate(d *schema.ResourceData, meta interface{}) error {
	err := resourceRateSet(d, meta)
	if err != nil {
		return err
	}

	return resourceRateRead(d, meta)
}

func resourceRateDelete(d *schema.ResourceData, meta interface{}) error {
	c := meta.(*providerConfig).client
	r := stingray.NewRate(d.Id())

	_, err := c.Delete(r)
	if err != nil {
		return err
	}

	return nil
}

func resourceRateSet(d *schema.ResourceData, meta interface{}) error {
	c := meta.(*providerConfig).client
	r := stingray.NewRate(d.Get("name").(string))

	setInt(&r.Basic.MaxRatePerMinute, d, "max_rate_per_minute")
	setInt(&r.Basic.MaxRatePerSecond, d, "max_rate_per_second")
	setString(&r.Basic.Note, d, "note")

	_, err := c.Set(r)
	if err != nil {
		return err
	}

	d.SetId(d.Get("name").(string))

	return nil
}
<commit_msg>stingray_rate: Set default values<commit_after>package main

import (
	"fmt"

	"github.com/whitepages/terraform-provider-stingray/Godeps/_workspace/src/github.com/hashicorp/terraform/helper/schema"
	"github.com/whitepages/terraform-provider-stingray/Godeps/_workspace/src/github.com/whitepages/go-stingray"
)

func resourceRate() *schema.Resource {
	return &schema.Resource{
		Create: resourceRateCreate,
		Read:   resourceRateRead,
		Update: resourceRateUpdate,
		Delete: resourceRateDelete,

		Schema: map[string]*schema.Schema{
			"name": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"max_rate_per_minute": &schema.Schema{
				Type:     schema.TypeInt,
				Optional: true,
				Default:  0,
			},

			"max_rate_per_second": &schema.Schema{
				Type:     schema.TypeInt,
				Optional: true,
				Default:  0,
			},

			"note": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Default:  "",
			},
		},
	}
}

func resourceRateCreate(d *schema.ResourceData, meta interface{}) error {
	err := resourceRateSet(d, meta)
	if err != nil {
		return err
	}

	return resourceRateRead(d, meta)
}

func resourceRateRead(d *schema.ResourceData, meta interface{}) error {
	c := meta.(*providerConfig).client

	r, resp, err := c.GetRate(d.Get("name").(string))
	if err != nil {
		if resp != nil && resp.StatusCode == 404 {
			// The resource doesn't exist anymore
			d.SetId("")

			return nil
		}

		return fmt.Errorf("Error reading resource: %s", err)
	}

	d.Set("max_rate_per_minute", int(*r.Basic.MaxRatePerMinute))
	d.Set("max_rate_per_second", int(*r.Basic.MaxRatePerSecond))
	d.Set("note", string(*r.Basic.Note))

	return nil
}

func resourceRateUpdate(d *schema.ResourceData, meta interface{}) error {
	err := resourceRateSet(d, meta)
	if err != nil {
		return err
	}

	return resourceRateRead(d, meta)
}

func resourceRateDelete(d *schema.ResourceData, meta interface{}) error {
	c := meta.(*providerConfig).client
	r := stingray.NewRate(d.Id())

	_, err := c.Delete(r)
	if err != nil {
		return err
	}

	return nil
}

func resourceRateSet(d *schema.ResourceData, meta interface{}) error {
	c := meta.(*providerConfig).client
	r := stingray.NewRate(d.Get("name").(string))

	setInt(&r.Basic.MaxRatePerMinute, d, "max_rate_per_minute")
	setInt(&r.Basic.MaxRatePerSecond, d, "max_rate_per_second")
	setString(&r.Basic.Note, d, "note")

	_, err := c.Set(r)
	if err != nil {
		return err
	}

	d.SetId(d.Get("name").(string))

	return nil
}
<|endoftext|>


<commit_before>package oauth2

import (
	"net/http"
	"net/http/httptest"
	"testing"

	"github.com/stretchr/testify/assert"
)

func TestNewTokenResponse(t *testing.T) {
	r := NewTokenResponse("foo", "bar", 1)
	assert.Equal(t, "foo", r.TokenType)
	assert.Equal(t, "bar", r.AccessToken)
	assert.Equal(t, 1, r.ExpiresIn)
	assert.Equal(t, map[string]string{
		"token_type":   "foo",
		"access_token": "bar",
		"expires_in":   "1",
	}, r.Map())
}

func TestTokenResponseMap(t *testing.T) {
	r := NewTokenResponse("foo", "bar", 1)
	r.RefreshToken = "baz"
	r.Scope = Scope([]string{"qux"})
	r.State = "quuz"

	assert.Equal(t, map[string]string{
		"token_type":    "foo",
		"access_token":  "bar",
		"expires_in":    "1",
		"refresh_token": "baz",
		"scope":         "qux",
		"state":         "quuz",
	}, r.Map())
}

func TestWriteTokenResponse(t *testing.T) {
	w := httptest.NewRecorder()
	r := NewTokenResponse("foo", "bar", 1)

	err := WriteTokenResponse(w, r)
	assert.NoError(t, err)
	assert.Equal(t, http.StatusOK, w.Code)
	assert.JSONEq(t, `{
		"token_type": "foo",
		"access_token": "bar",
		"expires_in": 1
	}`, w.Body.String())
}

func TestRedirectTokenResponse(t *testing.T) {
	w := httptest.NewRecorder()
	r := NewTokenResponse("foo", "bar", 1)
	r = r.SetRedirect("http://example.com", "baz")

	err := WriteTokenResponse(w, r)
	assert.NoError(t, err)
	assert.Equal(t, http.StatusSeeOther, w.Code)
	assert.Equal(t,
		"http://example.com#access_token=bar&expires_in=1&state=baz&token_type=foo",
		w.Header().Get("Location"),
	)
}

func TestNewCodeResponse(t *testing.T) {
	r := NewCodeResponse("foo", "http://example.com", "bar")
	assert.Equal(t, "foo", r.Code)
	assert.Equal(t, map[string]string{
		"code":  "foo",
		"state": "bar",
	}, r.Map())
}

func TestWriteCodeResponse(t *testing.T) {
	w := httptest.NewRecorder()
	r := NewCodeResponse("foo", "http://example.com", "bar")

	err := WriteCodeResponse(w, r)
	assert.NoError(t, err)
	assert.Equal(t, http.StatusSeeOther, w.Code)
	assert.Equal(t, "http://example.com?code=foo&state=bar", w.Header().Get("Location"))
}
<commit_msg>test redirect uri query parameters handling<commit_after>package oauth2

import (
	"net/http"
	"net/http/httptest"
	"testing"

	"github.com/stretchr/testify/assert"
)

func TestNewTokenResponse(t *testing.T) {
	r := NewTokenResponse("foo", "bar", 1)
	assert.Equal(t, "foo", r.TokenType)
	assert.Equal(t, "bar", r.AccessToken)
	assert.Equal(t, 1, r.ExpiresIn)
	assert.Equal(t, map[string]string{
		"token_type":   "foo",
		"access_token": "bar",
		"expires_in":   "1",
	}, r.Map())
}

func TestTokenResponseMap(t *testing.T) {
	r := NewTokenResponse("foo", "bar", 1)
	r.RefreshToken = "baz"
	r.Scope = Scope([]string{"qux"})
	r.State = "quuz"

	assert.Equal(t, map[string]string{
		"token_type":    "foo",
		"access_token":  "bar",
		"expires_in":    "1",
		"refresh_token": "baz",
		"scope":         "qux",
		"state":         "quuz",
	}, r.Map())
}

func TestWriteTokenResponse(t *testing.T) {
	w := httptest.NewRecorder()
	r := NewTokenResponse("foo", "bar", 1)

	err := WriteTokenResponse(w, r)
	assert.NoError(t, err)
	assert.Equal(t, http.StatusOK, w.Code)
	assert.JSONEq(t, `{
		"token_type": "foo",
		"access_token": "bar",
		"expires_in": 1
	}`, w.Body.String())
}

func TestRedirectTokenResponse(t *testing.T) {
	w := httptest.NewRecorder()
	r := NewTokenResponse("foo", "bar", 1)
	r = r.SetRedirect("http://example.com?foo=bar", "baz")

	err := WriteTokenResponse(w, r)
	assert.NoError(t, err)
	assert.Equal(t, http.StatusSeeOther, w.Code)
	assert.Equal(t,
		"http://example.com?foo=bar#access_token=bar&expires_in=1&state=baz&token_type=foo",
		w.Header().Get("Location"),
	)
}

func TestNewCodeResponse(t *testing.T) {
	r := NewCodeResponse("foo", "http://example.com", "bar")
	assert.Equal(t, "foo", r.Code)
	assert.Equal(t, map[string]string{
		"code":  "foo",
		"state": "bar",
	}, r.Map())
}

func TestWriteCodeResponse(t *testing.T) {
	w := httptest.NewRecorder()
	r := NewCodeResponse("foo", "http://example.com?foo=bar", "bar")

	err := WriteCodeResponse(w, r)
	assert.NoError(t, err)
	assert.Equal(t, http.StatusSeeOther, w.Code)
	assert.Equal(t, "http://example.com?code=foo&foo=bar&state=bar", w.Header().Get("Location"))
}
<|endoftext|>


<commit_before>package pipeline

import (
	"time"

	"github.com/influxdata/kapacitor/tick"
)

// A SourceStreamNode represents the source of data being
// streamed to Kapacitor via any of its inputs.
// The `stream` variable in stream tasks is an instance of
// a SourceStreamNode.
// SourceStreamNode.From is the method/property of this node.
type SourceStreamNode struct {
	node
}

func newSourceStreamNode() *SourceStreamNode {
	return &SourceStreamNode{
		node: node{
			desc:     "srcstream",
			wants:    StreamEdge,
			provides: StreamEdge,
		},
	}
}

// Creates a new StreamNode that can be further
// filtered using the Database, RetentionPolicy, Measurement and Where properties.
// From can be called multiple times to create multiple
// independent forks of the data stream.
//
// Example:
//    // Select the 'cpu' measurement from just the database 'mydb'
//    // and retention policy 'myrp'.
//    var cpu = stream
//        |from()
//            .database('mydb')
//            .retentionPolicy('myrp')
//            .measurement('cpu')
//    // Select the 'load' measurement from any database and retention policy.
//    var load = stream
//        |from()
//            .measurement('load')
//    // Join cpu and load streams and do further processing.
//    cpu
//        |join(load)
//            .as('cpu', 'load')
//        ...
//
func (s *SourceStreamNode) From() *StreamNode {
	f := newStreamNode()
	s.linkChild(f)
	return f
}

// A StreamNode selects a subset of the data flowing through a SourceStreamNode.
// The stream node allows you to select which portion of the stream you want to process.
//
// Example:
//    stream
//        |from()
//           .database('mydb')
//           .retentionPolicy('myrp')
//           .measurement('mymeasurement')
//           .where(lambda: "host" =~ /logger\d+/)
//        |window()
//        ...
//
// The above example selects only data points from the database `mydb`
// and retention policy `myrp` and measurement `mymeasurement` where
// the tag `host` matches the regex `logger\d+`
type StreamNode struct {
	chainnode
	// An expression to filter the data stream.
	// tick:ignore
	Expression tick.Node `tick:"Where"`

	// The dimensions by which to group to the data.
	// tick:ignore
	Dimensions []interface{} `tick:"GroupBy"`

	// The database name.
	// If empty any database will be used.
	Database string

	// The retention policy name
	// If empty any retention policy will be used.
	RetentionPolicy string

	// The measurement name
	// If empty any measurement will be used.
	Measurement string

	// Optional duration for truncating timestamps.
	// Helpful to ensure data points land on specfic boundaries
	// Example:
	//    stream
	//       |from()
	//           .measurement('mydata')
	//           .truncate(1s)
	//
	// All incoming data will be truncated to 1 second resolution.
	Truncate time.Duration
}

func newStreamNode() *StreamNode {
	return &StreamNode{
		chainnode: newBasicChainNode("stream", StreamEdge, StreamEdge),
	}
}

// Creates a new stream node that can be further
// filtered using the Database, RetentionPolicy, Measurement and Where properties.
// From can be called multiple times to create multiple
// independent forks of the data stream.
//
// Example:
//    // Select the 'cpu' measurement from just the database 'mydb'
//    // and retention policy 'myrp'.
//    var cpu = stream
//        |from()
//            .database('mydb')
//            .retentionPolicy('myrp')
//            .measurement('cpu')
//    // Select the 'load' measurement from any database and retention policy.
//    var load = stream
//        |from()
//            .measurement('load')
//    // Join cpu and load streams and do further processing.
//    cpu
//        |join(load)
//            .as('cpu', 'load')
//        ...
//
func (s *StreamNode) From() *StreamNode {
	f := newStreamNode()
	s.linkChild(f)
	return f
}

// Filter the current stream using the given expression.
// This expression is a Kapacitor expression. Kapacitor
// expressions are a superset of InfluxQL WHERE expressions.
// See the [expression](https://docs.influxdata.com/kapacitor/latest/tick/expr/) docs for more information.
//
// Multiple calls to the Where method will `AND` together each expression.
//
// Example:
//    stream
//       |from()
//          .where(lambda: condition1)
//          .where(lambda: condition2)
//
// The above is equivalent to this
// Example:
//    stream
//       |from()
//          .where(lambda: condition1 AND condition2)
//
//
// NOTE: Becareful to always use `|from` if you want multiple different streams.
//
// Example:
//  var data = stream
//      |from()
//          .measurement('cpu')
//  var total = data
//      .where(lambda: "cpu" == 'cpu-total')
//  var others = data
//      .where(lambda: "cpu" != 'cpu-total')
//
// The example above is equivalent to the example below,
// which is obviously not what was intended.
//
// Example:
//  var data = stream
//      |from()
//          .measurement('cpu')
//          .where(lambda: "cpu" == 'cpu-total' AND "cpu" != 'cpu-total')
//  var total = data
//  var others = total
//
// The example below will create two different streams each selecting
// a different subset of the original stream.
//
// Example:
//  var data = stream
//      |from()
//          .measurement('cpu')
//  var total = stream
//      |from()
//          .measurement('cpu')
//          .where(lambda: "cpu" == 'cpu-total')
//  var others = stream
//      |from()
//          .measurement('cpu')
//          .where(lambda: "cpu" != 'cpu-total')
//
//
// If empty then all data points are considered to match.
// tick:property
func (s *StreamNode) Where(expression tick.Node) *StreamNode {
	if s.Expression != nil {
		s.Expression = &tick.BinaryNode{
			Operator: tick.TokenAnd,
			Left:     s.Expression,
			Right:    expression,
		}
	} else {
		s.Expression = expression
	}
	return s
}

// Group the data by a set of tags.
//
// Can pass literal * to group by all dimensions.
// Example:
//  stream
//      |from()
//          .groupBy(*)
//
func (s *StreamNode) GroupBy(tag ...interface{}) *StreamNode {
	s.Dimensions = tag
	return s
}
<commit_msg>The GroupBy property method is currently documented in the wrong section.<commit_after>package pipeline

import (
	"time"

	"github.com/influxdata/kapacitor/tick"
)

// A SourceStreamNode represents the source of data being
// streamed to Kapacitor via any of its inputs.
// The `stream` variable in stream tasks is an instance of
// a SourceStreamNode.
// SourceStreamNode.From is the method/property of this node.
type SourceStreamNode struct {
	node
}

func newSourceStreamNode() *SourceStreamNode {
	return &SourceStreamNode{
		node: node{
			desc:     "srcstream",
			wants:    StreamEdge,
			provides: StreamEdge,
		},
	}
}

// Creates a new StreamNode that can be further
// filtered using the Database, RetentionPolicy, Measurement and Where properties.
// From can be called multiple times to create multiple
// independent forks of the data stream.
//
// Example:
//    // Select the 'cpu' measurement from just the database 'mydb'
//    // and retention policy 'myrp'.
//    var cpu = stream
//        |from()
//            .database('mydb')
//            .retentionPolicy('myrp')
//            .measurement('cpu')
//    // Select the 'load' measurement from any database and retention policy.
//    var load = stream
//        |from()
//            .measurement('load')
//    // Join cpu and load streams and do further processing.
//    cpu
//        |join(load)
//            .as('cpu', 'load')
//        ...
//
func (s *SourceStreamNode) From() *StreamNode {
	f := newStreamNode()
	s.linkChild(f)
	return f
}

// A StreamNode selects a subset of the data flowing through a SourceStreamNode.
// The stream node allows you to select which portion of the stream you want to process.
//
// Example:
//    stream
//        |from()
//           .database('mydb')
//           .retentionPolicy('myrp')
//           .measurement('mymeasurement')
//           .where(lambda: "host" =~ /logger\d+/)
//        |window()
//        ...
//
// The above example selects only data points from the database `mydb`
// and retention policy `myrp` and measurement `mymeasurement` where
// the tag `host` matches the regex `logger\d+`
type StreamNode struct {
	chainnode
	// An expression to filter the data stream.
	// tick:ignore
	Expression tick.Node `tick:"Where"`

	// The dimensions by which to group to the data.
	// tick:ignore
	Dimensions []interface{} `tick:"GroupBy"`

	// The database name.
	// If empty any database will be used.
	Database string

	// The retention policy name
	// If empty any retention policy will be used.
	RetentionPolicy string

	// The measurement name
	// If empty any measurement will be used.
	Measurement string

	// Optional duration for truncating timestamps.
	// Helpful to ensure data points land on specfic boundaries
	// Example:
	//    stream
	//       |from()
	//           .measurement('mydata')
	//           .truncate(1s)
	//
	// All incoming data will be truncated to 1 second resolution.
	Truncate time.Duration
}

func newStreamNode() *StreamNode {
	return &StreamNode{
		chainnode: newBasicChainNode("stream", StreamEdge, StreamEdge),
	}
}

// Creates a new stream node that can be further
// filtered using the Database, RetentionPolicy, Measurement and Where properties.
// From can be called multiple times to create multiple
// independent forks of the data stream.
//
// Example:
//    // Select the 'cpu' measurement from just the database 'mydb'
//    // and retention policy 'myrp'.
//    var cpu = stream
//        |from()
//            .database('mydb')
//            .retentionPolicy('myrp')
//            .measurement('cpu')
//    // Select the 'load' measurement from any database and retention policy.
//    var load = stream
//        |from()
//            .measurement('load')
//    // Join cpu and load streams and do further processing.
//    cpu
//        |join(load)
//            .as('cpu', 'load')
//        ...
//
func (s *StreamNode) From() *StreamNode {
	f := newStreamNode()
	s.linkChild(f)
	return f
}

// Filter the current stream using the given expression.
// This expression is a Kapacitor expression. Kapacitor
// expressions are a superset of InfluxQL WHERE expressions.
// See the [expression](https://docs.influxdata.com/kapacitor/latest/tick/expr/) docs for more information.
//
// Multiple calls to the Where method will `AND` together each expression.
//
// Example:
//    stream
//       |from()
//          .where(lambda: condition1)
//          .where(lambda: condition2)
//
// The above is equivalent to this
// Example:
//    stream
//       |from()
//          .where(lambda: condition1 AND condition2)
//
//
// NOTE: Becareful to always use `|from` if you want multiple different streams.
//
// Example:
//  var data = stream
//      |from()
//          .measurement('cpu')
//  var total = data
//      .where(lambda: "cpu" == 'cpu-total')
//  var others = data
//      .where(lambda: "cpu" != 'cpu-total')
//
// The example above is equivalent to the example below,
// which is obviously not what was intended.
//
// Example:
//  var data = stream
//      |from()
//          .measurement('cpu')
//          .where(lambda: "cpu" == 'cpu-total' AND "cpu" != 'cpu-total')
//  var total = data
//  var others = total
//
// The example below will create two different streams each selecting
// a different subset of the original stream.
//
// Example:
//  var data = stream
//      |from()
//          .measurement('cpu')
//  var total = stream
//      |from()
//          .measurement('cpu')
//          .where(lambda: "cpu" == 'cpu-total')
//  var others = stream
//      |from()
//          .measurement('cpu')
//          .where(lambda: "cpu" != 'cpu-total')
//
//
// If empty then all data points are considered to match.
// tick:property
func (s *StreamNode) Where(expression tick.Node) *StreamNode {
	if s.Expression != nil {
		s.Expression = &tick.BinaryNode{
			Operator: tick.TokenAnd,
			Left:     s.Expression,
			Right:    expression,
		}
	} else {
		s.Expression = expression
	}
	return s
}

// Group the data by a set of tags.
//
// Can pass literal * to group by all dimensions.
// Example:
//  stream
//      |from()
//          .groupBy(*)
// tick:property
func (s *StreamNode) GroupBy(tag ...interface{}) *StreamNode {
	s.Dimensions = tag
	return s
}
<|endoftext|>


<commit_before>// Package global provides an algorithm for globally adaptive hierarchical
// interpolation.
package global

import (
	"math"

	"github.com/ready-steady/adapt/algorithm/internal"
)

var (
	infinity = math.Inf(1.0)
)

// Basis is a functional basis.
type Basis interface {
	// Compute evaluates the value of a basis function.
	Compute([]uint64, []float64) float64
}

// Grid is a sparse grid.
type Grid interface {
	// Compute returns the nodes corresponding to a set of indices.
	Compute([]uint64) []float64

	// Index returns the indices of a set of levels.
	Index([]uint8) []uint64
}

// Interpolator is an instance of the algorithm.
type Interpolator struct {
	config Config
	basis  Basis
	grid   Grid
}

// Progress contains information about the interpolation process.
type Progress struct {
	Level       uint8 // Reached level
	Active      uint  // The number of active indices
	Passive     uint  // The number of passive indices
	Evaluations uint  // The number of function evaluations
}

type cursor map[uint]bool

// New creates an interpolator.
func New(grid Grid, basis Basis, config *Config) *Interpolator {
	return &Interpolator{
		config: *config,
		basis:  basis,
		grid:   grid,
	}
}

// Compute constructs an interpolant for a function.
func (self *Interpolator) Compute(target Target) *Surrogate {
	config := &self.config

	ni, no := target.Dimensions()
	nw := config.Workers

	lindices := make([]uint8, 1*ni)
	indices := self.grid.Index(lindices)
	counts := []uint{uint(len(indices)) / ni}
	nodes := self.grid.Compute(indices)

	values := internal.Invoke(target.Compute, nodes, ni, no, nw)
	surrogate := newSurrogate(ni, no)
	surrogate.push(indices, values)

	accuracy := newAccuracy(no, config)
	accuracy.push(values, values, counts)

	tracker := newTracker(ni, config)
	tracker.push(lindices, assess(target.Score, values, counts, no))

	progress := &Progress{Active: 1, Evaluations: counts[0]}

	for !accuracy.enough(tracker.active) {
		target.Monitor(progress)

		lindices = tracker.pull()
		nn := uint(len(lindices)) / ni

		progress.Active--
		progress.Passive++
		progress.Active += nn

		indices, counts = indices[:0], counts[:0]
		for i := uint(0); i < nn; i++ {
			newIndices := self.grid.Index(lindices[i*ni : (i+1)*ni])
			indices = append(indices, newIndices...)
			counts = append(counts, uint(len(newIndices))/ni)
		}

		level := maxUint8(lindices)
		if level > progress.Level {
			progress.Level = level
		}

		nn = uint(len(indices)) / ni
		progress.Evaluations += nn
		if progress.Evaluations > config.MaxEvaluations {
			break
		}

		nodes := self.grid.Compute(indices)
		values := internal.Invoke(target.Compute, nodes, ni, no, nw)
		surpluses := internal.Subtract(values, internal.Approximate(self.basis,
			surrogate.Indices, surrogate.Surpluses, nodes, ni, no, nw))

		surrogate.push(indices, surpluses)
		accuracy.push(values, surpluses, counts)
		tracker.push(nil, assess(target.Score, surpluses, counts, no))
	}

	return surrogate
}

// Evaluate computes the values of an interpolant at a set of points.
func (self *Interpolator) Evaluate(surrogate *Surrogate, points []float64) []float64 {
	return internal.Approximate(self.basis, surrogate.Indices, surrogate.Surpluses, points,
		surrogate.Inputs, surrogate.Outputs, self.config.Workers)
}
<commit_msg>a/global: refactor a bit<commit_after>// Package global provides an algorithm for globally adaptive hierarchical
// interpolation.
package global

import (
	"math"

	"github.com/ready-steady/adapt/algorithm/internal"
)

var (
	infinity = math.Inf(1.0)
)

// Basis is a functional basis.
type Basis interface {
	// Compute evaluates the value of a basis function.
	Compute([]uint64, []float64) float64
}

// Grid is a sparse grid.
type Grid interface {
	// Compute returns the nodes corresponding to a set of indices.
	Compute([]uint64) []float64

	// Index returns the indices of a set of levels.
	Index([]uint8) []uint64
}

// Interpolator is an instance of the algorithm.
type Interpolator struct {
	config Config
	basis  Basis
	grid   Grid
}

// Progress contains information about the interpolation process.
type Progress struct {
	Level       uint8 // Reached level
	Active      uint  // The number of active indices
	Passive     uint  // The number of passive indices
	Evaluations uint  // The number of function evaluations
}

type cursor map[uint]bool

// New creates an interpolator.
func New(grid Grid, basis Basis, config *Config) *Interpolator {
	return &Interpolator{
		config: *config,
		basis:  basis,
		grid:   grid,
	}
}

// Compute constructs an interpolant for a function.
func (self *Interpolator) Compute(target Target) *Surrogate {
	config := &self.config

	ni, no := target.Dimensions()
	nw := config.Workers

	lindices := make([]uint8, 1*ni)
	indices := self.grid.Index(lindices)
	counts := []uint{uint(len(indices)) / ni}

	surrogate := newSurrogate(ni, no)
	accuracy := newAccuracy(no, config)
	tracker := newTracker(ni, config)

	progress := &Progress{Active: 1}
	for {
		target.Monitor(progress)

		nodes := self.grid.Compute(indices)
		values := internal.Invoke(target.Compute, nodes, ni, no, nw)
		surpluses := internal.Subtract(values, internal.Approximate(self.basis,
			surrogate.Indices, surrogate.Surpluses, nodes, ni, no, nw))

		surrogate.push(indices, surpluses)
		accuracy.push(values, surpluses, counts)
		tracker.push(lindices, assess(target.Score, surpluses, counts, no))

		if accuracy.enough(tracker.active) {
			break
		}

		lindices = tracker.pull()

		progress.Active--
		progress.Passive++
		progress.Active += uint(len(lindices)) / ni

		indices, counts = indices[:0], counts[:0]
		for len(lindices) > 0 {
			newIndices := self.grid.Index(lindices[:ni])
			indices = append(indices, newIndices...)
			counts = append(counts, uint(len(newIndices))/ni)
			lindices = lindices[ni:]
		}

		level := maxUint8(lindices)
		if level > progress.Level {
			progress.Level = level
		}

		progress.Evaluations += uint(len(indices)) / ni
		if progress.Evaluations > config.MaxEvaluations {
			break
		}
	}

	return surrogate
}

// Evaluate computes the values of an interpolant at a set of points.
func (self *Interpolator) Evaluate(surrogate *Surrogate, points []float64) []float64 {
	return internal.Approximate(self.basis, surrogate.Indices, surrogate.Surpluses, points,
		surrogate.Inputs, surrogate.Outputs, self.config.Workers)
}
<|endoftext|>


<commit_before>package agent

import (
	"fmt"
	"sync"
	"time"

	"github.com/Sirupsen/logrus"
	"github.com/toni-moreno/snmpcollector/pkg/agent/bus"
	"github.com/toni-moreno/snmpcollector/pkg/agent/device"
	"github.com/toni-moreno/snmpcollector/pkg/agent/output"
	"github.com/toni-moreno/snmpcollector/pkg/agent/selfmon"
	"github.com/toni-moreno/snmpcollector/pkg/config"
)

// Version X.Y.Z based versioning
var (
	Version    string
	Commit     string
	Branch     string
	BuildStamp string
)

// RInfo  Release basic version info for the agent
type RInfo struct {
	InstanceID string
	Version    string
	Commit     string
	Branch     string
	BuildStamp string
}

// GetRInfo return Release Agent Information
func GetRInfo() *RInfo {
	info := &RInfo{
		InstanceID: MainConfig.General.InstanceID,
		Version:    Version,
		Commit:     Commit,
		Branch:     Branch,
		BuildStamp: BuildStamp,
	}
	return info
}

var (
	// Bus the bus messaging system to send messages over the devices
	Bus = bus.NewBus()

	// MainConfig has all configuration
	MainConfig config.Config

	// DBConfig db config
	DBConfig config.DBConfig

	log *logrus.Logger
	//mutex for devices map
	mutex sync.RWMutex
	//reload mutex
	reloadMutex   sync.Mutex
	reloadProcess bool
	//runtime devices
	devices map[string]*device.SnmpDevice
	//runtime output db's
	influxdb map[string]*output.InfluxDB

	selfmonProc *selfmon.SelfMon
	// for synchronize  deivce specific goroutines
	gatherWg sync.WaitGroup
	senderWg sync.WaitGroup
)

// SetLogger set log output
func SetLogger(l *logrus.Logger) {
	log = l
}

//Reload Mutex Related Methods.

// CheckReloadProcess check if the agent is doing a reloading just now
func CheckReloadProcess() bool {
	reloadMutex.Lock()
	defer reloadMutex.Unlock()
	return reloadProcess
}

// CheckAndSetReloadProcess set the reloadProcess flat to true and  return the last stat before true set
func CheckAndSetReloadProcess() bool {
	reloadMutex.Lock()
	defer reloadMutex.Unlock()
	retval := reloadProcess
	reloadProcess = true
	return retval
}

// CheckAndUnSetReloadProcess set the reloadProcess flat to false and  return the last stat before true set
func CheckAndUnSetReloadProcess() bool {
	reloadMutex.Lock()
	defer reloadMutex.Unlock()
	retval := reloadProcess
	reloadProcess = false
	return retval
}

//PrepareInfluxDBs review all configured db's in the SQL database
// and check if exist at least a "default", if not creates a dummy db which does nothing
func PrepareInfluxDBs() map[string]*output.InfluxDB {
	idb := make(map[string]*output.InfluxDB)

	var defFound bool
	for k, c := range DBConfig.Influxdb {
		//Inticialize each SNMP device
		if k == "default" {
			defFound = true
		}
		idb[k] = output.NewNotInitInfluxDB(c)
	}
	if defFound == false {
		//no devices configured  as default device we need to set some device as itcan send data transparent to snmpdevices goroutines
		log.Warn("No Output default found influxdb devices found !!")
		idb["default"] = output.DummyDB
	}
	return idb
}

//GetDevice is a safe method to get a Device Object
func GetDevice(id string) (*device.SnmpDevice, error) {
	var dev *device.SnmpDevice
	var ok bool
	if CheckReloadProcess() == true {
		log.Warning("There is a reload process running while trying to get device info")
		return nil, fmt.Errorf("There is a reload process running.... please wait until finished ")
	}
	mutex.RLock()
	if dev, ok = devices[id]; !ok {
		return nil, fmt.Errorf("there is not any device with id %s running", id)
	}
	mutex.RUnlock()
	return dev, nil
}

//GetDeviceJSONInfo get device data in JSON format just if not doing a reloading process
func GetDeviceJSONInfo(id string) ([]byte, error) {
	var dev *device.SnmpDevice
	var ok bool
	if CheckReloadProcess() == true {
		log.Warning("There is a reload process running while trying to get device info")
		return nil, fmt.Errorf("There is a reload process running.... please wait until finished ")
	}
	mutex.RLock()
	defer mutex.RUnlock()
	if dev, ok = devices[id]; !ok {
		return nil, fmt.Errorf("there is not any device with id %s running", id)
	}
	return dev.ToJSON()
}

// GetDevStats xx
func GetDevStats() map[string]*device.DevStat {
	devstats := make(map[string]*device.DevStat)
	mutex.RLock()
	for k, v := range devices {
		devstats[k] = v.GetBasicStats()
	}
	mutex.RUnlock()
	return devstats
}

// StopInfluxOut xx
func StopInfluxOut(idb map[string]*output.InfluxDB) {
	for k, v := range idb {
		log.Infof("Stopping Influxdb out %s", k)
		v.StopSender()
	}
}

// ReleaseInfluxOut xx
func ReleaseInfluxOut(idb map[string]*output.InfluxDB) {
	for k, v := range idb {
		log.Infof("Release Influxdb resources %s", k)
		v.End()
	}
}

// DeviceProcessStop stop all device goroutines
func DeviceProcessStop() {
	Bus.Broadcast(&bus.Message{Type: "exit"})
}

// DeviceProcessStart start all devices goroutines
func DeviceProcessStart() {
	mutex.Lock()
	devices = make(map[string]*device.SnmpDevice)
	mutex.Unlock()

	for k, c := range DBConfig.SnmpDevice {
		AddDeviceInRuntime(k, c)
	}
}

// ReleaseDevices Executes End for each device
func ReleaseDevices() {
	mutex.RLock()
	for _, c := range devices {
		c.End()
	}
	mutex.RUnlock()
}

func init() {
	go Bus.Start()
}

func initSelfMonitoring(idb map[string]*output.InfluxDB) {
	log.Debugf("INFLUXDB2: %+v", idb)
	selfmonProc = selfmon.NewNotInit(&MainConfig.Selfmon)

	if MainConfig.Selfmon.Enabled {
		if val, ok := idb["default"]; ok {
			//only executed if a "default" influxdb exist
			val.Init()
			val.StartSender(&senderWg)

			selfmonProc.Init()
			selfmonProc.SetOutDB(idb)
			selfmonProc.SetOutput(val)

			log.Printf("SELFMON enabled %+v", MainConfig.Selfmon)
			//Begin the statistic reporting
			selfmonProc.StartGather(&gatherWg)
		} else {
			MainConfig.Selfmon.Enabled = false
			log.Errorf("SELFMON disabled becaouse of no default db found !!! SELFMON[ %+v ]  INFLUXLIST[ %+v]\n", MainConfig.Selfmon, idb)
		}
	} else {
		log.Printf("SELFMON disabled %+v\n", MainConfig.Selfmon)
	}
}

// IsDeviceRuntime check if deviceID exist in the runtime array
func IsDeviceInRuntime(id string) bool {
	mutex.Lock()
	defer mutex.Unlock()
	if _, ok := devices[id]; ok {
		return true
	}
	return false

}

// DeleteDeviceInRuntime
func DeleteDeviceInRuntime(id string) error {

	if dev, ok := devices[id]; ok {
		dev.StopGather()
		log.Debugf("Bus retuned from the exit message to the ID device %s", id)
		dev.LeaveBus(Bus)
		dev.End()
		mutex.Lock()
		delete(devices, id)
		mutex.Unlock()
		return nil
		//do something here
	}
	log.Errorf("There is no  %s device in the runtime device list", id)
	return nil
}

// AddDeviceInRuntime
func AddDeviceInRuntime(k string, cfg *config.SnmpDeviceCfg) {
	//Inticialize each SNMP device and put pointer to the global map devices
	dev := device.New(cfg)
	dev.AttachToBus(Bus)
	dev.InitCatalogVar(DBConfig.VarCatalog)
	dev.SetSelfMonitoring(selfmonProc)
	//send db's map to initialize each one its own db if needed and not yet initialized

	outdb, _ := dev.GetOutSenderFromMap(influxdb)
	outdb.Init()
	outdb.StartSender(&senderWg)

	mutex.Lock()
	devices[k] = dev
	dev.StartGather(&gatherWg)
	mutex.Unlock()

}

// LoadConf call to initialize alln configurations
func LoadConf() {
	//Load all database info to Cfg struct
	MainConfig.Database.LoadDbConfig(&DBConfig)
	//Prepare the InfluxDataBases Configuration
	influxdb = PrepareInfluxDBs()

	// beginning self monitoring process if needed.( before each other gorotines could begin)

	initSelfMonitoring(influxdb)

	//Initialize Device Metrics CFG

	config.InitMetricsCfg(&DBConfig)

	//beginning  the gather process
}

// Start init the agent
func Start() {
	//Load Config
	LoadConf()
	//Init Processesing
	DeviceProcessStart()
}

// End finish all goroutines.
func End() (time.Duration, error) {

	start := time.Now()
	log.Infof("END: begin device Gather processes stop... at %s", start.String())
	//stop all device processes
	DeviceProcessStop()
	log.Info("END: begin selfmon Gather processes stop...")
	//stop the selfmon process
	selfmonProc.StopGather()
	log.Info("END: waiting for all Gather gorotines stop...")
	//wait until Done
	gatherWg.Wait()
	log.Info("END: releasing Device Resources")
	ReleaseDevices()
	log.Info("END: releasing Seflmonitoring Resources")
	selfmonProc.End()
	log.Info("END: begin sender processes stop...")
	//stop all Output Emmiter
	//log.Info("DEBUG Gather WAIT %+v", GatherWg)
	//log.Info("DEBUG SENDER WAIT %+v", senderWg)
	StopInfluxOut(influxdb)
	log.Info("END: waiting for all Sender gorotines stop..")
	senderWg.Wait()
	log.Info("END: releasing Sender Resources")
	ReleaseInfluxOut(influxdb)
	log.Infof("END: Finished from %s to %s [Duration : %s]", start.String(), time.Now().String(), time.Since(start).String())
	return time.Since(start), nil
}

// ReloadConf call to reinitialize alln configurations
func ReloadConf() (time.Duration, error) {
	start := time.Now()
	if CheckAndSetReloadProcess() == true {
		log.Warning("RELOADCONF: There is another reload process running while trying to reload at %s  ", start.String())
		return time.Since(start), fmt.Errorf("There is another reload process running.... please wait until finished ")
	}

	log.Infof("RELOADCONF INIT: begin device Gather processes stop... at %s", start.String())
	End()

	log.Info("RELOADCONF: loading configuration Again...")
	LoadConf()
	log.Info("RELOADCONF: Starting all device processes again...")
	//Initialize Devices in Runtime map
	DeviceProcessStart()

	log.Infof("RELOADCONF END: Finished from %s to %s [Duration : %s]", start.String(), time.Now().String(), time.Since(start).String())
	CheckAndUnSetReloadProcess()

	return time.Since(start), nil
}
<commit_msg>Bugfix: release mutex even on premature return.<commit_after>package agent

import (
	"fmt"
	"sync"
	"time"

	"github.com/Sirupsen/logrus"
	"github.com/toni-moreno/snmpcollector/pkg/agent/bus"
	"github.com/toni-moreno/snmpcollector/pkg/agent/device"
	"github.com/toni-moreno/snmpcollector/pkg/agent/output"
	"github.com/toni-moreno/snmpcollector/pkg/agent/selfmon"
	"github.com/toni-moreno/snmpcollector/pkg/config"
)

// Version X.Y.Z based versioning
var (
	Version    string
	Commit     string
	Branch     string
	BuildStamp string
)

// RInfo  Release basic version info for the agent
type RInfo struct {
	InstanceID string
	Version    string
	Commit     string
	Branch     string
	BuildStamp string
}

// GetRInfo return Release Agent Information
func GetRInfo() *RInfo {
	info := &RInfo{
		InstanceID: MainConfig.General.InstanceID,
		Version:    Version,
		Commit:     Commit,
		Branch:     Branch,
		BuildStamp: BuildStamp,
	}
	return info
}

var (
	// Bus the bus messaging system to send messages over the devices
	Bus = bus.NewBus()

	// MainConfig has all configuration
	MainConfig config.Config

	// DBConfig db config
	DBConfig config.DBConfig

	log *logrus.Logger
	//mutex for devices map
	mutex sync.RWMutex
	//reload mutex
	reloadMutex   sync.Mutex
	reloadProcess bool
	//runtime devices
	devices map[string]*device.SnmpDevice
	//runtime output db's
	influxdb map[string]*output.InfluxDB

	selfmonProc *selfmon.SelfMon
	// for synchronize  deivce specific goroutines
	gatherWg sync.WaitGroup
	senderWg sync.WaitGroup
)

// SetLogger set log output
func SetLogger(l *logrus.Logger) {
	log = l
}

//Reload Mutex Related Methods.

// CheckReloadProcess check if the agent is doing a reloading just now
func CheckReloadProcess() bool {
	reloadMutex.Lock()
	defer reloadMutex.Unlock()
	return reloadProcess
}

// CheckAndSetReloadProcess set the reloadProcess flat to true and  return the last stat before true set
func CheckAndSetReloadProcess() bool {
	reloadMutex.Lock()
	defer reloadMutex.Unlock()
	retval := reloadProcess
	reloadProcess = true
	return retval
}

// CheckAndUnSetReloadProcess set the reloadProcess flat to false and  return the last stat before true set
func CheckAndUnSetReloadProcess() bool {
	reloadMutex.Lock()
	defer reloadMutex.Unlock()
	retval := reloadProcess
	reloadProcess = false
	return retval
}

//PrepareInfluxDBs review all configured db's in the SQL database
// and check if exist at least a "default", if not creates a dummy db which does nothing
func PrepareInfluxDBs() map[string]*output.InfluxDB {
	idb := make(map[string]*output.InfluxDB)

	var defFound bool
	for k, c := range DBConfig.Influxdb {
		//Inticialize each SNMP device
		if k == "default" {
			defFound = true
		}
		idb[k] = output.NewNotInitInfluxDB(c)
	}
	if defFound == false {
		//no devices configured  as default device we need to set some device as itcan send data transparent to snmpdevices goroutines
		log.Warn("No Output default found influxdb devices found !!")
		idb["default"] = output.DummyDB
	}
	return idb
}

//GetDevice is a safe method to get a Device Object
func GetDevice(id string) (*device.SnmpDevice, error) {
	var dev *device.SnmpDevice
	var ok bool
	if CheckReloadProcess() == true {
		log.Warning("There is a reload process running while trying to get device info")
		return nil, fmt.Errorf("There is a reload process running.... please wait until finished ")
	}
	mutex.RLock()
	defer mutex.RUnlock()
	if dev, ok = devices[id]; !ok {
		return nil, fmt.Errorf("there is not any device with id %s running", id)
	}
	return dev, nil
}

//GetDeviceJSONInfo get device data in JSON format just if not doing a reloading process
func GetDeviceJSONInfo(id string) ([]byte, error) {
	var dev *device.SnmpDevice
	var ok bool
	if CheckReloadProcess() == true {
		log.Warning("There is a reload process running while trying to get device info")
		return nil, fmt.Errorf("There is a reload process running.... please wait until finished ")
	}
	mutex.RLock()
	defer mutex.RUnlock()
	if dev, ok = devices[id]; !ok {
		return nil, fmt.Errorf("there is not any device with id %s running", id)
	}
	return dev.ToJSON()
}

// GetDevStats xx
func GetDevStats() map[string]*device.DevStat {
	devstats := make(map[string]*device.DevStat)
	mutex.RLock()
	for k, v := range devices {
		devstats[k] = v.GetBasicStats()
	}
	mutex.RUnlock()
	return devstats
}

// StopInfluxOut xx
func StopInfluxOut(idb map[string]*output.InfluxDB) {
	for k, v := range idb {
		log.Infof("Stopping Influxdb out %s", k)
		v.StopSender()
	}
}

// ReleaseInfluxOut xx
func ReleaseInfluxOut(idb map[string]*output.InfluxDB) {
	for k, v := range idb {
		log.Infof("Release Influxdb resources %s", k)
		v.End()
	}
}

// DeviceProcessStop stop all device goroutines
func DeviceProcessStop() {
	Bus.Broadcast(&bus.Message{Type: "exit"})
}

// DeviceProcessStart start all devices goroutines
func DeviceProcessStart() {
	mutex.Lock()
	devices = make(map[string]*device.SnmpDevice)
	mutex.Unlock()

	for k, c := range DBConfig.SnmpDevice {
		AddDeviceInRuntime(k, c)
	}
}

// ReleaseDevices Executes End for each device
func ReleaseDevices() {
	mutex.RLock()
	for _, c := range devices {
		c.End()
	}
	mutex.RUnlock()
}

func init() {
	go Bus.Start()
}

func initSelfMonitoring(idb map[string]*output.InfluxDB) {
	log.Debugf("INFLUXDB2: %+v", idb)
	selfmonProc = selfmon.NewNotInit(&MainConfig.Selfmon)

	if MainConfig.Selfmon.Enabled {
		if val, ok := idb["default"]; ok {
			//only executed if a "default" influxdb exist
			val.Init()
			val.StartSender(&senderWg)

			selfmonProc.Init()
			selfmonProc.SetOutDB(idb)
			selfmonProc.SetOutput(val)

			log.Printf("SELFMON enabled %+v", MainConfig.Selfmon)
			//Begin the statistic reporting
			selfmonProc.StartGather(&gatherWg)
		} else {
			MainConfig.Selfmon.Enabled = false
			log.Errorf("SELFMON disabled becaouse of no default db found !!! SELFMON[ %+v ]  INFLUXLIST[ %+v]\n", MainConfig.Selfmon, idb)
		}
	} else {
		log.Printf("SELFMON disabled %+v\n", MainConfig.Selfmon)
	}
}

// IsDeviceRuntime check if deviceID exist in the runtime array
func IsDeviceInRuntime(id string) bool {
	mutex.Lock()
	defer mutex.Unlock()
	if _, ok := devices[id]; ok {
		return true
	}
	return false

}

// DeleteDeviceInRuntime
func DeleteDeviceInRuntime(id string) error {

	if dev, ok := devices[id]; ok {
		dev.StopGather()
		log.Debugf("Bus retuned from the exit message to the ID device %s", id)
		dev.LeaveBus(Bus)
		dev.End()
		mutex.Lock()
		delete(devices, id)
		mutex.Unlock()
		return nil
		//do something here
	}
	log.Errorf("There is no  %s device in the runtime device list", id)
	return nil
}

// AddDeviceInRuntime
func AddDeviceInRuntime(k string, cfg *config.SnmpDeviceCfg) {
	//Inticialize each SNMP device and put pointer to the global map devices
	dev := device.New(cfg)
	dev.AttachToBus(Bus)
	dev.InitCatalogVar(DBConfig.VarCatalog)
	dev.SetSelfMonitoring(selfmonProc)
	//send db's map to initialize each one its own db if needed and not yet initialized

	outdb, _ := dev.GetOutSenderFromMap(influxdb)
	outdb.Init()
	outdb.StartSender(&senderWg)

	mutex.Lock()
	devices[k] = dev
	dev.StartGather(&gatherWg)
	mutex.Unlock()

}

// LoadConf call to initialize alln configurations
func LoadConf() {
	//Load all database info to Cfg struct
	MainConfig.Database.LoadDbConfig(&DBConfig)
	//Prepare the InfluxDataBases Configuration
	influxdb = PrepareInfluxDBs()

	// beginning self monitoring process if needed.( before each other gorotines could begin)

	initSelfMonitoring(influxdb)

	//Initialize Device Metrics CFG

	config.InitMetricsCfg(&DBConfig)

	//beginning  the gather process
}

// Start init the agent
func Start() {
	//Load Config
	LoadConf()
	//Init Processesing
	DeviceProcessStart()
}

// End finish all goroutines.
func End() (time.Duration, error) {

	start := time.Now()
	log.Infof("END: begin device Gather processes stop... at %s", start.String())
	//stop all device processes
	DeviceProcessStop()
	log.Info("END: begin selfmon Gather processes stop...")
	//stop the selfmon process
	selfmonProc.StopGather()
	log.Info("END: waiting for all Gather gorotines stop...")
	//wait until Done
	gatherWg.Wait()
	log.Info("END: releasing Device Resources")
	ReleaseDevices()
	log.Info("END: releasing Seflmonitoring Resources")
	selfmonProc.End()
	log.Info("END: begin sender processes stop...")
	//stop all Output Emmiter
	//log.Info("DEBUG Gather WAIT %+v", GatherWg)
	//log.Info("DEBUG SENDER WAIT %+v", senderWg)
	StopInfluxOut(influxdb)
	log.Info("END: waiting for all Sender gorotines stop..")
	senderWg.Wait()
	log.Info("END: releasing Sender Resources")
	ReleaseInfluxOut(influxdb)
	log.Infof("END: Finished from %s to %s [Duration : %s]", start.String(), time.Now().String(), time.Since(start).String())
	return time.Since(start), nil
}

// ReloadConf call to reinitialize alln configurations
func ReloadConf() (time.Duration, error) {
	start := time.Now()
	if CheckAndSetReloadProcess() == true {
		log.Warning("RELOADCONF: There is another reload process running while trying to reload at %s  ", start.String())
		return time.Since(start), fmt.Errorf("There is another reload process running.... please wait until finished ")
	}

	log.Infof("RELOADCONF INIT: begin device Gather processes stop... at %s", start.String())
	End()

	log.Info("RELOADCONF: loading configuration Again...")
	LoadConf()
	log.Info("RELOADCONF: Starting all device processes again...")
	//Initialize Devices in Runtime map
	DeviceProcessStart()

	log.Infof("RELOADCONF END: Finished from %s to %s [Duration : %s]", start.String(), time.Now().String(), time.Since(start).String())
	CheckAndUnSetReloadProcess()

	return time.Since(start), nil
}
<|endoftext|>


<commit_before>package radosAPI

import (
	"encoding/json"
	"errors"
	"net/url"
	"time"

	"github.com/QuentinPerez/go-encodeUrl"
)

// UsageConfig usage request
type UsageConfig struct {
	UID         string     `url:"uid,ifStringIsNotEmpty"`     // The user for which the information is requested. If not specified will apply to all users
	Start       *time.Time `url:"start,ifTimeIsNotNilCeph"`   // Date and (optional) time that specifies the start time of the requested data
	End         *time.Time `url:"end,ifTimeIsNotNilCeph"`     // Date and (optional) time that specifies the end time of the requested data (non-inclusive)
	ShowEntries bool       `url:"show-entries,ifBoolIsFalse"` // Specifies whether data entries should be returned.
	ShowSummary bool       `url:"show-summary,ifBoolIsFalse"` // Specifies whether data summary should be returned
	RemoveAll   bool       `url:"remove-all,ifBoolIsTrue"`    // Required when uid is not specified, in order to acknowledge multi user data removal.
}

// GetUsage requests bandwidth usage information.
//
// !! caps: usage=read !!
//
// @UID
// @Start
// @End
// @ShowEntries
// @ShowSummary
//
func (api *API) GetUsage(conf UsageConfig) (*Usage, error) {
	var (
		ret    = &Usage{}
		values = url.Values{}
		errs   []error
	)

	values, errs = encurl.Translate(conf)
	if len(errs) > 0 {
		return nil, errs[0]
	}
	values.Add("format", "json")
	body, _, err := api.get("/admin/usage", values)
	if err != nil {
		return nil, err
	}
	if err = json.Unmarshal(body, &ret); err != nil {
		return nil, err
	}
	return ret, nil
}

// DeleteUsage removes usage information. With no dates specified, removes all usage information
//
// !! caps: usage=write !!
//
// @UID
// @Start
// @End
// @RemoveAll
//
func (api *API) DeleteUsage(conf UsageConfig) error {
	var (
		values = url.Values{}
		errs   []error
	)

	values, errs = encurl.Translate(conf)
	if len(errs) > 0 {
		return errs[0]
	}
	values.Add("format", "json")
	_, _, err := api.delete("/admin/usage", values)
	if err != nil {
		return err
	}
	return nil
}

// GetUser gets user information. If no user is specified returns the list of all users along with suspension information
//
// !! caps: users=read !!
//
// @uid
//
func (api *API) GetUser(uid ...string) (*User, error) {
	ret := &User{}
	values := url.Values{}

	values.Add("format", "json")
	if len(uid) != 0 {
		values.Add("uid", uid[0])
	}
	body, _, err := api.get("/admin/user", values)
	if err != nil {
		return nil, err
	}
	if err = json.Unmarshal(body, &ret); err != nil {
		return nil, err
	}
	return ret, nil
}

// UserConfig user request
type UserConfig struct {
	UID         string `url:"uid,ifStringIsNotEmpty"`          // The user ID to be created
	DisplayName string `url:"display-name,ifStringIsNotEmpty"` // The display name of the user to be created
	Email       string `url:"email,ifStringIsNotEmpty"`        // The email address associated with the user
	KeyType     string `url:"key-type,ifStringIsNotEmpty"`     // Key type to be generated, options are: swift, s3 (default)
	AccessKey   string `url:"access-key,ifStringIsNotEmpty"`   // Specify access key
	SecretKey   string `url:"secret-key,ifStringIsNotEmpty"`   // Specify secret key
	UserCaps    string `url:"user-caps,ifStringIsNotEmpty"`    // User capabilities
	GenerateKey bool   `url:"generate-key,ifBoolIsTrue"`       // Generate a new key pair and add to the existing keyring
	MaxBuckets  *int   `url:"max-buckets,itoaIfNotNil"`        // Specify the maximum number of buckets the user can own
	Suspended   bool   `url:"suspended,ifBoolIsTrue"`          // Specify whether the user should be suspended
	PurgeData   bool   `url:"suspended,ifBoolIsTrue"`          // When specified the buckets and objects belonging to the user will also be removed
}

// CreateUser creates a new user. By Default, a S3 key pair will be created automatically and returned in the response.
// If only one of access-key or secret-key is provided, the omitted key will be automatically generated.
// By default, a generated key is added to the keyring without replacing an existing key pair.
// If access-key is specified and refers to an existing key owned by the user then it will be modified
//
// !! caps: users=write !!
//
// @UID
// @DisplayName
// @Email
// @KeyType
// @AccessKey
// @SecretKey
// @UserCaps
// @GenerateKey
// @MaxBuckets
// @Suspended
//
func (api *API) CreateUser(conf UserConfig) (*User, error) {
	if conf.UID == "" {
		return nil, errors.New("UID field is required")
	}
	if conf.DisplayName == "" {
		return nil, errors.New("DisplayName field is required")
	}

	var (
		ret    = &User{}
		values = url.Values{}
		errs   []error
	)

	values, errs = encurl.Translate(conf)
	if len(errs) > 0 {
		return nil, errs[0]
	}
	values.Add("format", "json")
	body, _, err := api.put("/admin/user", values)
	if err != nil {
		return nil, err
	}
	if err = json.Unmarshal(body, &ret); err != nil {
		return nil, err
	}
	return ret, nil
}

// UpdateUser modifies a user
//
// !! caps: users=write !!
//
// @UID
// @DisplayName
// @Email
// @KeyType
// @AccessKey
// @SecretKey
// @UserCaps
// @GenerateKey
// @MaxBuckets
// @Suspended
//
func (api *API) UpdateUser(conf UserConfig) (*User, error) {
	if conf.UID == "" {
		return nil, errors.New("UID field is required")
	}

	var (
		ret    = &User{}
		values = url.Values{}
		errs   []error
	)

	values, errs = encurl.Translate(conf)
	if len(errs) > 0 {
		return nil, errs[0]
	}
	values.Add("format", "json")
	body, _, err := api.post("/admin/user", values)
	if err != nil {
		return nil, err
	}
	if err = json.Unmarshal(body, &ret); err != nil {
		return nil, err
	}
	return ret, nil
}

// RemoveUser removes an existing user.
//
// !! caps: users=write !!
//
// @UID
// @PurgeData
//
func (api *API) RemoveUser(conf UserConfig) error {
	if conf.UID == "" {
		return errors.New("UID field is required")
	}
	var (
		values = url.Values{}
		errs   []error
	)

	values, errs = encurl.Translate(conf)
	if len(errs) > 0 {
		return errs[0]
	}
	values.Add("format", "json")
	_, _, err := api.delete("/admin/user", values)
	if err != nil {
		return err
	}
	return nil
}

// SubUserConfig subuser request
type SubUserConfig struct {
	UID            string `url:"uid,ifStringIsNotEmpty"`        // The user ID under which a subuser is to be created
	SubUser        string `url:"subuser,ifStringIsNotEmpty"`    // Specify the subuser ID to be created
	KeyType        string `url:"key-type,ifStringIsNotEmpty"`   // Key type to be generated, options are: swift (default), s3
	Access         string `url:"access,ifStringIsNotEmpty"`     // Set access permissions for sub-user, should be one of read, write, readwrite, full
	Secret         string `url:"secret,ifStringIsNotEmpty"`     // Specify secret key
	SecretKey      string `url:"secret-key,ifStringIsNotEmpty"` // Specify secret key
	GenerateSecret bool   `url:"generate-secret,ifBoolIsTrue"`  // Generate the secret key
	PurgeKeys      bool   `url:"purge-keys,ifBoolIsTrue"`       // Remove keys belonging to the subuser
}

// CreateSubUser creates a new subuser (primarily useful for clients using the Swift API).
// Note that either gen-subuser or subuser is required for a valid request.
// Note that in general for a subuser to be useful, it must be granted permissions by specifying access.
// As with user creation if subuser is specified without secret, then a secret key will be automatically generated.
//
// !! caps:	users=write !!
//
// @UID
// @SubUser
// @KeyType
// @Access
// @SecretKey
// @GenerateSecret
//
func (api *API) CreateSubUser(conf SubUserConfig) (*SubUsers, error) {
	if conf.UID == "" {
		return nil, errors.New("UID field is required")
	}

	var (
		ret    = &SubUsers{}
		values = url.Values{}
		errs   []error
	)

	values, errs = encurl.Translate(conf)
	if len(errs) > 0 {
		return nil, errs[0]
	}
	values.Add("format", "json")
	body, _, err := api.put("/admin/user", values, "subuser")
	if err != nil {
		return nil, err
	}
	if err = json.Unmarshal(body, &ret); err != nil {
		return nil, err
	}
	return ret, nil
}

// UpdateSubUser modifies an existing subuser
//
// !! caps:	users=write !!
//
// @UID
// @SubUser
// @KeyType
// @Access
// @Secret
// @GenerateSecret
//
func (api *API) UpdateSubUser(conf SubUserConfig) (*SubUsers, error) {
	if conf.UID == "" {
		return nil, errors.New("UID field is required")
	}
	if conf.SubUser == "" {
		return nil, errors.New("SubUser field is required")
	}

	var (
		ret    = &SubUsers{}
		values = url.Values{}
		errs   []error
	)

	values, errs = encurl.Translate(conf)
	if len(errs) > 0 {
		return nil, errs[0]
	}
	values.Add("format", "json")
	body, _, err := api.post("/admin/user", values, "subuser")
	if err != nil {
		return nil, err
	}
	if err = json.Unmarshal(body, &ret); err != nil {
		return nil, err
	}
	return ret, nil
}

// RemoveSubUser remove an existing subuser
//
// !! caps:	users=write !!
//
// @UID
// @SubUser
// @PurgeKeys
//
func (api *API) RemoveSubUser(conf SubUserConfig) error {
	if conf.UID == "" {
		return errors.New("UID field is required")
	}
	if conf.SubUser == "" {
		return errors.New("SubUser field is required")
	}
	var (
		values = url.Values{}
		errs   []error
	)

	values, errs = encurl.Translate(conf)
	if len(errs) > 0 {
		return errs[0]
	}
	values.Add("format", "json")
	_, _, err := api.delete("/admin/user", values, "subuser")
	if err != nil {
		return err
	}
	return nil

}
<commit_msg>Add CreateKeys<commit_after>package radosAPI

import (
	"encoding/json"
	"errors"
	"net/url"
	"time"

	"github.com/QuentinPerez/go-encodeUrl"
)

// UsageConfig usage request
type UsageConfig struct {
	UID         string     `url:"uid,ifStringIsNotEmpty"`     // The user for which the information is requested. If not specified will apply to all users
	Start       *time.Time `url:"start,ifTimeIsNotNilCeph"`   // Date and (optional) time that specifies the start time of the requested data
	End         *time.Time `url:"end,ifTimeIsNotNilCeph"`     // Date and (optional) time that specifies the end time of the requested data (non-inclusive)
	ShowEntries bool       `url:"show-entries,ifBoolIsFalse"` // Specifies whether data entries should be returned.
	ShowSummary bool       `url:"show-summary,ifBoolIsFalse"` // Specifies whether data summary should be returned
	RemoveAll   bool       `url:"remove-all,ifBoolIsTrue"`    // Required when uid is not specified, in order to acknowledge multi user data removal.
}

// GetUsage requests bandwidth usage information.
//
// !! caps: usage=read !!
//
// @UID
// @Start
// @End
// @ShowEntries
// @ShowSummary
//
func (api *API) GetUsage(conf UsageConfig) (*Usage, error) {
	var (
		ret    = &Usage{}
		values = url.Values{}
		errs   []error
	)

	values, errs = encurl.Translate(conf)
	if len(errs) > 0 {
		return nil, errs[0]
	}
	values.Add("format", "json")
	body, _, err := api.get("/admin/usage", values)
	if err != nil {
		return nil, err
	}
	if err = json.Unmarshal(body, &ret); err != nil {
		return nil, err
	}
	return ret, nil
}

// DeleteUsage removes usage information. With no dates specified, removes all usage information
//
// !! caps: usage=write !!
//
// @UID
// @Start
// @End
// @RemoveAll
//
func (api *API) DeleteUsage(conf UsageConfig) error {
	var (
		values = url.Values{}
		errs   []error
	)

	values, errs = encurl.Translate(conf)
	if len(errs) > 0 {
		return errs[0]
	}
	values.Add("format", "json")
	_, _, err := api.delete("/admin/usage", values)
	if err != nil {
		return err
	}
	return nil
}

// GetUser gets user information. If no user is specified returns the list of all users along with suspension information
//
// !! caps: users=read !!
//
// @uid
//
func (api *API) GetUser(uid ...string) (*User, error) {
	ret := &User{}
	values := url.Values{}

	values.Add("format", "json")
	if len(uid) != 0 {
		values.Add("uid", uid[0])
	}
	body, _, err := api.get("/admin/user", values)
	if err != nil {
		return nil, err
	}
	if err = json.Unmarshal(body, &ret); err != nil {
		return nil, err
	}
	return ret, nil
}

// UserConfig user request
type UserConfig struct {
	UID         string `url:"uid,ifStringIsNotEmpty"`          // The user ID to be created
	DisplayName string `url:"display-name,ifStringIsNotEmpty"` // The display name of the user to be created
	Email       string `url:"email,ifStringIsNotEmpty"`        // The email address associated with the user
	KeyType     string `url:"key-type,ifStringIsNotEmpty"`     // Key type to be generated, options are: swift, s3 (default)
	AccessKey   string `url:"access-key,ifStringIsNotEmpty"`   // Specify access key
	SecretKey   string `url:"secret-key,ifStringIsNotEmpty"`   // Specify secret key
	UserCaps    string `url:"user-caps,ifStringIsNotEmpty"`    // User capabilities
	GenerateKey bool   `url:"generate-key,ifBoolIsTrue"`       // Generate a new key pair and add to the existing keyring
	MaxBuckets  *int   `url:"max-buckets,itoaIfNotNil"`        // Specify the maximum number of buckets the user can own
	Suspended   bool   `url:"suspended,ifBoolIsTrue"`          // Specify whether the user should be suspended
	PurgeData   bool   `url:"suspended,ifBoolIsTrue"`          // When specified the buckets and objects belonging to the user will also be removed
}

// CreateUser creates a new user. By Default, a S3 key pair will be created automatically and returned in the response.
// If only one of access-key or secret-key is provided, the omitted key will be automatically generated.
// By default, a generated key is added to the keyring without replacing an existing key pair.
// If access-key is specified and refers to an existing key owned by the user then it will be modified
//
// !! caps: users=write !!
//
// @UID
// @DisplayName
// @Email
// @KeyType
// @AccessKey
// @SecretKey
// @UserCaps
// @GenerateKey
// @MaxBuckets
// @Suspended
//
func (api *API) CreateUser(conf UserConfig) (*User, error) {
	if conf.UID == "" {
		return nil, errors.New("UID field is required")
	}
	if conf.DisplayName == "" {
		return nil, errors.New("DisplayName field is required")
	}

	var (
		ret    = &User{}
		values = url.Values{}
		errs   []error
	)

	values, errs = encurl.Translate(conf)
	if len(errs) > 0 {
		return nil, errs[0]
	}
	values.Add("format", "json")
	body, _, err := api.put("/admin/user", values)
	if err != nil {
		return nil, err
	}
	if err = json.Unmarshal(body, &ret); err != nil {
		return nil, err
	}
	return ret, nil
}

// UpdateUser modifies a user
//
// !! caps: users=write !!
//
// @UID
// @DisplayName
// @Email
// @KeyType
// @AccessKey
// @SecretKey
// @UserCaps
// @GenerateKey
// @MaxBuckets
// @Suspended
//
func (api *API) UpdateUser(conf UserConfig) (*User, error) {
	if conf.UID == "" {
		return nil, errors.New("UID field is required")
	}

	var (
		ret    = &User{}
		values = url.Values{}
		errs   []error
	)

	values, errs = encurl.Translate(conf)
	if len(errs) > 0 {
		return nil, errs[0]
	}
	values.Add("format", "json")
	body, _, err := api.post("/admin/user", values)
	if err != nil {
		return nil, err
	}
	if err = json.Unmarshal(body, &ret); err != nil {
		return nil, err
	}
	return ret, nil
}

// RemoveUser removes an existing user.
//
// !! caps: users=write !!
//
// @UID
// @PurgeData
//
func (api *API) RemoveUser(conf UserConfig) error {
	if conf.UID == "" {
		return errors.New("UID field is required")
	}
	var (
		values = url.Values{}
		errs   []error
	)

	values, errs = encurl.Translate(conf)
	if len(errs) > 0 {
		return errs[0]
	}
	values.Add("format", "json")
	_, _, err := api.delete("/admin/user", values)
	if err != nil {
		return err
	}
	return nil
}

// SubUserConfig subuser request
type SubUserConfig struct {
	UID            string `url:"uid,ifStringIsNotEmpty"`        // The user ID under which a subuser is to be created
	SubUser        string `url:"subuser,ifStringIsNotEmpty"`    // Specify the subuser ID to be created
	KeyType        string `url:"key-type,ifStringIsNotEmpty"`   // Key type to be generated, options are: swift (default), s3
	Access         string `url:"access,ifStringIsNotEmpty"`     // Set access permissions for sub-user, should be one of read, write, readwrite, full
	Secret         string `url:"secret,ifStringIsNotEmpty"`     // Specify secret key
	SecretKey      string `url:"secret-key,ifStringIsNotEmpty"` // Specify secret key
	GenerateSecret bool   `url:"generate-secret,ifBoolIsTrue"`  // Generate the secret key
	PurgeKeys      bool   `url:"purge-keys,ifBoolIsTrue"`       // Remove keys belonging to the subuser
}

// CreateSubUser creates a new subuser (primarily useful for clients using the Swift API).
// Note that either gen-subuser or subuser is required for a valid request.
// Note that in general for a subuser to be useful, it must be granted permissions by specifying access.
// As with user creation if subuser is specified without secret, then a secret key will be automatically generated.
//
// !! caps:	users=write !!
//
// @UID
// @SubUser
// @KeyType
// @Access
// @SecretKey
// @GenerateSecret
//
func (api *API) CreateSubUser(conf SubUserConfig) (*SubUsers, error) {
	if conf.UID == "" {
		return nil, errors.New("UID field is required")
	}

	var (
		ret    = &SubUsers{}
		values = url.Values{}
		errs   []error
	)

	values, errs = encurl.Translate(conf)
	if len(errs) > 0 {
		return nil, errs[0]
	}
	values.Add("format", "json")
	body, _, err := api.put("/admin/user", values, "subuser")
	if err != nil {
		return nil, err
	}
	if err = json.Unmarshal(body, &ret); err != nil {
		return nil, err
	}
	return ret, nil
}

// UpdateSubUser modifies an existing subuser
//
// !! caps:	users=write !!
//
// @UID
// @SubUser
// @KeyType
// @Access
// @Secret
// @GenerateSecret
//
func (api *API) UpdateSubUser(conf SubUserConfig) (*SubUsers, error) {
	if conf.UID == "" {
		return nil, errors.New("UID field is required")
	}
	if conf.SubUser == "" {
		return nil, errors.New("SubUser field is required")
	}

	var (
		ret    = &SubUsers{}
		values = url.Values{}
		errs   []error
	)

	values, errs = encurl.Translate(conf)
	if len(errs) > 0 {
		return nil, errs[0]
	}
	values.Add("format", "json")
	body, _, err := api.post("/admin/user", values, "subuser")
	if err != nil {
		return nil, err
	}
	if err = json.Unmarshal(body, &ret); err != nil {
		return nil, err
	}
	return ret, nil
}

// RemoveSubUser remove an existing subuser
//
// !! caps:	users=write !!
//
// @UID
// @SubUser
// @PurgeKeys
//
func (api *API) RemoveSubUser(conf SubUserConfig) error {
	if conf.UID == "" {
		return errors.New("UID field is required")
	}
	if conf.SubUser == "" {
		return errors.New("SubUser field is required")
	}
	var (
		values = url.Values{}
		errs   []error
	)

	values, errs = encurl.Translate(conf)
	if len(errs) > 0 {
		return errs[0]
	}
	values.Add("format", "json")
	_, _, err := api.delete("/admin/user", values, "subuser")
	if err != nil {
		return err
	}
	return nil

}

// KeyConfig key request
type KeyConfig struct {
	UID            string `url:"uid,ifStringIsNotEmpty"`        // The user ID to receive the new key
	SubUser        string `url:"subuser,ifStringIsNotEmpty"`    // The subuser ID to receive the new key
	KeyType        string `url:"key-type,ifStringIsNotEmpty"`   // Key type to be generated, options are: swift, s3 (default)
	AccessKey      string `url:"access-key,ifStringIsNotEmpty"` // Specify the access key
	SecretKey      string `url:"secret-key,ifStringIsNotEmpty"` // Specify secret key
	GenerateSecret bool   `url:"generate-secret,ifBoolIsTrue"`  // Generate a new key pair and add to the existing keyring
}

// CreateKey creates a new key. If a subuser is specified then by default created keys will be swift type.
// If only one of access-key or secret-key is provided the committed key will be automatically generated,
// that is if only secret-key is specified then access-key will be automatically generated.
// By default, a generated key is added to the keyring without replacing an existing key pair.
// If access-key is specified and refers to an existing key owned by the user then it will be modified.
// The response is a container listing all keys of the same type as the key created.
// Note that when creating a swift key, specifying the option access-key will have no effect.
// Additionally, only one swift key may be held by each user or subuser.
//
// !! caps:	users=write !!
//
func (api *API) CreateKey(conf KeyConfig) (*KeysDefinition, error) {
	if conf.UID == "" {
		return nil, errors.New("UID field is required")
	}

	var (
		ret    = &KeysDefinition{}
		values = url.Values{}
		errs   []error
	)

	values, errs = encurl.Translate(conf)
	if len(errs) > 0 {
		return nil, errs[0]
	}
	values.Add("format", "json")
	body, _, err := api.put("/admin/user", values, "key")
	if err != nil {
		return nil, err
	}
	if err = json.Unmarshal(body, &ret); err != nil {
		return nil, err
	}
	return ret, nil
}
<|endoftext|>


<commit_before>package asset

import (
	"encoding/json"
	"io/ioutil"
	"os"
	"path/filepath"
	"reflect"

	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"
)

const (
	stateFileName = ".openshift_install_state.json"
)

// Store is a store for the states of assets.
type Store interface {
	// Fetch retrieves the state of the given asset, generating it and its
	// dependencies if necessary.
	Fetch(Asset) error
}

// StoreImpl is the implementation of Store.
type StoreImpl struct {
	assets          map[reflect.Type]Asset
	stateFileAssets map[string]json.RawMessage
}

// Fetch retrieves the state of the given asset, generating it and its
// dependencies if necessary.
func (s *StoreImpl) Fetch(asset Asset) error {
	return s.fetch(asset, "")
}

// Load retrieves the state from the state file present in the given directory
// and returns the assets map
func (s *StoreImpl) Load(dir string) error {
	path := filepath.Join(dir, stateFileName)
	assets := make(map[string]json.RawMessage)
	data, err := ioutil.ReadFile(path)
	if err != nil {
		if os.IsNotExist(err) {
			return nil
		}
		return err
	}
	err = json.Unmarshal(data, &assets)
	if err != nil {
		return errors.Wrapf(err, "failed to unmarshal state file %s", path)
	}
	s.stateFileAssets = assets
	return nil
}

// GetStateAsset renders the asset object arguments from the state file contents
// also returns a boolean indicating whether the object was found in the state file or not
func (s *StoreImpl) GetStateAsset(asset Asset) (bool, error) {
	bytes, ok := s.stateFileAssets[reflect.TypeOf(asset).String()]
	if !ok {
		return false, nil
	}
	err := json.Unmarshal(bytes, asset)
	return true, err
}

// Save dumps the entire state map into a file
func (s *StoreImpl) Save(dir string) error {
	assetMap := make(map[string]Asset)
	for k, v := range s.assets {
		assetMap[k.String()] = v
	}
	data, err := json.MarshalIndent(&assetMap, "", "    ")
	if err != nil {
		return err
	}

	path := filepath.Join(dir, stateFileName)
	if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil {
		return err
	}
	if err := ioutil.WriteFile(path, data, 0644); err != nil {
		return err
	}
	return nil
}

func (s *StoreImpl) fetch(asset Asset, indent string) error {
	logrus.Debugf("%sFetching %s...", indent, asset.Name())
	storedAsset, ok := s.assets[reflect.TypeOf(asset)]
	if ok {
		logrus.Debugf("%sFound %s...", indent, asset.Name())
		reflect.ValueOf(asset).Elem().Set(reflect.ValueOf(storedAsset).Elem())
		return nil
	}

	dependencies := asset.Dependencies()
	parents := make(Parents, len(dependencies))
	if len(dependencies) > 0 {
		logrus.Debugf("%sGenerating dependencies of %s...", indent, asset.Name())
	}
	for _, d := range dependencies {
		err := s.fetch(d, indent+"  ")
		if err != nil {
			return errors.Wrapf(err, "failed to fetch dependency for %s", asset.Name())
		}
		parents.Add(d)
	}

	// Before generating the asset, look if we have it all ready in the state file
	// if yes, then use it instead
	logrus.Debugf("%sLooking up asset from state file: %s", indent, reflect.TypeOf(asset).String())
	ok, err := s.GetStateAsset(asset)
	if err != nil {
		return errors.Wrapf(err, "failed to unmarshal asset '%s' from state file '%s'", asset.Name(), stateFileName)
	}
	if ok {
		logrus.Debugf("%sAsset found in state file", indent)
	} else {
		logrus.Debugf("%sAsset not found in state file. Generating %s...", indent, asset.Name())
		err := asset.Generate(parents)
		if err != nil {
			return errors.Wrapf(err, "failed to generate asset %s", asset.Name())
		}
	}
	if s.assets == nil {
		s.assets = make(map[reflect.Type]Asset)
	}
	s.assets[reflect.TypeOf(asset)] = asset
	return nil
}
<commit_msg>pkg/asset/store: Use '%q' for formatting quoted strings<commit_after>package asset

import (
	"encoding/json"
	"io/ioutil"
	"os"
	"path/filepath"
	"reflect"

	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"
)

const (
	stateFileName = ".openshift_install_state.json"
)

// Store is a store for the states of assets.
type Store interface {
	// Fetch retrieves the state of the given asset, generating it and its
	// dependencies if necessary.
	Fetch(Asset) error
}

// StoreImpl is the implementation of Store.
type StoreImpl struct {
	assets          map[reflect.Type]Asset
	stateFileAssets map[string]json.RawMessage
}

// Fetch retrieves the state of the given asset, generating it and its
// dependencies if necessary.
func (s *StoreImpl) Fetch(asset Asset) error {
	return s.fetch(asset, "")
}

// Load retrieves the state from the state file present in the given directory
// and returns the assets map
func (s *StoreImpl) Load(dir string) error {
	path := filepath.Join(dir, stateFileName)
	assets := make(map[string]json.RawMessage)
	data, err := ioutil.ReadFile(path)
	if err != nil {
		if os.IsNotExist(err) {
			return nil
		}
		return err
	}
	err = json.Unmarshal(data, &assets)
	if err != nil {
		return errors.Wrapf(err, "failed to unmarshal state file %s", path)
	}
	s.stateFileAssets = assets
	return nil
}

// GetStateAsset renders the asset object arguments from the state file contents
// also returns a boolean indicating whether the object was found in the state file or not
func (s *StoreImpl) GetStateAsset(asset Asset) (bool, error) {
	bytes, ok := s.stateFileAssets[reflect.TypeOf(asset).String()]
	if !ok {
		return false, nil
	}
	err := json.Unmarshal(bytes, asset)
	return true, err
}

// Save dumps the entire state map into a file
func (s *StoreImpl) Save(dir string) error {
	assetMap := make(map[string]Asset)
	for k, v := range s.assets {
		assetMap[k.String()] = v
	}
	data, err := json.MarshalIndent(&assetMap, "", "    ")
	if err != nil {
		return err
	}

	path := filepath.Join(dir, stateFileName)
	if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil {
		return err
	}
	if err := ioutil.WriteFile(path, data, 0644); err != nil {
		return err
	}
	return nil
}

func (s *StoreImpl) fetch(asset Asset, indent string) error {
	logrus.Debugf("%sFetching %s...", indent, asset.Name())
	storedAsset, ok := s.assets[reflect.TypeOf(asset)]
	if ok {
		logrus.Debugf("%sFound %s...", indent, asset.Name())
		reflect.ValueOf(asset).Elem().Set(reflect.ValueOf(storedAsset).Elem())
		return nil
	}

	dependencies := asset.Dependencies()
	parents := make(Parents, len(dependencies))
	if len(dependencies) > 0 {
		logrus.Debugf("%sGenerating dependencies of %s...", indent, asset.Name())
	}
	for _, d := range dependencies {
		err := s.fetch(d, indent+"  ")
		if err != nil {
			return errors.Wrapf(err, "failed to fetch dependency for %s", asset.Name())
		}
		parents.Add(d)
	}

	// Before generating the asset, look if we have it all ready in the state file
	// if yes, then use it instead
	logrus.Debugf("%sLooking up asset from state file: %s", indent, reflect.TypeOf(asset).String())
	ok, err := s.GetStateAsset(asset)
	if err != nil {
		return errors.Wrapf(err, "failed to unmarshal asset %q from state file %q", asset.Name(), stateFileName)
	}
	if ok {
		logrus.Debugf("%sAsset found in state file", indent)
	} else {
		logrus.Debugf("%sAsset not found in state file. Generating %s...", indent, asset.Name())
		err := asset.Generate(parents)
		if err != nil {
			return errors.Wrapf(err, "failed to generate asset %s", asset.Name())
		}
	}
	if s.assets == nil {
		s.assets = make(map[reflect.Type]Asset)
	}
	s.assets[reflect.TypeOf(asset)] = asset
	return nil
}
<|endoftext|>