1// Copyright 2017-2018 VMware, Inc. All Rights Reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//    http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package mock
16
17import (
18	"fmt"
19	"io"
20	"net/url"
21	"os"
22
23	"github.com/vmware/govmomi/object"
24	"github.com/vmware/govmomi/vim25/mo"
25	"github.com/vmware/vic/lib/portlayer/storage/image"
26	"github.com/vmware/vic/lib/portlayer/util"
27	"github.com/vmware/vic/pkg/trace"
28	"github.com/vmware/vic/pkg/vsphere/vm"
29)
30
31type MockDataStore struct {
32	object.DatastorePath
33
34	// id -> image
35	db map[url.URL]map[string]*image.Image
36
37	createImageStoreError error
38	writeImageError       error
39}
40
41func NewMockDataStore(images map[url.URL]map[string]*image.Image) *MockDataStore {
42	m := &MockDataStore{
43		db: images,
44	}
45
46	if m.db == nil {
47		m.db = make(map[url.URL]map[string]*image.Image)
48	}
49
50	return m
51}
52
53// SetWriteImageError injects an error to be returned on next call to WriteImage
54func (c *MockDataStore) SetWriteImageError(err error) {
55	c.writeImageError = err
56}
57
58// SetCreateImageStoreError injects an error to be returned on next call to CreateImageStore
59func (c *MockDataStore) SetCreateImageStoreError(err error) {
60	c.createImageStoreError = err
61}
62
63// GetImageStore checks to see if a named image store exists and returls the
64// URL to it if so or error.
65func (c *MockDataStore) GetImageStore(op trace.Operation, storeName string) (*url.URL, error) {
66	u, err := util.ImageStoreNameToURL(storeName)
67	if err != nil {
68		return nil, err
69	}
70
71	if _, ok := c.db[*u]; !ok {
72		return nil, os.ErrNotExist
73	}
74
75	return u, nil
76}
77
78func (c *MockDataStore) CreateImageStore(op trace.Operation, storeName string) (*url.URL, error) {
79	if c.createImageStoreError != nil {
80		return nil, c.createImageStoreError
81	}
82
83	u, err := util.ImageStoreNameToURL(storeName)
84	if err != nil {
85		return nil, err
86	}
87
88	c.db[*u] = make(map[string]*image.Image)
89	return u, nil
90}
91
92func (c *MockDataStore) DeleteImageStore(op trace.Operation, storeName string) error {
93	u, err := util.ImageStoreNameToURL(storeName)
94	if err != nil {
95		return err
96	}
97
98	c.db[*u] = nil
99	return nil
100}
101
102func (c *MockDataStore) ListImageStores(op trace.Operation) ([]*url.URL, error) {
103	stores := make([]*url.URL, len(c.db))
104	i := 0
105	for k := range c.db {
106		stores[i] = &k
107		i++
108	}
109
110	return stores, nil
111}
112
113func (c *MockDataStore) URL(op trace.Operation, id string) (*url.URL, error) {
114	return nil, nil
115}
116
117func (c *MockDataStore) Owners(op trace.Operation, url *url.URL, filter func(vm *mo.VirtualMachine) bool) ([]*vm.VirtualMachine, error) {
118	return nil, nil
119}
120
121func (c *MockDataStore) WriteImage(op trace.Operation, parent *image.Image, ID string, meta map[string][]byte, sum string, r io.Reader) (*image.Image, error) {
122	if c.writeImageError != nil {
123		op.Infof("WriteImage: returning error")
124		return nil, c.writeImageError
125	}
126
127	storeName, err := util.ImageStoreName(parent.Store)
128	if err != nil {
129		return nil, err
130	}
131
132	selflink, err := util.ImageURL(storeName, ID)
133	if err != nil {
134		return nil, err
135	}
136
137	var parentLink *url.URL
138	if parent.ID != "" {
139		parentLink, err = util.ImageURL(storeName, parent.ID)
140		if err != nil {
141			return nil, err
142		}
143	}
144
145	i := &image.Image{
146		ID:         ID,
147		Store:      parent.Store,
148		ParentLink: parentLink,
149		SelfLink:   selflink,
150		Metadata:   meta,
151		DatastorePath: &object.DatastorePath{
152			Datastore: c.Datastore,
153			Path:      c.Path,
154		},
155	}
156
157	c.db[*parent.Store][ID] = i
158
159	return i, nil
160}
161
162func (c *MockDataStore) WriteMetadata(op trace.Operation, storeName string, ID string, meta map[string][]byte) error {
163	return nil
164}
165
166// GetImage gets the specified image from the given store by retreiving it from the cache.
167func (c *MockDataStore) GetImage(op trace.Operation, store *url.URL, ID string) (*image.Image, error) {
168	i, ok := c.db[*store][ID]
169	if !ok {
170		return nil, fmt.Errorf("not found")
171	}
172	return i, nil
173}
174
175// ListImages resturns a list of Images for a list of IDs, or all if no IDs are passed
176func (c *MockDataStore) ListImages(op trace.Operation, store *url.URL, IDs []string) ([]*image.Image, error) {
177	var imageList []*image.Image
178	for _, i := range c.db[*store] {
179		imageList = append(imageList, i)
180	}
181	return imageList, nil
182}
183
184// DeleteImage removes an image from the image store
185func (c *MockDataStore) DeleteImage(op trace.Operation, image *image.Image) (*image.Image, error) {
186	delete(c.db[*image.Store], image.ID)
187	return image, nil
188}
189
190func (c *MockDataStore) GetImageStorageUsage(op trace.Operation, storeName string) (int64, error) {
191	return 0, nil
192}
193
194func (c *MockDataStore) GetImageLayerStorageUsage(op trace.Operation, storeName, ID string) (int64, error) {
195	return 0, nil
196}
197